mirror of
https://github.com/sle118/squeezelite-esp32.git
synced 2025-12-06 19:47:02 +03:00
Compare commits
547 Commits
developmen
...
I2S-4MFlas
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
68a9970bed | ||
|
|
4a666af681 | ||
|
|
60ba05d3d9 | ||
|
|
099d9ffd1e | ||
|
|
3d30b45723 | ||
|
|
87fae72887 | ||
|
|
1f78db596e | ||
|
|
c0bd080ea1 | ||
|
|
29d4214e28 | ||
|
|
b828e7f3e6 | ||
|
|
6843d4b1ef | ||
|
|
78877914ef | ||
|
|
dbcaf15e7b | ||
|
|
4f318e217f | ||
|
|
270ee819ea | ||
|
|
ace8206b4d | ||
|
|
564e98d90e | ||
|
|
796d39d0a9 | ||
|
|
20c00de728 | ||
|
|
9775fd52b8 | ||
|
|
7a04ec03e9 | ||
|
|
3d8c3ae776 | ||
|
|
7bfaa05ad2 | ||
|
|
f813ad62e4 | ||
|
|
ebedbabf6e | ||
|
|
4c869975a8 | ||
|
|
297859a442 | ||
|
|
ed457a287c | ||
|
|
a2517374e7 | ||
|
|
455b2d0e66 | ||
|
|
2af8f6a55f | ||
|
|
6a68fd4dad | ||
|
|
2d96ed82d1 | ||
|
|
dbdd0739db | ||
|
|
964b94fa1e | ||
|
|
5830f72554 | ||
|
|
ff824ddacd | ||
|
|
34e7433905 | ||
|
|
2f70d0df31 | ||
|
|
946a564dcc | ||
|
|
413ebcb912 | ||
|
|
b93f97c52b | ||
|
|
411b2bd0f0 | ||
|
|
f613da5356 | ||
|
|
ac7ba228e8 | ||
|
|
94fe9b0acf | ||
|
|
86953fff14 | ||
|
|
4b704faaf3 | ||
|
|
1a8ab21b59 | ||
|
|
015ba4f970 | ||
|
|
8c61f9c18d | ||
|
|
58dc607f55 | ||
|
|
57cd86f538 | ||
|
|
ade446a102 | ||
|
|
10e36b0599 | ||
|
|
a4d2017a07 | ||
|
|
a16a1678e5 | ||
|
|
a39c4ab58f | ||
|
|
7dfab25cb4 | ||
|
|
df777e83d1 | ||
|
|
d0461d55e4 | ||
|
|
1c071d03dd | ||
|
|
0d142e7515 | ||
|
|
417b683401 | ||
|
|
e8f8239ee3 | ||
|
|
9789bef653 | ||
|
|
d2f8d51c28 | ||
|
|
1ee0a232f4 | ||
|
|
0d411d7295 | ||
|
|
fff5a6bf03 | ||
|
|
bf9410904d | ||
|
|
fed174a062 | ||
|
|
efc2c9515c | ||
|
|
29b3eee5b6 | ||
|
|
20a04550a8 | ||
|
|
c95302def1 | ||
|
|
e9890227a4 | ||
|
|
b3eec4b7d9 | ||
|
|
6c0e4fc589 | ||
|
|
16ec4c0d57 | ||
|
|
b13fa88033 | ||
|
|
de86a10d82 | ||
|
|
7f57cd5338 | ||
|
|
975f34f01b | ||
|
|
f872623785 | ||
|
|
326ddb6973 | ||
|
|
1c92fdcc96 | ||
|
|
828a36a9d1 | ||
|
|
f330314795 | ||
|
|
3b6299dc1a | ||
|
|
2055025468 | ||
|
|
458d7eacbe | ||
|
|
a266c07114 | ||
|
|
412880d628 | ||
|
|
518c2d24e9 | ||
|
|
7b361a0c2c | ||
|
|
333b295471 | ||
|
|
a60cbe53e2 | ||
|
|
5d255ea502 | ||
|
|
344730e1bc | ||
|
|
af7c181063 | ||
|
|
cf3393e76a | ||
|
|
4474c4378a | ||
|
|
f8079ea9e2 | ||
|
|
af48710e31 | ||
|
|
a59e1d9e54 | ||
|
|
65a1b4d7f3 | ||
|
|
a9efcfeca8 | ||
|
|
f38c2b8cb4 | ||
|
|
5ac153f808 | ||
|
|
ec6dcb83f8 | ||
|
|
16ba8e9e1f | ||
|
|
baaabb7d99 | ||
|
|
d2494b73db | ||
|
|
f8bfb807d9 | ||
|
|
30a891ffc8 | ||
|
|
1649a7e2a0 | ||
|
|
2fbea79a5b | ||
|
|
9f9f171c9a | ||
|
|
eebbf76466 | ||
|
|
2a9d87b6c5 | ||
|
|
f655244039 | ||
|
|
034f64c62a | ||
|
|
9848f2d7d7 | ||
|
|
c0f5ca1e10 | ||
|
|
559f4ce69f | ||
|
|
cde936eb60 | ||
|
|
652b921059 | ||
|
|
6fb458eff7 | ||
|
|
3b9ef05c6e | ||
|
|
970c72d416 | ||
|
|
f7a7ece582 | ||
|
|
5c99ab56f9 | ||
|
|
62b0b1fac0 | ||
|
|
4ee36c24f4 | ||
|
|
3d123e86ac | ||
|
|
507c2c9755 | ||
|
|
016bc1bb4d | ||
|
|
17a3058b23 | ||
|
|
92260f939d | ||
|
|
bbca38aaec | ||
|
|
ec860480a9 | ||
|
|
d4fa8638d7 | ||
|
|
c2f3e225d2 | ||
|
|
bc0783f7b9 | ||
|
|
8de6a5de68 | ||
|
|
a07cdbf3b5 | ||
|
|
a8521223c9 | ||
|
|
ada74ab127 | ||
|
|
4943df2ec7 | ||
|
|
9588ae9f39 | ||
|
|
c0c37bd98a | ||
|
|
d5a8e3a4a2 | ||
|
|
d4b0bc4edb | ||
|
|
635d382d71 | ||
|
|
5d09d4f853 | ||
|
|
33c4c1fb31 | ||
|
|
e0d76281df | ||
|
|
b3e67a8571 | ||
|
|
1e36180f05 | ||
|
|
08b22504bc | ||
|
|
c236044228 | ||
|
|
faa9976d3d | ||
|
|
1dbffe6753 | ||
|
|
8e5dbd2144 | ||
|
|
974ff5fa68 | ||
|
|
4dce4b307b | ||
|
|
4aa54537e5 | ||
|
|
d27a430664 | ||
|
|
0fa41e5ef7 | ||
|
|
2146014f04 | ||
|
|
7d409668c8 | ||
|
|
0ebce7472b | ||
|
|
5f5466fcb0 | ||
|
|
71911914cb | ||
|
|
4f6dcc2cc7 | ||
|
|
f4615462c7 | ||
|
|
6033c7fc14 | ||
|
|
a98b1d00b0 | ||
|
|
1e45348e4a | ||
|
|
96a05d8a6b | ||
|
|
7a9f3e0781 | ||
|
|
3575245324 | ||
|
|
c36d663a7f | ||
|
|
13294ddd0c | ||
|
|
449ef32a4e | ||
|
|
50390dbc61 | ||
|
|
fc5f3f5ac9 | ||
|
|
6f4ed0679e | ||
|
|
511df0b4b8 | ||
|
|
6682ee947e | ||
|
|
813e7ee712 | ||
|
|
6c9537e259 | ||
|
|
ac9ad2eee2 | ||
|
|
f38840bbe0 | ||
|
|
fd56f649ab | ||
|
|
c4bd320afe | ||
|
|
5e8978d1af | ||
|
|
6e082a5654 | ||
|
|
5af3250aea | ||
|
|
527187b2f8 | ||
|
|
102d2f6af5 | ||
|
|
4edd429b0a | ||
|
|
35099d1131 | ||
|
|
ce9c3952e8 | ||
|
|
4ee6352185 | ||
|
|
3a720a1e7d | ||
|
|
987fa5d18c | ||
|
|
23c936ec93 | ||
|
|
d4f10a761e | ||
|
|
d68d163538 | ||
|
|
94580c6771 | ||
|
|
2717277c6e | ||
|
|
b6d537a207 | ||
|
|
cf047c8098 | ||
|
|
21f3768ada | ||
|
|
9cb18fa980 | ||
|
|
d4f6289500 | ||
|
|
21c3ce1fba | ||
|
|
48e8525ba9 | ||
|
|
0db9631700 | ||
|
|
192cb975e2 | ||
|
|
d1f6085199 | ||
|
|
afaa5323d7 | ||
|
|
f92447e9b9 | ||
|
|
22f8d1d88b | ||
|
|
8136b7fd9a | ||
|
|
e588deb3af | ||
|
|
38ec8ac6f8 | ||
|
|
791167f794 | ||
|
|
c9b859ef8c | ||
|
|
db74419bd7 | ||
|
|
265403d364 | ||
|
|
d3dd8b9078 | ||
|
|
de41fb9583 | ||
|
|
2699216d25 | ||
|
|
c7b1c7cd83 | ||
|
|
f51af21b90 | ||
|
|
5ec63f400c | ||
|
|
1753e11698 | ||
|
|
58c6ca059b | ||
|
|
5ef63dc3e4 | ||
|
|
468c847499 | ||
|
|
8c0e766cd7 | ||
|
|
0f792d71ee | ||
|
|
1fc7675c14 | ||
|
|
7b439ae6ee | ||
|
|
c5d7fd521d | ||
|
|
a856b26181 | ||
|
|
a949ec2d24 | ||
|
|
5ec5236991 | ||
|
|
d4cd400cd9 | ||
|
|
64bb5f018b | ||
|
|
593927aac3 | ||
|
|
51761d0890 | ||
|
|
5c56abfe75 | ||
|
|
9ac7c5bbeb | ||
|
|
be28555a40 | ||
|
|
1d32479bc4 | ||
|
|
c83ddc4adc | ||
|
|
5a7cf9b8fe | ||
|
|
190326726c | ||
|
|
387276f2f3 | ||
|
|
87b8c46263 | ||
|
|
d7aef11856 | ||
|
|
be842d235d | ||
|
|
d49ad66177 | ||
|
|
ca28669b0a | ||
|
|
45f480d948 | ||
|
|
852e312879 | ||
|
|
c79cf5b58f | ||
|
|
1a4a8ba559 | ||
|
|
7ad39a02f5 | ||
|
|
f96d06912f | ||
|
|
36571d3dad | ||
|
|
b075bbaea3 | ||
|
|
ec7982dbfc | ||
|
|
afd76bdfbb | ||
|
|
89ecd19d32 | ||
|
|
8904ec1afd | ||
|
|
5120029643 | ||
|
|
4a529d6fbd | ||
|
|
afe697e4b1 | ||
|
|
879b1f9107 | ||
|
|
5a7d4fd535 | ||
|
|
d61c650f39 | ||
|
|
f096ee269e | ||
|
|
0610e1a2bc | ||
|
|
68db286777 | ||
|
|
5075878f05 | ||
|
|
d965187d2c | ||
|
|
e25b098678 | ||
|
|
a3b23bffc2 | ||
|
|
dbc7a6b14e | ||
|
|
a105f7fd99 | ||
|
|
1b39a4f7c9 | ||
|
|
cac6306a04 | ||
|
|
749d71a36f | ||
|
|
4d40355d5c | ||
|
|
c311faa90f | ||
|
|
0821551a2f | ||
|
|
3a2bfe470f | ||
|
|
f6b55c5ac9 | ||
|
|
f9e97036cf | ||
|
|
4444fed343 | ||
|
|
bc0d104290 | ||
|
|
bdec9d25c6 | ||
|
|
b25367fc0c | ||
|
|
603296d921 | ||
|
|
a5b7d24dca | ||
|
|
2733e3ec23 | ||
|
|
9c79888b72 | ||
|
|
2b59c38b4b | ||
|
|
a13afd76c9 | ||
|
|
b98a481858 | ||
|
|
9e27a0e21d | ||
|
|
d08f7142ae | ||
|
|
efa3f1f07d | ||
|
|
263679dcac | ||
|
|
50d7d57f48 | ||
|
|
99e4b107d6 | ||
|
|
d293de4b64 | ||
|
|
554cf89ac2 | ||
|
|
df36b65916 | ||
|
|
d9a6b37d19 | ||
|
|
0629b017b1 | ||
|
|
43aa62ac56 | ||
|
|
22c2044f17 | ||
|
|
7457632990 | ||
|
|
361cc08e3c | ||
|
|
e742905fbd | ||
|
|
4b719deddf | ||
|
|
b57e79ca5f | ||
|
|
6ef4c78b3b | ||
|
|
f0002293a0 | ||
|
|
29997c40b2 | ||
|
|
ac5d54e6c1 | ||
|
|
b3eae8dad1 | ||
|
|
6804e81249 | ||
|
|
8639566909 | ||
|
|
87bf6255f4 | ||
|
|
6084af8fbf | ||
|
|
8ec124c47c | ||
|
|
b8bb881820 | ||
|
|
ccb4842e13 | ||
|
|
3a7addad2e | ||
|
|
644f4eb1e6 | ||
|
|
00bab8f76b | ||
|
|
72c084d7c0 | ||
|
|
12e7d2d8fb | ||
|
|
f5bb058541 | ||
|
|
5871252869 | ||
|
|
d5bf498d3d | ||
|
|
eb647aeea3 | ||
|
|
451f187856 | ||
|
|
f79c7d4ace | ||
|
|
01a44be0ca | ||
|
|
4dc6424fed | ||
|
|
a989fe06c2 | ||
|
|
1b5a877b98 | ||
|
|
9c9f79b0b6 | ||
|
|
6fef6d679e | ||
|
|
aa54b9dff9 | ||
|
|
05a704e7ec | ||
|
|
09e6518870 | ||
|
|
4d70d0998c | ||
|
|
9d0d957ec3 | ||
|
|
1be4c89f3c | ||
|
|
893e67dfa4 | ||
|
|
eced71b2be | ||
|
|
1aa24393e4 | ||
|
|
06b0d9aa3e | ||
|
|
6d73ba2d96 | ||
|
|
43785f1a7d | ||
|
|
f80e923c2a | ||
|
|
f772b3d07b | ||
|
|
a6ae5d795a | ||
|
|
c08286874a | ||
|
|
7b10bee68a | ||
|
|
d42098d1c0 | ||
|
|
9563f1ed44 | ||
|
|
1f6b24db33 | ||
|
|
5f3a22bb63 | ||
|
|
574c7706a0 | ||
|
|
46a43efd70 | ||
|
|
e8bba8af24 | ||
|
|
b9466bf7b2 | ||
|
|
b0d8401274 | ||
|
|
1063cd5899 | ||
|
|
8f4b1022e2 | ||
|
|
6d45f6d1b6 | ||
|
|
6beafaa747 | ||
|
|
fe80ee3c18 | ||
|
|
a5d6600dea | ||
|
|
8132311c75 | ||
|
|
9ecd7e9a79 | ||
|
|
b3ff717d32 | ||
|
|
15f1cebcdb | ||
|
|
6d9eaf4109 | ||
|
|
3f0882ead6 | ||
|
|
9717f8288e | ||
|
|
d253bc34e5 | ||
|
|
0f56e43451 | ||
|
|
ed00f029a6 | ||
|
|
ee35e1dc99 | ||
|
|
84881ecb45 | ||
|
|
369a9cb9bc | ||
|
|
b9deead084 | ||
|
|
723e7442af | ||
|
|
8189a59d59 | ||
|
|
cc209be4f9 | ||
|
|
1d9e8e863c | ||
|
|
c37fd57b2c | ||
|
|
54420387ab | ||
|
|
173b2d13da | ||
|
|
d60506c63f | ||
|
|
2d80c44181 | ||
|
|
eb5df86733 | ||
|
|
096e1d636d | ||
|
|
434836782c | ||
|
|
3b9e50ada7 | ||
|
|
78a16e41dc | ||
|
|
2bc4a8c807 | ||
|
|
5066351b24 | ||
|
|
c521fba4a6 | ||
|
|
174942f509 | ||
|
|
9bf7b250e0 | ||
|
|
32c2a4d68a | ||
|
|
64f96c68dc | ||
|
|
9807bf5476 | ||
|
|
5a630887c4 | ||
|
|
2a8fb902da | ||
|
|
08fcf84d6c | ||
|
|
d162996042 | ||
|
|
7bd8c842c8 | ||
|
|
fd36f6fc71 | ||
|
|
fd9158e7c1 | ||
|
|
effd24ccd4 | ||
|
|
1c730905ec | ||
|
|
9a8991ebf2 | ||
|
|
014030513a | ||
|
|
bfb85271d4 | ||
|
|
7c13c130b8 | ||
|
|
347a795b5f | ||
|
|
1a3c888f44 | ||
|
|
90ee59754d | ||
|
|
c33c6187ca | ||
|
|
99019cd22f | ||
|
|
3dc2ed9629 | ||
|
|
99722a6f94 | ||
|
|
75580feaa0 | ||
|
|
2d573da503 | ||
|
|
2687023b6f | ||
|
|
0993186e01 | ||
|
|
ede495a145 | ||
|
|
c82ae71726 | ||
|
|
cd13577d93 | ||
|
|
1d24543359 | ||
|
|
08f04187ae | ||
|
|
8fbe1159f5 | ||
|
|
2c64f50093 | ||
|
|
cb646284c6 | ||
|
|
72c4f810fb | ||
|
|
6170f49673 | ||
|
|
d486a99aa1 | ||
|
|
f0bd81125b | ||
|
|
251882a400 | ||
|
|
0503d03e64 | ||
|
|
fed98f470f | ||
|
|
95d4dbc905 | ||
|
|
54b9da287f | ||
|
|
67ea623ba3 | ||
|
|
9dbddd2c18 | ||
|
|
72345e1394 | ||
|
|
f3662d4ca8 | ||
|
|
386f5a8cf7 | ||
|
|
d23def1c02 | ||
|
|
2861940b30 | ||
|
|
14f1e00540 | ||
|
|
f1232eb83a | ||
|
|
42882265dd | ||
|
|
56d3c86b60 | ||
|
|
445d335974 | ||
|
|
4825dc6644 | ||
|
|
33ad6d5950 | ||
|
|
8ad02bd24c | ||
|
|
412227b958 | ||
|
|
754b864647 | ||
|
|
65571c4fb6 | ||
|
|
81bcc0def5 | ||
|
|
24e060cb3b | ||
|
|
b46ae1e77c | ||
|
|
45b655c34c | ||
|
|
0d954b2132 | ||
|
|
6a215b81c7 | ||
|
|
bfc1544ed1 | ||
|
|
6866216dd0 | ||
|
|
42b9a54a45 | ||
|
|
f6282fb798 | ||
|
|
830f1324ec | ||
|
|
f8a425e188 | ||
|
|
117aab6bef | ||
|
|
c73566caef | ||
|
|
4167abb00e | ||
|
|
3e74292fc0 | ||
|
|
b301376fc6 | ||
|
|
262f5ff3e7 | ||
|
|
d379858dd2 | ||
|
|
368832d0d5 | ||
|
|
be1d841039 | ||
|
|
6ae47a908b | ||
|
|
797a21ee9f | ||
|
|
7f1db60c45 | ||
|
|
fb530645b8 | ||
|
|
7f932630fc | ||
|
|
458efb376a | ||
|
|
3ffbe022e5 | ||
|
|
762c529563 | ||
|
|
0c224b4b84 | ||
|
|
bbbc924fcd | ||
|
|
cc5fb49ff8 | ||
|
|
189bc763dd | ||
|
|
78b7639400 | ||
|
|
56954962a3 | ||
|
|
5ff673ae7d | ||
|
|
2eb995d621 | ||
|
|
573ddb6fda | ||
|
|
708a3f9c4a | ||
|
|
a73c659a1e | ||
|
|
b22143a3b6 | ||
|
|
6195750b41 | ||
|
|
889b1097cc | ||
|
|
41cdb8bcdd | ||
|
|
8c33acfd35 | ||
|
|
0222a34286 | ||
|
|
a90c9802ab | ||
|
|
94da8ca950 | ||
|
|
9a9a4fef65 | ||
|
|
3a7b1f48c7 | ||
|
|
a46bbb409f | ||
|
|
08d16c2ca2 | ||
|
|
b501352ddc | ||
|
|
1c51598366 | ||
|
|
db839a9ccd | ||
|
|
5aba426b98 | ||
|
|
6c184efa92 | ||
|
|
028a090864 |
160
.github/workflows/CrossBuild.yml
vendored
Normal file
160
.github/workflows/CrossBuild.yml
vendored
Normal file
@@ -0,0 +1,160 @@
|
||||
# This is a basic workflow to help you get started with Actions
|
||||
name: Cross-Build
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'master-cmake'
|
||||
pull_request:
|
||||
branches:
|
||||
- 'master-cmake'
|
||||
|
||||
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
|
||||
67
.github/workflows/codeql-analysis.yml
vendored
Normal file
67
.github/workflows/codeql-analysis.yml
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
# 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'
|
||||
|
||||
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@v1
|
||||
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@v1
|
||||
|
||||
# ℹ️ 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
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
||||
157
.github/workflows/esp-idf-v4.3-build.yml
vendored
Normal file
157
.github/workflows/esp-idf-v4.3-build.yml
vendored
Normal file
@@ -0,0 +1,157 @@
|
||||
# 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]
|
||||
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: idf4.3-${{ 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
|
||||
echo pulling docker version 4.3.1
|
||||
docker pull espressif/idf:v4.3.1
|
||||
docker info
|
||||
docker run --env-file=${TARGET_BUILD_NAME}-env.txt -v $PWD:/project -w /project espressif/idf:v4.3.1 /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
|
||||
31
.gitignore
vendored
31
.gitignore
vendored
@@ -69,3 +69,34 @@ squeezelite-esp32-jsonblob.zip
|
||||
/flash_cmd.txt
|
||||
/writeSequeezeEsp.bat
|
||||
/writeSequeezeEsp.sh
|
||||
all_releases.json
|
||||
alltags.txt
|
||||
releases.json
|
||||
sdkconfig
|
||||
|
||||
.vscode/c_cpp_properties.json
|
||||
|
||||
.vscode/launch.json
|
||||
|
||||
.vscode/settings.json
|
||||
|
||||
.vscode/tasks.json
|
||||
|
||||
components/wifi-manager/.project
|
||||
|
||||
components/wifi-manager/.settings/.jsdtscope
|
||||
|
||||
components/wifi-manager/.settings/org.eclipse.wst.jsdt.ui.superType.container
|
||||
|
||||
components/wifi-manager/.settings/org.eclipse.wst.jsdt.ui.superType.name
|
||||
|
||||
components/wifi-manager/res/backup/
|
||||
|
||||
*.code-workspace
|
||||
|
||||
test/.vscode/
|
||||
|
||||
node_modules/*
|
||||
esp-dsp/
|
||||
|
||||
|
||||
|
||||
@@ -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>
|
||||
@@ -1,15 +1,14 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
set(EXTRA_COMPONENT_DIRS components/platform_console/app_recovery components/platform_console/app_squeezelite )
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
|
||||
add_definitions(-DMODEL_NAME=SqueezeESP32)
|
||||
if(NOT DEFINED DEPTH)
|
||||
set(DEPTH "16")
|
||||
endif()
|
||||
message(STATUS "Building RECOVERY")
|
||||
project(recovery)
|
||||
set_property(TARGET recovery.elf PROPERTY RECOVERY_PREFIX app_recovery )
|
||||
|
||||
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)
|
||||
#target_compile_definitions(__idf_driver_bt PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
|
||||
|
||||
@@ -18,8 +18,6 @@ RUN wget https://dl.espressif.com/dl/xtensa-esp32-elf-linux64-1.22.0-80-g6c4433a
|
||||
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
|
||||
|
||||
# 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
|
||||
|
||||
|
||||
498
README.md
498
README.md
@@ -1,27 +1,136 @@
|
||||
# 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
|
||||

|
||||
|
||||
Use the `squeezelite-esp32-SqueezeAmp-sdkconfig.defaults` configuration file.
|
||||
# Squeezelite-esp32
|
||||
|
||||
## What is this?
|
||||
Squeezelite-esp32 is an audio software suite made to run on espressif's ESP32 wifi (b/g/n) and bluetooth chipset. It offers the following capabilities
|
||||
|
||||
- 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 from a Spotify controller
|
||||
|
||||
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.
|
||||
|
||||
Note that streaming **to** a Bluetooth speaker is not the main purpose and remains experimental, so your mileage will vary. We will not work on improving or fixing that feature, please don't open issues about that.
|
||||
|
||||
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 ...)
|
||||
- [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).
|
||||
- [Ethernet](#ethernet-required-unpublished-version-43) using a Microchip LAN8720 with RMII interface or Davicom DM9051/W5500 over SPI.
|
||||
|
||||
Other features include
|
||||
|
||||
- Resampling
|
||||
- 10-bands equalizer
|
||||
- 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.
|
||||
|
||||
## 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.
|
||||
|
||||
### 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`
|
||||
|
||||
### 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`
|
||||
- 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://www.aliexpress.com/item/4001060963585.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 (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=106,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:
|
||||
@@ -41,24 +150,51 @@ 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 3 user-accessible SPI sub-systems but SPI0 and SPI2 are reserved for internal use and Flash/PSRAM, so only SPI1 is available. The NVS parameter "spi_config" set the spi's gpio used for user purpose (e.g. display, ethernet, GPIO expander). 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][,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 SqueezeAMP and A1S where these are forced at runtime. Syntax is
|
||||
```
|
||||
bck=<gpio>,ws=<gpio>,do=<gpio>
|
||||
bck=<gpio>,ws=<gpio>,do=<gpio>[,mck][,mute=<gpio>[:0|1][,model=TAS57xx|TAS5713|AC101|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). Only GPIO0 can be used as MCLK and 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, speakder and headset on and off using a JSON syntax:
|
||||
```json
|
||||
{ <command>: [ {"reg":<register>,"val":<value>,"mode":<nothing>|"or"|"and"}, ... {{"reg":<register>,"val":<value>,"mode":<nothing>|"or"|"and"} ],
|
||||
<command>: [ {"reg":<register>,"val":<value>,"mode":<nothing>|"or"|"and"}, ... {{"reg":<register>,"val":<value>,"mode":<nothing>|"or"|"and"} ],
|
||||
... }
|
||||
```
|
||||
Where `<command>` is one of init, poweron, poweroff, speakeron, speakeroff, headseton, headsetoff
|
||||
|
||||
This is standard JSON notation, so if you are not familiar with it, Google is your best friend. Be aware that the '...' means you can have as many entries as you want, it's not part of the syntax. Every section is optional, but it does not make sense to set i2c in the 'dac_config' parameter and not setting anything here. The parameter 'mode' allows to *or* the register with the value or to *and* it. Don't set 'mode' if you simply want to write. 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
|
||||
|
||||
NB: For specific builds (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.
|
||||
|
||||
@@ -70,28 +206,54 @@ Leave it blank to disable SPDIF usage, you can also define them at compile time
|
||||
```
|
||||
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 well-known configuration, 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
|
||||
To optimize speed, a bit-manipulation trick is used and as a result, the bit depth is limited to 20 bits, even in 32 bits mode. As said before, this is more than enough for any human ear. In theory, it could be extended up to 23 bits but I don't see the need. Now, you can also get SPDIF using a specialized chip that offers a I2S interface like a DAC but spits out SPDIF (optical and coax). Refers to DAC chapter then.
|
||||
|
||||
If you want coax, you can also use a poor-man's trick to generate signal from a 3.3V GPIO. All that does is dividing the 3.3V to generate a 0.6V peak-to-peak and then remove DC
|
||||
```
|
||||
100nF
|
||||
GPIO ----210ohm-----------||---- coax S/PDIF signal out
|
||||
|
|
||||
110ohm
|
||||
|
|
||||
Ground -------------------------- coax signal ground
|
||||
```
|
||||
|
||||
### Display
|
||||
The NVS parameter "display_config" sets the parameters for an optional display. 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[:x=<offset>][:y=<offset>]|ST7789|ILI9341[:16|18][,rotate][,invert][,cswap]
|
||||
```
|
||||
- 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
|
||||
- invert: pixel invertion
|
||||
- cswap: some display require a GBR color ordering instead of RGB (ST77xx only)
|
||||
- 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.
|
||||
@@ -103,47 +265,87 @@ 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>`
|
||||
|
||||
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)
|
||||
|
||||
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]|ir|jack[:0|1]|green[:0|1]|red[:0|1]|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.
|
||||
You can define the defaults for jack, spkfault leds at compile time but nvs parameter takes precedence except for well-known configurations 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.
|
||||
|
||||
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>|100][,count=<n>|16][,intr=<gpio>][,cs=<gpio>][,speed=<Hz>]
|
||||
```
|
||||
- model: pca9535, pca85xx, mcp23017 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)
|
||||
- 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. In addition, their brightness can be controlled using the "led_brigthness" parameter. The syntax is
|
||||
```
|
||||
[green=0..100][,red=0..100]
|
||||
```
|
||||
NB: For well-known configuration, this is ignored
|
||||
|
||||
### 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.
|
||||
|
||||
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.
|
||||
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 (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 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**
|
||||
|
||||
### 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 +369,20 @@ 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,
|
||||
KNOB_LEFT, KNOB_RIGHT, KNOB_PUSH,
|
||||
```
|
||||
|
||||
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 +391,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 +399,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 +416,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 +428,99 @@ 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.
|
||||
|
||||
When buttons are mapped to a "function" (non "raw" mode) a *command* is sent to LMS using the CLI (Command Line Interface) but this only works if LMS does not have a password set. In "raw" mode, a button *code* is sent using the always-openn control socket between LMS and the player.
|
||||
|
||||
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 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.
|
||||
|
||||
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 (required unpublished version 4.3)
|
||||
Wired ethernet is supported by esp32 with various options but squeezelite 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, then you are out of luck. It is not possible to have both to work together. There might be some workaround using CLK_OUT2 and GPIO3, but I don't have time for this.
|
||||
#### 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>]
|
||||
```
|
||||
- The reset pin is optional but recommended
|
||||
- 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). Note that currently only SPI2 is available.
|
||||
|
||||
| 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>
|
||||
```
|
||||
NB: Set parameter to empty to disable battery reading
|
||||
## Setting up ESP-IDF
|
||||
### Docker
|
||||
#### **************** todo: Docker scripts needs some rework.
|
||||
|
||||
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
|
||||
|
||||
### 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
|
||||
|
||||
```
|
||||
idf.py -p PORT [-b BAUD] flash
|
||||
idf.py -p PORT [-b BAUD] monitor
|
||||
|
||||
channel=0..7,scale=<scale>,cells=<2|3>[,atten=<0|1|2|3>]
|
||||
```
|
||||
NB: Set parameter to empty to disable battery reading. For well-known configuration, this is ignored (except for SqueezeAMP where number of cells is required)
|
||||
|
||||
# Configuration
|
||||
1/ setup WiFi
|
||||
|
||||
## 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
|
||||
## 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]
|
||||
@@ -320,12 +536,50 @@ See squeezlite 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
|
||||
|
||||
## 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
|
||||
# Building everything yourself
|
||||
|
||||
## Setting up ESP-IDF
|
||||
|
||||
### Docker
|
||||
You can use docker to build squeezelite-esp32 (optional)
|
||||
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
|
||||
|
||||
### Manual Install of ESP-IDF
|
||||
You can install IDF manually on Linux or Windows (using the Subsystem for Linux) following the instructions at: https://www.instructables.com/id/ESP32-Development-on-Windows-Subsystem-for-Linux/ or see here https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/windows-setup.html for a direct install.
|
||||
|
||||
**Use the esp-idf 4.0 https://github.com/espressif/esp-idf/tree/release/v4.0 and a recent add esp-dsp (after 08/2020)**
|
||||
|
||||
## Building Squeezelite-esp32
|
||||
When initially cloning the repo, make sure you do it recursively. For example: `git clone --recursive https://github.com/sle118/squeezelite-esp32.git`
|
||||
|
||||
Don't forget to choose one of the config files in build_scripts/ and rename it sdkconfig.defaults or sdkconfig as many important WiFi/BT options are set there. **The codecs libraries will not be rebuilt by these scripts (it's a tedious process - see below)**
|
||||
|
||||
Create and tweak your config using `idf.py menuconfig` then build binaries using `idf.py all`. It will build the recovery and the application (squeezelite). then use `idf.py flash` to write everything. Otherwise, if you just want to download squeezelite, do (assuming you have set ESPPORT (e.g. COM10) and ESPBAUD (e.g. 921600)
|
||||
```
|
||||
<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 +591,8 @@ 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 ...
|
||||
|
||||
# Footnotes
|
||||
(1) SPDIF is made by tricking the I2S bus but this consumes a fair bit of CPU as it multiplies by four the throughput on the i2s bus. To optimize some computation, the parity of the spdif frames must always be 0, so at least one bit has to be available to force it. As SPDIF samples are 20+4 bits length maximum, the LSB is used for that purpose, so the bit 24 is randomly toggling. It does not matter for 16 bits samples but it has been chosen to truncate the last 4 bits for 24 bits samples. I'm sure that some smart dude can further optimize spdif_convert() and use the user bit instead. You're welcome to do a PR but, as said above, I (philippe44) am not interested by 24 bits mental illness :-) and I've already made an effort to provide 20 bits which already way more what's needed :-)
|
||||
|
||||
@@ -11,6 +11,7 @@ CONFIG_DISPLAY_CONFIG=""
|
||||
CONFIG_I2C_CONFIG=""
|
||||
CONFIG_SPI_CONFIG=""
|
||||
CONFIG_SET_GPIO=""
|
||||
CONFIG_GPIO_EXP_CONFIG=""
|
||||
CONFIG_ROTARY_ENCODER=""
|
||||
CONFIG_LED_GREEN_GPIO=-1
|
||||
CONFIG_LED_GREEN_GPIO_LEVEL=1
|
||||
@@ -29,7 +30,10 @@ CONFIG_SPDIF_DO_IO=-1
|
||||
CONFIG_DAC_CONFIG="model=AC101,bck=27,ws=26,do=25,di=35,sda=33,scl=32"
|
||||
CONFIG_MUTE_GPIO=-1
|
||||
CONFIG_MUTE_GPIO_LEVEL=-1
|
||||
|
||||
CONFIG_RELEASE_API="https://api.github.com/repos/sle118/squeezelite-esp32/releases"
|
||||
CONFIG_SQUEEZELITE_ESP32_RELEASE_URL "https://github.com/sle118/squeezelite-esp32/releases"
|
||||
CONFIG_PROJECT_NAME="Squeezelite ESP32-A1S"
|
||||
CONFIG_FW_PLATFORM_NAME="ESP32-A1S"
|
||||
CONFIG_IDF_TARGET_ESP32=y
|
||||
CONFIG_IDF_TARGET="esp32"
|
||||
CONFIG_IDF_FIRMWARE_CHIP_ID=0x0000
|
||||
@@ -127,8 +131,8 @@ CONFIG_DEFAULT_AP_BEACON_INTERVAL=100
|
||||
CONFIG_DEFAULT_COMMAND_LINE="squeezelite -o I2S -b 500:2000 -d all=info -C 30 -W"
|
||||
# CONFIG_COMPILER_OPTIMIZATION_LEVEL_DEBUG is not set
|
||||
CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE=y
|
||||
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE=y
|
||||
# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT is not set
|
||||
# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE is not set
|
||||
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y
|
||||
# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE is not set
|
||||
CONFIG_COMPILER_CXX_EXCEPTIONS=y
|
||||
CONFIG_COMPILER_CXX_EXCEPTIONS_EMG_POOL_SIZE=0
|
||||
@@ -180,183 +184,51 @@ CONFIG_BT_A2DP_ENABLE=y
|
||||
# CONFIG_BT_SPP_ENABLED is not set
|
||||
# CONFIG_BT_HFP_ENABLE is not set
|
||||
CONFIG_BT_SSP_ENABLED=y
|
||||
<<<<<<< HEAD
|
||||
# CONFIG_BT_BLE_ENABLED is not set
|
||||
CONFIG_BT_STACK_NO_LOG=y
|
||||
=======
|
||||
CONFIG_BT_BLE_ENABLED=n
|
||||
CONFIG_BT_BLE_SMP_ENABLE=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_STACK_NO_LOG=y
|
||||
CONFIG_BT_LOG_HCI_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_HCI_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_BTM_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_BTM_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_L2CAP_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_L2CAP_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_RFCOMM_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_RFCOMM_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_SDP_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_SDP_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_GAP_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_GAP_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_BNEP_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_BNEP_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_PAN_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_PAN_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_A2D_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_A2D_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_AVDT_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_AVDT_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_AVCT_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_AVCT_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_AVRC_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_AVRC_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_MCA_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_MCA_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_HID_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_HID_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_APPL_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_APPL_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_GATT_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_GATT_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_SMP_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_SMP_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_BTIF_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_BTIF_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_BTC_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_BTC_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_OSI_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_OSI_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_BLUFI_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_BLUFI_TRACE_LEVEL=2
|
||||
>>>>>>> refs/remotes/origin/master
|
||||
CONFIG_BT_ACL_CONNECTIONS=4
|
||||
CONFIG_BT_ALLOCATION_FROM_SPIRAM_FIRST=y
|
||||
CONFIG_BT_BLE_DYNAMIC_ENV_MEMORY=y
|
||||
@@ -595,7 +467,7 @@ CONFIG_FREERTOS_MAX_TASK_NAME_LEN=16
|
||||
CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION=y
|
||||
# CONFIG_FREERTOS_ENABLE_STATIC_TASK_CLEAN_UP is not set
|
||||
CONFIG_FREERTOS_TIMER_TASK_PRIORITY=1
|
||||
CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=2432
|
||||
CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=2800
|
||||
CONFIG_FREERTOS_TIMER_QUEUE_LENGTH=10
|
||||
CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE=0
|
||||
#CONFIG_FREERTOS_USE_TRACE_FACILITY=y
|
||||
@@ -630,19 +502,9 @@ CONFIG_LWIP_MAX_SOCKETS=16
|
||||
# CONFIG_LWIP_USE_ONLY_LWIP_SELECT is not set
|
||||
CONFIG_LWIP_SO_REUSE=y
|
||||
CONFIG_LWIP_SO_REUSE_RXTOALL=y
|
||||
<<<<<<< HEAD
|
||||
# CONFIG_LWIP_SO_RCVBUF is not set
|
||||
# CONFIG_LWIP_IP_REASSEMBLY is not set
|
||||
# CONFIG_LWIP_IP_FRAG is not set
|
||||
# CONFIG_LWIP_STATS is not set
|
||||
# CONFIG_LWIP_ETHARP_TRUST_IP_MAC is not set
|
||||
=======
|
||||
CONFIG_LWIP_IP_REASSEMBLY=y
|
||||
|
||||
|
||||
|
||||
|
||||
>>>>>>> refs/remotes/origin/master
|
||||
#CONFIG_LWIP_IP_REASSEMBLY is not set
|
||||
CONFIG_LWIP_IP6_REASSEMBLY=y
|
||||
CONFIG_LWIP_IP4_REASSEMBLY=y
|
||||
CONFIG_LWIP_ESP_GRATUITOUS_ARP=y
|
||||
CONFIG_LWIP_GARP_TMR_INTERVAL=60
|
||||
CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=32
|
||||
@@ -971,7 +833,7 @@ CONFIG_MB_TIMER_INDEX=0
|
||||
CONFIG_SUPPORT_STATIC_ALLOCATION=y
|
||||
# CONFIG_ENABLE_STATIC_TASK_CLEAN_UP_HOOK is not set
|
||||
CONFIG_TIMER_TASK_PRIORITY=1
|
||||
CONFIG_TIMER_TASK_STACK_DEPTH=2432
|
||||
CONFIG_TIMER_TASK_STACK_DEPTH=2800
|
||||
CONFIG_TIMER_QUEUE_LENGTH=10
|
||||
# CONFIG_L2_TO_L3_COPY is not set
|
||||
# CONFIG_USE_ONLY_LWIP_SELECT is not set
|
||||
|
||||
@@ -12,6 +12,9 @@ CONFIG_DISPLAY_CONFIG=""
|
||||
CONFIG_I2C_CONFIG=""
|
||||
CONFIG_SPI_CONFIG=""
|
||||
CONFIG_SET_GPIO=""
|
||||
CONFIG_TARGET_LOCKED=n
|
||||
CONFIG_TARGET=""
|
||||
CONFIG_GPIO_EXP_CONFIG=""
|
||||
CONFIG_ROTARY_ENCODER=""
|
||||
CONFIG_LED_GREEN_GPIO=-1
|
||||
CONFIG_LED_GREEN_GPIO_LEVEL=1
|
||||
@@ -21,8 +24,7 @@ CONFIG_JACK_GPIO=-1
|
||||
CONFIG_JACK_GPIO_LEVEL=0
|
||||
CONFIG_SPKFAULT_GPIO=-1
|
||||
CONFIG_SPKFAULT_GPIO_LEVEL=0
|
||||
CONFIG_BAT_CHANNEL=-1
|
||||
CONFIG_BAT_SCALE="0"
|
||||
CONFIG_BAT_CONFIG=""
|
||||
CONFIG_I2S_NUM=0
|
||||
CONFIG_I2S_BCK_IO=-1
|
||||
CONFIG_I2S_WS_IO=-1
|
||||
@@ -34,6 +36,12 @@ CONFIG_SPDIF_WS_IO=-1
|
||||
CONFIG_SPDIF_DO_IO=-1
|
||||
CONFIG_MUTE_GPIO=-1
|
||||
CONFIG_MUTE_GPIO_LEVEL=-1
|
||||
CONFIG_PROJECT_NAME="Squeezelite-ESP32"
|
||||
CONFIG_FW_PLATFORM_NAME="I2S-4MFlash"
|
||||
CONFIG_RELEASE_API="https://api.github.com/repos/sle118/squeezelite-esp32/releases"
|
||||
CONFIG_SQUEEZELITE_ESP32_RELEASE_URL "https://github.com/sle118/squeezelite-esp32/releases"
|
||||
CONFIG_AUDIO_CONTROLS=""
|
||||
CONFIG_AMP_GPIO=-1
|
||||
|
||||
#
|
||||
# SDK tool configuration
|
||||
@@ -126,8 +134,8 @@ CONFIG_DEFAULT_AP_BEACON_INTERVAL=100
|
||||
CONFIG_DEFAULT_COMMAND_LINE="squeezelite -o I2S -b 500:2000 -d all=info -C 30 -W"
|
||||
# CONFIG_COMPILER_OPTIMIZATION_LEVEL_DEBUG is not set
|
||||
CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE=y
|
||||
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE=y
|
||||
# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT is not set
|
||||
# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE is not set
|
||||
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y
|
||||
# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE is not set
|
||||
CONFIG_COMPILER_CXX_EXCEPTIONS=y
|
||||
CONFIG_COMPILER_CXX_EXCEPTIONS_EMG_POOL_SIZE=0
|
||||
@@ -179,183 +187,10 @@ CONFIG_BT_A2DP_ENABLE=y
|
||||
# CONFIG_BT_SPP_ENABLED is not set
|
||||
# CONFIG_BT_HFP_ENABLE is not set
|
||||
CONFIG_BT_SSP_ENABLED=y
|
||||
<<<<<<< HEAD
|
||||
# CONFIG_BT_BLE_ENABLED is not set
|
||||
CONFIG_BT_STACK_NO_LOG=y
|
||||
=======
|
||||
CONFIG_BT_BLE_ENABLED=n
|
||||
CONFIG_BT_BLE_SMP_ENABLE=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_HCI_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_HCI_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_BTM_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_BTM_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_L2CAP_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_L2CAP_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_RFCOMM_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_RFCOMM_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_SDP_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_SDP_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_GAP_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_GAP_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_BNEP_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_BNEP_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_PAN_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_PAN_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_A2D_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_A2D_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_AVDT_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_AVDT_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_AVCT_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_AVCT_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_AVRC_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_AVRC_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_MCA_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_MCA_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_HID_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_HID_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_APPL_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_APPL_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_GATT_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_GATT_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_SMP_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_SMP_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_BTIF_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_BTIF_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_BTC_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_BTC_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_OSI_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_OSI_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_BLUFI_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_BLUFI_TRACE_LEVEL=2
|
||||
>>>>>>> refs/remotes/origin/master
|
||||
CONFIG_BT_STACK_NO_LOG=y
|
||||
CONFIG_BT_ACL_CONNECTIONS=4
|
||||
CONFIG_BT_ALLOCATION_FROM_SPIRAM_FIRST=y
|
||||
CONFIG_BT_BLE_DYNAMIC_ENV_MEMORY=y
|
||||
@@ -368,8 +203,8 @@ CONFIG_BT_RESERVE_DRAM=0xdb5c
|
||||
CONFIG_ADC_DISABLE_DAC=y
|
||||
CONFIG_SPI_MASTER_IN_IRAM=y
|
||||
CONFIG_SPI_MASTER_ISR_IN_IRAM=y
|
||||
CONFIG_SPI_SLAVE_IN_IRAM=y
|
||||
CONFIG_SPI_SLAVE_ISR_IN_IRAM=y
|
||||
# CONFIG_SPI_SLAVE_IN_IRAM is not set
|
||||
# CONFIG_SPI_SLAVE_ISR_IN_IRAM is not set
|
||||
# CONFIG_EFUSE_CUSTOM_TABLE is not set
|
||||
# CONFIG_EFUSE_VIRTUAL is not set
|
||||
# CONFIG_EFUSE_CODE_SCHEME_COMPAT_NONE is not set
|
||||
@@ -377,11 +212,12 @@ CONFIG_EFUSE_CODE_SCHEME_COMPAT_3_4=y
|
||||
# CONFIG_EFUSE_CODE_SCHEME_COMPAT_REPEAT is not set
|
||||
CONFIG_EFUSE_MAX_BLK_LEN=192
|
||||
# CONFIG_ESP_TLS_SERVER is not set
|
||||
CONFIG_ESP32_REV_MIN_0=y
|
||||
# CONFIG_ESP32_REV_MIN_1 is not set
|
||||
CONFIG_ESP32_ECO3_CACHE_LOCK_FIX=y
|
||||
# CONFIG_ESP32_REV_MIN_0 is not set
|
||||
CONFIG_ESP32_REV_MIN_1=y
|
||||
# CONFIG_ESP32_REV_MIN_2 is not set
|
||||
# CONFIG_ESP32_REV_MIN_3 is not set
|
||||
CONFIG_ESP32_REV_MIN=0
|
||||
CONFIG_ESP32_REV_MIN=1
|
||||
CONFIG_ESP32_DPORT_WORKAROUND=y
|
||||
# CONFIG_ESP32_DEFAULT_CPU_FREQ_80 is not set
|
||||
# CONFIG_ESP32_DEFAULT_CPU_FREQ_160 is not set
|
||||
@@ -400,6 +236,9 @@ CONFIG_SPIRAM_SIZE=-1
|
||||
CONFIG_SPIRAM_SPEED_80M=y
|
||||
CONFIG_SPIRAM_MEMTEST=y
|
||||
CONFIG_SPIRAM_CACHE_WORKAROUND=y
|
||||
CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_MEMW=y
|
||||
# CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_DUPLDST is not set
|
||||
# CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_NOPS is not set
|
||||
CONFIG_SPIRAM_BANKSWITCH_ENABLE=y
|
||||
CONFIG_SPIRAM_BANKSWITCH_RESERVE=8
|
||||
CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=256
|
||||
@@ -498,8 +337,6 @@ CONFIG_HTTPD_PURGE_BUF_LEN=32
|
||||
CONFIG_OTA_ALLOW_HTTP=y
|
||||
# CONFIG_ESP_HTTPS_SERVER_ENABLE is not set
|
||||
CONFIG_ESP32_WIFI_SW_COEXIST_ENABLE=y
|
||||
# CONFIG_ESP32_WIFI_SW_COEXIST_PREFERENCE_WIFI is not set
|
||||
# CONFIG_ESP32_WIFI_SW_COEXIST_PREFERENCE_BT is not set
|
||||
CONFIG_ESP32_WIFI_SW_COEXIST_PREFERENCE_BALANCE=y
|
||||
CONFIG_ESP32_WIFI_SW_COEXIST_PREFERENCE_VALUE=2
|
||||
CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM=12
|
||||
@@ -507,11 +344,6 @@ CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=40
|
||||
CONFIG_ESP32_WIFI_STATIC_TX_BUFFER=y
|
||||
CONFIG_ESP32_WIFI_TX_BUFFER_TYPE=0
|
||||
CONFIG_ESP32_WIFI_STATIC_TX_BUFFER_NUM=12
|
||||
# CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED is not set
|
||||
# CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED is not set
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_ESP32_WIFI_NVS_ENABLED=y
|
||||
CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_0=y
|
||||
@@ -597,7 +429,7 @@ CONFIG_FREERTOS_MAX_TASK_NAME_LEN=16
|
||||
CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION=y
|
||||
# CONFIG_FREERTOS_ENABLE_STATIC_TASK_CLEAN_UP is not set
|
||||
CONFIG_FREERTOS_TIMER_TASK_PRIORITY=1
|
||||
CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=2432
|
||||
CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=2800
|
||||
CONFIG_FREERTOS_TIMER_QUEUE_LENGTH=10
|
||||
CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE=0
|
||||
#CONFIG_FREERTOS_USE_TRACE_FACILITY=y
|
||||
@@ -616,11 +448,9 @@ CONFIG_HEAP_TRACING_OFF=y
|
||||
# CONFIG_HEAP_TRACING_STANDALONE is not set
|
||||
# CONFIG_HEAP_TRACING_TOHOST is not set
|
||||
# CONFIG_HEAP_TRACING is not set
|
||||
|
||||
# CONFIG_LOG_DEFAULT_LEVEL_NONE is not set
|
||||
# CONFIG_LOG_DEFAULT_LEVEL_ERROR is not set
|
||||
CONFIG_LOG_DEFAULT_LEVEL_INFO=y
|
||||
# CONFIG_LOG_DEFAULT_LEVEL_INFO is not set
|
||||
# CONFIG_LOG_DEFAULT_LEVEL_DEBUG is not set
|
||||
# CONFIG_LOG_DEFAULT_LEVEL_VERBOSE is not set
|
||||
CONFIG_LOG_DEFAULT_LEVEL=3
|
||||
@@ -633,19 +463,9 @@ CONFIG_LWIP_MAX_SOCKETS=16
|
||||
# CONFIG_LWIP_USE_ONLY_LWIP_SELECT is not set
|
||||
CONFIG_LWIP_SO_REUSE=y
|
||||
CONFIG_LWIP_SO_REUSE_RXTOALL=y
|
||||
<<<<<<< HEAD
|
||||
# CONFIG_LWIP_SO_RCVBUF is not set
|
||||
# CONFIG_LWIP_IP_FRAG is not set
|
||||
# CONFIG_LWIP_IP_REASSEMBLY is not set
|
||||
# CONFIG_LWIP_STATS is not set
|
||||
# CONFIG_LWIP_ETHARP_TRUST_IP_MAC is not set
|
||||
=======
|
||||
CONFIG_LWIP_IP_REASSEMBLY=y
|
||||
|
||||
|
||||
|
||||
|
||||
>>>>>>> refs/remotes/origin/master
|
||||
#CONFIG_LWIP_IP_REASSEMBLY is not set
|
||||
CONFIG_LWIP_IP6_REASSEMBLY=y
|
||||
CONFIG_LWIP_IP4_REASSEMBLY=y
|
||||
CONFIG_LWIP_ESP_GRATUITOUS_ARP=y
|
||||
CONFIG_LWIP_GARP_TMR_INTERVAL=60
|
||||
CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=32
|
||||
@@ -953,8 +773,6 @@ CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU1=y
|
||||
CONFIG_POST_EVENTS_FROM_ISR=y
|
||||
CONFIG_POST_EVENTS_FROM_IRAM_ISR=y
|
||||
CONFIG_SW_COEXIST_ENABLE=y
|
||||
# CONFIG_SW_COEXIST_PREFERENCE_WIFI is not set
|
||||
# CONFIG_SW_COEXIST_PREFERENCE_BT is not set
|
||||
CONFIG_SW_COEXIST_PREFERENCE_BALANCE=y
|
||||
CONFIG_SW_COEXIST_PREFERENCE_VALUE=2
|
||||
CONFIG_MB_MASTER_TIMEOUT_MS_RESPOND=150
|
||||
@@ -974,7 +792,7 @@ CONFIG_MB_TIMER_INDEX=0
|
||||
CONFIG_SUPPORT_STATIC_ALLOCATION=y
|
||||
# CONFIG_ENABLE_STATIC_TASK_CLEAN_UP_HOOK is not set
|
||||
CONFIG_TIMER_TASK_PRIORITY=1
|
||||
CONFIG_TIMER_TASK_STACK_DEPTH=2432
|
||||
CONFIG_TIMER_TASK_STACK_DEPTH=2800
|
||||
CONFIG_TIMER_QUEUE_LENGTH=10
|
||||
# CONFIG_L2_TO_L3_COPY is not set
|
||||
# CONFIG_USE_ONLY_LWIP_SELECT is not set
|
||||
|
||||
@@ -6,32 +6,40 @@ CONFIG_IDF_TARGET_ESP32=y
|
||||
CONFIG_IDF_TARGET="esp32"
|
||||
CONFIG_IDF_FIRMWARE_CHIP_ID=0x0000
|
||||
|
||||
# SqueezeAMP defaults
|
||||
CONFIG_SQUEEZEAMP=y
|
||||
# Muse defaults
|
||||
CONFIG_MUSE=y
|
||||
CONFIG_AMP_LOCKED=y
|
||||
CONFIG_JACK_LOCKED=y
|
||||
CONFIG_BAT_LOCKED=y
|
||||
CONFIG_I2C_LOCKED=y
|
||||
CONFIG_LED_LOCKED=y
|
||||
CONFIG_TARGET_LOCKED=y
|
||||
CONFIG_TARGET="muse"
|
||||
CONFIG_DISPLAY_CONFIG=""
|
||||
CONFIG_I2C_CONFIG=""
|
||||
CONFIG_SPI_CONFIG=""
|
||||
CONFIG_SPI_CONFIG="mosi=15,miso=2,clk=14"
|
||||
CONFIG_SET_GPIO=""
|
||||
CONFIG_GPIO_EXP_CONFIG=""
|
||||
CONFIG_ROTARY_ENCODER=""
|
||||
CONFIG_LED_GREEN_GPIO=12
|
||||
CONFIG_LED_GREEN_GPIO_LEVEL=0
|
||||
CONFIG_LED_RED_GPIO=13
|
||||
CONFIG_LED_RED_GPIO_LEVEL=0
|
||||
CONFIG_LED_GREEN_GPIO=-1
|
||||
CONFIG_LED_RED_GPIO=-1
|
||||
CONFIG_JACK_GPIO=34
|
||||
CONFIG_JACK_GPIO_LEVEL=0
|
||||
CONFIG_SPKFAULT_GPIO=2
|
||||
CONFIG_SPKFAULT_GPIO_LEVEL=0
|
||||
CONFIG_BAT_CHANNEL=7
|
||||
CONFIG_BAT_SCALE="20.24"
|
||||
CONFIG_SPKFAULT_GPIO=-1
|
||||
|
||||
CONFIG_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} ]}"
|
||||
CONFIG_AUDIO_CONTROLS=CONFIG_AUDIO_CONTROLS="[{\"gpio\":32, \"pull\":true, \"long_press\":1000, \"normal\":{\"pressed\":\"ACTRLS_VOLDOWN\"}, \"longpress\":{\"pressed\":\"ACTRLS_PREV\"}}, {\"gpio\":19, \"pull\":true, \"long_press\":1000, \"normal\":{\"pressed\":\"ACTRLS_VOLUP\"}, \"longpress\":{\"pressed\":\"ACTRLS_NEXT\"}}, {\"gpio\":12, \"pull\":true, \"long_press\":1000, \"normal\":{\"pressed\":\"ACTRLS_TOGGLE\"},\"longpress\":{\"pressed\":\"ACTRLS_POWER\"}}]"
|
||||
CONFIG_BAT_CONFIG="channel=5,scale=7.00,atten=3,cells=1"
|
||||
CONFIG_I2S_NUM=0
|
||||
CONFIG_SPDIF_NUM=0
|
||||
CONFIG_SPDIF_CONFIG="bck=33,ws=25,do=15"
|
||||
CONFIG_DAC_CONFIG="model=TAS57xx,bck=33,ws=25,do=32,sda=27,scl=26,mute=14"
|
||||
CONFIG_SPDIF_CONFIG=""
|
||||
CONFIG_DAC_CONFIG="model=I2S,bck=5,ws=25,do=26,di=35,i2c=16,sda=18,scl=23,mck"
|
||||
CONFIG_MUTE_GPIO_LEVEL=-1
|
||||
CONFIG_PROJECT_NAME="Muse"
|
||||
CONFIG_FW_PLATFORM_NAME="Muse"
|
||||
CONFIG_RELEASE_API="https://api.github.com/repos/sle118/squeezelite-esp32/releases"
|
||||
CONFIG_SQUEEZELITE_ESP32_RELEASE_URL "https://github.com/sle118/squeezelite-esp32/releases"
|
||||
CONFIG_AMP_GPIO=21
|
||||
CONFIG_AMP_GPIO_LEVEL=1
|
||||
|
||||
#
|
||||
# SDK tool configuration
|
||||
@@ -42,7 +50,6 @@ CONFIG_APP_COMPILE_TIME_DATE=y
|
||||
# CONFIG_APP_EXCLUDE_PROJECT_NAME_VAR is not set
|
||||
# CONFIG_BOOTLOADER_LOG_LEVEL_NONE is not set
|
||||
# CONFIG_BOOTLOADER_LOG_LEVEL_ERROR is not set
|
||||
# CONFIG_BOOTLOADER_LOG_LEVEL_WARN is not set
|
||||
CONFIG_BOOTLOADER_LOG_LEVEL_INFO=y
|
||||
# CONFIG_BOOTLOADER_LOG_LEVEL_DEBUG is not set
|
||||
# CONFIG_BOOTLOADER_LOG_LEVEL_VERBOSE is not set
|
||||
@@ -71,9 +78,10 @@ CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
|
||||
CONFIG_ESPTOOLPY_FLASHFREQ="80m"
|
||||
# CONFIG_ESPTOOLPY_FLASHSIZE_1MB is not set
|
||||
# CONFIG_ESPTOOLPY_FLASHSIZE_2MB is not set
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
|
||||
# CONFIG_ESPTOOLPY_FLASHSIZE_8MB is not set
|
||||
# CONFIG_ESPTOOLPY_FLASHSIZE_16MB is not set
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE="8MB"
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE="4MB"
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_DETECT=y
|
||||
CONFIG_ESPTOOLPY_BEFORE_RESET=y
|
||||
# CONFIG_ESPTOOLPY_BEFORE_NORESET is not set
|
||||
@@ -124,8 +132,8 @@ CONFIG_DEFAULT_AP_BEACON_INTERVAL=100
|
||||
CONFIG_DEFAULT_COMMAND_LINE="squeezelite -o I2S -b 500:2000 -d all=info -C 30 -W"
|
||||
# CONFIG_COMPILER_OPTIMIZATION_LEVEL_DEBUG is not set
|
||||
CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE=y
|
||||
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE=y
|
||||
# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT is not set
|
||||
# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE is not set
|
||||
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y
|
||||
# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE is not set
|
||||
CONFIG_COMPILER_CXX_EXCEPTIONS=y
|
||||
CONFIG_COMPILER_CXX_EXCEPTIONS_EMG_POOL_SIZE=0
|
||||
@@ -149,7 +157,6 @@ CONFIG_BTDM_CTRL_BR_EDR_MAX_SYNC_CONN=0
|
||||
# CONFIG_BTDM_CTRL_BR_EDR_SCO_DATA_PATH_HCI is not set
|
||||
CONFIG_BTDM_CTRL_BR_EDR_SCO_DATA_PATH_PCM=y
|
||||
CONFIG_BTDM_CTRL_BR_EDR_SCO_DATA_PATH_EFF=1
|
||||
# CONFIG_BTDM_CTRL_AUTO_LATENCY_EFF is not set
|
||||
CONFIG_BTDM_CTRL_BLE_MAX_CONN_EFF=0
|
||||
CONFIG_BTDM_CTRL_BR_EDR_MAX_ACL_CONN_EFF=2
|
||||
CONFIG_BTDM_CTRL_BR_EDR_MAX_SYNC_CONN_EFF=0
|
||||
@@ -178,191 +185,10 @@ CONFIG_BT_A2DP_ENABLE=y
|
||||
# CONFIG_BT_SPP_ENABLED is not set
|
||||
# CONFIG_BT_HFP_ENABLE is not set
|
||||
CONFIG_BT_SSP_ENABLED=y
|
||||
<<<<<<< HEAD
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# CONFIG_BT_BLE_ENABLED is not set
|
||||
|
||||
|
||||
CONFIG_BT_STACK_NO_LOG=y
|
||||
=======
|
||||
CONFIG_BT_BLE_ENABLED=n
|
||||
CONFIG_BT_BLE_SMP_ENABLE=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_HCI_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_HCI_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_BTM_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_BTM_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_L2CAP_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_L2CAP_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_RFCOMM_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_RFCOMM_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_SDP_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_SDP_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_GAP_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_GAP_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_BNEP_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_BNEP_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_PAN_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_PAN_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_A2D_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_A2D_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_AVDT_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_AVDT_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_AVCT_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_AVCT_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_AVRC_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_AVRC_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_MCA_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_MCA_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_HID_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_HID_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_APPL_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_APPL_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_GATT_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_GATT_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_SMP_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_SMP_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_BTIF_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_BTIF_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_BTC_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_BTC_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_OSI_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_OSI_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_BLUFI_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_BLUFI_TRACE_LEVEL=2
|
||||
>>>>>>> refs/remotes/origin/master
|
||||
CONFIG_BT_STACK_NO_LOG=y
|
||||
CONFIG_BT_ACL_CONNECTIONS=4
|
||||
CONFIG_BT_ALLOCATION_FROM_SPIRAM_FIRST=y
|
||||
CONFIG_BT_BLE_DYNAMIC_ENV_MEMORY=y
|
||||
@@ -384,11 +210,12 @@ CONFIG_EFUSE_CODE_SCHEME_COMPAT_3_4=y
|
||||
# CONFIG_EFUSE_CODE_SCHEME_COMPAT_REPEAT is not set
|
||||
CONFIG_EFUSE_MAX_BLK_LEN=192
|
||||
# CONFIG_ESP_TLS_SERVER is not set
|
||||
CONFIG_ESP32_REV_MIN_0=y
|
||||
# CONFIG_ESP32_REV_MIN_1 is not set
|
||||
CONFIG_ESP32_ECO3_CACHE_LOCK_FIX=y
|
||||
# CONFIG_ESP32_REV_MIN_0 is not set
|
||||
CONFIG_ESP32_REV_MIN_1=y
|
||||
# CONFIG_ESP32_REV_MIN_2 is not set
|
||||
# CONFIG_ESP32_REV_MIN_3 is not set
|
||||
CONFIG_ESP32_REV_MIN=0
|
||||
CONFIG_ESP32_REV_MIN=1
|
||||
CONFIG_ESP32_DPORT_WORKAROUND=y
|
||||
# CONFIG_ESP32_DEFAULT_CPU_FREQ_80 is not set
|
||||
# CONFIG_ESP32_DEFAULT_CPU_FREQ_160 is not set
|
||||
@@ -407,6 +234,9 @@ CONFIG_SPIRAM_SIZE=-1
|
||||
CONFIG_SPIRAM_SPEED_80M=y
|
||||
CONFIG_SPIRAM_MEMTEST=y
|
||||
CONFIG_SPIRAM_CACHE_WORKAROUND=y
|
||||
CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_MEMW=y
|
||||
# CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_DUPLDST is not set
|
||||
# CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_NOPS is not set
|
||||
CONFIG_SPIRAM_BANKSWITCH_ENABLE=y
|
||||
CONFIG_SPIRAM_BANKSWITCH_RESERVE=8
|
||||
CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=256
|
||||
@@ -512,10 +342,6 @@ CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=40
|
||||
CONFIG_ESP32_WIFI_STATIC_TX_BUFFER=y
|
||||
CONFIG_ESP32_WIFI_TX_BUFFER_TYPE=0
|
||||
CONFIG_ESP32_WIFI_STATIC_TX_BUFFER_NUM=12
|
||||
# CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED is not set
|
||||
# CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED is not set
|
||||
|
||||
|
||||
|
||||
CONFIG_ESP32_WIFI_NVS_ENABLED=y
|
||||
CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_0=y
|
||||
@@ -601,7 +427,7 @@ CONFIG_FREERTOS_MAX_TASK_NAME_LEN=16
|
||||
CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION=y
|
||||
# CONFIG_FREERTOS_ENABLE_STATIC_TASK_CLEAN_UP is not set
|
||||
CONFIG_FREERTOS_TIMER_TASK_PRIORITY=1
|
||||
CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=2432
|
||||
CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=2800
|
||||
CONFIG_FREERTOS_TIMER_QUEUE_LENGTH=10
|
||||
CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE=0
|
||||
#CONFIG_FREERTOS_USE_TRACE_FACILITY=y
|
||||
@@ -623,7 +449,6 @@ CONFIG_HEAP_TRACING_OFF=y
|
||||
# CONFIG_LOG_DEFAULT_LEVEL_NONE is not set
|
||||
# CONFIG_LOG_DEFAULT_LEVEL_ERROR is not set
|
||||
CONFIG_LOG_DEFAULT_LEVEL_INFO=y
|
||||
|
||||
# CONFIG_LOG_DEFAULT_LEVEL_DEBUG is not set
|
||||
# CONFIG_LOG_DEFAULT_LEVEL_VERBOSE is not set
|
||||
CONFIG_LOG_DEFAULT_LEVEL=3
|
||||
@@ -636,19 +461,9 @@ CONFIG_LWIP_MAX_SOCKETS=16
|
||||
# CONFIG_LWIP_USE_ONLY_LWIP_SELECT is not set
|
||||
CONFIG_LWIP_SO_REUSE=y
|
||||
CONFIG_LWIP_SO_REUSE_RXTOALL=y
|
||||
<<<<<<< HEAD
|
||||
# CONFIG_LWIP_SO_RCVBUF is not set
|
||||
# CONFIG_LWIP_IP_FRAG is not set
|
||||
# CONFIG_LWIP_IP_REASSEMBLY is not set
|
||||
# CONFIG_LWIP_STATS is not set
|
||||
# CONFIG_LWIP_ETHARP_TRUST_IP_MAC is not set
|
||||
=======
|
||||
CONFIG_LWIP_IP_REASSEMBLY=y
|
||||
|
||||
|
||||
|
||||
|
||||
>>>>>>> refs/remotes/origin/master
|
||||
#CONFIG_LWIP_IP_REASSEMBLY is not set
|
||||
CONFIG_LWIP_IP6_REASSEMBLY=y
|
||||
CONFIG_LWIP_IP4_REASSEMBLY=y
|
||||
CONFIG_LWIP_ESP_GRATUITOUS_ARP=y
|
||||
CONFIG_LWIP_GARP_TMR_INTERVAL=60
|
||||
CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=32
|
||||
@@ -657,7 +472,6 @@ CONFIG_LWIP_DHCP_RESTORE_LAST_IP=y
|
||||
CONFIG_LWIP_DHCPS_LEASE_UNIT=60
|
||||
CONFIG_LWIP_DHCPS_MAX_STATION_NUM=8
|
||||
# CONFIG_LWIP_AUTOIP is not set
|
||||
# CONFIG_LWIP_IPV6_AUTOCONFIG is not set
|
||||
CONFIG_LWIP_NETIF_LOOPBACK=y
|
||||
CONFIG_LWIP_LOOPBACK_MAX_PBUFS=8
|
||||
CONFIG_LWIP_MAX_ACTIVE_TCP=16
|
||||
@@ -692,7 +506,6 @@ CONFIG_LWIP_SNTP_UPDATE_DELAY=3600000
|
||||
CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC=y
|
||||
# CONFIG_MBEDTLS_DEFAULT_MEM_ALLOC is not set
|
||||
# CONFIG_MBEDTLS_CUSTOM_MEM_ALLOC is not set
|
||||
|
||||
CONFIG_MBEDTLS_SSL_MAX_CONTENT_LEN=16384
|
||||
# CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN is not set
|
||||
# CONFIG_MBEDTLS_DEBUG is not set
|
||||
@@ -831,7 +644,6 @@ CONFIG_WL_SECTOR_SIZE=512
|
||||
CONFIG_WL_SECTOR_MODE_SAFE=y
|
||||
CONFIG_WL_SECTOR_MODE=1
|
||||
CONFIG_WIFI_PROV_SCAN_MAX_ENTRIES=16
|
||||
|
||||
CONFIG_WPA_MBEDTLS_CRYPTO=y
|
||||
# CONFIG_DSP_ANSI is not set
|
||||
CONFIG_DSP_OPTIMIZED=y
|
||||
@@ -906,14 +718,6 @@ CONFIG_BTU_TASK_STACK_SIZE=4096
|
||||
CONFIG_CLASSIC_BT_ENABLED=y
|
||||
CONFIG_A2DP_ENABLE=y
|
||||
# CONFIG_HFP_ENABLE is not set
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# CONFIG_BLE_HOST_QUEUE_CONGESTION_CHECK is not set
|
||||
CONFIG_SMP_ENABLE=y
|
||||
CONFIG_BLE_ESTABLISH_LINK_CONNECTION_TIMEOUT=30
|
||||
@@ -986,7 +790,7 @@ CONFIG_MB_TIMER_INDEX=0
|
||||
CONFIG_SUPPORT_STATIC_ALLOCATION=y
|
||||
# CONFIG_ENABLE_STATIC_TASK_CLEAN_UP_HOOK is not set
|
||||
CONFIG_TIMER_TASK_PRIORITY=1
|
||||
CONFIG_TIMER_TASK_STACK_DEPTH=2432
|
||||
CONFIG_TIMER_TASK_STACK_DEPTH=2800
|
||||
CONFIG_TIMER_QUEUE_LENGTH=10
|
||||
# CONFIG_L2_TO_L3_COPY is not set
|
||||
# CONFIG_USE_ONLY_LWIP_SELECT is not set
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -12,10 +12,13 @@ CONFIG_JACK_LOCKED=y
|
||||
CONFIG_BAT_LOCKED=y
|
||||
CONFIG_I2C_LOCKED=y
|
||||
CONFIG_LED_LOCKED=y
|
||||
CONFIG_TARGET_LOCKED=y
|
||||
CONFIG_TARGET="squeezeamp"
|
||||
CONFIG_DISPLAY_CONFIG=""
|
||||
CONFIG_I2C_CONFIG=""
|
||||
CONFIG_SPI_CONFIG=""
|
||||
CONFIG_SET_GPIO=""
|
||||
CONFIG_GPIO_EXP_CONFIG=""
|
||||
CONFIG_ROTARY_ENCODER=""
|
||||
CONFIG_LED_GREEN_GPIO=12
|
||||
CONFIG_LED_GREEN_GPIO_LEVEL=0
|
||||
@@ -25,13 +28,18 @@ CONFIG_JACK_GPIO=34
|
||||
CONFIG_JACK_GPIO_LEVEL=0
|
||||
CONFIG_SPKFAULT_GPIO=2
|
||||
CONFIG_SPKFAULT_GPIO_LEVEL=0
|
||||
CONFIG_BAT_CHANNEL=7
|
||||
CONFIG_BAT_SCALE="20.24"
|
||||
CONFIG_BAT_CONFIG="channel=7,scale=20.24,atten=0"
|
||||
CONFIG_I2S_NUM=0
|
||||
CONFIG_SPDIF_NUM=0
|
||||
CONFIG_SPDIF_CONFIG="bck=33,ws=25,do=15"
|
||||
CONFIG_DAC_CONFIG="model=TAS57xx,bck=33,ws=25,do=32,sda=27,scl=26,mute=14:0"
|
||||
CONFIG_MUTE_GPIO_LEVEL=-1
|
||||
CONFIG_PROJECT_NAME="SqueezeAmp"
|
||||
CONFIG_FW_PLATFORM_NAME="SqueezeAmp"
|
||||
CONFIG_RELEASE_API="https://api.github.com/repos/sle118/squeezelite-esp32/releases"
|
||||
CONFIG_SQUEEZELITE_ESP32_RELEASE_URL "https://github.com/sle118/squeezelite-esp32/releases"
|
||||
CONFIG_AUDIO_CONTROLS=""
|
||||
CONFIG_AMP_GPIO=-1
|
||||
|
||||
#
|
||||
# SDK tool configuration
|
||||
@@ -42,7 +50,6 @@ CONFIG_APP_COMPILE_TIME_DATE=y
|
||||
# CONFIG_APP_EXCLUDE_PROJECT_NAME_VAR is not set
|
||||
# CONFIG_BOOTLOADER_LOG_LEVEL_NONE is not set
|
||||
# CONFIG_BOOTLOADER_LOG_LEVEL_ERROR is not set
|
||||
# CONFIG_BOOTLOADER_LOG_LEVEL_WARN is not set
|
||||
CONFIG_BOOTLOADER_LOG_LEVEL_INFO=y
|
||||
# CONFIG_BOOTLOADER_LOG_LEVEL_DEBUG is not set
|
||||
# CONFIG_BOOTLOADER_LOG_LEVEL_VERBOSE is not set
|
||||
@@ -102,7 +109,6 @@ CONFIG_LOGGING_SLIMPROTO="info"
|
||||
CONFIG_LOGGING_STREAM="info"
|
||||
CONFIG_LOGGING_DECODE="info"
|
||||
CONFIG_LOGGING_OUTPUT="info"
|
||||
# CONFIG_BASIC_I2C_BT is not set
|
||||
CONFIG_A2DP_SINK_NAME="SMSL BT4.2"
|
||||
CONFIG_A2DP_DEV_NAME="Squeezelite"
|
||||
CONFIG_A2DP_CONTROL_DELAY_MS=500
|
||||
@@ -126,8 +132,8 @@ CONFIG_DEFAULT_AP_BEACON_INTERVAL=100
|
||||
CONFIG_DEFAULT_COMMAND_LINE="squeezelite -o I2S -b 500:2000 -d all=info -C 30 -W"
|
||||
# CONFIG_COMPILER_OPTIMIZATION_LEVEL_DEBUG is not set
|
||||
CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE=y
|
||||
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE=y
|
||||
# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT is not set
|
||||
# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE is not set
|
||||
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y
|
||||
# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE is not set
|
||||
CONFIG_COMPILER_CXX_EXCEPTIONS=y
|
||||
CONFIG_COMPILER_CXX_EXCEPTIONS_EMG_POOL_SIZE=0
|
||||
@@ -151,7 +157,6 @@ CONFIG_BTDM_CTRL_BR_EDR_MAX_SYNC_CONN=0
|
||||
# CONFIG_BTDM_CTRL_BR_EDR_SCO_DATA_PATH_HCI is not set
|
||||
CONFIG_BTDM_CTRL_BR_EDR_SCO_DATA_PATH_PCM=y
|
||||
CONFIG_BTDM_CTRL_BR_EDR_SCO_DATA_PATH_EFF=1
|
||||
# CONFIG_BTDM_CTRL_AUTO_LATENCY_EFF is not set
|
||||
CONFIG_BTDM_CTRL_BLE_MAX_CONN_EFF=0
|
||||
CONFIG_BTDM_CTRL_BR_EDR_MAX_ACL_CONN_EFF=2
|
||||
CONFIG_BTDM_CTRL_BR_EDR_MAX_SYNC_CONN_EFF=0
|
||||
@@ -180,183 +185,10 @@ CONFIG_BT_A2DP_ENABLE=y
|
||||
# CONFIG_BT_SPP_ENABLED is not set
|
||||
# CONFIG_BT_HFP_ENABLE is not set
|
||||
CONFIG_BT_SSP_ENABLED=y
|
||||
<<<<<<< HEAD
|
||||
# CONFIG_BT_BLE_ENABLED is not set
|
||||
CONFIG_BT_STACK_NO_LOG=y
|
||||
=======
|
||||
CONFIG_BT_BLE_ENABLED=n
|
||||
CONFIG_BT_BLE_SMP_ENABLE=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_HCI_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_HCI_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_BTM_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_BTM_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_L2CAP_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_L2CAP_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_RFCOMM_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_RFCOMM_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_SDP_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_SDP_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_GAP_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_GAP_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_BNEP_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_BNEP_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_PAN_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_PAN_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_A2D_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_A2D_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_AVDT_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_AVDT_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_AVCT_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_AVCT_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_AVRC_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_AVRC_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_MCA_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_MCA_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_HID_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_HID_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_APPL_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_APPL_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_GATT_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_GATT_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_SMP_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_SMP_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_BTIF_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_BTIF_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_BTC_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_BTC_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_OSI_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_OSI_TRACE_LEVEL=2
|
||||
|
||||
|
||||
CONFIG_BT_LOG_BLUFI_TRACE_LEVEL_WARNING=y
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_BT_LOG_BLUFI_TRACE_LEVEL=2
|
||||
>>>>>>> refs/remotes/origin/master
|
||||
CONFIG_BT_STACK_NO_LOG=y
|
||||
CONFIG_BT_ACL_CONNECTIONS=4
|
||||
CONFIG_BT_ALLOCATION_FROM_SPIRAM_FIRST=y
|
||||
CONFIG_BT_BLE_DYNAMIC_ENV_MEMORY=y
|
||||
@@ -369,8 +201,8 @@ CONFIG_BT_RESERVE_DRAM=0xdb5c
|
||||
CONFIG_ADC_DISABLE_DAC=y
|
||||
CONFIG_SPI_MASTER_IN_IRAM=y
|
||||
CONFIG_SPI_MASTER_ISR_IN_IRAM=y
|
||||
CONFIG_SPI_SLAVE_IN_IRAM=y
|
||||
CONFIG_SPI_SLAVE_ISR_IN_IRAM=y
|
||||
# CONFIG_SPI_SLAVE_IN_IRAM is not set
|
||||
# CONFIG_SPI_SLAVE_ISR_IN_IRAM is not set
|
||||
# CONFIG_EFUSE_CUSTOM_TABLE is not set
|
||||
# CONFIG_EFUSE_VIRTUAL is not set
|
||||
# CONFIG_EFUSE_CODE_SCHEME_COMPAT_NONE is not set
|
||||
@@ -378,11 +210,12 @@ CONFIG_EFUSE_CODE_SCHEME_COMPAT_3_4=y
|
||||
# CONFIG_EFUSE_CODE_SCHEME_COMPAT_REPEAT is not set
|
||||
CONFIG_EFUSE_MAX_BLK_LEN=192
|
||||
# CONFIG_ESP_TLS_SERVER is not set
|
||||
CONFIG_ESP32_REV_MIN_0=y
|
||||
# CONFIG_ESP32_REV_MIN_1 is not set
|
||||
CONFIG_ESP32_ECO3_CACHE_LOCK_FIX=y
|
||||
# CONFIG_ESP32_REV_MIN_0 is not set
|
||||
CONFIG_ESP32_REV_MIN_1=y
|
||||
# CONFIG_ESP32_REV_MIN_2 is not set
|
||||
# CONFIG_ESP32_REV_MIN_3 is not set
|
||||
CONFIG_ESP32_REV_MIN=0
|
||||
CONFIG_ESP32_REV_MIN=1
|
||||
CONFIG_ESP32_DPORT_WORKAROUND=y
|
||||
# CONFIG_ESP32_DEFAULT_CPU_FREQ_80 is not set
|
||||
# CONFIG_ESP32_DEFAULT_CPU_FREQ_160 is not set
|
||||
@@ -401,6 +234,9 @@ CONFIG_SPIRAM_SIZE=-1
|
||||
CONFIG_SPIRAM_SPEED_80M=y
|
||||
CONFIG_SPIRAM_MEMTEST=y
|
||||
CONFIG_SPIRAM_CACHE_WORKAROUND=y
|
||||
CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_MEMW=y
|
||||
# CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_DUPLDST is not set
|
||||
# CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_NOPS is not set
|
||||
CONFIG_SPIRAM_BANKSWITCH_ENABLE=y
|
||||
CONFIG_SPIRAM_BANKSWITCH_RESERVE=8
|
||||
CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=256
|
||||
@@ -506,11 +342,6 @@ CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=40
|
||||
CONFIG_ESP32_WIFI_STATIC_TX_BUFFER=y
|
||||
CONFIG_ESP32_WIFI_TX_BUFFER_TYPE=0
|
||||
CONFIG_ESP32_WIFI_STATIC_TX_BUFFER_NUM=12
|
||||
# CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED is not set
|
||||
# CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED is not set
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIG_ESP32_WIFI_NVS_ENABLED=y
|
||||
CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_0=y
|
||||
@@ -596,7 +427,7 @@ CONFIG_FREERTOS_MAX_TASK_NAME_LEN=16
|
||||
CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION=y
|
||||
# CONFIG_FREERTOS_ENABLE_STATIC_TASK_CLEAN_UP is not set
|
||||
CONFIG_FREERTOS_TIMER_TASK_PRIORITY=1
|
||||
CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=2432
|
||||
CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=2800
|
||||
CONFIG_FREERTOS_TIMER_QUEUE_LENGTH=10
|
||||
CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE=0
|
||||
#CONFIG_FREERTOS_USE_TRACE_FACILITY=y
|
||||
@@ -630,19 +461,9 @@ CONFIG_LWIP_MAX_SOCKETS=16
|
||||
# CONFIG_LWIP_USE_ONLY_LWIP_SELECT is not set
|
||||
CONFIG_LWIP_SO_REUSE=y
|
||||
CONFIG_LWIP_SO_REUSE_RXTOALL=y
|
||||
<<<<<<< HEAD
|
||||
# CONFIG_LWIP_SO_RCVBUF is not set
|
||||
# CONFIG_LWIP_IP_FRAG is not set
|
||||
# CONFIG_LWIP_IP_REASSEMBLY is not set
|
||||
# CONFIG_LWIP_STATS is not set
|
||||
# CONFIG_LWIP_ETHARP_TRUST_IP_MAC is not set
|
||||
=======
|
||||
CONFIG_LWIP_IP_REASSEMBLY=y
|
||||
|
||||
|
||||
|
||||
|
||||
>>>>>>> refs/remotes/origin/master
|
||||
#CONFIG_LWIP_IP_REASSEMBLY is not set
|
||||
CONFIG_LWIP_IP6_REASSEMBLY=y
|
||||
CONFIG_LWIP_IP4_REASSEMBLY=y
|
||||
CONFIG_LWIP_ESP_GRATUITOUS_ARP=y
|
||||
CONFIG_LWIP_GARP_TMR_INTERVAL=60
|
||||
CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=32
|
||||
@@ -651,7 +472,6 @@ CONFIG_LWIP_DHCP_RESTORE_LAST_IP=y
|
||||
CONFIG_LWIP_DHCPS_LEASE_UNIT=60
|
||||
CONFIG_LWIP_DHCPS_MAX_STATION_NUM=8
|
||||
# CONFIG_LWIP_AUTOIP is not set
|
||||
# CONFIG_LWIP_IPV6_AUTOCONFIG is not set
|
||||
CONFIG_LWIP_NETIF_LOOPBACK=y
|
||||
CONFIG_LWIP_LOOPBACK_MAX_PBUFS=8
|
||||
CONFIG_LWIP_MAX_ACTIVE_TCP=16
|
||||
@@ -686,7 +506,6 @@ CONFIG_LWIP_SNTP_UPDATE_DELAY=3600000
|
||||
CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC=y
|
||||
# CONFIG_MBEDTLS_DEFAULT_MEM_ALLOC is not set
|
||||
# CONFIG_MBEDTLS_CUSTOM_MEM_ALLOC is not set
|
||||
|
||||
CONFIG_MBEDTLS_SSL_MAX_CONTENT_LEN=16384
|
||||
# CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN is not set
|
||||
# CONFIG_MBEDTLS_DEBUG is not set
|
||||
@@ -971,7 +790,7 @@ CONFIG_MB_TIMER_INDEX=0
|
||||
CONFIG_SUPPORT_STATIC_ALLOCATION=y
|
||||
# CONFIG_ENABLE_STATIC_TASK_CLEAN_UP_HOOK is not set
|
||||
CONFIG_TIMER_TASK_PRIORITY=1
|
||||
CONFIG_TIMER_TASK_STACK_DEPTH=2432
|
||||
CONFIG_TIMER_TASK_STACK_DEPTH=2800
|
||||
CONFIG_TIMER_QUEUE_LENGTH=10
|
||||
# CONFIG_L2_TO_L3_COPY is not set
|
||||
# CONFIG_USE_ONLY_LWIP_SELECT is not set
|
||||
@@ -1,840 +0,0 @@
|
||||
#
|
||||
# Automatically generated file. DO NOT EDIT.
|
||||
# Espressif IoT Development Framework (ESP-IDF) Project Configuration
|
||||
#
|
||||
CONFIG_IDF_TARGET_ESP32=y
|
||||
CONFIG_IDF_TARGET="esp32"
|
||||
CONFIG_IDF_FIRMWARE_CHIP_ID=0x0000
|
||||
|
||||
#
|
||||
# SDK tool configuration
|
||||
#
|
||||
CONFIG_SDK_TOOLPREFIX="xtensa-esp32-elf-"
|
||||
CONFIG_APP_COMPILE_TIME_DATE=y
|
||||
# CONFIG_APP_EXCLUDE_PROJECT_VER_VAR is not set
|
||||
# CONFIG_APP_EXCLUDE_PROJECT_NAME_VAR is not set
|
||||
# CONFIG_BOOTLOADER_LOG_LEVEL_NONE is not set
|
||||
# CONFIG_BOOTLOADER_LOG_LEVEL_ERROR is not set
|
||||
# CONFIG_BOOTLOADER_LOG_LEVEL_WARN is not set
|
||||
CONFIG_BOOTLOADER_LOG_LEVEL_INFO=y
|
||||
# CONFIG_BOOTLOADER_LOG_LEVEL_DEBUG is not set
|
||||
# CONFIG_BOOTLOADER_LOG_LEVEL_VERBOSE is not set
|
||||
CONFIG_BOOTLOADER_LOG_LEVEL=3
|
||||
CONFIG_BOOTLOADER_SPI_WP_PIN=7
|
||||
CONFIG_BOOTLOADER_VDDSDIO_BOOST_1_9V=y
|
||||
# CONFIG_BOOTLOADER_FACTORY_RESET is not set
|
||||
# CONFIG_BOOTLOADER_APP_TEST is not set
|
||||
CONFIG_BOOTLOADER_WDT_ENABLE=y
|
||||
# CONFIG_BOOTLOADER_WDT_DISABLE_IN_USER_CODE is not set
|
||||
CONFIG_BOOTLOADER_WDT_TIME_MS=9000
|
||||
# CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE is not set
|
||||
# CONFIG_SECURE_SIGNED_APPS_NO_SECURE_BOOT is not set
|
||||
# CONFIG_SECURE_BOOT_ENABLED is not set
|
||||
# CONFIG_SECURE_FLASH_ENC_ENABLED is not set
|
||||
CONFIG_ESPTOOLPY_BAUD_OTHER_VAL=115200
|
||||
CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
|
||||
# CONFIG_ESPTOOLPY_FLASHMODE_QOUT is not set
|
||||
# CONFIG_ESPTOOLPY_FLASHMODE_DIO is not set
|
||||
# CONFIG_ESPTOOLPY_FLASHMODE_DOUT is not set
|
||||
CONFIG_ESPTOOLPY_FLASHMODE="dio"
|
||||
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
|
||||
# CONFIG_ESPTOOLPY_FLASHFREQ_40M is not set
|
||||
# CONFIG_ESPTOOLPY_FLASHFREQ_26M is not set
|
||||
# CONFIG_ESPTOOLPY_FLASHFREQ_20M is not set
|
||||
CONFIG_ESPTOOLPY_FLASHFREQ="80m"
|
||||
# CONFIG_ESPTOOLPY_FLASHSIZE_1MB is not set
|
||||
# CONFIG_ESPTOOLPY_FLASHSIZE_2MB is not set
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
|
||||
# CONFIG_ESPTOOLPY_FLASHSIZE_8MB is not set
|
||||
# CONFIG_ESPTOOLPY_FLASHSIZE_16MB is not set
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE="4MB"
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_DETECT=y
|
||||
CONFIG_ESPTOOLPY_BEFORE_RESET=y
|
||||
# CONFIG_ESPTOOLPY_BEFORE_NORESET is not set
|
||||
CONFIG_ESPTOOLPY_BEFORE="default_reset"
|
||||
CONFIG_ESPTOOLPY_AFTER_RESET=y
|
||||
# CONFIG_ESPTOOLPY_AFTER_NORESET is not set
|
||||
CONFIG_ESPTOOLPY_AFTER="hard_reset"
|
||||
# CONFIG_ESPTOOLPY_MONITOR_BAUD_9600B is not set
|
||||
# CONFIG_ESPTOOLPY_MONITOR_BAUD_57600B is not set
|
||||
CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B=y
|
||||
# CONFIG_ESPTOOLPY_MONITOR_BAUD_230400B is not set
|
||||
# CONFIG_ESPTOOLPY_MONITOR_BAUD_921600B is not set
|
||||
# CONFIG_ESPTOOLPY_MONITOR_BAUD_2MB is not set
|
||||
# CONFIG_ESPTOOLPY_MONITOR_BAUD_OTHER is not set
|
||||
CONFIG_ESPTOOLPY_MONITOR_BAUD_OTHER_VAL=115200
|
||||
CONFIG_ESPTOOLPY_MONITOR_BAUD=115200
|
||||
# CONFIG_PARTITION_TABLE_SINGLE_APP is not set
|
||||
# CONFIG_PARTITION_TABLE_TWO_OTA is not set
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
|
||||
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
|
||||
CONFIG_PARTITION_TABLE_OFFSET=0x8000
|
||||
CONFIG_PARTITION_TABLE_MD5=y
|
||||
CONFIG_LOGGING_SLIMPROTO="info"
|
||||
CONFIG_LOGGING_STREAM="info"
|
||||
CONFIG_LOGGING_DECODE="info"
|
||||
CONFIG_LOGGING_OUTPUT="info"
|
||||
# CONFIG_SQUEEZEAMP is not set
|
||||
# CONFIG_A1S is not set
|
||||
CONFIG_BASIC_I2C_BT=y
|
||||
CONFIG_I2S_NUM=0
|
||||
CONFIG_I2S_BCK_IO=33
|
||||
CONFIG_I2S_WS_IO=25
|
||||
CONFIG_I2S_DO_IO=32
|
||||
CONFIG_I2S_DI_IO=-1
|
||||
CONFIG_SDIF_NUM=0
|
||||
CONFIG_SPDIF_BCK_IO=33
|
||||
CONFIG_SPDIF_WS_IO=25
|
||||
CONFIG_SPDIF_DO_IO=15
|
||||
CONFIG_A2DP_SINK_NAME="SMSL BT4.2"
|
||||
CONFIG_A2DP_DEV_NAME="Squeezelite"
|
||||
CONFIG_A2DP_CONTROL_DELAY_MS=500
|
||||
CONFIG_A2DP_CONNECT_TIMEOUT_MS=1000
|
||||
CONFIG_BT_SINK=y
|
||||
CONFIG_BT_NAME="ESP32-BT"
|
||||
CONFIG_BT_SINK_PIN=1234
|
||||
CONFIG_AIRPLAY_SINK=y
|
||||
CONFIG_AIRPLAY_NAME="ESP32-AirPlay"
|
||||
CONFIG_AIRPLAY_PORT="5000"
|
||||
CONFIG_DISPLAY_CONFIG=""
|
||||
CONFIG_I2C_CONFIG=""
|
||||
CONFIG_SPI_CONFIG=""
|
||||
CONFIG_SET_GPIO=""
|
||||
CONFIG_ROTARY_ENCODER=""
|
||||
CONFIG_LED_GREEN_GPIO=-1
|
||||
CONFIG_LED_RED_GPIO=-1
|
||||
CONFIG_JACK_GPIO=-1
|
||||
CONFIG_SPKFAULT_GPIO=-1
|
||||
CONFIG_BAT_CHANNEL=-1
|
||||
CONFIG_WIFI_MANAGER_TASK_PRIORITY=5
|
||||
CONFIG_WIFI_MANAGER_MAX_RETRY=2
|
||||
CONFIG_DEFAULT_AP_SSID="squeezelite"
|
||||
CONFIG_DEFAULT_AP_PASSWORD="squeezelite"
|
||||
CONFIG_DEFAULT_AP_CHANNEL=1
|
||||
CONFIG_DEFAULT_AP_IP="192.168.4.1"
|
||||
CONFIG_DEFAULT_AP_GATEWAY="192.168.4.1"
|
||||
CONFIG_DEFAULT_AP_NETMASK="255.255.255.0"
|
||||
CONFIG_DEFAULT_AP_MAX_CONNECTIONS=4
|
||||
CONFIG_DEFAULT_AP_BEACON_INTERVAL=100
|
||||
CONFIG_DEFAULT_COMMAND_LINE="squeezelite -o I2S -b 500:2000 -d all=info -C 30"
|
||||
# CONFIG_COMPILER_OPTIMIZATION_LEVEL_DEBUG is not set
|
||||
CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE=y
|
||||
# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE is not set
|
||||
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y
|
||||
# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE is not set
|
||||
# CONFIG_COMPILER_CXX_EXCEPTIONS is not set
|
||||
CONFIG_COMPILER_STACK_CHECK_MODE_NONE=y
|
||||
# CONFIG_COMPILER_STACK_CHECK_MODE_NORM is not set
|
||||
# CONFIG_COMPILER_STACK_CHECK_MODE_STRONG is not set
|
||||
# CONFIG_COMPILER_STACK_CHECK_MODE_ALL is not set
|
||||
# CONFIG_COMPILER_STACK_CHECK is not set
|
||||
# CONFIG_COMPILER_WARN_WRITE_STRINGS is not set
|
||||
# CONFIG_COMPILER_DISABLE_GCC8_WARNINGS is not set
|
||||
# CONFIG_ESP32_APPTRACE_DEST_TRAX is not set
|
||||
CONFIG_ESP32_APPTRACE_DEST_NONE=y
|
||||
# CONFIG_ESP32_APPTRACE_ENABLE is not set
|
||||
CONFIG_ESP32_APPTRACE_LOCK_ENABLE=y
|
||||
CONFIG_BT_ENABLED=y
|
||||
# CONFIG_BTDM_CTRL_MODE_BLE_ONLY is not set
|
||||
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=y
|
||||
# CONFIG_BTDM_CTRL_MODE_BTDM is not set
|
||||
CONFIG_BTDM_CTRL_BR_EDR_MAX_ACL_CONN=2
|
||||
CONFIG_BTDM_CTRL_BR_EDR_MAX_SYNC_CONN=0
|
||||
# CONFIG_BTDM_CTRL_BR_EDR_SCO_DATA_PATH_HCI is not set
|
||||
CONFIG_BTDM_CTRL_BR_EDR_SCO_DATA_PATH_PCM=y
|
||||
CONFIG_BTDM_CTRL_BR_EDR_SCO_DATA_PATH_EFF=1
|
||||
# CONFIG_BTDM_CTRL_AUTO_LATENCY_EFF is not set
|
||||
CONFIG_BTDM_CTRL_BLE_MAX_CONN_EFF=0
|
||||
CONFIG_BTDM_CTRL_BR_EDR_MAX_ACL_CONN_EFF=2
|
||||
CONFIG_BTDM_CTRL_BR_EDR_MAX_SYNC_CONN_EFF=0
|
||||
CONFIG_BTDM_CTRL_PINNED_TO_CORE_0=y
|
||||
# CONFIG_BTDM_CTRL_PINNED_TO_CORE_1 is not set
|
||||
CONFIG_BTDM_CTRL_PINNED_TO_CORE=0
|
||||
CONFIG_BTDM_CTRL_HCI_MODE_VHCI=y
|
||||
# CONFIG_BTDM_CTRL_HCI_MODE_UART_H4 is not set
|
||||
CONFIG_BTDM_MODEM_SLEEP=y
|
||||
CONFIG_BTDM_MODEM_SLEEP_MODE_ORIG=y
|
||||
# CONFIG_BTDM_MODEM_SLEEP_MODE_EVED is not set
|
||||
CONFIG_BTDM_LPCLK_SEL_MAIN_XTAL=y
|
||||
CONFIG_BTDM_BLE_SLEEP_CLOCK_ACCURACY_INDEX_EFF=1
|
||||
# CONFIG_BTDM_COEX_BT_OPTIONS is not set
|
||||
CONFIG_BT_BLUEDROID_ENABLED=y
|
||||
# CONFIG_BT_NIMBLE_ENABLED is not set
|
||||
# CONFIG_BT_CONTROLLER_ONLY is not set
|
||||
CONFIG_BT_BTC_TASK_STACK_SIZE=3072
|
||||
CONFIG_BT_BLUEDROID_PINNED_TO_CORE_0=y
|
||||
# CONFIG_BT_BLUEDROID_PINNED_TO_CORE_1 is not set
|
||||
CONFIG_BT_BLUEDROID_PINNED_TO_CORE=0
|
||||
CONFIG_BT_BTU_TASK_STACK_SIZE=4096
|
||||
# CONFIG_BT_BLUEDROID_MEM_DEBUG is not set
|
||||
CONFIG_BT_CLASSIC_ENABLED=y
|
||||
CONFIG_BT_A2DP_ENABLE=y
|
||||
# CONFIG_BT_SPP_ENABLED is not set
|
||||
# CONFIG_BT_HFP_ENABLE is not set
|
||||
CONFIG_BT_SSP_ENABLED=y
|
||||
CONFIG_BT_BLE_ENABLED=y
|
||||
CONFIG_BT_GATTS_ENABLE=y
|
||||
# CONFIG_BT_GATTS_SEND_SERVICE_CHANGE_MANUAL is not set
|
||||
CONFIG_BT_GATTS_SEND_SERVICE_CHANGE_AUTO=y
|
||||
CONFIG_BT_GATTS_SEND_SERVICE_CHANGE_MODE=0
|
||||
CONFIG_BT_GATTC_ENABLE=y
|
||||
# CONFIG_BT_GATTC_CACHE_NVS_FLASH is not set
|
||||
CONFIG_BT_BLE_SMP_ENABLE=y
|
||||
# CONFIG_BT_SMP_SLAVE_CON_PARAMS_UPD_ENABLE is not set
|
||||
CONFIG_BT_STACK_NO_LOG=y
|
||||
CONFIG_BT_ACL_CONNECTIONS=4
|
||||
CONFIG_BT_ALLOCATION_FROM_SPIRAM_FIRST=y
|
||||
CONFIG_BT_BLE_DYNAMIC_ENV_MEMORY=y
|
||||
# CONFIG_BT_BLE_HOST_QUEUE_CONG_CHECK is not set
|
||||
CONFIG_BT_SMP_ENABLE=y
|
||||
CONFIG_BT_BLE_ESTAB_LINK_CONN_TOUT=30
|
||||
CONFIG_BT_RESERVE_DRAM=0xdb5c
|
||||
# CONFIG_BLE_MESH is not set
|
||||
# CONFIG_ADC_FORCE_XPD_FSM is not set
|
||||
CONFIG_ADC_DISABLE_DAC=y
|
||||
# CONFIG_SPI_MASTER_IN_IRAM is not set
|
||||
CONFIG_SPI_MASTER_ISR_IN_IRAM=y
|
||||
# CONFIG_SPI_SLAVE_IN_IRAM is not set
|
||||
CONFIG_SPI_SLAVE_ISR_IN_IRAM=y
|
||||
# CONFIG_EFUSE_CUSTOM_TABLE is not set
|
||||
# CONFIG_EFUSE_VIRTUAL is not set
|
||||
# CONFIG_EFUSE_CODE_SCHEME_COMPAT_NONE is not set
|
||||
CONFIG_EFUSE_CODE_SCHEME_COMPAT_3_4=y
|
||||
# CONFIG_EFUSE_CODE_SCHEME_COMPAT_REPEAT is not set
|
||||
CONFIG_EFUSE_MAX_BLK_LEN=192
|
||||
# CONFIG_ESP_TLS_SERVER is not set
|
||||
CONFIG_ESP32_REV_MIN_0=y
|
||||
# CONFIG_ESP32_REV_MIN_1 is not set
|
||||
# CONFIG_ESP32_REV_MIN_2 is not set
|
||||
# CONFIG_ESP32_REV_MIN_3 is not set
|
||||
CONFIG_ESP32_REV_MIN=0
|
||||
CONFIG_ESP32_DPORT_WORKAROUND=y
|
||||
# CONFIG_ESP32_DEFAULT_CPU_FREQ_80 is not set
|
||||
# CONFIG_ESP32_DEFAULT_CPU_FREQ_160 is not set
|
||||
CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y
|
||||
CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ=240
|
||||
CONFIG_ESP32_SPIRAM_SUPPORT=y
|
||||
CONFIG_SPIRAM_BOOT_INIT=y
|
||||
# CONFIG_SPIRAM_USE_MEMMAP is not set
|
||||
# CONFIG_SPIRAM_USE_CAPS_ALLOC is not set
|
||||
CONFIG_SPIRAM_USE_MALLOC=y
|
||||
CONFIG_SPIRAM_TYPE_AUTO=y
|
||||
# CONFIG_SPIRAM_TYPE_ESPPSRAM32 is not set
|
||||
# CONFIG_SPIRAM_TYPE_ESPPSRAM64 is not set
|
||||
CONFIG_SPIRAM_SIZE=-1
|
||||
# CONFIG_SPIRAM_SPEED_40M is not set
|
||||
CONFIG_SPIRAM_SPEED_80M=y
|
||||
CONFIG_SPIRAM_MEMTEST=y
|
||||
CONFIG_SPIRAM_CACHE_WORKAROUND=y
|
||||
CONFIG_SPIRAM_BANKSWITCH_ENABLE=y
|
||||
CONFIG_SPIRAM_BANKSWITCH_RESERVE=8
|
||||
CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=256
|
||||
CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP=y
|
||||
CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL=65536
|
||||
CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY=y
|
||||
CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY=y
|
||||
# CONFIG_SPIRAM_OCCUPY_HSPI_HOST is not set
|
||||
CONFIG_SPIRAM_OCCUPY_VSPI_HOST=y
|
||||
# CONFIG_SPIRAM_OCCUPY_NO_HOST is not set
|
||||
CONFIG_D0WD_PSRAM_CLK_IO=17
|
||||
CONFIG_D0WD_PSRAM_CS_IO=16
|
||||
CONFIG_D2WD_PSRAM_CLK_IO=9
|
||||
CONFIG_D2WD_PSRAM_CS_IO=10
|
||||
CONFIG_PICO_PSRAM_CS_IO=10
|
||||
# CONFIG_ESP32_MEMMAP_TRACEMEM is not set
|
||||
# CONFIG_ESP32_MEMMAP_TRACEMEM_TWOBANKS is not set
|
||||
# CONFIG_ESP32_TRAX is not set
|
||||
CONFIG_ESP32_TRACEMEM_RESERVE_DRAM=0x0
|
||||
# CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES_TWO is not set
|
||||
CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES_FOUR=y
|
||||
CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES=4
|
||||
# CONFIG_ESP32_ULP_COPROC_ENABLED is not set
|
||||
CONFIG_ESP32_ULP_COPROC_RESERVE_MEM=0
|
||||
# CONFIG_ESP32_PANIC_PRINT_HALT is not set
|
||||
CONFIG_ESP32_PANIC_PRINT_REBOOT=y
|
||||
# CONFIG_ESP32_PANIC_SILENT_REBOOT is not set
|
||||
# CONFIG_ESP32_PANIC_GDBSTUB is not set
|
||||
CONFIG_ESP32_DEBUG_OCDAWARE=y
|
||||
# CONFIG_ESP32_DEBUG_STUBS_ENABLE is not set
|
||||
CONFIG_ESP32_BROWNOUT_DET=y
|
||||
CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_0=y
|
||||
# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_1 is not set
|
||||
# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_2 is not set
|
||||
# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_3 is not set
|
||||
# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_4 is not set
|
||||
# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_5 is not set
|
||||
# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_6 is not set
|
||||
# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_7 is not set
|
||||
CONFIG_ESP32_BROWNOUT_DET_LVL=0
|
||||
CONFIG_ESP32_REDUCE_PHY_TX_POWER=y
|
||||
CONFIG_ESP32_TIME_SYSCALL_USE_RTC_FRC1=y
|
||||
# CONFIG_ESP32_TIME_SYSCALL_USE_RTC is not set
|
||||
# CONFIG_ESP32_TIME_SYSCALL_USE_FRC1 is not set
|
||||
# CONFIG_ESP32_TIME_SYSCALL_USE_NONE is not set
|
||||
CONFIG_ESP32_RTC_CLK_SRC_INT_RC=y
|
||||
# CONFIG_ESP32_RTC_CLK_SRC_EXT_CRYS is not set
|
||||
# CONFIG_ESP32_RTC_CLK_SRC_EXT_OSC is not set
|
||||
# CONFIG_ESP32_RTC_CLK_SRC_INT_8MD256 is not set
|
||||
CONFIG_ESP32_RTC_CLK_CAL_CYCLES=1024
|
||||
CONFIG_ESP32_DEEP_SLEEP_WAKEUP_DELAY=2000
|
||||
CONFIG_ESP32_XTAL_FREQ_40=y
|
||||
# CONFIG_ESP32_XTAL_FREQ_26 is not set
|
||||
# CONFIG_ESP32_XTAL_FREQ_AUTO is not set
|
||||
CONFIG_ESP32_XTAL_FREQ=40
|
||||
# CONFIG_ESP32_DISABLE_BASIC_ROM_CONSOLE is not set
|
||||
# CONFIG_ESP32_COMPATIBLE_PRE_V2_1_BOOTLOADERS is not set
|
||||
# CONFIG_ESP32_USE_FIXED_STATIC_RAM_SIZE is not set
|
||||
CONFIG_ESP32_DPORT_DIS_INTERRUPT_LVL=5
|
||||
# CONFIG_PM_ENABLE is not set
|
||||
CONFIG_ADC_CAL_EFUSE_TP_ENABLE=y
|
||||
CONFIG_ADC_CAL_EFUSE_VREF_ENABLE=y
|
||||
CONFIG_ADC_CAL_LUT_ENABLE=y
|
||||
# CONFIG_ESP_TIMER_PROFILING is not set
|
||||
CONFIG_ESP_ERR_TO_NAME_LOOKUP=y
|
||||
CONFIG_ESP_SYSTEM_EVENT_QUEUE_SIZE=32
|
||||
CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=2304
|
||||
CONFIG_ESP_MAIN_TASK_STACK_SIZE=8192
|
||||
CONFIG_ESP_IPC_TASK_STACK_SIZE=1024
|
||||
CONFIG_ESP_TIMER_TASK_STACK_SIZE=3584
|
||||
CONFIG_ESP_CONSOLE_UART_DEFAULT=y
|
||||
# CONFIG_ESP_CONSOLE_UART_CUSTOM is not set
|
||||
# CONFIG_ESP_CONSOLE_UART_NONE is not set
|
||||
CONFIG_ESP_CONSOLE_UART_NUM=0
|
||||
CONFIG_ESP_CONSOLE_UART_BAUDRATE=115200
|
||||
CONFIG_ESP_INT_WDT=y
|
||||
CONFIG_ESP_INT_WDT_TIMEOUT_MS=800
|
||||
CONFIG_ESP_INT_WDT_CHECK_CPU1=y
|
||||
CONFIG_ESP_TASK_WDT=y
|
||||
# CONFIG_ESP_TASK_WDT_PANIC is not set
|
||||
CONFIG_ESP_TASK_WDT_TIMEOUT_S=5
|
||||
CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0=y
|
||||
CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1=y
|
||||
CONFIG_ETH_USE_ESP32_EMAC=y
|
||||
CONFIG_ETH_PHY_INTERFACE_RMII=y
|
||||
# CONFIG_ETH_PHY_INTERFACE_MII is not set
|
||||
CONFIG_ETH_RMII_CLK_INPUT=y
|
||||
# CONFIG_ETH_RMII_CLK_OUTPUT is not set
|
||||
CONFIG_ETH_RMII_CLK_IN_GPIO=0
|
||||
CONFIG_ETH_DMA_BUFFER_SIZE=512
|
||||
CONFIG_ETH_DMA_RX_BUFFER_NUM=10
|
||||
CONFIG_ETH_DMA_TX_BUFFER_NUM=10
|
||||
# CONFIG_ETH_USE_SPI_ETHERNET is not set
|
||||
# CONFIG_ESP_EVENT_LOOP_PROFILING is not set
|
||||
CONFIG_ESP_EVENT_POST_FROM_ISR=y
|
||||
CONFIG_ESP_EVENT_POST_FROM_IRAM_ISR=y
|
||||
CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS=y
|
||||
# CONFIG_ESP_HTTP_CLIENT_ENABLE_BASIC_AUTH is not set
|
||||
CONFIG_HTTPD_MAX_REQ_HDR_LEN=1024
|
||||
CONFIG_HTTPD_MAX_URI_LEN=512
|
||||
CONFIG_HTTPD_ERR_RESP_NO_DELAY=y
|
||||
CONFIG_HTTPD_PURGE_BUF_LEN=32
|
||||
# CONFIG_HTTPD_LOG_PURGE_DATA is not set
|
||||
CONFIG_OTA_ALLOW_HTTP=y
|
||||
# CONFIG_ESP_HTTPS_SERVER_ENABLE is not set
|
||||
CONFIG_ESP32_WIFI_SW_COEXIST_ENABLE=y
|
||||
CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM=12
|
||||
CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=40
|
||||
CONFIG_ESP32_WIFI_STATIC_TX_BUFFER=y
|
||||
CONFIG_ESP32_WIFI_TX_BUFFER_TYPE=0
|
||||
CONFIG_ESP32_WIFI_STATIC_TX_BUFFER_NUM=12
|
||||
# CONFIG_ESP32_WIFI_CSI_ENABLED is not set
|
||||
# CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED is not set
|
||||
# CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED is not set
|
||||
CONFIG_ESP32_WIFI_RX_BA_WIN=16
|
||||
CONFIG_ESP32_WIFI_NVS_ENABLED=y
|
||||
CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_0=y
|
||||
# CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_1 is not set
|
||||
CONFIG_ESP32_WIFI_SOFTAP_BEACON_MAX_LEN=752
|
||||
CONFIG_ESP32_WIFI_MGMT_SBUF_NUM=32
|
||||
# CONFIG_ESP32_WIFI_DEBUG_LOG_ENABLE is not set
|
||||
# CONFIG_ESP32_WIFI_IRAM_OPT is not set
|
||||
# CONFIG_ESP32_WIFI_RX_IRAM_OPT is not set
|
||||
CONFIG_ESP32_PHY_CALIBRATION_AND_DATA_STORAGE=y
|
||||
#CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION=y
|
||||
CONFIG_ESP32_PHY_MAX_WIFI_TX_POWER=20
|
||||
CONFIG_ESP32_PHY_MAX_TX_POWER=20
|
||||
# CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH is not set
|
||||
# CONFIG_ESP32_ENABLE_COREDUMP_TO_UART is not set
|
||||
CONFIG_ESP32_ENABLE_COREDUMP_TO_NONE=y
|
||||
# CONFIG_ESP32_ENABLE_COREDUMP is not set
|
||||
# CONFIG_FATFS_CODEPAGE_DYNAMIC is not set
|
||||
CONFIG_FATFS_CODEPAGE_437=y
|
||||
# CONFIG_FATFS_CODEPAGE_720 is not set
|
||||
# CONFIG_FATFS_CODEPAGE_737 is not set
|
||||
# CONFIG_FATFS_CODEPAGE_771 is not set
|
||||
# CONFIG_FATFS_CODEPAGE_775 is not set
|
||||
# CONFIG_FATFS_CODEPAGE_850 is not set
|
||||
# CONFIG_FATFS_CODEPAGE_852 is not set
|
||||
# CONFIG_FATFS_CODEPAGE_855 is not set
|
||||
# CONFIG_FATFS_CODEPAGE_857 is not set
|
||||
# CONFIG_FATFS_CODEPAGE_860 is not set
|
||||
# CONFIG_FATFS_CODEPAGE_861 is not set
|
||||
# CONFIG_FATFS_CODEPAGE_862 is not set
|
||||
# CONFIG_FATFS_CODEPAGE_863 is not set
|
||||
# CONFIG_FATFS_CODEPAGE_864 is not set
|
||||
# CONFIG_FATFS_CODEPAGE_865 is not set
|
||||
# CONFIG_FATFS_CODEPAGE_866 is not set
|
||||
# CONFIG_FATFS_CODEPAGE_869 is not set
|
||||
# CONFIG_FATFS_CODEPAGE_932 is not set
|
||||
# CONFIG_FATFS_CODEPAGE_936 is not set
|
||||
# CONFIG_FATFS_CODEPAGE_949 is not set
|
||||
# CONFIG_FATFS_CODEPAGE_950 is not set
|
||||
CONFIG_FATFS_CODEPAGE=437
|
||||
CONFIG_FATFS_LFN_NONE=y
|
||||
# CONFIG_FATFS_LFN_HEAP is not set
|
||||
# CONFIG_FATFS_LFN_STACK is not set
|
||||
CONFIG_FATFS_FS_LOCK=0
|
||||
CONFIG_FATFS_TIMEOUT_MS=10000
|
||||
CONFIG_FATFS_PER_FILE_CACHE=y
|
||||
CONFIG_FATFS_ALLOC_PREFER_EXTRAM=y
|
||||
CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND=150
|
||||
CONFIG_FMB_MASTER_DELAY_MS_CONVERT=200
|
||||
CONFIG_FMB_QUEUE_LENGTH=20
|
||||
CONFIG_FMB_SERIAL_TASK_STACK_SIZE=2048
|
||||
CONFIG_FMB_SERIAL_BUF_SIZE=256
|
||||
CONFIG_FMB_SERIAL_TASK_PRIO=10
|
||||
# CONFIG_FMB_CONTROLLER_SLAVE_ID_SUPPORT is not set
|
||||
CONFIG_FMB_CONTROLLER_NOTIFY_TIMEOUT=20
|
||||
CONFIG_FMB_CONTROLLER_NOTIFY_QUEUE_SIZE=20
|
||||
CONFIG_FMB_CONTROLLER_STACK_SIZE=4096
|
||||
CONFIG_FMB_EVENT_QUEUE_TIMEOUT=20
|
||||
CONFIG_FMB_TIMER_PORT_ENABLED=y
|
||||
CONFIG_FMB_TIMER_GROUP=0
|
||||
CONFIG_FMB_TIMER_INDEX=0
|
||||
# CONFIG_FREERTOS_UNICORE is not set
|
||||
CONFIG_FREERTOS_NO_AFFINITY=0x7FFFFFFF
|
||||
CONFIG_FREERTOS_CORETIMER_0=y
|
||||
# CONFIG_FREERTOS_CORETIMER_1 is not set
|
||||
CONFIG_FREERTOS_HZ=100
|
||||
CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION=y
|
||||
# CONFIG_FREERTOS_CHECK_STACKOVERFLOW_NONE is not set
|
||||
# CONFIG_FREERTOS_CHECK_STACKOVERFLOW_PTRVAL is not set
|
||||
CONFIG_FREERTOS_CHECK_STACKOVERFLOW_CANARY=y
|
||||
# CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK is not set
|
||||
CONFIG_FREERTOS_INTERRUPT_BACKTRACE=y
|
||||
CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS=1
|
||||
CONFIG_FREERTOS_ASSERT_FAIL_ABORT=y
|
||||
# CONFIG_FREERTOS_ASSERT_FAIL_PRINT_CONTINUE is not set
|
||||
# CONFIG_FREERTOS_ASSERT_DISABLE is not set
|
||||
CONFIG_FREERTOS_IDLE_TASK_STACKSIZE=1536
|
||||
CONFIG_FREERTOS_ISR_STACKSIZE=1536
|
||||
# CONFIG_FREERTOS_LEGACY_HOOKS is not set
|
||||
CONFIG_FREERTOS_MAX_TASK_NAME_LEN=16
|
||||
CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION=y
|
||||
# CONFIG_FREERTOS_ENABLE_STATIC_TASK_CLEAN_UP is not set
|
||||
CONFIG_FREERTOS_TIMER_TASK_PRIORITY=1
|
||||
CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=2432
|
||||
CONFIG_FREERTOS_TIMER_QUEUE_LENGTH=10
|
||||
CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE=0
|
||||
CONFIG_FREERTOS_USE_TRACE_FACILITY=y
|
||||
CONFIG_FREERTOS_USE_STATS_FORMATTING_FUNCTIONS=y
|
||||
CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID=y
|
||||
CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS=y
|
||||
CONFIG_FREERTOS_RUN_TIME_STATS_USING_ESP_TIMER=y
|
||||
# CONFIG_FREERTOS_RUN_TIME_STATS_USING_CPU_CLK is not set
|
||||
# CONFIG_FREERTOS_DEBUG_INTERNALS is not set
|
||||
CONFIG_FREERTOS_CHECK_MUTEX_GIVEN_BY_OWNER=y
|
||||
# CONFIG_FREERTOS_CHECK_PORT_CRITICAL_COMPLIANCE is not set
|
||||
CONFIG_HEAP_POISONING_DISABLED=y
|
||||
# CONFIG_HEAP_POISONING_LIGHT is not set
|
||||
# CONFIG_HEAP_POISONING_COMPREHENSIVE is not set
|
||||
CONFIG_HEAP_TRACING_OFF=y
|
||||
# CONFIG_HEAP_TRACING_STANDALONE is not set
|
||||
# CONFIG_HEAP_TRACING_TOHOST is not set
|
||||
# CONFIG_HEAP_TRACING is not set
|
||||
# CONFIG_LOG_DEFAULT_LEVEL_NONE is not set
|
||||
# CONFIG_LOG_DEFAULT_LEVEL_ERROR is not set
|
||||
CONFIG_LOG_DEFAULT_LEVEL_INFO=y
|
||||
# CONFIG_LOG_DEFAULT_LEVEL_INFO is not set
|
||||
# CONFIG_LOG_DEFAULT_LEVEL_DEBUG is not set
|
||||
# CONFIG_LOG_DEFAULT_LEVEL_VERBOSE is not set
|
||||
CONFIG_LOG_DEFAULT_LEVEL=3
|
||||
CONFIG_LOG_COLORS=y
|
||||
CONFIG_LWIP_LOCAL_HOSTNAME="squeezelite-esp32"
|
||||
# CONFIG_LWIP_L2_TO_L3_COPY is not set
|
||||
# CONFIG_LWIP_IRAM_OPTIMIZATION is not set
|
||||
CONFIG_LWIP_TIMERS_ONDEMAND=y
|
||||
CONFIG_LWIP_MAX_SOCKETS=16
|
||||
# CONFIG_LWIP_USE_ONLY_LWIP_SELECT is not set
|
||||
CONFIG_LWIP_SO_REUSE=y
|
||||
CONFIG_LWIP_SO_REUSE_RXTOALL=y
|
||||
# CONFIG_LWIP_SO_RCVBUF is not set
|
||||
CONFIG_LWIP_IP_FRAG=y
|
||||
# CONFIG_LWIP_IP_REASSEMBLY is not set
|
||||
# CONFIG_LWIP_STATS is not set
|
||||
# CONFIG_LWIP_ETHARP_TRUST_IP_MAC is not set
|
||||
CONFIG_LWIP_ESP_GRATUITOUS_ARP=y
|
||||
CONFIG_LWIP_GARP_TMR_INTERVAL=60
|
||||
CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=32
|
||||
CONFIG_LWIP_DHCP_DOES_ARP_CHECK=y
|
||||
CONFIG_LWIP_DHCP_RESTORE_LAST_IP=y
|
||||
CONFIG_LWIP_DHCPS_LEASE_UNIT=60
|
||||
CONFIG_LWIP_DHCPS_MAX_STATION_NUM=8
|
||||
# CONFIG_LWIP_AUTOIP is not set
|
||||
# CONFIG_LWIP_IPV6_AUTOCONFIG is not set
|
||||
CONFIG_LWIP_NETIF_LOOPBACK=y
|
||||
CONFIG_LWIP_LOOPBACK_MAX_PBUFS=8
|
||||
CONFIG_LWIP_MAX_ACTIVE_TCP=16
|
||||
CONFIG_LWIP_MAX_LISTENING_TCP=16
|
||||
CONFIG_LWIP_TCP_MAXRTX=12
|
||||
CONFIG_LWIP_TCP_SYNMAXRTX=6
|
||||
CONFIG_LWIP_TCP_MSS=1440
|
||||
CONFIG_LWIP_TCP_MSL=60000
|
||||
CONFIG_LWIP_TCP_SND_BUF_DEFAULT=8192
|
||||
CONFIG_LWIP_TCP_WND_DEFAULT=32768
|
||||
CONFIG_LWIP_TCP_RECVMBOX_SIZE=32
|
||||
CONFIG_LWIP_TCP_QUEUE_OOSEQ=y
|
||||
# CONFIG_LWIP_TCP_KEEP_CONNECTION_WHEN_IP_CHANGES is not set
|
||||
CONFIG_LWIP_TCP_OVERSIZE_MSS=y
|
||||
# CONFIG_LWIP_TCP_OVERSIZE_QUARTER_MSS is not set
|
||||
# CONFIG_LWIP_TCP_OVERSIZE_DISABLE is not set
|
||||
# CONFIG_LWIP_WND_SCALE is not set
|
||||
CONFIG_LWIP_MAX_UDP_PCBS=16
|
||||
CONFIG_LWIP_UDP_RECVMBOX_SIZE=32
|
||||
CONFIG_LWIP_TCPIP_TASK_STACK_SIZE=3072
|
||||
CONFIG_LWIP_TCPIP_TASK_AFFINITY_NO_AFFINITY=y
|
||||
# CONFIG_LWIP_TCPIP_TASK_AFFINITY_CPU0 is not set
|
||||
# CONFIG_LWIP_TCPIP_TASK_AFFINITY_CPU1 is not set
|
||||
CONFIG_LWIP_TCPIP_TASK_AFFINITY=0x7FFFFFFF
|
||||
# CONFIG_LWIP_PPP_SUPPORT is not set
|
||||
# CONFIG_LWIP_MULTICAST_PING is not set
|
||||
# CONFIG_LWIP_BROADCAST_PING is not set
|
||||
CONFIG_LWIP_MAX_RAW_PCBS=16
|
||||
CONFIG_LWIP_DHCP_MAX_NTP_SERVERS=1
|
||||
CONFIG_LWIP_SNTP_UPDATE_DELAY=3600000
|
||||
# CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC is not set
|
||||
CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC=y
|
||||
# CONFIG_MBEDTLS_DEFAULT_MEM_ALLOC is not set
|
||||
# CONFIG_MBEDTLS_CUSTOM_MEM_ALLOC is not set
|
||||
CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN=y
|
||||
CONFIG_MBEDTLS_SSL_IN_CONTENT_LEN=16384
|
||||
CONFIG_MBEDTLS_SSL_OUT_CONTENT_LEN=4096
|
||||
# CONFIG_MBEDTLS_DEBUG is not set
|
||||
# CONFIG_MBEDTLS_ECP_RESTARTABLE is not set
|
||||
# CONFIG_MBEDTLS_CMAC_C is not set
|
||||
CONFIG_MBEDTLS_HARDWARE_AES=y
|
||||
# CONFIG_MBEDTLS_HARDWARE_MPI is not set
|
||||
CONFIG_MBEDTLS_HARDWARE_SHA=y
|
||||
CONFIG_MBEDTLS_HAVE_TIME=y
|
||||
# CONFIG_MBEDTLS_HAVE_TIME_DATE is not set
|
||||
# CONFIG_MBEDTLS_TLS_SERVER_AND_CLIENT is not set
|
||||
# CONFIG_MBEDTLS_TLS_SERVER_ONLY is not set
|
||||
CONFIG_MBEDTLS_TLS_CLIENT_ONLY=y
|
||||
# CONFIG_MBEDTLS_TLS_DISABLED is not set
|
||||
CONFIG_MBEDTLS_TLS_CLIENT=y
|
||||
CONFIG_MBEDTLS_TLS_ENABLED=y
|
||||
# CONFIG_MBEDTLS_PSK_MODES is not set
|
||||
CONFIG_MBEDTLS_KEY_EXCHANGE_RSA=y
|
||||
CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_RSA=y
|
||||
CONFIG_MBEDTLS_KEY_EXCHANGE_ELLIPTIC_CURVE=y
|
||||
CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_RSA=y
|
||||
CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA=y
|
||||
CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA=y
|
||||
CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_RSA=y
|
||||
CONFIG_MBEDTLS_SSL_RENEGOTIATION=y
|
||||
# CONFIG_MBEDTLS_SSL_PROTO_SSL3 is not set
|
||||
CONFIG_MBEDTLS_SSL_PROTO_TLS1=y
|
||||
CONFIG_MBEDTLS_SSL_PROTO_TLS1_1=y
|
||||
CONFIG_MBEDTLS_SSL_PROTO_TLS1_2=y
|
||||
# CONFIG_MBEDTLS_SSL_PROTO_DTLS is not set
|
||||
CONFIG_MBEDTLS_SSL_ALPN=y
|
||||
CONFIG_MBEDTLS_CLIENT_SSL_SESSION_TICKETS=y
|
||||
CONFIG_MBEDTLS_SERVER_SSL_SESSION_TICKETS=y
|
||||
CONFIG_MBEDTLS_AES_C=y
|
||||
# CONFIG_MBEDTLS_CAMELLIA_C is not set
|
||||
# CONFIG_MBEDTLS_DES_C is not set
|
||||
CONFIG_MBEDTLS_RC4_DISABLED=y
|
||||
# CONFIG_MBEDTLS_RC4_ENABLED_NO_DEFAULT is not set
|
||||
# CONFIG_MBEDTLS_RC4_ENABLED is not set
|
||||
# CONFIG_MBEDTLS_BLOWFISH_C is not set
|
||||
# CONFIG_MBEDTLS_XTEA_C is not set
|
||||
CONFIG_MBEDTLS_CCM_C=y
|
||||
CONFIG_MBEDTLS_GCM_C=y
|
||||
# CONFIG_MBEDTLS_RIPEMD160_C is not set
|
||||
CONFIG_MBEDTLS_PEM_PARSE_C=y
|
||||
CONFIG_MBEDTLS_PEM_WRITE_C=y
|
||||
CONFIG_MBEDTLS_X509_CRL_PARSE_C=y
|
||||
CONFIG_MBEDTLS_X509_CSR_PARSE_C=y
|
||||
CONFIG_MBEDTLS_ECP_C=y
|
||||
CONFIG_MBEDTLS_ECDH_C=y
|
||||
CONFIG_MBEDTLS_ECDSA_C=y
|
||||
CONFIG_MBEDTLS_ECP_DP_SECP192R1_ENABLED=y
|
||||
CONFIG_MBEDTLS_ECP_DP_SECP224R1_ENABLED=y
|
||||
CONFIG_MBEDTLS_ECP_DP_SECP256R1_ENABLED=y
|
||||
CONFIG_MBEDTLS_ECP_DP_SECP384R1_ENABLED=y
|
||||
CONFIG_MBEDTLS_ECP_DP_SECP521R1_ENABLED=y
|
||||
CONFIG_MBEDTLS_ECP_DP_SECP192K1_ENABLED=y
|
||||
CONFIG_MBEDTLS_ECP_DP_SECP224K1_ENABLED=y
|
||||
CONFIG_MBEDTLS_ECP_DP_SECP256K1_ENABLED=y
|
||||
CONFIG_MBEDTLS_ECP_DP_BP256R1_ENABLED=y
|
||||
CONFIG_MBEDTLS_ECP_DP_BP384R1_ENABLED=y
|
||||
CONFIG_MBEDTLS_ECP_DP_BP512R1_ENABLED=y
|
||||
CONFIG_MBEDTLS_ECP_DP_CURVE25519_ENABLED=y
|
||||
CONFIG_MBEDTLS_ECP_NIST_OPTIM=y
|
||||
CONFIG_MDNS_MAX_SERVICES=10
|
||||
CONFIG_MQTT_PROTOCOL_311=y
|
||||
CONFIG_MQTT_TRANSPORT_SSL=y
|
||||
CONFIG_MQTT_TRANSPORT_WEBSOCKET=y
|
||||
CONFIG_MQTT_TRANSPORT_WEBSOCKET_SECURE=y
|
||||
# CONFIG_MQTT_USE_CUSTOM_CONFIG is not set
|
||||
# CONFIG_MQTT_TASK_CORE_SELECTION_ENABLED is not set
|
||||
# CONFIG_MQTT_CUSTOM_OUTBOX is not set
|
||||
CONFIG_NEWLIB_STDOUT_LINE_ENDING_CRLF=y
|
||||
# CONFIG_NEWLIB_STDOUT_LINE_ENDING_LF is not set
|
||||
# CONFIG_NEWLIB_STDOUT_LINE_ENDING_CR is not set
|
||||
# CONFIG_NEWLIB_STDIN_LINE_ENDING_CRLF is not set
|
||||
# CONFIG_NEWLIB_STDIN_LINE_ENDING_LF is not set
|
||||
CONFIG_NEWLIB_STDIN_LINE_ENDING_CR=y
|
||||
# CONFIG_NEWLIB_NANO_FORMAT is not set
|
||||
# CONFIG_OPENSSL_DEBUG is not set
|
||||
CONFIG_OPENSSL_ASSERT_DO_NOTHING=y
|
||||
# CONFIG_OPENSSL_ASSERT_EXIT is not set
|
||||
CONFIG_PTHREAD_TASK_PRIO_DEFAULT=5
|
||||
CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT=3072
|
||||
CONFIG_PTHREAD_STACK_MIN=768
|
||||
# CONFIG_PTHREAD_DEFAULT_CORE_NO_AFFINITY is not set
|
||||
# CONFIG_PTHREAD_DEFAULT_CORE_0 is not set
|
||||
CONFIG_PTHREAD_DEFAULT_CORE_1=y
|
||||
CONFIG_PTHREAD_TASK_CORE_DEFAULT=1
|
||||
CONFIG_PTHREAD_TASK_NAME_DEFAULT="pthread"
|
||||
# CONFIG_SPI_FLASH_VERIFY_WRITE is not set
|
||||
# CONFIG_SPI_FLASH_ENABLE_COUNTERS is not set
|
||||
CONFIG_SPI_FLASH_ROM_DRIVER_PATCH=y
|
||||
CONFIG_SPI_FLASH_DANGEROUS_WRITE_ABORTS=y
|
||||
# CONFIG_SPI_FLASH_DANGEROUS_WRITE_FAILS is not set
|
||||
# CONFIG_SPI_FLASH_DANGEROUS_WRITE_ALLOWED is not set
|
||||
# CONFIG_SPI_FLASH_USE_LEGACY_IMPL is not set
|
||||
CONFIG_SPI_FLASH_SUPPORT_ISSI_CHIP=y
|
||||
CONFIG_SPI_FLASH_SUPPORT_GD_CHIP=y
|
||||
CONFIG_SPIFFS_MAX_PARTITIONS=3
|
||||
CONFIG_SPIFFS_CACHE=y
|
||||
CONFIG_SPIFFS_CACHE_WR=y
|
||||
# CONFIG_SPIFFS_CACHE_STATS is not set
|
||||
CONFIG_SPIFFS_PAGE_CHECK=y
|
||||
CONFIG_SPIFFS_GC_MAX_RUNS=10
|
||||
# CONFIG_SPIFFS_GC_STATS is not set
|
||||
CONFIG_SPIFFS_PAGE_SIZE=256
|
||||
CONFIG_SPIFFS_OBJ_NAME_LEN=32
|
||||
CONFIG_SPIFFS_USE_MAGIC=y
|
||||
CONFIG_SPIFFS_USE_MAGIC_LENGTH=y
|
||||
CONFIG_SPIFFS_META_LENGTH=4
|
||||
CONFIG_SPIFFS_USE_MTIME=y
|
||||
# CONFIG_SPIFFS_DBG is not set
|
||||
# CONFIG_SPIFFS_API_DBG is not set
|
||||
# CONFIG_SPIFFS_GC_DBG is not set
|
||||
# CONFIG_SPIFFS_CACHE_DBG is not set
|
||||
# CONFIG_SPIFFS_CHECK_DBG is not set
|
||||
# CONFIG_SPIFFS_TEST_VISUALISATION is not set
|
||||
CONFIG_NETIF_IP_LOST_TIMER_INTERVAL=120
|
||||
CONFIG_TCPIP_LWIP=y
|
||||
CONFIG_UNITY_ENABLE_FLOAT=y
|
||||
CONFIG_UNITY_ENABLE_DOUBLE=y
|
||||
# CONFIG_UNITY_ENABLE_COLOR is not set
|
||||
CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y
|
||||
# CONFIG_UNITY_ENABLE_FIXTURE is not set
|
||||
# CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL is not set
|
||||
CONFIG_VFS_SUPPRESS_SELECT_DEBUG_OUTPUT=y
|
||||
CONFIG_VFS_SUPPORT_TERMIOS=y
|
||||
CONFIG_SEMIHOSTFS_MAX_MOUNT_POINTS=1
|
||||
CONFIG_SEMIHOSTFS_HOST_PATH_MAX_LEN=128
|
||||
CONFIG_WL_SECTOR_SIZE_512=y
|
||||
# CONFIG_WL_SECTOR_SIZE_4096 is not set
|
||||
CONFIG_WL_SECTOR_SIZE=512
|
||||
# CONFIG_WL_SECTOR_MODE_PERF is not set
|
||||
CONFIG_WL_SECTOR_MODE_SAFE=y
|
||||
CONFIG_WL_SECTOR_MODE=1
|
||||
CONFIG_WIFI_PROV_SCAN_MAX_ENTRIES=16
|
||||
CONFIG_WIFI_PROV_AUTOSTOP_TIMEOUT=30
|
||||
CONFIG_WPA_MBEDTLS_CRYPTO=y
|
||||
# CONFIG_DSP_ANSI is not set
|
||||
CONFIG_DSP_OPTIMIZED=y
|
||||
CONFIG_DSP_OPTIMIZATION=1
|
||||
CONFIG_DSP_MAX_FFT_SIZE_512=y
|
||||
# CONFIG_DSP_MAX_FFT_SIZE_1024 is not set
|
||||
# CONFIG_DSP_MAX_FFT_SIZE_2048 is not set
|
||||
# CONFIG_DSP_MAX_FFT_SIZE_4096 is not set
|
||||
# CONFIG_DSP_MAX_FFT_SIZE_8192 is not set
|
||||
# CONFIG_DSP_MAX_FFT_SIZE_16384 is not set
|
||||
# CONFIG_DSP_MAX_FFT_SIZE_32768 is not set
|
||||
CONFIG_DSP_MAX_FFT_SIZE=512
|
||||
# CONFIG_LEGACY_INCLUDE_COMMON_HEADERS is not set
|
||||
|
||||
# Deprecated options for backward compatibility
|
||||
CONFIG_TOOLPREFIX="xtensa-esp32-elf-"
|
||||
# CONFIG_LOG_BOOTLOADER_LEVEL_NONE is not set
|
||||
# CONFIG_LOG_BOOTLOADER_LEVEL_ERROR is not set
|
||||
# CONFIG_LOG_BOOTLOADER_LEVEL_WARN is not set
|
||||
CONFIG_LOG_BOOTLOADER_LEVEL_INFO=y
|
||||
# CONFIG_LOG_BOOTLOADER_LEVEL_DEBUG is not set
|
||||
# CONFIG_LOG_BOOTLOADER_LEVEL_VERBOSE is not set
|
||||
CONFIG_LOG_BOOTLOADER_LEVEL=3
|
||||
# CONFIG_APP_ROLLBACK_ENABLE is not set
|
||||
# CONFIG_FLASH_ENCRYPTION_ENABLED is not set
|
||||
CONFIG_FLASHMODE_QIO=y
|
||||
# CONFIG_FLASHMODE_QOUT is not set
|
||||
# CONFIG_FLASHMODE_DIO is not set
|
||||
# CONFIG_FLASHMODE_DOUT is not set
|
||||
# CONFIG_MONITOR_BAUD_9600B is not set
|
||||
# CONFIG_MONITOR_BAUD_57600B is not set
|
||||
CONFIG_MONITOR_BAUD_115200B=y
|
||||
# CONFIG_MONITOR_BAUD_230400B is not set
|
||||
# CONFIG_MONITOR_BAUD_921600B is not set
|
||||
# CONFIG_MONITOR_BAUD_2MB is not set
|
||||
# CONFIG_MONITOR_BAUD_OTHER is not set
|
||||
CONFIG_MONITOR_BAUD_OTHER_VAL=115200
|
||||
CONFIG_MONITOR_BAUD=115200
|
||||
# CONFIG_OPTIMIZATION_LEVEL_DEBUG is not set
|
||||
CONFIG_OPTIMIZATION_LEVEL_RELEASE=y
|
||||
# CONFIG_OPTIMIZATION_ASSERTIONS_ENABLED is not set
|
||||
CONFIG_OPTIMIZATION_ASSERTIONS_SILENT=y
|
||||
# CONFIG_OPTIMIZATION_ASSERTIONS_DISABLED is not set
|
||||
# CONFIG_CXX_EXCEPTIONS is not set
|
||||
CONFIG_STACK_CHECK_NONE=y
|
||||
# CONFIG_STACK_CHECK_NORM is not set
|
||||
# CONFIG_STACK_CHECK_STRONG is not set
|
||||
# CONFIG_STACK_CHECK_ALL is not set
|
||||
# CONFIG_STACK_CHECK is not set
|
||||
# CONFIG_WARN_WRITE_STRINGS is not set
|
||||
# CONFIG_DISABLE_GCC8_WARNINGS is not set
|
||||
# CONFIG_BTDM_CONTROLLER_MODE_BLE_ONLY is not set
|
||||
CONFIG_BTDM_CONTROLLER_MODE_BR_EDR_ONLY=y
|
||||
# CONFIG_BTDM_CONTROLLER_MODE_BTDM is not set
|
||||
CONFIG_BTDM_CONTROLLER_BR_EDR_MAX_ACL_CONN=2
|
||||
CONFIG_BTDM_CONTROLLER_BR_EDR_MAX_SYNC_CONN=0
|
||||
CONFIG_BTDM_CONTROLLER_BLE_MAX_CONN_EFF=0
|
||||
CONFIG_BTDM_CONTROLLER_BR_EDR_MAX_ACL_CONN_EFF=2
|
||||
CONFIG_BTDM_CONTROLLER_BR_EDR_MAX_SYNC_CONN_EFF=0
|
||||
CONFIG_BTDM_CONTROLLER_PINNED_TO_CORE=0
|
||||
CONFIG_BTDM_CONTROLLER_HCI_MODE_VHCI=y
|
||||
# CONFIG_BTDM_CONTROLLER_HCI_MODE_UART_H4 is not set
|
||||
CONFIG_BTDM_CONTROLLER_MODEM_SLEEP=y
|
||||
CONFIG_BLUEDROID_ENABLED=y
|
||||
CONFIG_BTC_TASK_STACK_SIZE=3072
|
||||
CONFIG_BLUEDROID_PINNED_TO_CORE_0=y
|
||||
# CONFIG_BLUEDROID_PINNED_TO_CORE_1 is not set
|
||||
CONFIG_BLUEDROID_PINNED_TO_CORE=0
|
||||
CONFIG_BTU_TASK_STACK_SIZE=4096
|
||||
# CONFIG_BLUEDROID_MEM_DEBUG is not set
|
||||
CONFIG_CLASSIC_BT_ENABLED=y
|
||||
CONFIG_A2DP_ENABLE=y
|
||||
# CONFIG_HFP_ENABLE is not set
|
||||
CONFIG_GATTS_ENABLE=y
|
||||
# CONFIG_GATTS_SEND_SERVICE_CHANGE_MANUAL is not set
|
||||
CONFIG_GATTS_SEND_SERVICE_CHANGE_AUTO=y
|
||||
CONFIG_GATTS_SEND_SERVICE_CHANGE_MODE=0
|
||||
CONFIG_GATTC_ENABLE=y
|
||||
# CONFIG_GATTC_CACHE_NVS_FLASH is not set
|
||||
CONFIG_BLE_SMP_ENABLE=y
|
||||
# CONFIG_SMP_SLAVE_CON_PARAMS_UPD_ENABLE is not set
|
||||
# CONFIG_BLE_HOST_QUEUE_CONGESTION_CHECK is not set
|
||||
CONFIG_SMP_ENABLE=y
|
||||
CONFIG_BLE_ESTABLISH_LINK_CONNECTION_TIMEOUT=30
|
||||
CONFIG_ADC2_DISABLE_DAC=y
|
||||
CONFIG_SPIRAM_SUPPORT=y
|
||||
CONFIG_WIFI_LWIP_ALLOCATION_FROM_SPIRAM_FIRST=y
|
||||
# CONFIG_MEMMAP_TRACEMEM is not set
|
||||
# CONFIG_MEMMAP_TRACEMEM_TWOBANKS is not set
|
||||
CONFIG_TRACEMEM_RESERVE_DRAM=0x0
|
||||
# CONFIG_TWO_UNIVERSAL_MAC_ADDRESS is not set
|
||||
CONFIG_FOUR_UNIVERSAL_MAC_ADDRESS=y
|
||||
CONFIG_NUMBER_OF_UNIVERSAL_MAC_ADDRESS=4
|
||||
# CONFIG_ULP_COPROC_ENABLED is not set
|
||||
CONFIG_ULP_COPROC_RESERVE_MEM=0
|
||||
CONFIG_BROWNOUT_DET=y
|
||||
CONFIG_BROWNOUT_DET_LVL_SEL_0=y
|
||||
# CONFIG_BROWNOUT_DET_LVL_SEL_1 is not set
|
||||
# CONFIG_BROWNOUT_DET_LVL_SEL_2 is not set
|
||||
# CONFIG_BROWNOUT_DET_LVL_SEL_3 is not set
|
||||
# CONFIG_BROWNOUT_DET_LVL_SEL_4 is not set
|
||||
# CONFIG_BROWNOUT_DET_LVL_SEL_5 is not set
|
||||
# CONFIG_BROWNOUT_DET_LVL_SEL_6 is not set
|
||||
# CONFIG_BROWNOUT_DET_LVL_SEL_7 is not set
|
||||
CONFIG_BROWNOUT_DET_LVL=0
|
||||
CONFIG_REDUCE_PHY_TX_POWER=y
|
||||
CONFIG_ESP32_RTC_CLOCK_SOURCE_INTERNAL_RC=y
|
||||
# CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL is not set
|
||||
# CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_OSC is not set
|
||||
# CONFIG_ESP32_RTC_CLOCK_SOURCE_INTERNAL_8MD256 is not set
|
||||
# CONFIG_DISABLE_BASIC_ROM_CONSOLE is not set
|
||||
# CONFIG_COMPATIBLE_PRE_V2_1_BOOTLOADERS is not set
|
||||
CONFIG_SYSTEM_EVENT_QUEUE_SIZE=32
|
||||
CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE=2304
|
||||
CONFIG_MAIN_TASK_STACK_SIZE=8192
|
||||
CONFIG_IPC_TASK_STACK_SIZE=1024
|
||||
CONFIG_TIMER_TASK_STACK_SIZE=3584
|
||||
CONFIG_CONSOLE_UART_DEFAULT=y
|
||||
# CONFIG_CONSOLE_UART_CUSTOM is not set
|
||||
# CONFIG_CONSOLE_UART_NONE is not set
|
||||
CONFIG_CONSOLE_UART_NUM=0
|
||||
CONFIG_CONSOLE_UART_BAUDRATE=115200
|
||||
CONFIG_INT_WDT=y
|
||||
CONFIG_INT_WDT_TIMEOUT_MS=800
|
||||
CONFIG_INT_WDT_CHECK_CPU1=y
|
||||
CONFIG_TASK_WDT=y
|
||||
# CONFIG_TASK_WDT_PANIC is not set
|
||||
CONFIG_TASK_WDT_TIMEOUT_S=5
|
||||
CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU0=y
|
||||
CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU1=y
|
||||
# CONFIG_EVENT_LOOP_PROFILING is not set
|
||||
CONFIG_POST_EVENTS_FROM_ISR=y
|
||||
CONFIG_POST_EVENTS_FROM_IRAM_ISR=y
|
||||
CONFIG_SW_COEXIST_ENABLE=y
|
||||
CONFIG_MB_MASTER_TIMEOUT_MS_RESPOND=150
|
||||
CONFIG_MB_MASTER_DELAY_MS_CONVERT=200
|
||||
CONFIG_MB_QUEUE_LENGTH=20
|
||||
CONFIG_MB_SERIAL_TASK_STACK_SIZE=2048
|
||||
CONFIG_MB_SERIAL_BUF_SIZE=256
|
||||
CONFIG_MB_SERIAL_TASK_PRIO=10
|
||||
# CONFIG_MB_CONTROLLER_SLAVE_ID_SUPPORT is not set
|
||||
CONFIG_MB_CONTROLLER_NOTIFY_TIMEOUT=20
|
||||
CONFIG_MB_CONTROLLER_NOTIFY_QUEUE_SIZE=20
|
||||
CONFIG_MB_CONTROLLER_STACK_SIZE=4096
|
||||
CONFIG_MB_EVENT_QUEUE_TIMEOUT=20
|
||||
CONFIG_MB_TIMER_PORT_ENABLED=y
|
||||
CONFIG_MB_TIMER_GROUP=0
|
||||
CONFIG_MB_TIMER_INDEX=0
|
||||
CONFIG_SUPPORT_STATIC_ALLOCATION=y
|
||||
# CONFIG_ENABLE_STATIC_TASK_CLEAN_UP_HOOK is not set
|
||||
CONFIG_TIMER_TASK_PRIORITY=1
|
||||
CONFIG_TIMER_TASK_STACK_DEPTH=2432
|
||||
CONFIG_TIMER_QUEUE_LENGTH=10
|
||||
# CONFIG_L2_TO_L3_COPY is not set
|
||||
# CONFIG_USE_ONLY_LWIP_SELECT is not set
|
||||
CONFIG_ESP_GRATUITOUS_ARP=y
|
||||
CONFIG_GARP_TMR_INTERVAL=60
|
||||
CONFIG_TCPIP_RECVMBOX_SIZE=32
|
||||
CONFIG_TCP_MAXRTX=12
|
||||
CONFIG_TCP_SYNMAXRTX=6
|
||||
CONFIG_TCP_MSS=1440
|
||||
CONFIG_TCP_MSL=60000
|
||||
CONFIG_TCP_SND_BUF_DEFAULT=8192
|
||||
CONFIG_TCP_WND_DEFAULT=32768
|
||||
CONFIG_TCP_RECVMBOX_SIZE=32
|
||||
CONFIG_TCP_QUEUE_OOSEQ=y
|
||||
# CONFIG_ESP_TCP_KEEP_CONNECTION_WHEN_IP_CHANGES is not set
|
||||
CONFIG_TCP_OVERSIZE_MSS=y
|
||||
# CONFIG_TCP_OVERSIZE_QUARTER_MSS is not set
|
||||
# CONFIG_TCP_OVERSIZE_DISABLE is not set
|
||||
CONFIG_UDP_RECVMBOX_SIZE=32
|
||||
CONFIG_TCPIP_TASK_STACK_SIZE=3072
|
||||
CONFIG_TCPIP_TASK_AFFINITY_NO_AFFINITY=y
|
||||
# CONFIG_TCPIP_TASK_AFFINITY_CPU0 is not set
|
||||
# CONFIG_TCPIP_TASK_AFFINITY_CPU1 is not set
|
||||
CONFIG_TCPIP_TASK_AFFINITY=0x7FFFFFFF
|
||||
# CONFIG_PPP_SUPPORT is not set
|
||||
CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT=5
|
||||
CONFIG_ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT=3072
|
||||
CONFIG_ESP32_PTHREAD_STACK_MIN=768
|
||||
# CONFIG_ESP32_DEFAULT_PTHREAD_CORE_NO_AFFINITY is not set
|
||||
# CONFIG_ESP32_DEFAULT_PTHREAD_CORE_0 is not set
|
||||
CONFIG_ESP32_DEFAULT_PTHREAD_CORE_1=y
|
||||
CONFIG_ESP32_PTHREAD_TASK_CORE_DEFAULT=1
|
||||
CONFIG_ESP32_PTHREAD_TASK_NAME_DEFAULT="pthread"
|
||||
CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ABORTS=y
|
||||
# CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_FAILS is not set
|
||||
# CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ALLOWED is not set
|
||||
CONFIG_IP_LOST_TIMER_INTERVAL=120
|
||||
CONFIG_SUPPRESS_SELECT_DEBUG_OUTPUT=y
|
||||
CONFIG_SUPPORT_TERMIOS=y
|
||||
# End of deprecated options
|
||||
@@ -1,24 +1,28 @@
|
||||
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/FLAC inc/helix-aac inc/mad inc/ogg inc/opus inc/opusfile inc/resample16 inc/soxr inc/vorbis
|
||||
)
|
||||
|
||||
if (DEFINED AAC_DISABLE_SBR)
|
||||
add_prebuilt_library(libhelix-aac lib/libhelix-aac.a )
|
||||
else ()
|
||||
add_prebuilt_library(libhelix-aac lib/libhelix-aac-sbr.a )
|
||||
endif()
|
||||
|
||||
add_prebuilt_library(libmad lib/libmad.a)
|
||||
add_prebuilt_library(libFLAC lib/libFLAC.a )
|
||||
add_prebuilt_library(libhelix-aac lib/libhelix-aac.a )
|
||||
add_prebuilt_library(libvorbisidec lib/libvorbisidec.a )
|
||||
add_prebuilt_library(libogg lib/libogg.a )
|
||||
add_prebuilt_library(libalac lib/libalac.a )
|
||||
add_prebuilt_library(libremple16 lib/libresample16.a )
|
||||
add_prebuilt_library(libresample16 lib/libresample16.a )
|
||||
add_prebuilt_library(libopusfile lib/libopusfile.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 libopusfile)
|
||||
target_link_libraries(${COMPONENT_LIB} INTERFACE libopus)
|
||||
|
||||
@@ -19,7 +19,7 @@ extern "C" {
|
||||
|
||||
struct alac_codec_s *alac_create_decoder(int magic_cookie_size, unsigned char *magic_cookie,
|
||||
unsigned char *sample_size, unsigned *sample_rate,
|
||||
unsigned char *channels);
|
||||
unsigned char *channels, unsigned int *block_size);
|
||||
void alac_delete_decoder(struct alac_codec_s *codec);
|
||||
bool alac_to_pcm(struct alac_codec_s *codec, unsigned char* input,
|
||||
unsigned char *output, char channels, unsigned *out_frames);
|
||||
|
||||
Binary file not shown.
BIN
components/codecs/lib/libhelix-aac-sbr.a
Normal file
BIN
components/codecs/lib/libhelix-aac-sbr.a
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,3 +0,0 @@
|
||||
void dummy_obj() {
|
||||
return;
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
|
||||
idf_component_register(SRC_DIRS . core core/ifaces fonts
|
||||
INCLUDE_DIRS . fonts core
|
||||
REQUIRES platform_config tools esp_common
|
||||
PRIV_REQUIRES services freertos driver
|
||||
EMBED_FILES note.jpg
|
||||
)
|
||||
|
||||
set_source_files_properties(display.c
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -96,13 +96,14 @@ static void Update( 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 );
|
||||
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 +146,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 );
|
||||
|
||||
|
||||
@@ -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 : 0xA6 );
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -188,20 +188,25 @@ 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 );
|
||||
Private->MADCtl = Layout->ColorSwap ? (Private->MADCtl & ~(1 << 3)) : (Private->MADCtl | (1 << 3));
|
||||
} else {
|
||||
Device->WriteCommand( Device, Layout->Invert ? 0x21 : 0x20 );
|
||||
Private->MADCtl = Layout->ColorSwap ? (Private->MADCtl | (1 << 3)) : (Private->MADCtl & ~(1 << 3));
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
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 +240,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 +286,14 @@ 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;
|
||||
|
||||
if (Model == ST7735) {
|
||||
sscanf(Driver, "%*[^:]%*[^x]%*[^=]=%hu", &Private->Offset.Height);
|
||||
sscanf(Driver, "%*[^:]%*[^y]%*[^=]=%hu", &Private->Offset.Width);
|
||||
}
|
||||
|
||||
if (Depth == 18) {
|
||||
Device->Mode = GDS_RGB666;
|
||||
|
||||
@@ -235,12 +235,13 @@ void GDS_SetContrast( struct GDS_Device* Device, uint8_t Contrast ) {
|
||||
ledc_update_duty( LEDC_HIGH_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 ); }
|
||||
@@ -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 );
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#include "gds_private.h"
|
||||
#include "gds_image.h"
|
||||
|
||||
const char TAG[] = "ImageDec";
|
||||
const static char TAG[] = "ImageDec";
|
||||
|
||||
#define SCRATCH_SIZE 3100
|
||||
|
||||
@@ -142,7 +142,7 @@ static unsigned OutHandlerDirect(JDEC *Decoder, void *Bitmap, JRECT *Frame) {
|
||||
JpegCtx *Context = (JpegCtx*) Decoder->device;
|
||||
uint8_t *Pixels = (uint8_t*) Bitmap;
|
||||
int Shift = 8 - Context->Depth;
|
||||
|
||||
|
||||
// decoded image is RGB888, shift only make sense for grayscale
|
||||
if (Context->Mode == GDS_RGB888) {
|
||||
OUTHANDLERDIRECT(Scaler888, 0);
|
||||
@@ -167,7 +167,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 +372,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");
|
||||
|
||||
@@ -95,7 +95,7 @@ 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;
|
||||
|
||||
@@ -117,13 +117,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, uint8_t *CS_pre, uint8_t *CS_post);
|
||||
|
||||
// interface-specific methods
|
||||
WriteCommandProc WriteCommand;
|
||||
|
||||
@@ -99,13 +99,13 @@ 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 );
|
||||
}
|
||||
@@ -118,7 +118,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 +145,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 +156,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';
|
||||
}
|
||||
|
||||
@@ -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, ...);
|
||||
@@ -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 ) {
|
||||
|
||||
@@ -35,7 +35,7 @@ bool GDS_SPIInit( int SPI, int DC ) {
|
||||
}
|
||||
|
||||
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;
|
||||
spi_device_interface_config_t SPIDeviceConfig = { };
|
||||
spi_device_handle_t SPIDevice;
|
||||
|
||||
NullCheck( Device, return false );
|
||||
@@ -43,15 +43,15 @@ 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.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 +61,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 +74,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 );
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "gds_draw.h"
|
||||
#include "gds_text.h"
|
||||
#include "gds_font.h"
|
||||
#include "gds_image.h"
|
||||
|
||||
static const char *TAG = "display";
|
||||
|
||||
@@ -30,6 +31,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,7 +45,19 @@ 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;
|
||||
|
||||
@@ -52,15 +68,16 @@ static const char *known_drivers[] = {"SH1106",
|
||||
"SSD1327",
|
||||
"SSD1675",
|
||||
"SSD1351",
|
||||
"ST77xx",
|
||||
"ST7735",
|
||||
"ST7789",
|
||||
"ILI9341",
|
||||
NULL
|
||||
};
|
||||
static void displayer_task(void *args);
|
||||
|
||||
struct GDS_Device *display;
|
||||
extern GDS_DetectFunc SSD1306_Detect, SSD132x_Detect, SH1106_Detect, SSD1675_Detect, SSD1322_Detect, SSD1351_Detect, ST77xx_Detect;
|
||||
GDS_DetectFunc *drivers[] = { SH1106_Detect, SSD1306_Detect, SSD132x_Detect, SSD1675_Detect, SSD1322_Detect, SSD1351_Detect, ST77xx_Detect, NULL };
|
||||
extern GDS_DetectFunc SSD1306_Detect, SSD132x_Detect, SH1106_Detect, SSD1675_Detect, SSD1322_Detect, SSD1351_Detect, ST77xx_Detect, ILI9341_Detect;
|
||||
GDS_DetectFunc *drivers[] = { SH1106_Detect, SSD1306_Detect, SSD132x_Detect, SSD1675_Detect, SSD1322_Detect, SSD1351_Detect, ST77xx_Detect, ILI9341_Detect, NULL };
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
@@ -70,11 +87,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,29 +100,29 @@ 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) {
|
||||
} else if (strcasestr(config, "SPI") && spi_system_host != -1) {
|
||||
int CS_pin = -1, speed = 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);
|
||||
|
||||
init = true;
|
||||
GDS_SPIInit( spi_system_host, spi_system_dc_gpio );
|
||||
@@ -124,8 +141,15 @@ 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"));
|
||||
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_droid_sans_fallback_15x17 );
|
||||
GDS_TextPos(display, GDS_FONT_MEDIUM, GDS_TEXT_CENTERED, GDS_TEXT_CLEAR | GDS_TEXT_UPDATE, welcome);
|
||||
|
||||
@@ -134,13 +158,21 @@ void display_init(char *welcome) {
|
||||
displayer.by = 2;
|
||||
displayer.pause = 3600;
|
||||
displayer.speed = 33;
|
||||
displayer.task = xTaskCreateStatic( (TaskFunction_t) displayer_task, "displayer_thread", DISPLAYER_STACK_SIZE, NULL, ESP_TASK_PRIO_MIN + 1, xStack, &xTaskBuffer);
|
||||
displayer.task = xTaskCreateStatic( (TaskFunction_t) displayer_task, "common_displayer", DISPLAYER_STACK_SIZE, NULL, ESP_TASK_PRIO_MIN + 1, xStack, &xTaskBuffer);
|
||||
|
||||
// set lines for "fixed" text mode
|
||||
GDS_TextSetFontAuto(display, 1, GDS_FONT_LINE_1, -3);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
free(config);
|
||||
@@ -192,18 +224,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 +269,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 +357,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 +396,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 +435,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 +484,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 +499,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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
BIN
components/display/note.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
@@ -6,27 +6,26 @@
|
||||
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"
|
||||
|
||||
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)
|
||||
{
|
||||
@@ -78,9 +77,49 @@ 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 ((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);
|
||||
@@ -88,36 +127,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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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, // pre1-6
|
||||
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);
|
||||
@@ -283,6 +280,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 +293,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 +380,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 +489,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 +536,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 +562,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 +597,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
10
components/esp_http_server/CMakeLists.txt
Normal file
10
components/esp_http_server/CMakeLists.txt
Normal 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
|
||||
)
|
||||
1
components/esp_http_server/Kconfig
Normal file
1
components/esp_http_server/Kconfig
Normal file
@@ -0,0 +1 @@
|
||||
source "$IDF_PATH/components/esp_http_server/Kconfig"
|
||||
68
components/esp_http_server/osal.h
Normal file
68
components/esp_http_server/osal.h
Normal 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_ */
|
||||
@@ -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
|
||||
REQUIRES nvs_flash json
|
||||
)
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -45,3 +61,7 @@ esp_err_t config_set_value(nvs_type_t nvs_type, const char *key, const void * va
|
||||
nvs_type_t config_get_item_type(cJSON * entry);
|
||||
void * config_safe_alloc_get_entry_value(nvs_type_t nvs_type, cJSON * entry);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -5,8 +5,14 @@ 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 )
|
||||
PRIV_REQUIRES console app_update tools services spi_flash platform_config vfs pthread wifi-manager platform_config newlib telnet display squeezelite)
|
||||
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 )
|
||||
set_source_files_properties(cmd_config.c
|
||||
PROPERTIES COMPILE_FLAGS
|
||||
-Wno-unused-function
|
||||
)
|
||||
|
||||
|
||||
@@ -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}\"")
|
||||
|
||||
@@ -1,2 +1,6 @@
|
||||
#pragma once
|
||||
#define PROJECT_NAME "recovery"
|
||||
#include "sdkconfig.h"
|
||||
#ifndef CONFIG_PROJECT_NAME
|
||||
#pragma message "Defaulting project name."
|
||||
#define CONFIG_PROJECT_NAME "Squeezelite-ESP32"
|
||||
#endif
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "application_name.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_app_format.h"
|
||||
|
||||
extern esp_err_t process_recovery_ota(const char * bin_url, char * bin_buffer, uint32_t length);
|
||||
|
||||
const __attribute__((section(".rodata_desc"))) esp_app_desc_t esp_app_desc = {
|
||||
.magic_word = ESP_APP_DESC_MAGIC_WORD,
|
||||
.version = PROJECT_VER,
|
||||
.project_name = PROJECT_NAME,
|
||||
.project_name = CONFIG_PROJECT_NAME,
|
||||
.idf_ver = IDF_VER,
|
||||
|
||||
#ifdef CONFIG_BOOTLOADER_APP_SECURE_VERSION
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
idf_build_get_property(idf_path IDF_PATH)
|
||||
idf_build_get_property(idf_path IDF_PATH)
|
||||
idf_component_register( SRCS cmd_squeezelite.c
|
||||
INCLUDE_DIRS .
|
||||
PRIV_REQUIRES spi_flash bootloader_support partition_table bootloader_support console codecs squeezelite newlib pthread tools platform_config display )
|
||||
@@ -13,7 +13,8 @@ target_link_libraries(${COMPONENT_LIB} INTERFACE "-Wl,--undefined=lround")
|
||||
target_link_libraries(${COMPONENT_LIB} INTERFACE "-Wl,--undefined=esp_app_desc")
|
||||
|
||||
idf_build_get_property(project_ver PROJECT_VER)
|
||||
message("******************* ${project_ver}")
|
||||
string(SUBSTRING "${project_ver}" 0 31 PROJECT_VER_CUT)
|
||||
set_source_files_properties(cmd_squeezelite.c PROPERTIES COMPILE_DEFINITIONS "PROJECT_VER=\"${PROJECT_VER_CUT}\"; PROJECT_NAME=\"squeezelite\"")
|
||||
set_source_files_properties(cmd_squeezelite.c PROPERTIES COMPILE_DEFINITIONS "PROJECT_VER=\"${PROJECT_VER_CUT}\" ")
|
||||
|
||||
|
||||
|
||||
@@ -1,2 +1,6 @@
|
||||
#pragma once
|
||||
#define PROJECT_NAME "squeezelite"
|
||||
#include "sdkconfig.h"
|
||||
#ifndef CONFIG_PROJECT_NAME
|
||||
#pragma message "Defaulting project name."
|
||||
#define CONFIG_PROJECT_NAME "Squeezelite-ESP32"
|
||||
#endif
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "application_name.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_console.h"
|
||||
#include "esp_pthread.h"
|
||||
#include "../cmd_system.h"
|
||||
#include "argtable3/argtable3.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
@@ -14,15 +13,13 @@
|
||||
#include "esp_app_format.h"
|
||||
extern esp_err_t process_recovery_ota(const char * bin_url, char * bin_buffer, uint32_t length);
|
||||
static const char * TAG = "squeezelite_cmd";
|
||||
#define SQUEEZELITE_THREAD_STACK_SIZE (6*1024)
|
||||
|
||||
|
||||
#define SQUEEZELITE_THREAD_STACK_SIZE (8*1024)
|
||||
|
||||
const __attribute__((section(".rodata_desc"))) esp_app_desc_t esp_app_desc = {
|
||||
|
||||
.magic_word = ESP_APP_DESC_MAGIC_WORD,
|
||||
.version = PROJECT_VER,
|
||||
.project_name = PROJECT_NAME,
|
||||
.project_name = CONFIG_PROJECT_NAME,
|
||||
.idf_ver = IDF_VER,
|
||||
|
||||
#ifdef CONFIG_BOOTLOADER_APP_SECURE_VERSION
|
||||
@@ -42,8 +39,7 @@ const __attribute__((section(".rodata_desc"))) esp_app_desc_t esp_app_desc = {
|
||||
|
||||
extern int main(int argc, char **argv);
|
||||
static int launchsqueezelite(int argc, char **argv);
|
||||
pthread_t thread_squeezelite;
|
||||
pthread_t thread_squeezelite_runner;
|
||||
|
||||
/** Arguments used by 'squeezelite' function */
|
||||
static struct {
|
||||
struct arg_str *parameters;
|
||||
@@ -53,57 +49,47 @@ static struct {
|
||||
int argc;
|
||||
char ** argv;
|
||||
} thread_parms ;
|
||||
static void * squeezelite_runner_thread(){
|
||||
ESP_LOGI(TAG ,"Calling squeezelite");
|
||||
main(thread_parms.argc,thread_parms.argv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define ADDITIONAL_SQUEEZELITE_ARGS 5
|
||||
static void * squeezelite_thread(){
|
||||
int * exit_code;
|
||||
static bool isRunning=false;
|
||||
if(isRunning) {
|
||||
ESP_LOGE(TAG,"Squeezelite already running. Exiting!");
|
||||
return NULL;
|
||||
}
|
||||
isRunning=true;
|
||||
static void squeezelite_thread(void *arg){
|
||||
ESP_LOGV(TAG ,"Number of args received: %u",thread_parms.argc );
|
||||
ESP_LOGV(TAG ,"Values:");
|
||||
for(int i = 0;i<thread_parms.argc; i++){
|
||||
ESP_LOGV(TAG ," %s",thread_parms.argv[i]);
|
||||
}
|
||||
|
||||
ESP_LOGV(TAG,"Starting Squeezelite runner Thread");
|
||||
esp_pthread_cfg_t cfg = esp_pthread_get_default_config();
|
||||
cfg.thread_name= "squeezelite-run";
|
||||
cfg.inherit_cfg = true;
|
||||
cfg.stack_size = SQUEEZELITE_THREAD_STACK_SIZE ;
|
||||
esp_pthread_set_cfg(&cfg);
|
||||
// no attribute if we want esp stack stack to prevail
|
||||
pthread_create(&thread_squeezelite_runner, NULL, squeezelite_runner_thread,NULL);
|
||||
// Wait for thread completion so we can free up memory.
|
||||
pthread_join(thread_squeezelite_runner,(void **)&exit_code);
|
||||
|
||||
ESP_LOGI(TAG ,"Calling squeezelite");
|
||||
main(thread_parms.argc,thread_parms.argv);
|
||||
ESP_LOGV(TAG ,"Exited from squeezelite's main(). Freeing argv structure.");
|
||||
|
||||
for(int i=0;i<thread_parms.argc;i++){
|
||||
ESP_LOGV(TAG ,"Freeing char buffer for parameter %u", i+1);
|
||||
free(thread_parms.argv[i]);
|
||||
}
|
||||
ESP_LOGV(TAG ,"Freeing argv pointer");
|
||||
free(thread_parms.argv);
|
||||
isRunning=false;
|
||||
|
||||
ESP_LOGE(TAG, "Exited from squeezelite thread, something's wrong ... rebooting (wait 30s for user to take action)");
|
||||
if(!wait_for_commit()){
|
||||
ESP_LOGW(TAG,"Unable to commit configuration. ");
|
||||
}
|
||||
|
||||
vTaskDelay( pdMS_TO_TICKS( 30*1000 ) );
|
||||
esp_restart();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int launchsqueezelite(int argc, char **argv)
|
||||
{
|
||||
static int launchsqueezelite(int argc, char **argv) {
|
||||
static DRAM_ATTR StaticTask_t xTaskBuffer __attribute__ ((aligned (4)));
|
||||
static EXT_RAM_ATTR StackType_t xStack[SQUEEZELITE_THREAD_STACK_SIZE] __attribute__ ((aligned (4)));
|
||||
static bool isRunning = false;
|
||||
|
||||
if (isRunning) {
|
||||
ESP_LOGE(TAG,"Squeezelite already running. Exiting!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ESP_LOGV(TAG ,"Begin");
|
||||
isRunning = true;
|
||||
|
||||
ESP_LOGV(TAG, "Parameters:");
|
||||
for(int i = 0;i<argc; i++){
|
||||
@@ -128,16 +114,14 @@ static int launchsqueezelite(int argc, char **argv)
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG,"Starting Squeezelite Thread");
|
||||
esp_pthread_cfg_t cfg = esp_pthread_get_default_config();
|
||||
cfg.thread_name= "squeezelite";
|
||||
cfg.inherit_cfg = true;
|
||||
esp_pthread_set_cfg(&cfg);
|
||||
pthread_create(&thread_squeezelite, NULL, squeezelite_thread,NULL);
|
||||
xTaskCreateStaticPinnedToCore(squeezelite_thread, "squeezelite", SQUEEZELITE_THREAD_STACK_SIZE,
|
||||
NULL, CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT, xStack, &xTaskBuffer, CONFIG_PTHREAD_TASK_CORE_DEFAULT);
|
||||
ESP_LOGD(TAG ,"Back to console thread!");
|
||||
|
||||
return 0;
|
||||
}
|
||||
void register_squeezelite(){
|
||||
|
||||
void register_squeezelite() {
|
||||
squeezelite_args.parameters = arg_str0(NULL, NULL, "<parms>", "command line for squeezelite. -h for help, --defaults to launch with default values.");
|
||||
squeezelite_args.end = arg_end(1);
|
||||
const esp_console_cmd_t launch_squeezelite = {
|
||||
@@ -148,10 +132,9 @@ void register_squeezelite(){
|
||||
.argtable = &squeezelite_args
|
||||
};
|
||||
ESP_ERROR_CHECK( esp_console_cmd_register(&launch_squeezelite) );
|
||||
|
||||
}
|
||||
esp_err_t start_ota(const char * bin_url, char * bin_buffer, uint32_t length)
|
||||
{
|
||||
|
||||
esp_err_t start_ota(const char * bin_url, char * bin_buffer, uint32_t length) {
|
||||
if(!bin_url){
|
||||
ESP_LOGE(TAG,"missing URL parameter. Unable to start OTA");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
@@ -169,5 +152,4 @@ esp_err_t start_ota(const char * bin_url, char * bin_buffer, uint32_t length)
|
||||
ESP_LOGW(TAG, "Rebooting to recovery to complete the installation");
|
||||
return guided_factory();
|
||||
return ESP_OK;
|
||||
|
||||
}
|
||||
|
||||
1019
components/platform_console/cmd_config.c
Normal file
1019
components/platform_console/cmd_config.c
Normal file
File diff suppressed because it is too large
Load Diff
19
components/platform_console/cmd_config.h
Normal file
19
components/platform_console/cmd_config.h
Normal file
@@ -0,0 +1,19 @@
|
||||
/* cmd_i2ctools.h
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "stdbool.h"
|
||||
#include "stdio.h"
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void register_config_cmd(void);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -17,6 +17,7 @@ extern "C" {
|
||||
#include "cmd_nvs.h"
|
||||
#include "cmd_i2ctools.h"
|
||||
#include "cmd_ota.h"
|
||||
#include "cmd_config.h"
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -330,11 +330,11 @@ static int set_value(int argc, char **argv)
|
||||
const char *key = set_args.key->sval[0];
|
||||
const char *type = set_args.type->sval[0];
|
||||
const char *values = set_args.value->sval[0];
|
||||
log_send_messaging(MESSAGING_INFO, "Setting '%s' (type %s)", key,type);
|
||||
cmd_send_messaging(argv[0],MESSAGING_INFO, "Setting '%s' (type %s)", key,type);
|
||||
esp_err_t err = set_value_in_nvs(key, type, values);
|
||||
|
||||
if (err != ESP_OK) {
|
||||
log_send_messaging(MESSAGING_ERROR, "%s", esp_err_to_name(err));
|
||||
cmd_send_messaging(argv[0],MESSAGING_ERROR, "%s", esp_err_to_name(err));
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -355,7 +355,7 @@ static int get_value(int argc, char **argv)
|
||||
esp_err_t err = get_value_from_nvs(key, type);
|
||||
|
||||
if (err != ESP_OK) {
|
||||
log_send_messaging(MESSAGING_ERROR, "%s", esp_err_to_name(err));
|
||||
cmd_send_messaging(argv[0],MESSAGING_ERROR, "%s", esp_err_to_name(err));
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -374,7 +374,7 @@ static int erase_value(int argc, char **argv)
|
||||
esp_err_t err = erase(key);
|
||||
|
||||
if (err != ESP_OK) {
|
||||
log_send_messaging(MESSAGING_ERROR, "%s", esp_err_to_name(err));
|
||||
cmd_send_messaging(argv[0],MESSAGING_ERROR, "%s", esp_err_to_name(err));
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -392,7 +392,7 @@ static int erase_namespace(int argc, char **argv)
|
||||
|
||||
esp_err_t err = erase_all(name);
|
||||
if (err != ESP_OK) {
|
||||
log_send_messaging(MESSAGING_ERROR, "%s", esp_err_to_name(err));
|
||||
cmd_send_messaging(argv[0],MESSAGING_ERROR, "%s", esp_err_to_name(err));
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -411,11 +411,11 @@ static int erase_wifi_manager(int argc, char **argv)
|
||||
}
|
||||
nvs_close(nvs);
|
||||
if (err != ESP_OK) {
|
||||
log_send_messaging(MESSAGING_ERROR, "wifi manager configuration was not erase. %s", esp_err_to_name(err));
|
||||
cmd_send_messaging(argv[0],MESSAGING_ERROR, "wifi manager configuration was not erase. %s", esp_err_to_name(err));
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
log_send_messaging(MESSAGING_WARNING, "Wifi manager configuration was erased");
|
||||
cmd_send_messaging(argv[0],MESSAGING_WARNING, "Wifi manager configuration was erased");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* Console example — various system commands
|
||||
|
||||
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.
|
||||
@@ -31,17 +31,35 @@
|
||||
#include "driver/uart.h" // for the uart driver access
|
||||
#include "messaging.h"
|
||||
#include "platform_console.h"
|
||||
|
||||
|
||||
#ifdef CONFIG_FREERTOS_USE_STATS_FORMATTING_FUNCTIONS
|
||||
#include "trace.h"
|
||||
#ifdef CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS
|
||||
#pragma message("Runtime stats enabled")
|
||||
#define WITH_TASKS_INFO 1
|
||||
#else
|
||||
#pragma message("Runtime stats disabled")
|
||||
#endif
|
||||
|
||||
|
||||
static struct {
|
||||
struct arg_str *scanmode;
|
||||
struct arg_end *end;
|
||||
} wifi_parms_arg;
|
||||
static struct {
|
||||
struct arg_str *name;
|
||||
struct arg_end *end;
|
||||
} name_args;
|
||||
static struct {
|
||||
struct arg_lit *btspeaker;
|
||||
struct arg_lit *airplay;
|
||||
struct arg_str *telnet;
|
||||
#if WITH_TASKS_INFO
|
||||
struct arg_lit *stats;
|
||||
#endif
|
||||
struct arg_end *end;
|
||||
} set_services_args;
|
||||
static const char * TAG = "cmd_system";
|
||||
|
||||
static void register_setbtsource();
|
||||
//static void register_setbtsource();
|
||||
static void register_free();
|
||||
static void register_setdevicename();
|
||||
static void register_heap();
|
||||
static void register_version();
|
||||
static void register_restart();
|
||||
@@ -50,15 +68,20 @@ static void register_light_sleep();
|
||||
static void register_factory_boot();
|
||||
static void register_restart_ota();
|
||||
static void register_update_certs();
|
||||
static void register_set_services();
|
||||
static void register_set_wifi_parms();
|
||||
#if WITH_TASKS_INFO
|
||||
static void register_tasks();
|
||||
#endif
|
||||
extern BaseType_t wifi_manager_task;
|
||||
void register_system()
|
||||
{
|
||||
register_setbtsource();
|
||||
register_set_wifi_parms();
|
||||
// register_setbtsource();
|
||||
register_free();
|
||||
register_set_services();
|
||||
register_heap();
|
||||
register_setdevicename();
|
||||
register_version();
|
||||
register_restart();
|
||||
register_deep_sleep();
|
||||
@@ -76,7 +99,7 @@ static int get_version(int argc, char **argv)
|
||||
{
|
||||
esp_chip_info_t info;
|
||||
esp_chip_info(&info);
|
||||
log_send_messaging(MESSAGING_INFO,
|
||||
cmd_send_messaging(argv[0],MESSAGING_INFO,
|
||||
"IDF Version:%s\r\n"
|
||||
"Chip info:\r\n"
|
||||
"\tmodel:%s\r\n"
|
||||
@@ -104,35 +127,32 @@ static void register_version()
|
||||
ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) );
|
||||
}
|
||||
|
||||
/** 'restart' command restarts the program */
|
||||
|
||||
|
||||
esp_err_t guided_boot(esp_partition_subtype_t partition_subtype)
|
||||
{
|
||||
if(is_recovery_running){
|
||||
if(partition_subtype ==ESP_PARTITION_SUBTYPE_APP_FACTORY){
|
||||
log_send_messaging(MESSAGING_WARNING,"RECOVERY application is already active");
|
||||
if(!wait_for_commit()){
|
||||
log_send_messaging(MESSAGING_WARNING,"Unable to commit configuration. ");
|
||||
}
|
||||
|
||||
vTaskDelay(750/ portTICK_PERIOD_MS);
|
||||
esp_restart();
|
||||
return ESP_OK;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(partition_subtype !=ESP_PARTITION_SUBTYPE_APP_FACTORY){
|
||||
log_send_messaging(MESSAGING_WARNING,"SQUEEZELITE application is already active");
|
||||
if(!wait_for_commit()){
|
||||
log_send_messaging(MESSAGING_WARNING,"Unable to commit configuration. ");
|
||||
}
|
||||
|
||||
vTaskDelay(750/ portTICK_PERIOD_MS);
|
||||
esp_restart();
|
||||
return ESP_OK;
|
||||
}
|
||||
}
|
||||
if(is_recovery_running){
|
||||
if(partition_subtype ==ESP_PARTITION_SUBTYPE_APP_FACTORY){
|
||||
log_send_messaging(MESSAGING_WARNING,"RECOVERY application is already active");
|
||||
if(!wait_for_commit()){
|
||||
log_send_messaging(MESSAGING_WARNING,"Unable to commit configuration. ");
|
||||
}
|
||||
|
||||
vTaskDelay(750/ portTICK_PERIOD_MS);
|
||||
esp_restart();
|
||||
return ESP_OK;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(partition_subtype !=ESP_PARTITION_SUBTYPE_APP_FACTORY){
|
||||
log_send_messaging(MESSAGING_WARNING,"SQUEEZELITE application is already active");
|
||||
if(!wait_for_commit()){
|
||||
log_send_messaging(MESSAGING_WARNING,"Unable to commit configuration. ");
|
||||
}
|
||||
|
||||
vTaskDelay(750/ portTICK_PERIOD_MS);
|
||||
esp_restart();
|
||||
return ESP_OK;
|
||||
}
|
||||
}
|
||||
esp_err_t err = ESP_OK;
|
||||
bool bFound=false;
|
||||
log_send_messaging(MESSAGING_INFO, "Looking for partition type %u",partition_subtype);
|
||||
@@ -156,9 +176,7 @@ else {
|
||||
log_send_messaging(MESSAGING_ERROR,"Unable to select partition for reboot: %s",esp_err_to_name(err));
|
||||
}
|
||||
else{
|
||||
log_send_messaging(MESSAGING_WARNING, "Application partition %s sub type %u is selected for boot", partition->label,partition_subtype);
|
||||
bFound=true;
|
||||
messaging_post_message(MESSAGING_WARNING,MESSAGING_CLASS_SYSTEM,"Reboot failed. Cannot iterate through partitions");
|
||||
bFound=true;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -169,9 +187,8 @@ else {
|
||||
ESP_LOGD(TAG, "Yielding to other processes");
|
||||
taskYIELD();
|
||||
if(bFound) {
|
||||
log_send_messaging(MESSAGING_WARNING,"Configuration %s changes. ",config_has_changes()?"has":"does not have");
|
||||
if(!wait_for_commit()){
|
||||
log_send_messaging(MESSAGING_WARNING,"Unable to commit configuration. ");
|
||||
log_send_messaging(MESSAGING_WARNING,"Unable to commit configuration changes. ");
|
||||
}
|
||||
vTaskDelay(750/ portTICK_PERIOD_MS);
|
||||
esp_restart();
|
||||
@@ -185,7 +202,7 @@ static int restart(int argc, char **argv)
|
||||
{
|
||||
log_send_messaging(MESSAGING_WARNING, "\n\nPerforming a simple restart to the currently active partition.");
|
||||
if(!wait_for_commit()){
|
||||
log_send_messaging(MESSAGING_WARNING,"Unable to commit configuration. ");
|
||||
cmd_send_messaging(argv[0],MESSAGING_WARNING,"Unable to commit configuration. ");
|
||||
}
|
||||
vTaskDelay(750/ portTICK_PERIOD_MS);
|
||||
esp_restart();
|
||||
@@ -194,7 +211,7 @@ static int restart(int argc, char **argv)
|
||||
|
||||
void simple_restart()
|
||||
{
|
||||
log_send_messaging(MESSAGING_WARNING,"\n\n Called to perform a simple system reboot.");
|
||||
log_send_messaging(MESSAGING_WARNING,"System reboot requested.");
|
||||
if(!wait_for_commit()){
|
||||
log_send_messaging(MESSAGING_WARNING,"Unable to commit configuration. ");
|
||||
}
|
||||
@@ -205,24 +222,24 @@ void simple_restart()
|
||||
}
|
||||
|
||||
esp_err_t guided_restart_ota(){
|
||||
log_send_messaging(MESSAGING_WARNING,"\n\nCalled for a reboot to OTA Application");
|
||||
log_send_messaging(MESSAGING_WARNING,"System reboot to Application requested");
|
||||
guided_boot(ESP_PARTITION_SUBTYPE_APP_OTA_0);
|
||||
return ESP_FAIL; // return fail. This should never return... we're rebooting!
|
||||
}
|
||||
esp_err_t guided_factory(){
|
||||
log_send_messaging(MESSAGING_WARNING,"\n\nCalled for a reboot to recovery application");
|
||||
log_send_messaging(MESSAGING_WARNING,"System reboot to recovery requested");
|
||||
guided_boot(ESP_PARTITION_SUBTYPE_APP_FACTORY);
|
||||
return ESP_FAIL; // return fail. This should never return... we're rebooting!
|
||||
}
|
||||
static int restart_factory(int argc, char **argv)
|
||||
{
|
||||
log_send_messaging(MESSAGING_WARNING, "Executing guided boot into recovery");
|
||||
cmd_send_messaging(argv[0],MESSAGING_WARNING, "Executing guided boot into recovery");
|
||||
guided_boot(ESP_PARTITION_SUBTYPE_APP_FACTORY);
|
||||
return 0; // return fail. This should never return... we're rebooting!
|
||||
}
|
||||
static int restart_ota(int argc, char **argv)
|
||||
{
|
||||
log_send_messaging(MESSAGING_WARNING, "Executing guided boot into ota app 0");
|
||||
cmd_send_messaging(argv[0],MESSAGING_WARNING, "Executing guided boot into ota app 0");
|
||||
guided_boot(ESP_PARTITION_SUBTYPE_APP_OTA_0);
|
||||
return 0; // return fail. This should never return... we're rebooting!
|
||||
}
|
||||
@@ -230,7 +247,7 @@ static void register_restart()
|
||||
{
|
||||
const esp_console_cmd_t cmd = {
|
||||
.command = "restart",
|
||||
.help = "Software reset of the chip",
|
||||
.help = "Reboot system",
|
||||
.hint = NULL,
|
||||
.func = &restart,
|
||||
};
|
||||
@@ -241,7 +258,7 @@ static void register_restart_ota()
|
||||
{
|
||||
const esp_console_cmd_t cmd = {
|
||||
.command = "restart_ota",
|
||||
.help = "Selects the ota app partition to boot from and performa a software reset of the chip",
|
||||
.help = "Reboot system to Squeezelite",
|
||||
.hint = NULL,
|
||||
.func = &restart_ota,
|
||||
};
|
||||
@@ -253,7 +270,7 @@ static void register_factory_boot()
|
||||
{
|
||||
const esp_console_cmd_t cmd = {
|
||||
.command = "recovery",
|
||||
.help = "Resets and boot to recovery (if available)",
|
||||
.help = "Reboot system to Recovery",
|
||||
.hint = NULL,
|
||||
.func = &restart_factory,
|
||||
};
|
||||
@@ -264,94 +281,10 @@ static void register_factory_boot()
|
||||
|
||||
static int free_mem(int argc, char **argv)
|
||||
{
|
||||
log_send_messaging(MESSAGING_INFO,"%d", esp_get_free_heap_size());
|
||||
cmd_send_messaging(argv[0],MESSAGING_INFO,"%d", esp_get_free_heap_size());
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
static struct {
|
||||
struct arg_str *a2dp_dev_name;
|
||||
struct arg_str *a2dp_sink_name;
|
||||
struct arg_str *wakeup_gpio_level;
|
||||
struct arg_str *bt_sink_pin;
|
||||
struct arg_str *enable_bt_sink;
|
||||
struct arg_end *end;
|
||||
} set_btsource_args;
|
||||
*/
|
||||
|
||||
//static int do_set_btsource(int argc, char **argv)
|
||||
//{
|
||||
// a2dp_dev_name;
|
||||
// a2dp_sink_name;
|
||||
// wakeup_gpio_level;
|
||||
// bt_sink_pin;
|
||||
// enable_bt_sink;
|
||||
|
||||
|
||||
|
||||
// int nerrors = arg_parse_msg(argc, argv,(struct arg_hdr **)&deep_sleep_args);
|
||||
// if (nerrors != 0) {
|
||||
// return 1;
|
||||
// }
|
||||
// if (deep_sleep_args.wakeup_time->count) {
|
||||
// uint64_t timeout = 1000ULL * deep_sleep_args.wakeup_time->ival[0];
|
||||
// log_send_messaging(MESSAGING_INFO, "Enabling timer wakeup, timeout=%lluus", timeout);
|
||||
// ESP_ERROR_CHECK( esp_sleep_enable_timer_wakeup(timeout) );
|
||||
// }
|
||||
// if (deep_sleep_args.wakeup_gpio_num->count) {
|
||||
// int io_num = deep_sleep_args.wakeup_gpio_num->ival[0];
|
||||
// if (!rtc_gpio_is_valid_gpio(io_num)) {
|
||||
// log_send_messaging(MESSAGING_ERROR, "GPIO %d is not an RTC IO", io_num);
|
||||
// return 1;
|
||||
// }
|
||||
// int level = 0;
|
||||
// if (deep_sleep_args.wakeup_gpio_level->count) {
|
||||
// level = deep_sleep_args.wakeup_gpio_level->ival[0];
|
||||
// if (level != 0 && level != 1) {
|
||||
// log_send_messaging(MESSAGING_ERROR, "Invalid wakeup level: %d", level);
|
||||
// return 1;
|
||||
// }
|
||||
// }
|
||||
// log_send_messaging(MESSAGING_INFO, "Enabling wakeup on GPIO%d, wakeup on %s level",
|
||||
// io_num, level ? "HIGH" : "LOW");
|
||||
//
|
||||
// ESP_ERROR_CHECK( esp_sleep_enable_ext1_wakeup(1ULL << io_num, level) );
|
||||
// }
|
||||
// rtc_gpio_isolate(GPIO_NUM_12);
|
||||
// esp_deep_sleep_start();
|
||||
//return 0;
|
||||
//}
|
||||
|
||||
|
||||
|
||||
static void register_setbtsource(){
|
||||
|
||||
// a2dp_dev_name;
|
||||
// a2dp_sink_name;
|
||||
// wakeup_gpio_level;
|
||||
// bt_sink_pin;
|
||||
// enable_bt_sink;
|
||||
//
|
||||
// set_btsource_args.wakeup_time =
|
||||
// arg_int0("t", "time", "<t>", "Wake up time, ms");
|
||||
// set_btsource_args.wakeup_gpio_num =
|
||||
// arg_int0(NULL, "io", "<n>",
|
||||
// "If specified, wakeup using GPIO with given number");
|
||||
// set_btsource_args.wakeup_gpio_level =
|
||||
// arg_int0(NULL, "io_level", "<0|1>", "GPIO level to trigger wakeup");
|
||||
// set_btsource_args.end = arg_end(3);
|
||||
//
|
||||
// const esp_console_cmd_t cmd = {
|
||||
// .command = "deep_sleep",
|
||||
// .help = "Enter deep sleep mode. "
|
||||
// "Two wakeup modes are supported: timer and GPIO. "
|
||||
// "If no wakeup option is specified, will sleep indefinitely.",
|
||||
// .hint = NULL,
|
||||
// .func = &do_set_btsource,
|
||||
// .argtable = &set_btsource_args
|
||||
// };
|
||||
// ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) );
|
||||
}
|
||||
|
||||
static void register_free()
|
||||
{
|
||||
@@ -369,9 +302,138 @@ static void register_free()
|
||||
static int heap_size(int argc, char **argv)
|
||||
{
|
||||
uint32_t heap_size = heap_caps_get_minimum_free_size(MALLOC_CAP_DEFAULT);
|
||||
log_send_messaging(MESSAGING_INFO, "min heap size: %u", heap_size);
|
||||
cmd_send_messaging(argv[0],MESSAGING_INFO, "min heap size: %u", heap_size);
|
||||
return 0;
|
||||
}
|
||||
cJSON * setdevicename_cb(){
|
||||
char * default_host_name = config_alloc_get_str("host_name",NULL,"Squeezelite");
|
||||
cJSON * values = cJSON_CreateObject();
|
||||
cJSON_AddStringToObject(values,"name",default_host_name);
|
||||
free(default_host_name);
|
||||
return values;
|
||||
}
|
||||
static int setnamevar(char * nvsname, FILE *f, char * value){
|
||||
esp_err_t err=ESP_OK;
|
||||
if((err=config_set_value(NVS_TYPE_STR, nvsname, value))!=ESP_OK){
|
||||
fprintf(f,"Unable to set %s=%s. %s\n",nvsname,value,esp_err_to_name(err));
|
||||
}
|
||||
return err==ESP_OK?0:1;
|
||||
}
|
||||
typedef enum {
|
||||
SCANNING,
|
||||
PROCESSING_NAME
|
||||
} scanstate_t;
|
||||
int set_squeezelite_player_name(FILE * f,const char * name){
|
||||
char * nvs_config= config_alloc_get(NVS_TYPE_STR, "autoexec1");
|
||||
char **argv = NULL;
|
||||
esp_err_t err=ESP_OK;
|
||||
int nerrors=0;
|
||||
bool bFoundParm=false;
|
||||
scanstate_t state=SCANNING;
|
||||
char * newCommandLine = NULL;
|
||||
char * parm = " -n ";
|
||||
char * cleaned_name = strdup(name);
|
||||
for(char * p=cleaned_name;*p!='\0';p++){
|
||||
if(*p == ' '){
|
||||
*p='_'; // no spaces allowed
|
||||
}
|
||||
}
|
||||
if(nvs_config && strlen(nvs_config)>0){
|
||||
// allocate enough memory to hold the new command line
|
||||
size_t cmdLength = strlen(nvs_config) + strlen(cleaned_name) + strlen(parm) +1 ;
|
||||
newCommandLine = malloc(cmdLength);
|
||||
memset(newCommandLine,0x00, cmdLength);
|
||||
ESP_LOGD(TAG,"Parsing command %s",nvs_config);
|
||||
argv = (char **) calloc(22, sizeof(char *));
|
||||
if (argv == NULL) {
|
||||
FREE_AND_NULL(nvs_config);
|
||||
return 1;
|
||||
}
|
||||
size_t argc = esp_console_split_argv(nvs_config, argv,22);
|
||||
for(int i=0;i<argc;i++) {
|
||||
if(i>0){
|
||||
strcat(newCommandLine," ");
|
||||
}
|
||||
switch (state)
|
||||
{
|
||||
case SCANNING:
|
||||
strcat(newCommandLine,argv[i]);
|
||||
if(strcasecmp(argv[i],"--name")==0 || strcasecmp(argv[i],"-n")==0 ){
|
||||
state = PROCESSING_NAME;
|
||||
}
|
||||
break;
|
||||
case PROCESSING_NAME:
|
||||
bFoundParm=true;
|
||||
strcat(newCommandLine,cleaned_name);
|
||||
state = SCANNING;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!bFoundParm){
|
||||
strcat(newCommandLine,parm);
|
||||
strcat(newCommandLine,name);
|
||||
}
|
||||
fprintf(f,"Squeezelite player name changed to %s\n",newCommandLine);
|
||||
if((err=config_set_value(NVS_TYPE_STR, "autoexec1",newCommandLine))!=ESP_OK){
|
||||
nerrors++;
|
||||
fprintf(f,"Failed updating squeezelite command. %s", esp_err_to_name(err));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
FREE_AND_NULL(nvs_config);
|
||||
FREE_AND_NULL(argv);
|
||||
free(cleaned_name);
|
||||
return nerrors;
|
||||
|
||||
}
|
||||
static int setdevicename(int argc, char **argv)
|
||||
{
|
||||
char * name = NULL;
|
||||
int nerrors = arg_parse_msg(argc, argv,(struct arg_hdr **)&name_args);
|
||||
if (nerrors != 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Check "--name" option */
|
||||
if (name_args.name->count) {
|
||||
name=strdup(name_args.name->sval[0]);
|
||||
}
|
||||
else {
|
||||
cmd_send_messaging(argv[0],MESSAGING_ERROR,"Name must be specified.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
char *buf = NULL;
|
||||
size_t buf_size = 0;
|
||||
FILE *f = open_memstream(&buf, &buf_size);
|
||||
if (f == NULL) {
|
||||
cmd_send_messaging(argv[0],MESSAGING_ERROR,"Unable to open memory stream.");
|
||||
return 1;
|
||||
}
|
||||
nerrors+=setnamevar("a2dp_dev_name", f, name);
|
||||
nerrors+=setnamevar("airplay_name", f, name);
|
||||
nerrors+=setnamevar("ap_ssid", f, name);
|
||||
nerrors+=setnamevar("bt_name", f, name);
|
||||
nerrors+=setnamevar("host_name", f, name);
|
||||
nerrors+=set_squeezelite_player_name(f, name);
|
||||
if(nerrors==0){
|
||||
fprintf(f,"Device name changed to %s\n",name);
|
||||
}
|
||||
if(!nerrors ){
|
||||
fprintf(f,"Done.\n");
|
||||
}
|
||||
FREE_AND_NULL(name);
|
||||
fflush (f);
|
||||
cmd_send_messaging(argv[0],nerrors>0?MESSAGING_ERROR:MESSAGING_INFO,"%s", buf);
|
||||
fclose(f);
|
||||
FREE_AND_NULL(buf);
|
||||
return nerrors;
|
||||
|
||||
}
|
||||
|
||||
static void register_heap()
|
||||
{
|
||||
@@ -386,6 +448,22 @@ static void register_heap()
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void register_setdevicename()
|
||||
{
|
||||
char * default_host_name = config_alloc_get_str("host_name",NULL,"Squeezelite");
|
||||
name_args.name = arg_str0("n", "name", default_host_name, "New Name");
|
||||
name_args.end = arg_end(8);
|
||||
const esp_console_cmd_t set_name= {
|
||||
.command = CFG_TYPE_SYST("name"),
|
||||
.help="Device Name",
|
||||
.hint = NULL,
|
||||
.func = &setdevicename,
|
||||
.argtable = &name_args
|
||||
};
|
||||
cmd_to_json_with_cb(&set_name,&setdevicename_cb);
|
||||
ESP_ERROR_CHECK(esp_console_cmd_register(&set_name));
|
||||
}
|
||||
/** 'tasks' command prints the list of tasks and related information */
|
||||
#if WITH_TASKS_INFO
|
||||
|
||||
@@ -394,16 +472,16 @@ static int tasks_info(int argc, char **argv)
|
||||
const size_t bytes_per_task = 40; /* see vTaskList description */
|
||||
char *task_list_buffer = malloc(uxTaskGetNumberOfTasks() * bytes_per_task);
|
||||
if (task_list_buffer == NULL) {
|
||||
log_send_messaging(MESSAGING_ERROR, "failed to allocate buffer for vTaskList output");
|
||||
cmd_send_messaging(argv[0],MESSAGING_ERROR, "failed to allocate buffer for vTaskList output");
|
||||
return 1;
|
||||
}
|
||||
log_send_messaging(MESSAGING_INFO,"Task Name\tStatus\tPrio\tHWM\tTask#"
|
||||
cmd_send_messaging(argv[0],MESSAGING_INFO,"Task Name\tStatus\tPrio\tHWM\tTask#"
|
||||
#ifdef CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID
|
||||
"\tAffinity"
|
||||
#endif
|
||||
"\n");
|
||||
vTaskList(task_list_buffer);
|
||||
log_send_messaging(MESSAGING_INFO,"%s", task_list_buffer);
|
||||
cmd_send_messaging(argv[0],MESSAGING_INFO,"%s", task_list_buffer);
|
||||
free(task_list_buffer);
|
||||
return 0;
|
||||
}
|
||||
@@ -423,7 +501,7 @@ static void register_tasks()
|
||||
|
||||
extern esp_err_t update_certificates(bool force);
|
||||
static int force_update_cert(int argc, char **argv){
|
||||
return update_certificates(true)==ESP_OK;
|
||||
return update_certificates(true);
|
||||
}
|
||||
|
||||
static void register_update_certs()
|
||||
@@ -457,30 +535,31 @@ static int deep_sleep(int argc, char **argv)
|
||||
}
|
||||
if (deep_sleep_args.wakeup_time->count) {
|
||||
uint64_t timeout = 1000ULL * deep_sleep_args.wakeup_time->ival[0];
|
||||
log_send_messaging(MESSAGING_INFO, "Enabling timer wakeup, timeout=%lluus", timeout);
|
||||
cmd_send_messaging(argv[0],MESSAGING_INFO, "Enabling timer wakeup, timeout=%lluus", timeout);
|
||||
ESP_ERROR_CHECK( esp_sleep_enable_timer_wakeup(timeout) );
|
||||
}
|
||||
if (deep_sleep_args.wakeup_gpio_num->count) {
|
||||
int io_num = deep_sleep_args.wakeup_gpio_num->ival[0];
|
||||
if (!rtc_gpio_is_valid_gpio(io_num)) {
|
||||
log_send_messaging(MESSAGING_ERROR, "GPIO %d is not an RTC IO", io_num);
|
||||
cmd_send_messaging(argv[0],MESSAGING_ERROR, "GPIO %d is not an RTC IO", io_num);
|
||||
return 1;
|
||||
}
|
||||
int level = 0;
|
||||
if (deep_sleep_args.wakeup_gpio_level->count) {
|
||||
level = deep_sleep_args.wakeup_gpio_level->ival[0];
|
||||
if (level != 0 && level != 1) {
|
||||
log_send_messaging(MESSAGING_ERROR, "Invalid wakeup level: %d", level);
|
||||
cmd_send_messaging(argv[0],MESSAGING_ERROR, "Invalid wakeup level: %d", level);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
log_send_messaging(MESSAGING_INFO, "Enabling wakeup on GPIO%d, wakeup on %s level",
|
||||
cmd_send_messaging(argv[0],MESSAGING_INFO, "Enabling wakeup on GPIO%d, wakeup on %s level",
|
||||
io_num, level ? "HIGH" : "LOW");
|
||||
|
||||
ESP_ERROR_CHECK( esp_sleep_enable_ext1_wakeup(1ULL << io_num, level) );
|
||||
}
|
||||
rtc_gpio_isolate(GPIO_NUM_12);
|
||||
esp_deep_sleep_start();
|
||||
return 0; // this code will never run. deep sleep will cause the system to restart
|
||||
}
|
||||
|
||||
static void register_deep_sleep()
|
||||
@@ -505,7 +584,184 @@ static void register_deep_sleep()
|
||||
};
|
||||
ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) );
|
||||
}
|
||||
static int enable_disable(FILE * f,char * nvs_name, struct arg_lit *arg){
|
||||
esp_err_t err = config_set_value(NVS_TYPE_STR, nvs_name, arg->count>0?"Y":"N");
|
||||
const char * name = arg->hdr.longopts?arg->hdr.longopts:arg->hdr.glossary;
|
||||
|
||||
if(err!=ESP_OK){
|
||||
fprintf(f,"Error %s %s. %s\n",arg->count>0?"Enabling":"Disabling", name, esp_err_to_name(err));
|
||||
}
|
||||
else {
|
||||
fprintf(f,"%s %s\n",arg->count>0?"Enabled":"Disabled",name);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
static int do_configure_wifi(int argc, char **argv){
|
||||
esp_err_t err = ESP_OK;
|
||||
int nerrors = arg_parse_msg(argc, argv,(struct arg_hdr **)&wifi_parms_arg);
|
||||
if (nerrors != 0) {
|
||||
return 1;
|
||||
}
|
||||
char *buf = NULL;
|
||||
size_t buf_size = 0;
|
||||
FILE *f = open_memstream(&buf, &buf_size);
|
||||
if (f == NULL) {
|
||||
cmd_send_messaging(argv[0],MESSAGING_ERROR,"Unable to open memory stream.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(wifi_parms_arg.scanmode->count>0){
|
||||
if(strcasecmp(wifi_parms_arg.scanmode->sval[0],"Comprehensive") == 0){
|
||||
err = config_set_value(NVS_TYPE_STR, "wifi_smode", "A");
|
||||
}
|
||||
else {
|
||||
err = config_set_value(NVS_TYPE_STR, "wifi_smode", "F");
|
||||
}
|
||||
if(err!=ESP_OK){
|
||||
nerrors++;
|
||||
fprintf(f,"Error setting wifi scan mode to %s. %s\n",wifi_parms_arg.scanmode->sval[0], esp_err_to_name(err));
|
||||
}
|
||||
else {
|
||||
fprintf(f,"Wifi Scan Mode changed to %s\n",wifi_parms_arg.scanmode->sval[0]);
|
||||
}
|
||||
}
|
||||
if(!nerrors ){
|
||||
fprintf(f,"Done.\n");
|
||||
}
|
||||
fflush (f);
|
||||
cmd_send_messaging(argv[0],nerrors>0?MESSAGING_ERROR:MESSAGING_INFO,"%s", buf);
|
||||
fclose(f);
|
||||
FREE_AND_NULL(buf);
|
||||
return nerrors;
|
||||
}
|
||||
static int do_set_services(int argc, char **argv)
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
int nerrors = arg_parse_msg(argc, argv,(struct arg_hdr **)&set_services_args);
|
||||
if (nerrors != 0) {
|
||||
return 1;
|
||||
}
|
||||
char *buf = NULL;
|
||||
size_t buf_size = 0;
|
||||
FILE *f = open_memstream(&buf, &buf_size);
|
||||
if (f == NULL) {
|
||||
cmd_send_messaging(argv[0],MESSAGING_ERROR,"Unable to open memory stream.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
nerrors += enable_disable(f,"enable_airplay",set_services_args.airplay);
|
||||
nerrors += enable_disable(f,"enable_bt_sink",set_services_args.btspeaker);
|
||||
|
||||
if(set_services_args.telnet->count>0){
|
||||
if(strcasecmp(set_services_args.telnet->sval[0],"Disabled") == 0){
|
||||
err = config_set_value(NVS_TYPE_STR, "telnet_enable", "N");
|
||||
}
|
||||
else if(strcasecmp(set_services_args.telnet->sval[0],"Telnet Only") == 0){
|
||||
err = config_set_value(NVS_TYPE_STR, "telnet_enable", "Y");
|
||||
}
|
||||
else if(strcasecmp(set_services_args.telnet->sval[0],"Telnet and Serial") == 0){
|
||||
err = config_set_value(NVS_TYPE_STR, "telnet_enable", "D");
|
||||
}
|
||||
|
||||
if(err!=ESP_OK){
|
||||
nerrors++;
|
||||
fprintf(f,"Error setting telnet service to %s. %s\n",set_services_args.telnet->sval[0], esp_err_to_name(err));
|
||||
}
|
||||
else {
|
||||
fprintf(f,"Telnet service changed to %s\n",set_services_args.telnet->sval[0]);
|
||||
}
|
||||
}
|
||||
|
||||
#if WITH_TASKS_INFO
|
||||
nerrors += enable_disable(f,"stats",set_services_args.stats);
|
||||
#endif
|
||||
if(!nerrors ){
|
||||
fprintf(f,"Done.\n");
|
||||
}
|
||||
fflush (f);
|
||||
cmd_send_messaging(argv[0],nerrors>0?MESSAGING_ERROR:MESSAGING_INFO,"%s", buf);
|
||||
fclose(f);
|
||||
FREE_AND_NULL(buf);
|
||||
return nerrors;
|
||||
}
|
||||
|
||||
cJSON * configure_wifi_cb(){
|
||||
cJSON * values = cJSON_CreateObject();
|
||||
char * p=NULL;
|
||||
|
||||
if ((p = config_alloc_get(NVS_TYPE_STR, "wifi_smode")) != NULL) {
|
||||
cJSON_AddStringToObject(values,"scanmode",strcasecmp(p,"a") == 0 ?"Comprehensive":"Fast");
|
||||
FREE_AND_NULL(p);
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
|
||||
|
||||
cJSON * set_services_cb(){
|
||||
cJSON * values = cJSON_CreateObject();
|
||||
char * p=NULL;
|
||||
if ((p = config_alloc_get(NVS_TYPE_STR, "enable_bt_sink")) != NULL) {
|
||||
cJSON_AddBoolToObject(values,"BT_Speaker",strcmp(p,"1") == 0 || strcasecmp(p,"y") == 0);
|
||||
FREE_AND_NULL(p);
|
||||
}
|
||||
if ((p = config_alloc_get(NVS_TYPE_STR, "enable_airplay")) != NULL) {
|
||||
cJSON_AddBoolToObject(values,"AirPlay",strcmp(p,"1") == 0 || strcasecmp(p,"y") == 0);
|
||||
FREE_AND_NULL(p);
|
||||
}
|
||||
if ((p = config_alloc_get(NVS_TYPE_STR, "telnet_enable")) != NULL) {
|
||||
if(strcasestr("YX",p)!=NULL){
|
||||
cJSON_AddStringToObject(values,"telnet","Telnet Only");
|
||||
}
|
||||
else if(strcasestr("D",p)!=NULL){
|
||||
cJSON_AddStringToObject(values,"telnet","Telnet and Serial");
|
||||
}
|
||||
else {
|
||||
cJSON_AddStringToObject(values,"telnet","Disabled");
|
||||
}
|
||||
|
||||
FREE_AND_NULL(p);
|
||||
}
|
||||
#if WITH_TASKS_INFO
|
||||
if((p = config_alloc_get_default(NVS_TYPE_STR, "stats", "n", 0))!=NULL){
|
||||
cJSON_AddBoolToObject(values,"stats",(*p == '1' || *p == 'Y' || *p == 'y')) ;
|
||||
}
|
||||
#endif
|
||||
return values;
|
||||
}
|
||||
|
||||
static void register_set_services(){
|
||||
set_services_args.airplay = arg_lit0(NULL, "AirPlay", "AirPlay");
|
||||
set_services_args.btspeaker = arg_lit0(NULL, "BT_Speaker", "Bluetooth Speaker");
|
||||
set_services_args.telnet= arg_str0("t", "telnet","Disabled|Telnet Only|Telnet and Serial","Telnet server. Use only for troubleshooting");
|
||||
#if WITH_TASKS_INFO
|
||||
set_services_args.stats= arg_lit0(NULL, "stats", "System Statistics. Use only for troubleshooting");
|
||||
#endif
|
||||
set_services_args.end=arg_end(2);
|
||||
const esp_console_cmd_t cmd = {
|
||||
.command = CFG_TYPE_SYST("services"),
|
||||
.help = "Services",
|
||||
.argtable = &set_services_args,
|
||||
.hint = NULL,
|
||||
.func = &do_set_services,
|
||||
};
|
||||
cmd_to_json_with_cb(&cmd,&set_services_cb);
|
||||
ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) );
|
||||
}
|
||||
|
||||
static void register_set_wifi_parms(){
|
||||
wifi_parms_arg.scanmode = arg_str0(NULL, "scanmode", "Fast|Comprehensive","Sets the WiFi Scan Mode. Use Comprehensive where more than one AP has the same name on different channels. This will ensure that the AP with the strongest signal is chosen.");
|
||||
wifi_parms_arg.end=arg_end(2);
|
||||
const esp_console_cmd_t cmd = {
|
||||
.command = CFG_TYPE_SYST("wifi"),
|
||||
.help = "WiFi",
|
||||
.argtable = &wifi_parms_arg,
|
||||
.hint = NULL,
|
||||
.func = &do_configure_wifi,
|
||||
};
|
||||
cmd_to_json_with_cb(&cmd,&configure_wifi_cb);
|
||||
ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) );
|
||||
}
|
||||
/** 'light_sleep' command puts the chip into light sleep mode */
|
||||
|
||||
static struct {
|
||||
@@ -524,22 +780,22 @@ static int light_sleep(int argc, char **argv)
|
||||
esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_ALL);
|
||||
if (light_sleep_args.wakeup_time->count) {
|
||||
uint64_t timeout = 1000ULL * light_sleep_args.wakeup_time->ival[0];
|
||||
log_send_messaging(MESSAGING_INFO, "Enabling timer wakeup, timeout=%lluus", timeout);
|
||||
cmd_send_messaging(argv[0],MESSAGING_INFO, "Enabling timer wakeup, timeout=%lluus", timeout);
|
||||
ESP_ERROR_CHECK( esp_sleep_enable_timer_wakeup(timeout) );
|
||||
}
|
||||
int io_count = light_sleep_args.wakeup_gpio_num->count;
|
||||
if (io_count != light_sleep_args.wakeup_gpio_level->count) {
|
||||
log_send_messaging(MESSAGING_INFO, "Should have same number of 'io' and 'io_level' arguments");
|
||||
cmd_send_messaging(argv[0],MESSAGING_INFO, "Should have same number of 'io' and 'io_level' arguments");
|
||||
return 1;
|
||||
}
|
||||
for (int i = 0; i < io_count; ++i) {
|
||||
int io_num = light_sleep_args.wakeup_gpio_num->ival[i];
|
||||
int level = light_sleep_args.wakeup_gpio_level->ival[i];
|
||||
if (level != 0 && level != 1) {
|
||||
log_send_messaging(MESSAGING_ERROR, "Invalid wakeup level: %d", level);
|
||||
cmd_send_messaging(argv[0],MESSAGING_ERROR, "Invalid wakeup level: %d", level);
|
||||
return 1;
|
||||
}
|
||||
log_send_messaging(MESSAGING_INFO, "Enabling wakeup on GPIO%d, wakeup on %s level",
|
||||
cmd_send_messaging(argv[0],MESSAGING_INFO, "Enabling wakeup on GPIO%d, wakeup on %s level",
|
||||
io_num, level ? "HIGH" : "LOW");
|
||||
|
||||
ESP_ERROR_CHECK( gpio_wakeup_enable(io_num, level ? GPIO_INTR_HIGH_LEVEL : GPIO_INTR_LOW_LEVEL) );
|
||||
@@ -548,7 +804,7 @@ static int light_sleep(int argc, char **argv)
|
||||
ESP_ERROR_CHECK( esp_sleep_enable_gpio_wakeup() );
|
||||
}
|
||||
if (CONFIG_ESP_CONSOLE_UART_NUM <= UART_NUM_1) {
|
||||
log_send_messaging(MESSAGING_INFO, "Enabling UART wakeup (press ENTER to exit light sleep)");
|
||||
cmd_send_messaging(argv[0],MESSAGING_INFO, "Enabling UART wakeup (press ENTER to exit light sleep)");
|
||||
ESP_ERROR_CHECK( uart_set_wakeup_threshold(CONFIG_ESP_CONSOLE_UART_NUM, 3) );
|
||||
ESP_ERROR_CHECK( esp_sleep_enable_uart_wakeup(CONFIG_ESP_CONSOLE_UART_NUM) );
|
||||
}
|
||||
@@ -571,7 +827,7 @@ static int light_sleep(int argc, char **argv)
|
||||
cause_str = "unknown";
|
||||
printf("%d\n", cause);
|
||||
}
|
||||
log_send_messaging(MESSAGING_INFO, "Woke up from: %s", cause_str);
|
||||
cmd_send_messaging(argv[0],MESSAGING_INFO, "Woke up from: %s", cause_str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "esp_console.h"
|
||||
#include "argtable3/argtable3.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/timers.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include "esp_wifi.h"
|
||||
#include "tcpip_adapter.h"
|
||||
@@ -99,8 +100,6 @@ static void initialise_wifi(void)
|
||||
return;
|
||||
}
|
||||
tcpip_adapter_init();
|
||||
// Now moved to esp_app_main: wifi_event_group = xEventGroupCreate();
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
||||
ESP_ERROR_CHECK( esp_wifi_init(&cfg) );
|
||||
ESP_ERROR_CHECK( esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, &event_handler, NULL) );
|
||||
@@ -112,13 +111,19 @@ static void initialise_wifi(void)
|
||||
led_blink(LED_GREEN, 250, 250);
|
||||
}
|
||||
|
||||
static bool wifi_join(const char *ssid, const char *pass, int timeout_ms)
|
||||
static void wifi_join(void *arg)
|
||||
{
|
||||
const char *ssid = join_args.ssid->sval[0];
|
||||
const char *pass = join_args.password->sval[0];
|
||||
int timeout_ms = join_args.timeout->ival[0];
|
||||
|
||||
initialise_wifi();
|
||||
wifi_config_t wifi_config = { 0 };
|
||||
strncpy((char *) wifi_config.sta.ssid, ssid, sizeof(wifi_config.sta.ssid));
|
||||
wifi_config.sta.ssid[sizeof(wifi_config.sta.ssid) - 1] = '\0';
|
||||
if (pass) {
|
||||
strncpy((char *) wifi_config.sta.password, pass, sizeof(wifi_config.sta.password));
|
||||
wifi_config.sta.password[sizeof(wifi_config.sta.password) - 1] = '\0';
|
||||
}
|
||||
|
||||
ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) );
|
||||
@@ -127,7 +132,12 @@ static bool wifi_join(const char *ssid, const char *pass, int timeout_ms)
|
||||
|
||||
int bits = xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT,
|
||||
pdFALSE, pdTRUE, timeout_ms / portTICK_PERIOD_MS);
|
||||
return (bits & CONNECTED_BIT) != 0;
|
||||
|
||||
if (bits & CONNECTED_BIT) {
|
||||
ESP_LOGI(__func__, "Connected");
|
||||
} else {
|
||||
ESP_LOGW(__func__, "Connection timed out");
|
||||
}
|
||||
}
|
||||
|
||||
//static int set_auto_connect(int argc, char **argv)
|
||||
@@ -170,14 +180,9 @@ static int connect(int argc, char **argv)
|
||||
join_args.timeout->ival[0] = JOIN_TIMEOUT_MS;
|
||||
}
|
||||
|
||||
bool connected = wifi_join(join_args.ssid->sval[0],
|
||||
join_args.password->sval[0],
|
||||
join_args.timeout->ival[0]);
|
||||
if (!connected) {
|
||||
ESP_LOGW(__func__, "Connection timed out");
|
||||
return 1;
|
||||
}
|
||||
ESP_LOGI(__func__, "Connected");
|
||||
// need to use that trick to make sure we use internal stack
|
||||
xTimerStart(xTimerCreate("wifi_join", 1, pdFALSE, NULL, wifi_join), portMAX_DELAY);
|
||||
|
||||
return 0;
|
||||
}
|
||||
void register_wifi_join()
|
||||
|
||||
@@ -30,13 +30,21 @@
|
||||
#include "messaging.h"
|
||||
|
||||
#include "config.h"
|
||||
pthread_t thread_console;
|
||||
static pthread_t thread_console;
|
||||
static void * console_thread();
|
||||
void console_start();
|
||||
static const char * TAG = "console";
|
||||
extern bool bypass_wifi_manager;
|
||||
extern void register_squeezelite();
|
||||
|
||||
static EXT_RAM_ATTR QueueHandle_t uart_queue;
|
||||
static EXT_RAM_ATTR struct {
|
||||
uint8_t _buf[128];
|
||||
StaticRingbuffer_t _ringbuf;
|
||||
RingbufHandle_t handle;
|
||||
QueueSetHandle_t queue_set;
|
||||
} stdin_redir;
|
||||
|
||||
/* Prompt to be printed before each line.
|
||||
* This can be customized, made dynamic, etc.
|
||||
*/
|
||||
@@ -50,7 +58,7 @@ const char* recovery_prompt = LOG_COLOR_E "recovery-squeezelite-esp32> " LOG_RES
|
||||
|
||||
#define MOUNT_PATH "/data"
|
||||
#define HISTORY_PATH MOUNT_PATH "/history.txt"
|
||||
void run_command(char * line);
|
||||
static esp_err_t run_command(char * line);
|
||||
#define ADD_TO_JSON(o,t,n) if (t->n) cJSON_AddStringToObject(o,QUOTE(n),t->n);
|
||||
#define ADD_PARMS_TO_CMD(o,t,n) { cJSON * parms = ParmsToJSON(&t.n->hdr); if(parms) cJSON_AddItemToObject(o,QUOTE(n),parms); }
|
||||
cJSON * cmdList;
|
||||
@@ -97,8 +105,11 @@ cJSON * ParmsToJSON(struct arg_hdr * * argtable){
|
||||
ADD_TO_JSON(entry,table[tabindex],glossary);
|
||||
ADD_TO_JSON(entry,table[tabindex],longopts);
|
||||
ADD_TO_JSON(entry,table[tabindex],shortopts);
|
||||
cJSON_AddBoolToObject(entry, "checkbox", (table[tabindex]->flag & ARG_HASOPTVALUE)==0 && (table[tabindex]->flag & ARG_HASVALUE)==0);
|
||||
cJSON_AddBoolToObject(entry, "checkbox", (table[tabindex]->flag & ARG_HASOPTVALUE)==0 && (table[tabindex]->flag & ARG_HASVALUE)==0 && (table[tabindex]->longopts || table[tabindex]->shortopts) );
|
||||
cJSON_AddBoolToObject(entry, "remark", (table[tabindex]->flag & ARG_HASOPTVALUE)==0 && (table[tabindex]->flag & ARG_HASVALUE)==0 && (!table[tabindex]->longopts && !table[tabindex]->shortopts));
|
||||
cJSON_AddBoolToObject(entry, "hasvalue", table[tabindex]->flag & ARG_HASVALUE);
|
||||
cJSON_AddNumberToObject(entry,"mincount",table[tabindex]->mincount);
|
||||
cJSON_AddNumberToObject(entry,"maxcount",table[tabindex]->maxcount);
|
||||
cJSON_AddItemToArray(arg_list, entry);
|
||||
tabindex++;
|
||||
}
|
||||
@@ -171,7 +182,7 @@ int arg_parse_msg(int argc, char **argv, struct arg_hdr ** args){
|
||||
if (f != NULL) {
|
||||
arg_print_errors(f, getParmsEnd(args), argv[0]);
|
||||
fflush (f);
|
||||
log_send_messaging(MESSAGING_ERROR,"%s", buf);
|
||||
cmd_send_messaging(argv[0],MESSAGING_ERROR,"%s", buf);
|
||||
}
|
||||
fclose(f);
|
||||
FREE_AND_NULL(buf);
|
||||
@@ -227,34 +238,78 @@ void process_autoexec(){
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t stdin_read(int fd, void* data, size_t size) {
|
||||
size_t bytes = -1;
|
||||
|
||||
while (1) {
|
||||
QueueSetMemberHandle_t activated = xQueueSelectFromSet(stdin_redir.queue_set, portMAX_DELAY);
|
||||
|
||||
if (activated == uart_queue) {
|
||||
uart_event_t event;
|
||||
|
||||
xQueueReceive(uart_queue, &event, 0);
|
||||
|
||||
if (event.type == UART_DATA) {
|
||||
bytes = uart_read_bytes(CONFIG_ESP_CONSOLE_UART_NUM, data, size < event.size ? size : event.size, 0);
|
||||
// we have to do our own line ending translation here
|
||||
for (int i = 0; i < bytes; i++) if (((char*)data)[i] == '\r') ((char*)data)[i] = '\n';
|
||||
break;
|
||||
}
|
||||
} else if (xRingbufferCanRead(stdin_redir.handle, activated)) {
|
||||
char *p = xRingbufferReceiveUpTo(stdin_redir.handle, &bytes, 0, size);
|
||||
// we might receive strings, replace null by \n
|
||||
for (int i = 0; i < bytes; i++) if (p[i] == '\0' || p[i] == '\r') p[i] = '\n';
|
||||
memcpy(data, p, bytes);
|
||||
vRingbufferReturnItem(stdin_redir.handle, p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
static int stdin_dummy(const char * path, int flags, int mode) { return 0; }
|
||||
|
||||
void initialize_console() {
|
||||
|
||||
/* Disable buffering on stdin */
|
||||
setvbuf(stdin, NULL, _IONBF, 0);
|
||||
|
||||
/* Minicom, screen, idf_monitor send CR when ENTER key is pressed */
|
||||
esp_vfs_dev_uart_set_rx_line_endings(ESP_LINE_ENDINGS_CR);
|
||||
/* Minicom, screen, idf_monitor send CR when ENTER key is pressed (unused if we redirect stdin) */
|
||||
esp_vfs_dev_uart_port_set_rx_line_endings(CONFIG_ESP_CONSOLE_UART_NUM, ESP_LINE_ENDINGS_CR);
|
||||
/* Move the caret to the beginning of the next line on '\n' */
|
||||
esp_vfs_dev_uart_set_tx_line_endings(ESP_LINE_ENDINGS_CRLF);
|
||||
esp_vfs_dev_uart_port_set_tx_line_endings(CONFIG_ESP_CONSOLE_UART_NUM, ESP_LINE_ENDINGS_CRLF);
|
||||
|
||||
/* Configure UART. Note that REF_TICK is used so that the baud rate remains
|
||||
* correct while APB frequency is changing in light sleep mode.
|
||||
*/
|
||||
const uart_config_t uart_config = { .baud_rate =
|
||||
CONFIG_CONSOLE_UART_BAUDRATE, .data_bits = UART_DATA_8_BITS,
|
||||
CONFIG_ESP_CONSOLE_UART_BAUDRATE, .data_bits = UART_DATA_8_BITS,
|
||||
.parity = UART_PARITY_DISABLE, .stop_bits = UART_STOP_BITS_1,
|
||||
.use_ref_tick = true };
|
||||
ESP_ERROR_CHECK(uart_param_config(CONFIG_ESP_CONSOLE_UART_NUM, &uart_config));
|
||||
|
||||
/* Install UART driver for interrupt-driven reads and writes */
|
||||
ESP_ERROR_CHECK( uart_driver_install(CONFIG_ESP_CONSOLE_UART_NUM, 256, 0, 0, NULL, 0));
|
||||
|
||||
ESP_ERROR_CHECK( uart_driver_install(CONFIG_ESP_CONSOLE_UART_NUM, 256, 0, 3, &uart_queue, 0));
|
||||
|
||||
/* Tell VFS to use UART driver */
|
||||
esp_vfs_dev_uart_use_driver(CONFIG_ESP_CONSOLE_UART_NUM);
|
||||
|
||||
/* re-direct stdin to our own driver so we can gather data from various sources */
|
||||
stdin_redir.queue_set = xQueueCreateSet(2);
|
||||
stdin_redir.handle = xRingbufferCreateStatic(sizeof(stdin_redir._buf), RINGBUF_TYPE_BYTEBUF, stdin_redir._buf, &stdin_redir._ringbuf);
|
||||
xRingbufferAddToQueueSetRead(stdin_redir.handle, stdin_redir.queue_set);
|
||||
xQueueAddToSet(uart_queue, stdin_redir.queue_set);
|
||||
|
||||
esp_vfs_t vfs = { };
|
||||
vfs.flags = ESP_VFS_FLAG_DEFAULT;
|
||||
vfs.open = stdin_dummy;
|
||||
vfs.read = stdin_read;
|
||||
|
||||
ESP_ERROR_CHECK(esp_vfs_register("/dev/console", &vfs, NULL));
|
||||
freopen("/dev/console", "r", stdin);
|
||||
|
||||
/* Disable buffering on stdin */
|
||||
setvbuf(stdin, NULL, _IONBF, 0);
|
||||
|
||||
/* Initialize the console */
|
||||
esp_console_config_t console_config = { .max_cmdline_args = 22,
|
||||
esp_console_config_t console_config = { .max_cmdline_args = 28,
|
||||
.max_cmdline_length = 600,
|
||||
#if CONFIG_LOG_COLORS
|
||||
.hint_color = atoi(LOG_COLOR_CYAN)
|
||||
@@ -279,25 +334,21 @@ void initialize_console() {
|
||||
//linenoiseHistoryLoad(HISTORY_PATH);
|
||||
}
|
||||
|
||||
bool console_push(const char *data, size_t size) {
|
||||
return xRingbufferSend(stdin_redir.handle, data, size, pdMS_TO_TICKS(100)) == pdPASS;
|
||||
}
|
||||
|
||||
void console_start() {
|
||||
if(!is_serial_suppressed()){
|
||||
initialize_console();
|
||||
}
|
||||
else {
|
||||
/* Initialize the console */
|
||||
esp_console_config_t console_config = { .max_cmdline_args = 22,
|
||||
.max_cmdline_length = 600,
|
||||
#if CONFIG_LOG_COLORS
|
||||
.hint_color = atoi(LOG_COLOR_CYAN)
|
||||
#endif
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_console_init(&console_config));
|
||||
}
|
||||
/* we always run console b/c telnet sends commands to stdin */
|
||||
initialize_console();
|
||||
|
||||
/* Register commands */
|
||||
esp_console_register_help_command();
|
||||
register_system();
|
||||
register_config_cmd();
|
||||
register_nvs();
|
||||
register_wifi();
|
||||
|
||||
if(!is_recovery_running){
|
||||
register_squeezelite();
|
||||
}
|
||||
@@ -306,65 +357,56 @@ void console_start() {
|
||||
}
|
||||
register_i2ctools();
|
||||
|
||||
if(!is_serial_suppressed()){
|
||||
printf("\n");
|
||||
if(is_recovery_running){
|
||||
printf("****************************************************************\n"
|
||||
"RECOVERY APPLICATION\n"
|
||||
"This mode is used to flash Squeezelite into the OTA partition\n"
|
||||
"****\n\n");
|
||||
}
|
||||
printf("Type 'help' to get the list of commands.\n"
|
||||
"Use UP/DOWN arrows to navigate through command history.\n"
|
||||
"Press TAB when typing command name to auto-complete.\n"
|
||||
"\n");
|
||||
if(!is_recovery_running){
|
||||
printf("To automatically execute lines at startup:\n"
|
||||
"\tSet NVS variable autoexec (U8) = 1 to enable, 0 to disable automatic execution.\n"
|
||||
"\tSet NVS variable autoexec[1~9] (string)to a command that should be executed automatically\n");
|
||||
}
|
||||
printf("\n\n");
|
||||
|
||||
/* Figure out if the terminal supports escape sequences */
|
||||
int probe_status = linenoiseProbe();
|
||||
if (probe_status) { /* zero indicates success */
|
||||
printf("\n****************************\n"
|
||||
"Your terminal application does not support escape sequences.\n"
|
||||
"Line editing and history features are disabled.\n"
|
||||
"On Windows, try using Putty instead.\n"
|
||||
"****************************\n");
|
||||
linenoiseSetDumbMode(1);
|
||||
#if CONFIG_LOG_COLORS
|
||||
/* Since the terminal doesn't support escape sequences,
|
||||
* don't use color codes in the prompt.
|
||||
*/
|
||||
if(is_recovery_running){
|
||||
recovery_prompt= "recovery-squeezelite-esp32>";
|
||||
}
|
||||
prompt = "squeezelite-esp32> ";
|
||||
|
||||
#endif //CONFIG_LOG_COLORS
|
||||
}
|
||||
esp_pthread_cfg_t cfg = esp_pthread_get_default_config();
|
||||
cfg.thread_name= "console";
|
||||
cfg.inherit_cfg = true;
|
||||
if(is_recovery_running){
|
||||
prompt = recovery_prompt;
|
||||
cfg.stack_size = 4096 ;
|
||||
}
|
||||
esp_pthread_set_cfg(&cfg);
|
||||
pthread_attr_t attr;
|
||||
pthread_attr_init(&attr);
|
||||
|
||||
pthread_create(&thread_console, &attr, console_thread, NULL);
|
||||
pthread_attr_destroy(&attr);
|
||||
}
|
||||
else if(!is_recovery_running){
|
||||
process_autoexec();
|
||||
printf("\n");
|
||||
if(is_recovery_running){
|
||||
printf("****************************************************************\n"
|
||||
"RECOVERY APPLICATION\n"
|
||||
"This mode is used to flash Squeezelite into the OTA partition\n"
|
||||
"****\n\n");
|
||||
}
|
||||
printf("Type 'help' to get the list of commands.\n"
|
||||
"Use UP/DOWN arrows to navigate through command history.\n"
|
||||
"Press TAB when typing command name to auto-complete.\n"
|
||||
"\n");
|
||||
if(!is_recovery_running){
|
||||
printf("To automatically execute lines at startup:\n"
|
||||
"\tSet NVS variable autoexec (U8) = 1 to enable, 0 to disable automatic execution.\n"
|
||||
"\tSet NVS variable autoexec[1~9] (string)to a command that should be executed automatically\n");
|
||||
}
|
||||
printf("\n\n");
|
||||
|
||||
/* Figure out if the terminal supports escape sequences */
|
||||
int probe_status = linenoiseProbe();
|
||||
if (probe_status) { /* zero indicates success */
|
||||
printf("\n****************************\n"
|
||||
"Your terminal application does not support escape sequences.\n"
|
||||
"Line editing and history features are disabled.\n"
|
||||
"On Windows, try using Putty instead.\n"
|
||||
"****************************\n");
|
||||
linenoiseSetDumbMode(1);
|
||||
#if CONFIG_LOG_COLORS
|
||||
/* Since the terminal doesn't support escape sequences,
|
||||
* don't use color codes in the prompt.
|
||||
*/
|
||||
if(is_recovery_running){
|
||||
recovery_prompt= "recovery-squeezelite-esp32>";
|
||||
}
|
||||
prompt = "squeezelite-esp32> ";
|
||||
#endif //CONFIG_LOG_COLORS
|
||||
}
|
||||
esp_pthread_cfg_t cfg = esp_pthread_get_default_config();
|
||||
cfg.thread_name= "console";
|
||||
cfg.inherit_cfg = true;
|
||||
cfg.stack_size = 4*1024;
|
||||
if(is_recovery_running){
|
||||
prompt = recovery_prompt;
|
||||
}
|
||||
esp_pthread_set_cfg(&cfg);
|
||||
pthread_create(&thread_console, NULL, console_thread, NULL);
|
||||
|
||||
}
|
||||
void run_command(char * line){
|
||||
|
||||
static esp_err_t run_command(char * line){
|
||||
/* Try to run the command */
|
||||
int ret;
|
||||
esp_err_t err = esp_console_run(line, &ret);
|
||||
@@ -373,14 +415,18 @@ void run_command(char * line){
|
||||
ESP_LOGE(TAG,"Unrecognized command: %s", line);
|
||||
} else if (err == ESP_ERR_INVALID_ARG) {
|
||||
// command was empty
|
||||
} else if (err == ESP_OK && ret != ESP_OK) {
|
||||
} else if (err != ESP_OK && ret != ESP_OK) {
|
||||
ESP_LOGW(TAG,"Command returned non-zero error code: 0x%x (%s)", ret,
|
||||
esp_err_to_name(err));
|
||||
esp_err_to_name(err));
|
||||
} else if (err == ESP_OK && ret != ESP_OK) {
|
||||
ESP_LOGW(TAG,"Command returned in error");
|
||||
err = ESP_FAIL;
|
||||
} else if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG,"Internal error: %s", esp_err_to_name(err));
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void * console_thread() {
|
||||
if(!is_recovery_running){
|
||||
process_autoexec();
|
||||
|
||||
@@ -13,6 +13,11 @@
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#define CFG_TYPE_HW(a) "cfg-hw-" a
|
||||
#define CFG_TYPE_AUDIO(a) "cfg-audio-" a
|
||||
#define CFG_TYPE_SYST(a) "cfg-syst-" a
|
||||
#define CFG_TYPE_FW(a) "cfg-fw-" a
|
||||
#define CFG_TYPE_GEN(a) "cfg-gen-" a
|
||||
typedef cJSON * parm_values_fn_t(void);
|
||||
esp_err_t cmd_to_json(const esp_console_cmd_t *cmd);
|
||||
esp_err_t cmd_to_json_with_cb(const esp_console_cmd_t *cmd, parm_values_fn_t parm_values_fn);
|
||||
|
||||
3
components/platform_console/test/CMakeLists.txt
Normal file
3
components/platform_console/test/CMakeLists.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
idf_component_register(SRCS "test_system.c"
|
||||
INCLUDE_DIRS "."
|
||||
REQUIRES unity tools console json platform_console platform_config )
|
||||
189
components/platform_console/test/test_system.c
Normal file
189
components/platform_console/test/test_system.c
Normal file
@@ -0,0 +1,189 @@
|
||||
/* test_mean.c: Implementation of a testable component.
|
||||
|
||||
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 <limits.h>
|
||||
#include "unity.h"
|
||||
#include "platform_console.h"
|
||||
#include "platform_esp32.h"
|
||||
#include "platform_config.h"
|
||||
#include "string.h"
|
||||
struct arg_lit *arglit;
|
||||
struct arg_int *argint;
|
||||
struct arg_str *argstr;
|
||||
struct arg_end *end;
|
||||
|
||||
extern int is_output_gpio(struct arg_int * gpio, FILE * f, int * gpio_out, bool mandatory);
|
||||
extern void initialize_console();
|
||||
extern esp_err_t run_command(char * line);
|
||||
static char *buf = NULL;
|
||||
static char * s_tmp_line_buf=NULL;
|
||||
static size_t buf_size = 0;
|
||||
static FILE * f;
|
||||
static size_t argc=1;
|
||||
static char ** argv=NULL;
|
||||
static bool config_initialized=false;
|
||||
void init_console(){
|
||||
if(config_initialized) return;
|
||||
initialize_console();
|
||||
config_initialized=true;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
void open_mem_stream_file(){
|
||||
f = open_memstream(&buf, &buf_size);
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
void close_flush_all(void * argtable, int count,bool print){
|
||||
fflush (f);
|
||||
if(print){
|
||||
printf("%s", buf);
|
||||
}
|
||||
fclose(f);
|
||||
free(buf);
|
||||
arg_freetable(argtable,count);
|
||||
free(argv);
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
int alloc_split_command_line(char * cmdline){
|
||||
argv = (char **) calloc(22, sizeof(char *));
|
||||
if(!s_tmp_line_buf){
|
||||
s_tmp_line_buf= calloc(strlen(cmdline), 1);
|
||||
}
|
||||
strlcpy(s_tmp_line_buf, cmdline, 22);
|
||||
argc = esp_console_split_argv(s_tmp_line_buf, argv,22);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
int alloc_split_parse_command_line(char * cmdline, void ** args){
|
||||
alloc_split_command_line(cmdline);
|
||||
return arg_parse(argc, argv,args);
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
TEST_CASE("Invalid GPIO detected", "[config][ui]")
|
||||
{
|
||||
char * cmdline = "test -i 55\n";
|
||||
void *argtable[] = {
|
||||
argint = arg_int1("i","int","<gpio>","GPIO number"),
|
||||
end = arg_end(6)
|
||||
};
|
||||
open_mem_stream_file();
|
||||
alloc_split_parse_command_line(cmdline, &argtable);
|
||||
int out_val = 0;
|
||||
TEST_ASSERT_EQUAL_INT_MESSAGE(1,is_output_gpio(argtable[0], f, &out_val, true),"Invalid GPIO not detected");
|
||||
TEST_ASSERT_EQUAL_INT_MESSAGE(-1,out_val,"GPIO Should be set to -1");
|
||||
fflush (f);
|
||||
TEST_ASSERT_EQUAL_STRING_MESSAGE("Invalid int gpio: [55] is not a GPIO\n",buf,"Invalid GPIO message wrong");
|
||||
close_flush_all(argtable,sizeof(argtable)/sizeof(argtable[0]),false);
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
TEST_CASE("Input Only GPIO detected", "[config][ui]")
|
||||
{
|
||||
char * cmdline = "test -i 35\n";
|
||||
void *argtable[] = {
|
||||
argint = arg_int1("i","int","<gpio>","GPIO number"),
|
||||
end = arg_end(6)
|
||||
};
|
||||
open_mem_stream_file();
|
||||
alloc_split_parse_command_line(cmdline, &argtable);
|
||||
int out_val = 0;
|
||||
TEST_ASSERT_EQUAL_INT_MESSAGE(1,is_output_gpio(argtable[0], f, &out_val, true),"Input only GPIO not detected");
|
||||
TEST_ASSERT_EQUAL_INT_MESSAGE(-1,out_val,"GPIO Should be set to -1");
|
||||
fflush (f);
|
||||
TEST_ASSERT_EQUAL_STRING_MESSAGE("Invalid int gpio: [35] has input capabilities only\n",buf,"Missing GPIO message wrong");
|
||||
close_flush_all(argtable,sizeof(argtable)/sizeof(argtable[0]),false);
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
TEST_CASE("Valid GPIO Processed", "[config][ui]")
|
||||
{
|
||||
char * cmdline = "test -i 33\n";
|
||||
void *argtable[] = {
|
||||
argint = arg_int1("i","int","<gpio>","GPIO number"),
|
||||
end = arg_end(6)
|
||||
};
|
||||
open_mem_stream_file();
|
||||
alloc_split_parse_command_line(cmdline, &argtable);
|
||||
int out_val = 0;
|
||||
TEST_ASSERT_EQUAL_INT_MESSAGE(0,is_output_gpio(argtable[0], f, &out_val, true),"Valid GPIO not recognized");
|
||||
TEST_ASSERT_EQUAL_INT_MESSAGE(33,out_val,"GPIO Should be set to 33");
|
||||
fflush (f);
|
||||
TEST_ASSERT_EQUAL_STRING_MESSAGE("",buf,"Valid GPIO shouldn't produce a message");
|
||||
close_flush_all(argtable,sizeof(argtable)/sizeof(argtable[0]),false);
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
TEST_CASE("Missing mandatory GPIO detected", "[config][ui]")
|
||||
{
|
||||
char * cmdline = "test \n";
|
||||
void *argtable[] = {
|
||||
argint = arg_int1("i","int","<gpio>","GPIO number"),
|
||||
end = arg_end(6)
|
||||
};
|
||||
open_mem_stream_file();
|
||||
alloc_split_parse_command_line(cmdline, &argtable);
|
||||
int out_val = 0;
|
||||
TEST_ASSERT_EQUAL_INT_MESSAGE(1,is_output_gpio(argtable[0], f, &out_val, true),"Missing GPIO not detected");
|
||||
fflush (f);
|
||||
TEST_ASSERT_EQUAL_STRING_MESSAGE("Missing: int\n",buf,"Missing GPIO parameter message wrong");
|
||||
TEST_ASSERT_EQUAL_INT_MESSAGE(-1,out_val,"GPIO Should be set to -1");
|
||||
close_flush_all(argtable,sizeof(argtable)/sizeof(argtable[0]),false);
|
||||
}
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
TEST_CASE("Missing mandatory parameter detected", "[config][ui]")
|
||||
{
|
||||
char * cmdline = "test \n";
|
||||
void *argtable[] = {
|
||||
argint = arg_int1("i","int","<gpio>","GPIO number"),
|
||||
end = arg_end(6)
|
||||
};
|
||||
open_mem_stream_file();
|
||||
alloc_split_parse_command_line(cmdline, &argtable);
|
||||
int out_val = 0;
|
||||
TEST_ASSERT_EQUAL_INT_MESSAGE(1,is_output_gpio(argtable[0], f, &out_val, true),"Missing parameter not detected");
|
||||
fflush (f);
|
||||
TEST_ASSERT_EQUAL_STRING_MESSAGE("Missing: int\n",buf,"Missing parameter message wrong");
|
||||
TEST_ASSERT_EQUAL_INT_MESSAGE(-1,out_val,"GPIO Should be set to -1");
|
||||
close_flush_all(argtable,sizeof(argtable)/sizeof(argtable[0]),false);
|
||||
}
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
TEST_CASE("dac config command", "[config_cmd]")
|
||||
{
|
||||
config_set_value(NVS_TYPE_STR, "dac_config", "");
|
||||
esp_err_t err=run_command("cfg-hw-dac\n");
|
||||
char * nvs_value = config_alloc_get_str("dac_config", NULL,NULL);
|
||||
TEST_ASSERT_NOT_NULL(nvs_value);
|
||||
TEST_ASSERT_EQUAL_MESSAGE(ESP_OK,err,"Running command failed");
|
||||
free(nvs_value);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,23 +1,19 @@
|
||||
/*
|
||||
* AirCast: Chromecast to AirPlay
|
||||
*
|
||||
* (c) Philippe 2016-2017, philippe_44@outlook.com
|
||||
* (c) Philippe 2020, philippe_44@outlook.com
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __RAOP_H
|
||||
#define __RAOP_H
|
||||
#pragma once
|
||||
|
||||
#include "platform.h"
|
||||
#include "raop_sink.h"
|
||||
|
||||
struct raop_ctx_s* raop_create(struct in_addr host, char *name, unsigned char mac[6], int latency,
|
||||
struct raop_ctx_s* raop_create(uint32_t host, char *name, unsigned char mac[6], int latency,
|
||||
raop_cmd_cb_t cmd_cb, raop_data_cb_t data_cb);
|
||||
void raop_delete(struct raop_ctx_s *ctx);
|
||||
void raop_abort(struct raop_ctx_s *ctx);
|
||||
bool raop_cmd(struct raop_ctx_s *ctx, raop_event_t event, void *param);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
#include "audio_controls.h"
|
||||
#include "display.h"
|
||||
#include "accessors.h"
|
||||
|
||||
#include "log_util.h"
|
||||
#include "trace.h"
|
||||
|
||||
@@ -25,6 +24,11 @@
|
||||
#define CONFIG_AIRPLAY_NAME "ESP32-AirPlay"
|
||||
#endif
|
||||
|
||||
static EXT_RAM_ATTR struct raop_cb_s {
|
||||
raop_cmd_vcb_t cmd;
|
||||
raop_data_cb_t data;
|
||||
} raop_cbs;
|
||||
|
||||
log_level raop_loglevel = lINFO;
|
||||
log_level util_loglevel;
|
||||
|
||||
@@ -81,12 +85,14 @@ static void raop_next(bool pressed) {
|
||||
}
|
||||
|
||||
const static actrls_t controls = {
|
||||
NULL, // power
|
||||
raop_volume_up, raop_volume_down, // volume up, volume down
|
||||
raop_toggle, raop_play, // toggle, play
|
||||
raop_pause, raop_stop, // pause, stop
|
||||
NULL, NULL, // rew, fwd
|
||||
raop_prev, raop_next, // prev, next
|
||||
NULL, NULL, NULL, NULL, // left, right, up, down
|
||||
NULL, NULL, NULL, NULL, NULL, NULL, // pre1-6
|
||||
raop_volume_down, raop_volume_up, raop_toggle// knob left, knob_right, knob push
|
||||
};
|
||||
|
||||
@@ -108,7 +114,7 @@ static bool cmd_handler(raop_event_t event, ...) {
|
||||
switch(event) {
|
||||
case RAOP_SETUP:
|
||||
actrls_set(controls, false, NULL, actrls_ir_action);
|
||||
displayer_control(DISPLAYER_ACTIVATE, "AIRPLAY");
|
||||
displayer_control(DISPLAYER_ACTIVATE, "AIRPLAY", true);
|
||||
break;
|
||||
case RAOP_PLAY:
|
||||
displayer_control(DISPLAYER_TIMER_RUN);
|
||||
@@ -123,8 +129,14 @@ static bool cmd_handler(raop_event_t event, ...) {
|
||||
case RAOP_METADATA: {
|
||||
char *artist = va_arg(args, char*), *album = va_arg(args, char*), *title = va_arg(args, char*);
|
||||
displayer_metadata(artist, album, title);
|
||||
displayer_artwork(NULL);
|
||||
break;
|
||||
}
|
||||
case RAOP_ARTWORK: {
|
||||
uint8_t *data = va_arg(args, uint8_t*);
|
||||
displayer_artwork(data);
|
||||
break;
|
||||
}
|
||||
case RAOP_PROGRESS: {
|
||||
int elapsed = va_arg(args, int), duration = va_arg(args, int);
|
||||
displayer_timer(DISPLAYER_ELAPSED, elapsed, duration);
|
||||
@@ -148,37 +160,68 @@ void raop_sink_deinit(void) {
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* Airplay sink initialization
|
||||
* Airplay sink startup
|
||||
*/
|
||||
void raop_sink_init(raop_cmd_vcb_t cmd_cb, raop_data_cb_t data_cb) {
|
||||
const char *hostname;
|
||||
static bool raop_sink_start(raop_cmd_vcb_t cmd_cb, raop_data_cb_t data_cb) {
|
||||
const char *hostname = NULL;
|
||||
char sink_name[64-6] = CONFIG_AIRPLAY_NAME;
|
||||
tcpip_adapter_ip_info_t ipInfo;
|
||||
struct in_addr host;
|
||||
tcpip_adapter_ip_info_t ipInfo = { };
|
||||
tcpip_adapter_if_t ifs[] = { TCPIP_ADAPTER_IF_ETH, TCPIP_ADAPTER_IF_STA, TCPIP_ADAPTER_IF_AP };
|
||||
|
||||
// get various IP info
|
||||
tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &ipInfo);
|
||||
tcpip_adapter_get_hostname(TCPIP_ADAPTER_IF_STA, &hostname);
|
||||
host.s_addr = ipInfo.ip.addr;
|
||||
for (int i = 0; i < sizeof(ifs) / sizeof(tcpip_adapter_if_t); i++)
|
||||
if (tcpip_adapter_get_ip_info(ifs[i], &ipInfo) == ESP_OK && ipInfo.ip.addr != IPADDR_ANY) {
|
||||
tcpip_adapter_get_hostname(ifs[i], &hostname);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!hostname) {
|
||||
LOG_INFO( "no hostname/IP found, can't start AirPlay");
|
||||
return false;
|
||||
}
|
||||
|
||||
// initialize mDNS
|
||||
ESP_ERROR_CHECK( mdns_init() );
|
||||
ESP_ERROR_CHECK( mdns_hostname_set(hostname) );
|
||||
|
||||
char * sink_name_buffer= (char *)config_alloc_get(NVS_TYPE_STR,"airplay_name");
|
||||
if(sink_name_buffer != NULL){
|
||||
if (sink_name_buffer != NULL){
|
||||
memset(sink_name, 0x00, sizeof(sink_name));
|
||||
strncpy(sink_name,sink_name_buffer,sizeof(sink_name)-1 );
|
||||
free(sink_name_buffer);
|
||||
}
|
||||
|
||||
LOG_INFO( "mdns hostname for ip %s set to: [%s] with servicename %s", inet_ntoa(host), hostname, sink_name);
|
||||
LOG_INFO( "mdns hostname for ip %s set to: [%s] with servicename %s", inet_ntoa(ipInfo.ip.addr), hostname, sink_name);
|
||||
|
||||
// create RAOP instance, latency is set by controller
|
||||
uint8_t mac[6];
|
||||
esp_read_mac(mac, ESP_MAC_WIFI_STA);
|
||||
cmd_handler_chain = cmd_cb;
|
||||
raop = raop_create(host, sink_name, mac, 0, cmd_handler, data_cb);
|
||||
raop = raop_create(ipInfo.ip.addr, sink_name, mac, 0, cmd_handler, data_cb);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* Airplay sink timer handler
|
||||
*/
|
||||
static void raop_start_handler( TimerHandle_t xTimer ) {
|
||||
if (raop_sink_start(raop_cbs.cmd, raop_cbs.data)) {
|
||||
xTimerDelete(xTimer, portMAX_DELAY);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* Airplay sink initialization
|
||||
*/
|
||||
void raop_sink_init(raop_cmd_vcb_t cmd_cb, raop_data_cb_t data_cb) {
|
||||
if (!raop_sink_start(cmd_cb, data_cb)) {
|
||||
raop_cbs.cmd = cmd_cb;
|
||||
raop_cbs.data = data_cb;
|
||||
TimerHandle_t timer = xTimerCreate("raopStart", 5000 / portTICK_RATE_MS, pdTRUE, NULL, raop_start_handler);
|
||||
xTimerStart(timer, portMAX_DELAY);
|
||||
LOG_INFO( "Delaying AirPlay start");
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
#define RAOP_SAMPLE_RATE 44100
|
||||
|
||||
typedef enum { RAOP_SETUP, RAOP_STREAM, RAOP_PLAY, RAOP_FLUSH, RAOP_METADATA, RAOP_PROGRESS, RAOP_PAUSE, RAOP_STOP,
|
||||
typedef enum { RAOP_SETUP, RAOP_STREAM, RAOP_PLAY, RAOP_FLUSH, RAOP_METADATA, RAOP_ARTWORK, RAOP_PROGRESS, RAOP_PAUSE, RAOP_STOP,
|
||||
RAOP_VOLUME, RAOP_TIMING, RAOP_PREV, RAOP_NEXT, RAOP_REW, RAOP_FWD,
|
||||
RAOP_VOLUME_UP, RAOP_VOLUME_DOWN, RAOP_RESUME, RAOP_TOGGLE } raop_event_t ;
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -12,6 +12,7 @@ typedef struct {
|
||||
rtp_resp_t rtp_init(struct in_addr host, int latency,
|
||||
char *aeskey, char *aesiv, char *fmtpstr,
|
||||
short unsigned pCtrlPort, short unsigned pTimingPort,
|
||||
uint8_t *buffer, size_t size,
|
||||
raop_cmd_cb_t cmd_cb, raop_data_cb_t data_cb);
|
||||
void rtp_end(struct rtp_s *ctx);
|
||||
bool rtp_flush(struct rtp_s *ctx, unsigned short seqno, unsigned rtptime, bool exit_locked);
|
||||
|
||||
@@ -18,6 +18,11 @@
|
||||
#include "platform.h"
|
||||
#include "pthread.h"
|
||||
|
||||
#ifndef WIN32
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/timers.h"
|
||||
#endif
|
||||
|
||||
#define NFREE(p) if (p) { free(p); p = NULL; }
|
||||
|
||||
typedef struct metadata_s {
|
||||
@@ -46,9 +51,21 @@ char *strndup(const char *s, size_t n);
|
||||
char *strndup(const char *s, size_t n);
|
||||
int asprintf(char **strp, const char *fmt, ...);
|
||||
void winsock_init(void);
|
||||
void winsock_close(void);
|
||||
void winsock_close(void);
|
||||
#define SAFE_PTR_FREE(P) free(P)
|
||||
#else
|
||||
char *strlwr(char *str);
|
||||
|
||||
// reason is that TCB might be cleanup in idle task
|
||||
#define SAFE_PTR_FREE(P) \
|
||||
do { \
|
||||
TimerHandle_t timer = xTimerCreate("cleanup", pdMS_TO_TICKS(10000), pdFALSE, P, _delayed_free); \
|
||||
xTimerStart(timer, portMAX_DELAY); \
|
||||
} while (0)
|
||||
static void inline _delayed_free(TimerHandle_t xTimer) {
|
||||
free(pvTimerGetTimerID(xTimer));
|
||||
xTimerDelete(xTimer, portMAX_DELAY);
|
||||
}
|
||||
#endif
|
||||
|
||||
char* strextract(char *s1, char *beg, char *end);
|
||||
@@ -67,5 +84,6 @@ char* kd_dump(key_data_t *kd);
|
||||
char* http_send(int sock, char *method, key_data_t *rkd);
|
||||
|
||||
char* kd_lookup(key_data_t *kd, char *key);
|
||||
bool kd_add(key_data_t *kd, char *key, char *value);
|
||||
bool kd_add(key_data_t *kd, char *key, char *value);
|
||||
char* kd_dump(key_data_t *kd);
|
||||
void kd_free(key_data_t *kd);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
idf_component_register(SRC_DIRS .
|
||||
INCLUDE_DIRS . ${IDF_PATH}/components/driver
|
||||
REQUIRES json tools platform_config display
|
||||
|
||||
INCLUDE_DIRS . ${IDF_PATH}/components/driver
|
||||
REQUIRES json tools platform_config display
|
||||
PRIV_REQUIRES soc esp32
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -15,33 +15,363 @@
|
||||
#include "accessors.h"
|
||||
#include "globdefs.h"
|
||||
#include "display.h"
|
||||
#include "cJSON.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "stdbool.h"
|
||||
#include "driver/adc.h"
|
||||
#include "esp_attr.h"
|
||||
#include "soc/spi_periph.h"
|
||||
#include "esp_err.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "soc/efuse_periph.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/spi_common_internal.h"
|
||||
#include "esp32/rom/efuse.h"
|
||||
#include "trace.h"
|
||||
#include "monitor.h"
|
||||
#include "messaging.h"
|
||||
|
||||
|
||||
static const char *TAG = "services";
|
||||
static const char *i2c_name="I2C";
|
||||
static const char *spi_name="SPI";
|
||||
|
||||
const char *i2c_name_type="I2C";
|
||||
const char *spi_name_type="SPI";
|
||||
cJSON * gpio_list=NULL;
|
||||
#define min(a,b) (((a) < (b)) ? (a) : (b))
|
||||
#ifndef QUOTE
|
||||
#define QUOTE(name) #name
|
||||
#endif
|
||||
#ifndef STR
|
||||
#define STR(macro) QUOTE(macro)
|
||||
#endif
|
||||
|
||||
bool are_statistics_enabled(){
|
||||
#if defined(CONFIG_FREERTOS_USE_TRACE_FACILITY) && defined (CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS)
|
||||
return true;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
static char * config_spdif_get_string(){
|
||||
return config_alloc_get_str("spdif_config", CONFIG_SPDIF_CONFIG, "bck=" STR(CONFIG_SPDIF_BCK_IO)
|
||||
",ws=" STR(CONFIG_SPDIF_WS_IO) ",do=" STR(CONFIG_SPDIF_DO_IO));
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
static char * get_dac_config_string(){
|
||||
return config_alloc_get_str("dac_config", CONFIG_DAC_CONFIG, "model=i2s,bck=" STR(CONFIG_I2S_BCK_IO)
|
||||
",ws=" STR(CONFIG_I2S_WS_IO) ",do=" STR(CONFIG_I2S_DO_IO)
|
||||
",sda=" STR(CONFIG_I2C_SDA) ",scl=" STR(CONFIG_I2C_SCL)
|
||||
",mute=" STR(CONFIG_MUTE_GPIO));
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
bool is_dac_config_locked(){
|
||||
#if ( defined CONFIG_DAC_CONFIG )
|
||||
if(strlen(CONFIG_DAC_CONFIG) > 0){
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
#if defined(CONFIG_I2S_BCK_IO) && CONFIG_I2S_BCK_IO>0
|
||||
return true;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
bool is_spdif_config_locked(){
|
||||
#if ( defined CONFIG_SPDIF_CONFIG )
|
||||
if(strlen(CONFIG_SPDIF_CONFIG) > 0){
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
#if defined(CONFIG_SPDIF_BCK_IO) && CONFIG_SPDIF_BCK_IO>0
|
||||
return true;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* Set pin from config string
|
||||
*/
|
||||
static void set_i2s_pin(char *config, i2s_pin_config_t *pin_config) {
|
||||
char *p;
|
||||
pin_config->bck_io_num = pin_config->ws_io_num = pin_config->data_out_num = pin_config->data_in_num = -1;
|
||||
if ((p = strcasestr(config, "bck"))) sscanf(p, "bck%*[^=]=%d", &pin_config->bck_io_num);
|
||||
if ((p = strcasestr(config, "ws"))) sscanf(p, "ws%*[^=]=%d", &pin_config->ws_io_num);
|
||||
if ((p = strcasestr(config, "do"))) sscanf(p, "do%*[^=]=%d", &pin_config->data_out_num);
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* Get i2s config structure from config string
|
||||
*/
|
||||
const i2s_platform_config_t * config_i2s_get_from_str(char * dac_config ){
|
||||
static i2s_platform_config_t i2s_dac_pin = {
|
||||
.i2c_addr = -1,
|
||||
.sda= -1,
|
||||
.scl = -1,
|
||||
.mute_gpio = -1,
|
||||
.mute_level = -1
|
||||
};
|
||||
set_i2s_pin(dac_config, &i2s_dac_pin.pin);
|
||||
strcpy(i2s_dac_pin.model, "i2s");
|
||||
char * p=NULL;
|
||||
|
||||
PARSE_PARAM(dac_config, "i2c", '=', i2s_dac_pin.i2c_addr);
|
||||
PARSE_PARAM(dac_config, "sda", '=', i2s_dac_pin.sda);
|
||||
PARSE_PARAM(dac_config, "scl", '=', i2s_dac_pin.scl);
|
||||
PARSE_PARAM_STR(dac_config, "model", '=', i2s_dac_pin.model, 31);
|
||||
if ((p = strcasestr(dac_config, "mute"))) {
|
||||
char mute[8] = "";
|
||||
sscanf(p, "%*[^=]=%7[^,]", mute);
|
||||
i2s_dac_pin.mute_gpio = atoi(mute);
|
||||
PARSE_PARAM(p, "mute", ':', i2s_dac_pin.mute_level);
|
||||
}
|
||||
return &i2s_dac_pin;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* Get spdif config structure
|
||||
*/
|
||||
const i2s_platform_config_t * config_spdif_get( ){
|
||||
char * spdif_config = config_spdif_get_string();
|
||||
static EXT_RAM_ATTR i2s_platform_config_t i2s_dac_config;
|
||||
memcpy(&i2s_dac_config, config_i2s_get_from_str(spdif_config), sizeof(i2s_dac_config));
|
||||
free(spdif_config);
|
||||
return &i2s_dac_config;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* Get dac config structure
|
||||
*/
|
||||
const i2s_platform_config_t * config_dac_get(){
|
||||
char * spdif_config = get_dac_config_string();
|
||||
static EXT_RAM_ATTR i2s_platform_config_t i2s_dac_config;
|
||||
memcpy(&i2s_dac_config, config_i2s_get_from_str(spdif_config), sizeof(i2s_dac_config));
|
||||
free(spdif_config);
|
||||
return &i2s_dac_config;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
esp_err_t config_i2c_set(const i2c_config_t * config, int port){
|
||||
int buffer_size=255;
|
||||
esp_err_t err=ESP_OK;
|
||||
char * config_buffer=calloc(buffer_size,1);
|
||||
if(config_buffer) {
|
||||
snprintf(config_buffer,buffer_size,"scl=%u sda=%u speed=%u port=%u",config->scl_io_num,config->sda_io_num,config->master.clk_speed,port);
|
||||
ESP_LOGI(TAG,"Updating i2c configuration to %s",config_buffer);
|
||||
config_set_value(NVS_TYPE_STR, "i2c_config", config_buffer);
|
||||
snprintf(config_buffer,buffer_size,"scl=%u,sda=%u,speed=%u,port=%u",config->scl_io_num,config->sda_io_num,config->master.clk_speed,port);
|
||||
log_send_messaging(MESSAGING_INFO,"Updating I2C configuration to %s",config_buffer);
|
||||
err = config_set_value(NVS_TYPE_STR, "i2c_config", config_buffer);
|
||||
if(err!=ESP_OK){
|
||||
log_send_messaging(MESSAGING_ERROR,"Error: %s",esp_err_to_name(err));
|
||||
}
|
||||
free(config_buffer);
|
||||
}
|
||||
return ESP_OK;
|
||||
return err;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
esp_err_t config_rotary_set(rotary_struct_t * config){
|
||||
int buffer_size=512;
|
||||
esp_err_t err=ESP_OK;
|
||||
char * config_buffer=calloc(buffer_size,1);
|
||||
char * config_buffer2=calloc(buffer_size,1);
|
||||
if(config_buffer && config_buffer2) {
|
||||
snprintf(config_buffer,buffer_size,"A=%i,B=%i",config->A, config->B);
|
||||
if(config->SW >=0 ){
|
||||
snprintf(config_buffer2,buffer_size,"%s,SW=%i",config_buffer,config->SW);
|
||||
strcpy(config_buffer,config_buffer2);
|
||||
}
|
||||
if(config->knobonly){
|
||||
strncat(config_buffer,",knobonly",buffer_size);
|
||||
if(config->timer>0){
|
||||
snprintf(config_buffer2,buffer_size,"%s=%i",config_buffer,config->timer);
|
||||
strcpy(config_buffer,config_buffer2);
|
||||
}
|
||||
}
|
||||
if(config->volume_lock){
|
||||
strncat(config_buffer,",volume",buffer_size);
|
||||
}
|
||||
if(config->longpress){
|
||||
strncat(config_buffer,",longpress",buffer_size);
|
||||
}
|
||||
log_send_messaging(MESSAGING_INFO,"Updating rotary configuration to %s",config_buffer);
|
||||
err = config_set_value(NVS_TYPE_STR, "rotary_config", config_buffer);
|
||||
if(err!=ESP_OK){
|
||||
log_send_messaging(MESSAGING_ERROR,"Error: %s",esp_err_to_name(err));
|
||||
}
|
||||
}
|
||||
else {
|
||||
err = ESP_ERR_NO_MEM;
|
||||
}
|
||||
FREE_AND_NULL(config_buffer);
|
||||
FREE_AND_NULL(config_buffer2);
|
||||
return err;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
esp_err_t config_display_set(const display_config_t * config){
|
||||
int buffer_size=512;
|
||||
esp_err_t err=ESP_OK;
|
||||
char * config_buffer=calloc(buffer_size,1);
|
||||
char * config_buffer2=calloc(buffer_size,1);
|
||||
if(config_buffer && config_buffer2) {
|
||||
snprintf(config_buffer,buffer_size,"%s,width=%i,height=%i",config->type,config->width,config->height);
|
||||
if(strcasecmp("I2C",config->type)==0){
|
||||
if(config->address>0 ){
|
||||
snprintf(config_buffer2,buffer_size,"%s,address=%i",config_buffer,config->address);
|
||||
strcpy(config_buffer,config_buffer2);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(config->CS_pin >=0 ){
|
||||
snprintf(config_buffer2,buffer_size,"%s,cs=%i",config_buffer,config->CS_pin);
|
||||
strcpy(config_buffer,config_buffer2);
|
||||
}
|
||||
}
|
||||
if(config->RST_pin >=0 ){
|
||||
snprintf(config_buffer2,buffer_size,"%s,reset=%i",config_buffer,config->RST_pin);
|
||||
strcpy(config_buffer,config_buffer2);
|
||||
}
|
||||
// I2C,width=<pixels>,height=<pixels>[address=<i2c_address>][,reset=<gpio>][,HFlip][,VFlip][driver=SSD1306|SSD1326[:1|4]|SSD1327|SH1106]
|
||||
// SPI,width=<pixels>,height=<pixels>,cs=<gpio>[,back=<gpio>][,reset=<gpio>][,speed=<speed>][,HFlip][,VFlip][driver=SSD1306|SSD1322|SSD1326[:1|4]|SSD1327|SH1106|SSD1675|ST7735|ST7789[,rotate]]
|
||||
if(config->back >=0 ){
|
||||
snprintf(config_buffer2,buffer_size,"%s,back=%i",config_buffer,config->back);
|
||||
strcpy(config_buffer,config_buffer2);
|
||||
}
|
||||
if(config->speed >0 && strcasecmp("SPI",config->type)==0){
|
||||
snprintf(config_buffer2,buffer_size,"%s,speed=%i",config_buffer,config->speed);
|
||||
strcpy(config_buffer,config_buffer2);
|
||||
}
|
||||
snprintf(config_buffer2,buffer_size,"%s,driver=%s%s%s%s",config_buffer,config->drivername,config->hflip?",HFlip":"",config->vflip?",VFlip":"",config->rotate?",rotate":"");
|
||||
strcpy(config_buffer,config_buffer2);
|
||||
log_send_messaging(MESSAGING_INFO,"Updating display configuration to %s",config_buffer);
|
||||
err = config_set_value(NVS_TYPE_STR, "display_config", config_buffer);
|
||||
if(err!=ESP_OK){
|
||||
log_send_messaging(MESSAGING_ERROR,"Error: %s",esp_err_to_name(err));
|
||||
}
|
||||
}
|
||||
else {
|
||||
err = ESP_ERR_NO_MEM;
|
||||
}
|
||||
FREE_AND_NULL(config_buffer);
|
||||
FREE_AND_NULL(config_buffer2);
|
||||
return err;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
esp_err_t config_i2s_set(const i2s_platform_config_t * config, const char * nvs_name){
|
||||
int buffer_size=255;
|
||||
esp_err_t err=ESP_OK;
|
||||
char * config_buffer=calloc(buffer_size,1);
|
||||
char * config_buffer2=calloc(buffer_size,1);
|
||||
if(config_buffer && config_buffer2) {
|
||||
snprintf(config_buffer,buffer_size,"model=%s,bck=%u,ws=%u,do=%u",config->model,config->pin.bck_io_num,config->pin.ws_io_num,config->pin.data_out_num);
|
||||
if(config->mute_gpio>=0){
|
||||
snprintf(config_buffer2,buffer_size,"%s,mute=%u:%u",config_buffer,config->mute_gpio,config->mute_level);
|
||||
strcpy(config_buffer,config_buffer2);
|
||||
}
|
||||
if(config->sda>=0){
|
||||
snprintf(config_buffer2,buffer_size,"%s,sda=%u,scl=%u",config_buffer,config->sda,config->scl);
|
||||
strcpy(config_buffer,config_buffer2);
|
||||
}
|
||||
if(config->i2c_addr>0){
|
||||
snprintf(config_buffer2,buffer_size,"%s,i2c=%u",config_buffer,config->i2c_addr);
|
||||
strcpy(config_buffer,config_buffer2);
|
||||
}
|
||||
log_send_messaging(MESSAGING_INFO,"Updating dac configuration to %s",config_buffer);
|
||||
err = config_set_value(NVS_TYPE_STR, nvs_name, config_buffer);
|
||||
if(err!=ESP_OK){
|
||||
log_send_messaging(MESSAGING_ERROR,"Error: %s",esp_err_to_name(err));
|
||||
}
|
||||
}
|
||||
else {
|
||||
err = ESP_ERR_NO_MEM;
|
||||
}
|
||||
FREE_AND_NULL(config_buffer);
|
||||
FREE_AND_NULL(config_buffer2);
|
||||
return err;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
esp_err_t config_spdif_set(const i2s_platform_config_t * config){
|
||||
int buffer_size=255;
|
||||
esp_err_t err=ESP_OK;
|
||||
char * config_buffer=calloc(buffer_size,1);
|
||||
if(config_buffer ) {
|
||||
snprintf(config_buffer,buffer_size,"bck=%u,ws=%u,do=%u",config->pin.bck_io_num,config->pin.ws_io_num,config->pin.data_out_num);
|
||||
log_send_messaging(MESSAGING_INFO,"Updating SPDIF configuration to %s",config_buffer);
|
||||
err = config_set_value(NVS_TYPE_STR, "spdif_config", config_buffer);
|
||||
if(err!=ESP_OK){
|
||||
log_send_messaging(MESSAGING_ERROR,"Error: %s",esp_err_to_name(err));
|
||||
}
|
||||
}
|
||||
else {
|
||||
err = ESP_ERR_NO_MEM;
|
||||
}
|
||||
FREE_AND_NULL(config_buffer);
|
||||
return err;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
esp_err_t config_spi_set(const spi_bus_config_t * config, int host, int dc){
|
||||
int buffer_size=255;
|
||||
esp_err_t err = ESP_OK;
|
||||
char * config_buffer=calloc(buffer_size,1);
|
||||
if(config_buffer) {
|
||||
snprintf(config_buffer,buffer_size,"data=%u,clk=%u,dc=%u,host=%u,miso=%d",config->mosi_io_num,config->sclk_io_num,dc,host,config->miso_io_num);
|
||||
log_send_messaging(MESSAGING_INFO,"Updating SPI configuration to %s",config_buffer);
|
||||
err = config_set_value(NVS_TYPE_STR, "spi_config", config_buffer);
|
||||
if(err!=ESP_OK){
|
||||
log_send_messaging(MESSAGING_ERROR,"Error: %s",esp_err_to_name(err));
|
||||
}
|
||||
free(config_buffer);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
const display_config_t * config_display_get(){
|
||||
static display_config_t dstruct;
|
||||
static display_config_t dstruct = {
|
||||
.back = -1,
|
||||
.CS_pin = -1,
|
||||
.RST_pin = -1,
|
||||
.depth = -1,
|
||||
.address = 0,
|
||||
.drivername = NULL,
|
||||
.height = 0,
|
||||
.width = 0,
|
||||
.vflip = false,
|
||||
.hflip = false,
|
||||
.type = NULL,
|
||||
.speed = 0,
|
||||
.rotate = false,
|
||||
.invert = false,
|
||||
.colorswap = 0,
|
||||
};
|
||||
char *config = config_alloc_get(NVS_TYPE_STR, "display_config");
|
||||
if (!config) {
|
||||
return NULL;
|
||||
@@ -50,22 +380,26 @@ const display_config_t * config_display_get(){
|
||||
char * p=NULL;
|
||||
|
||||
if ((p = strcasestr(config, "driver")) != NULL){
|
||||
sscanf(p, "%*[^:]:%u", &dstruct.depth);
|
||||
dstruct.drivername = display_conf_get_driver_name(strchr(p, '=') + 1);
|
||||
}
|
||||
|
||||
dstruct.drivername=dstruct.drivername?dstruct.drivername:"SSD1306";
|
||||
if ((p = strcasestr(config, "width")) != NULL) dstruct.width = atoi(strchr(p, '=') + 1);
|
||||
if ((p = strcasestr(config, "height")) != NULL) dstruct.height = atoi(strchr(p, '=') + 1);
|
||||
if ((p = strcasestr(config, "reset")) != NULL) dstruct.RST_pin = atoi(strchr(p, '=') + 1);
|
||||
dstruct.i2c_system_port=i2c_system_port;
|
||||
if (strstr(config, "I2C") ) dstruct.type=i2c_name;
|
||||
if ((p = strcasestr(config, "address")) != NULL) dstruct.address = atoi(strchr(p, '=') + 1);
|
||||
if (strstr(config, "SPI") ) dstruct.type=spi_name;
|
||||
if ((p = strcasestr(config, "cs")) != NULL) dstruct.CS_pin = atoi(strchr(p, '=') + 1);
|
||||
if ((p = strcasestr(config, "speed")) != NULL) dstruct.speed = atoi(strchr(p, '=') + 1);
|
||||
PARSE_PARAM(config, "width", '=', dstruct.width);
|
||||
PARSE_PARAM(config, "height", '=', dstruct.height);
|
||||
PARSE_PARAM(config, "reset", '=', dstruct.RST_pin);
|
||||
PARSE_PARAM(config, "address", '=', dstruct.address);
|
||||
PARSE_PARAM(config, "cs", '=', dstruct.CS_pin);
|
||||
PARSE_PARAM(config, "speed", '=', dstruct.speed);
|
||||
PARSE_PARAM(config, "back", '=', dstruct.back);
|
||||
|
||||
if (strstr(config, "I2C") ) dstruct.type=i2c_name_type;
|
||||
if (strstr(config, "SPI") ) dstruct.type=spi_name_type;
|
||||
|
||||
dstruct.hflip= strcasestr(config, "HFlip") ? true : false;
|
||||
dstruct.vflip= strcasestr(config, "VFlip") ? true : false;
|
||||
dstruct.rotate= strcasestr(config, "rotate") ? true : false;
|
||||
dstruct.invert= strcasestr(config, "invert") ? true : false;
|
||||
dstruct.colorswap= strcasestr(config, "cswap") ? 1 : 0;
|
||||
return &dstruct;
|
||||
}
|
||||
|
||||
@@ -73,7 +407,7 @@ const display_config_t * config_display_get(){
|
||||
*
|
||||
*/
|
||||
const i2c_config_t * config_i2c_get(int * i2c_port) {
|
||||
char *nvs_item, *p;
|
||||
char *nvs_item;
|
||||
static i2c_config_t i2c = {
|
||||
.mode = I2C_MODE_MASTER,
|
||||
.sda_io_num = -1,
|
||||
@@ -87,21 +421,141 @@ const i2c_config_t * config_i2c_get(int * i2c_port) {
|
||||
|
||||
nvs_item = config_alloc_get(NVS_TYPE_STR, "i2c_config");
|
||||
if (nvs_item) {
|
||||
if ((p = strcasestr(nvs_item, "scl")) != NULL) i2c.scl_io_num = atoi(strchr(p, '=') + 1);
|
||||
if ((p = strcasestr(nvs_item, "sda")) != NULL) i2c.sda_io_num = atoi(strchr(p, '=') + 1);
|
||||
if ((p = strcasestr(nvs_item, "speed")) != NULL) i2c.master.clk_speed = atoi(strchr(p, '=') + 1);
|
||||
if ((p = strcasestr(nvs_item, "port")) != NULL) i2c_system_port = atoi(strchr(p, '=') + 1);
|
||||
PARSE_PARAM(nvs_item, "scl", '=', i2c.scl_io_num);
|
||||
PARSE_PARAM(nvs_item, "sda", '=', i2c.sda_io_num);
|
||||
PARSE_PARAM(nvs_item, "speed", '=', i2c.master.clk_speed);
|
||||
PARSE_PARAM(nvs_item, "port", '=', i2c_system_port);
|
||||
free(nvs_item);
|
||||
}
|
||||
if(i2c_port) *i2c_port=i2c_system_port;
|
||||
if(i2c_port) {
|
||||
#ifdef CONFIG_I2C_LOCKED
|
||||
*i2c_port= I2C_NUM_1;
|
||||
#else
|
||||
*i2c_port=i2c_system_port;
|
||||
#endif
|
||||
}
|
||||
return &i2c;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* Get IO expander config structure from config string
|
||||
*/
|
||||
const gpio_exp_config_t* config_gpio_exp_get(int index) {
|
||||
char *nvs_item, *item, *p;
|
||||
static gpio_exp_config_t config;
|
||||
|
||||
// re-initialize config every time
|
||||
memset(&config, 0, sizeof(config));
|
||||
config.intr = -1; config.count = 16; config.base = GPIO_NUM_MAX; config.phy.port = i2c_system_port; config.phy.host = spi_system_host;
|
||||
|
||||
nvs_item = config_alloc_get(NVS_TYPE_STR, "gpio_exp_config");
|
||||
if (!nvs_item || !*nvs_item) return NULL;
|
||||
|
||||
// search index items
|
||||
for (item = strtok(nvs_item, ";"); index && item; index--) {
|
||||
if ((item = strtok(NULL, ";")) == NULL) {
|
||||
free(nvs_item);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
PARSE_PARAM(item, "addr", '=', config.phy.addr);
|
||||
PARSE_PARAM(item, "cs", '=', config.phy.cs_pin);
|
||||
PARSE_PARAM(item, "speed", '=', config.phy.speed);
|
||||
PARSE_PARAM(item, "intr", '=', config.intr);
|
||||
PARSE_PARAM(item, "base", '=', config.base);
|
||||
PARSE_PARAM(item, "count", '=', config.count);
|
||||
PARSE_PARAM_STR(item, "model", '=', config.model, 31);
|
||||
|
||||
if ((p = strcasestr(item, "port")) != NULL) {
|
||||
char port[8] = "";
|
||||
sscanf(p, "%*[^=]=%7[^,]", port);
|
||||
if (strcasestr(port, "dac")) config.phy.port = 0;
|
||||
}
|
||||
|
||||
free(nvs_item);
|
||||
return &config;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
const gpio_with_level_t * get_gpio_struct_member(const char * nvs_item, const char * name){
|
||||
static gpio_with_level_t gpio_member={
|
||||
.gpio=-1,
|
||||
.level=0
|
||||
};
|
||||
if(!nvs_item) return &gpio_member;
|
||||
const char * p=nvs_item;
|
||||
char type[20]={0};
|
||||
int match=0;
|
||||
do {
|
||||
if ((match=sscanf(p, "%d=%19[^,:]:%d", &gpio_member.gpio, type,&gpio_member.level)) >0 && (GPIO_IS_VALID_GPIO(gpio_member.gpio) || gpio_member.gpio==GPIO_NUM_NC) && strcasestr(type,name)){
|
||||
return &gpio_member;
|
||||
}
|
||||
p = strchr(p, ',');
|
||||
} while (p++);
|
||||
gpio_member.gpio=-1;
|
||||
gpio_member.level=0;
|
||||
return &gpio_member;
|
||||
}
|
||||
|
||||
#define HANDLE_GPIO_STRUCT_MEMBER(name,fixval) memcpy(&gpio_struct.name, get_gpio_struct_member(nvs_item, QUOTE(name)), sizeof(gpio_struct.name)); gpio_struct.name.fixed=fixval
|
||||
#define ADD_GPIO_STRUCT_MEMBER_TO_ARRAY(array,structvar,name,type) if(((set_GPIO_struct_t *)structvar)->name.gpio>=0){cJSON_AddItemToArray(array,get_gpio_entry(QUOTE(name),type,((set_GPIO_struct_t *)structvar)->name.gpio, ((set_GPIO_struct_t *)structvar)->name.fixed));}
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
const set_GPIO_struct_t * get_gpio_struct(){
|
||||
static set_GPIO_struct_t gpio_struct;
|
||||
char * nvs_item=config_alloc_get(NVS_TYPE_STR, "set_GPIO");
|
||||
#ifdef CONFIG_LED_GREEN_GPIO_LEVEL
|
||||
gpio_struct.green.level = CONFIG_LED_GREEN_GPIO_LEVEL;
|
||||
#endif
|
||||
#ifdef CONFIG_LED_GREEN_GPIO
|
||||
gpio_struct.green.gpio = CONFIG_LED_GREEN_GPIO;
|
||||
#endif
|
||||
#ifdef CONFIG_LED_RED_GPIO_LEVEL
|
||||
gpio_struct.green.level = CONFIG_LED_RED_GPIO_LEVEL;
|
||||
#endif
|
||||
#ifdef CONFIG_LED_RED_GPIO
|
||||
gpio_struct.red.gpio = CONFIG_LED_RED_GPIO;
|
||||
#endif
|
||||
if(nvs_item){
|
||||
HANDLE_GPIO_STRUCT_MEMBER(amp,false);
|
||||
#ifndef CONFIG_LED_LOCKED
|
||||
HANDLE_GPIO_STRUCT_MEMBER(green,false);
|
||||
HANDLE_GPIO_STRUCT_MEMBER(red,false);
|
||||
#endif
|
||||
HANDLE_GPIO_STRUCT_MEMBER(jack,false);
|
||||
HANDLE_GPIO_STRUCT_MEMBER(spkfault,false);
|
||||
HANDLE_GPIO_STRUCT_MEMBER(vcc,false);
|
||||
HANDLE_GPIO_STRUCT_MEMBER(gnd,false);
|
||||
HANDLE_GPIO_STRUCT_MEMBER(ir,false);
|
||||
free(nvs_item);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_LED_LOCKED
|
||||
gpio_struct.red.fixed=true;
|
||||
gpio_struct.green.fixed=true;
|
||||
#endif
|
||||
#ifdef CONFIG_JACK_LOCKED
|
||||
gpio_struct.jack.gpio=CONFIG_JACK_GPIO;
|
||||
gpio_struct.jack.fixed=true;
|
||||
gpio_struct.jack.level=CONFIG_JACK_GPIO_LEVEL;
|
||||
#endif
|
||||
#ifdef CONFIG_SPKFAULT_LOCKED
|
||||
gpio_struct.spkfault.gpio=CONFIG_SPKFAULT_GPIO;
|
||||
gpio_struct.spkfault.fixed=true;
|
||||
gpio_struct.spkfault.level=CONFIG_SPKFAULT_GPIO_LEVEL;
|
||||
#endif
|
||||
return &gpio_struct;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
const spi_bus_config_t * config_spi_get(spi_host_device_t * spi_host) {
|
||||
char *nvs_item, *p;
|
||||
char *nvs_item;
|
||||
static spi_bus_config_t spi = {
|
||||
.mosi_io_num = -1,
|
||||
.sclk_io_num = -1,
|
||||
@@ -112,10 +566,13 @@ const spi_bus_config_t * config_spi_get(spi_host_device_t * spi_host) {
|
||||
|
||||
nvs_item = config_alloc_get_str("spi_config", CONFIG_SPI_CONFIG, NULL);
|
||||
if (nvs_item) {
|
||||
if ((p = strcasestr(nvs_item, "data")) != NULL) spi.mosi_io_num = atoi(strchr(p, '=') + 1);
|
||||
if ((p = strcasestr(nvs_item, "clk")) != NULL) spi.sclk_io_num = atoi(strchr(p, '=') + 1);
|
||||
if ((p = strcasestr(nvs_item, "dc")) != NULL) spi_system_dc_gpio = atoi(strchr(p, '=') + 1);
|
||||
if ((p = strcasestr(nvs_item, "host")) != NULL) spi_system_host = atoi(strchr(p, '=') + 1);
|
||||
PARSE_PARAM(nvs_item, "data", '=', spi.mosi_io_num);
|
||||
PARSE_PARAM(nvs_item, "mosi", '=', spi.mosi_io_num);
|
||||
PARSE_PARAM(nvs_item, "miso", '=', spi.miso_io_num);
|
||||
PARSE_PARAM(nvs_item, "clk", '=', spi.sclk_io_num);
|
||||
PARSE_PARAM(nvs_item, "dc", '=', spi_system_dc_gpio);
|
||||
// only VSPI (1) can be used as Flash and PSRAM run at 80MHz
|
||||
// if ((p = strcasestr(nvs_item, "host")) != NULL) spi_system_host = atoi(strchr(p, '=') + 1);
|
||||
free(nvs_item);
|
||||
}
|
||||
if(spi_host) *spi_host = spi_system_host;
|
||||
@@ -140,3 +597,406 @@ void parse_set_GPIO(void (*cb)(int gpio, char *value)) {
|
||||
|
||||
free(nvs_item);
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
const rotary_struct_t * config_rotary_get() {
|
||||
|
||||
static rotary_struct_t rotary={ .A = -1, .B = -1, .SW = -1, .longpress = false, .knobonly=false,.timer=0,.volume_lock=false};
|
||||
char *config = config_alloc_get_default(NVS_TYPE_STR, "rotary_config", NULL, 0);
|
||||
if (config && *config) {
|
||||
char *p;
|
||||
|
||||
// parse config
|
||||
PARSE_PARAM(config, "A", '=', rotary.A);
|
||||
PARSE_PARAM(config, "B", '=', rotary.B);
|
||||
PARSE_PARAM(config, "SW", '=', rotary.SW);
|
||||
if ((p = strcasestr(config, "knobonly")) != NULL) {
|
||||
p = strchr(p, '=');
|
||||
rotary.knobonly = true;
|
||||
rotary.timer = p ? atoi(p + 1) : 350;
|
||||
rotary.longpress = false;
|
||||
} else {
|
||||
rotary.knobonly = false;
|
||||
rotary.timer = 0;
|
||||
if ((p = strcasestr(config, "volume")) != NULL) rotary.volume_lock = true;
|
||||
if ((p = strcasestr(config, "longpress")) != NULL) rotary.longpress = true;
|
||||
}
|
||||
free(config);
|
||||
}
|
||||
return &rotary;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
cJSON * get_gpio_entry(const char * name, const char * prefix, int gpio, bool fixed){
|
||||
cJSON * entry = cJSON_CreateObject();
|
||||
cJSON_AddNumberToObject(entry,"gpio",gpio);
|
||||
cJSON_AddStringToObject(entry,"name",name);
|
||||
cJSON_AddStringToObject(entry,"group",prefix);
|
||||
cJSON_AddBoolToObject(entry,"fixed",fixed);
|
||||
return entry;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
cJSON * add_gpio_for_value(cJSON * list,const char * name,int gpio, const char * prefix, bool fixed){
|
||||
cJSON * llist = list?list:cJSON_CreateArray();
|
||||
if(GPIO_IS_VALID_GPIO(gpio) && gpio>0){
|
||||
cJSON_AddItemToArray(llist,get_gpio_entry(name,prefix,gpio,fixed));
|
||||
}
|
||||
return llist;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
cJSON * add_gpio_for_name(cJSON * list,const char * nvs_entry,const char * name, const char * prefix, bool fixed){
|
||||
cJSON * llist = list?list:cJSON_CreateArray();
|
||||
int gpioNum=0;
|
||||
PARSE_PARAM(nvs_entry, name, '=', gpioNum);
|
||||
if(gpioNum>=0){
|
||||
cJSON_AddItemToArray(llist,get_gpio_entry(name,prefix,gpioNum,fixed));
|
||||
}
|
||||
return llist;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
cJSON * get_GPIO_nvs_list(cJSON * list) {
|
||||
cJSON * ilist = list?list:cJSON_CreateArray();
|
||||
const set_GPIO_struct_t * gpios = get_gpio_struct();
|
||||
ADD_GPIO_STRUCT_MEMBER_TO_ARRAY(ilist,gpios,vcc,"other");
|
||||
ADD_GPIO_STRUCT_MEMBER_TO_ARRAY(ilist,gpios,gnd,"other");
|
||||
ADD_GPIO_STRUCT_MEMBER_TO_ARRAY(ilist,gpios,amp,"other");
|
||||
ADD_GPIO_STRUCT_MEMBER_TO_ARRAY(ilist,gpios,ir,"other");
|
||||
ADD_GPIO_STRUCT_MEMBER_TO_ARRAY(ilist,gpios,jack,"other");
|
||||
ADD_GPIO_STRUCT_MEMBER_TO_ARRAY(ilist,gpios,green,"other");
|
||||
ADD_GPIO_STRUCT_MEMBER_TO_ARRAY(ilist,gpios,red,"other");
|
||||
ADD_GPIO_STRUCT_MEMBER_TO_ARRAY(ilist,gpios,spkfault,"other");
|
||||
return ilist;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
cJSON * get_DAC_GPIO(cJSON * list){
|
||||
cJSON * llist = list;
|
||||
if(!llist){
|
||||
llist = cJSON_CreateArray();
|
||||
}
|
||||
const i2s_platform_config_t * i2s_config= config_dac_get();
|
||||
if(i2s_config->pin.bck_io_num>=0){
|
||||
cJSON_AddItemToArray(llist,get_gpio_entry("bck","dac",i2s_config->pin.bck_io_num,is_dac_config_locked()));
|
||||
cJSON_AddItemToArray(llist,get_gpio_entry("ws","dac",i2s_config->pin.ws_io_num,is_dac_config_locked()));
|
||||
cJSON_AddItemToArray(llist,get_gpio_entry("do","dac",i2s_config->pin.data_out_num,is_dac_config_locked()));
|
||||
if(i2s_config->sda>=0){
|
||||
cJSON_AddItemToArray(llist,get_gpio_entry("sda","dac",i2s_config->sda,is_dac_config_locked()));
|
||||
cJSON_AddItemToArray(llist,get_gpio_entry("scl","dac",i2s_config->scl,is_dac_config_locked()));
|
||||
}
|
||||
if(i2s_config->mute_gpio>=0){
|
||||
cJSON_AddItemToArray(llist,get_gpio_entry("mute","dac",i2s_config->mute_gpio,is_dac_config_locked()));
|
||||
}
|
||||
}
|
||||
return llist;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
cJSON * get_Display_GPIO(cJSON * list){
|
||||
cJSON * llist = list;
|
||||
if(!llist){
|
||||
llist = cJSON_CreateArray();
|
||||
}
|
||||
const display_config_t * config= config_display_get();
|
||||
if(config->back >=0){
|
||||
cJSON_AddItemToArray(llist,get_gpio_entry("backlight","display",config->back,false));
|
||||
}
|
||||
if(config->CS_pin >=0){
|
||||
cJSON_AddItemToArray(llist,get_gpio_entry("CS","display",config->CS_pin,false));
|
||||
}
|
||||
if(config->RST_pin >=0){
|
||||
cJSON_AddItemToArray(llist,get_gpio_entry("reset","display",config->RST_pin,false));
|
||||
}
|
||||
return llist;
|
||||
}
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
cJSON * get_I2C_GPIO(cJSON * list){
|
||||
cJSON * llist = list;
|
||||
if(!llist){
|
||||
llist = cJSON_CreateArray();
|
||||
}
|
||||
int port=0;
|
||||
const i2c_config_t * i2c_config = config_i2c_get(&port);
|
||||
if(i2c_config->scl_io_num>=0){
|
||||
cJSON_AddItemToArray(llist,get_gpio_entry("scl","i2c",i2c_config->scl_io_num,false));
|
||||
cJSON_AddItemToArray(llist,get_gpio_entry("sda","i2c",i2c_config->sda_io_num,false));
|
||||
}
|
||||
return llist;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
cJSON * get_SPI_GPIO(cJSON * list){
|
||||
cJSON * llist = list;
|
||||
if(!llist){
|
||||
llist = cJSON_CreateArray();
|
||||
}
|
||||
spi_host_device_t spi_host;
|
||||
const spi_bus_config_t * spi_config = config_spi_get(&spi_host);
|
||||
|
||||
if(spi_config->miso_io_num>=0){
|
||||
cJSON_AddItemToArray(llist,get_gpio_entry("data","spi",spi_config->miso_io_num,false));
|
||||
cJSON_AddItemToArray(llist,get_gpio_entry("data","clk",spi_config->sclk_io_num,false));
|
||||
}
|
||||
if(spi_system_dc_gpio>0){
|
||||
cJSON_AddItemToArray(llist,get_gpio_entry("data","dc",spi_system_dc_gpio,false));
|
||||
}
|
||||
return llist;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
cJSON * get_SPDIF_GPIO(cJSON * list, bool fixed){
|
||||
cJSON * llist = list?list:cJSON_CreateArray();
|
||||
char * spdif_config = config_spdif_get_string();
|
||||
if(spdif_config){
|
||||
llist = add_gpio_for_name(llist,spdif_config,"bck", "spdif", fixed);
|
||||
llist = add_gpio_for_name(llist,spdif_config,"ws", "spdif", fixed);
|
||||
llist = add_gpio_for_name(llist,spdif_config,"do", "spdif", fixed);
|
||||
free(spdif_config);
|
||||
}
|
||||
return llist;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
cJSON * get_Rotary_GPIO(cJSON * list){
|
||||
cJSON * llist = list?list:cJSON_CreateArray();
|
||||
|
||||
const rotary_struct_t *rotary= config_rotary_get();
|
||||
add_gpio_for_value(llist,"A",rotary->A, "rotary", false);
|
||||
add_gpio_for_value(llist,"B",rotary->B, "rotary", false);
|
||||
add_gpio_for_value(llist,"SW",rotary->SW, "rotary", false);
|
||||
return llist;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
esp_err_t get_gpio_structure(cJSON * gpio_entry, gpio_entry_t ** gpio){
|
||||
esp_err_t err = ESP_OK;
|
||||
*gpio = malloc(sizeof(gpio_entry_t));
|
||||
cJSON * val = cJSON_GetObjectItem(gpio_entry,"gpio");
|
||||
if(val){
|
||||
(*gpio)->gpio= (int)val->valuedouble;
|
||||
} else {
|
||||
ESP_LOGE(TAG,"gpio pin not found");
|
||||
err=ESP_FAIL;
|
||||
}
|
||||
val = cJSON_GetObjectItem(gpio_entry,"name");
|
||||
if(val){
|
||||
(*gpio)->name= strdup(cJSON_GetStringValue(val));
|
||||
} else {
|
||||
ESP_LOGE(TAG,"gpio name value not found");
|
||||
err=ESP_FAIL;
|
||||
}
|
||||
val = cJSON_GetObjectItem(gpio_entry,"group");
|
||||
if(val){
|
||||
(*gpio)->group= strdup(cJSON_GetStringValue(val));
|
||||
} else {
|
||||
ESP_LOGE(TAG,"gpio group value not found");
|
||||
err=ESP_FAIL;
|
||||
}
|
||||
val = cJSON_GetObjectItem(gpio_entry,"fixed");
|
||||
if(val){
|
||||
(*gpio)->fixed= cJSON_IsTrue(val);
|
||||
} else {
|
||||
ESP_LOGE(TAG,"gpio fixed indicator not found");
|
||||
err=ESP_FAIL;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
esp_err_t free_gpio_entry( gpio_entry_t ** gpio) {
|
||||
if(* gpio){
|
||||
free((* gpio)->name);
|
||||
free((* gpio)->group);
|
||||
free(* gpio);
|
||||
* gpio=NULL;
|
||||
return ESP_OK;
|
||||
}
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
gpio_entry_t * get_gpio_by_no(int gpionum, bool refresh){
|
||||
cJSON * gpio_header=NULL;
|
||||
gpio_entry_t * gpio=NULL;
|
||||
get_gpio_list(refresh);
|
||||
cJSON_ArrayForEach(gpio_header,gpio_list)
|
||||
{
|
||||
if(get_gpio_structure(gpio_header, &gpio)==ESP_OK && gpio->gpio==gpionum){
|
||||
ESP_LOGD(TAG,"Found GPIO: %s=%d %s", gpio->name,gpio->gpio,gpio->fixed?"(FIXED)":"(VARIABLE)");
|
||||
}
|
||||
}
|
||||
return gpio;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
gpio_entry_t * get_gpio_by_name(char * name,char * group, bool refresh){
|
||||
cJSON * gpio_header=NULL;
|
||||
gpio_entry_t * gpio=NULL;
|
||||
get_gpio_list(refresh);
|
||||
cJSON_ArrayForEach(gpio_header,gpio_list)
|
||||
{
|
||||
if(get_gpio_structure(gpio_header, &gpio)==ESP_OK && strcasecmp(gpio->name,name)&& strcasecmp(gpio->group,group)){
|
||||
ESP_LOGD(TAG,"Found GPIO: %s=%d %s", gpio->name,gpio->gpio,gpio->fixed?"(FIXED)":"(VARIABLE)");
|
||||
}
|
||||
}
|
||||
return gpio;
|
||||
}
|
||||
|
||||
#ifndef PICO_PSRAM_CLK_IO
|
||||
#define PICO_PSRAM_CLK_IO 6
|
||||
#endif
|
||||
#ifndef PSRAM_SPIQ_SD0_IO
|
||||
#define PSRAM_SPIQ_SD0_IO 7
|
||||
#define PSRAM_SPID_SD1_IO 8
|
||||
#define PSRAM_SPIWP_SD3_IO 10
|
||||
#define PSRAM_SPIHD_SD2_IO 9
|
||||
#define FLASH_HSPI_CLK_IO 14
|
||||
#define FLASH_HSPI_CS_IO 15
|
||||
#define PSRAM_HSPI_SPIQ_SD0_IO 12
|
||||
#define PSRAM_HSPI_SPID_SD1_IO 13
|
||||
#define PSRAM_HSPI_SPIWP_SD3_IO 2
|
||||
#define PSRAM_HSPI_SPIHD_SD2_IO 4
|
||||
#endif
|
||||
|
||||
|
||||
cJSON * get_psram_gpio_list(cJSON * list){
|
||||
const char * psram_dev = "psram";
|
||||
const char * flash_dev = "flash";
|
||||
const char * clk = "clk";
|
||||
const char * cs = "cs";
|
||||
const char * spiq_sd0_io="spiq_sd0_io";
|
||||
const char * spid_sd1_io = "spid_sd1_io";
|
||||
const char * spiwp_sd3_io = "spiwp_sd3_io";
|
||||
const char * spihd_sd2_io = "spihd_sd2_io";
|
||||
cJSON * llist=list;
|
||||
|
||||
uint32_t chip_ver = REG_GET_FIELD(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_VER_PKG);
|
||||
uint32_t pkg_ver = chip_ver & 0x7;
|
||||
if (pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32D2WDQ5) {
|
||||
rtc_vddsdio_config_t cfg = rtc_vddsdio_get_config();
|
||||
if (cfg.tieh != RTC_VDDSDIO_TIEH_1_8V) {
|
||||
return llist;
|
||||
}
|
||||
cJSON_AddItemToArray(list,get_gpio_entry(clk,psram_dev,CONFIG_D2WD_PSRAM_CLK_IO,true));
|
||||
cJSON_AddItemToArray(list,get_gpio_entry(cs,psram_dev,CONFIG_D2WD_PSRAM_CS_IO,true));
|
||||
} else if ((pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32PICOD2) || (pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32PICOD4)) {
|
||||
rtc_vddsdio_config_t cfg = rtc_vddsdio_get_config();
|
||||
if (cfg.tieh != RTC_VDDSDIO_TIEH_3_3V) {
|
||||
return llist;
|
||||
}
|
||||
cJSON_AddItemToArray(list,get_gpio_entry(clk,psram_dev,PICO_PSRAM_CLK_IO,true));
|
||||
cJSON_AddItemToArray(list,get_gpio_entry(cs,psram_dev,CONFIG_PICO_PSRAM_CS_IO,true));
|
||||
} else if ((pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32D0WDQ6) || (pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32D0WDQ5)){
|
||||
cJSON_AddItemToArray(list,get_gpio_entry(clk,psram_dev,CONFIG_D0WD_PSRAM_CLK_IO,true));
|
||||
cJSON_AddItemToArray(list,get_gpio_entry(cs,psram_dev,CONFIG_D0WD_PSRAM_CS_IO,true));
|
||||
} else {
|
||||
ESP_LOGW(TAG, "Cant' determine GPIOs for PSRAM chip id: %d", pkg_ver);
|
||||
cJSON_AddItemToArray(list,get_gpio_entry(clk,psram_dev,-1,true));
|
||||
cJSON_AddItemToArray(list,get_gpio_entry(cs,psram_dev,-1,true));
|
||||
}
|
||||
|
||||
const uint32_t spiconfig = ets_efuse_get_spiconfig();
|
||||
if (spiconfig == EFUSE_SPICONFIG_SPI_DEFAULTS) {
|
||||
cJSON_AddItemToArray(list,get_gpio_entry(spiq_sd0_io,psram_dev,PSRAM_SPIQ_SD0_IO,true));
|
||||
cJSON_AddItemToArray(list,get_gpio_entry(spid_sd1_io,psram_dev,PSRAM_SPID_SD1_IO,true));
|
||||
cJSON_AddItemToArray(list,get_gpio_entry(spiwp_sd3_io,psram_dev,PSRAM_SPIWP_SD3_IO,true));
|
||||
cJSON_AddItemToArray(list,get_gpio_entry(spihd_sd2_io,psram_dev,PSRAM_SPIHD_SD2_IO,true));
|
||||
} else if (spiconfig == EFUSE_SPICONFIG_HSPI_DEFAULTS) {
|
||||
cJSON_AddItemToArray(list,get_gpio_entry(spiq_sd0_io,psram_dev,PSRAM_HSPI_SPIQ_SD0_IO,true));
|
||||
cJSON_AddItemToArray(list,get_gpio_entry(spid_sd1_io,psram_dev,PSRAM_HSPI_SPID_SD1_IO,true));
|
||||
cJSON_AddItemToArray(list,get_gpio_entry(spiwp_sd3_io,psram_dev,PSRAM_HSPI_SPIWP_SD3_IO,true));
|
||||
cJSON_AddItemToArray(list,get_gpio_entry(spihd_sd2_io,psram_dev,PSRAM_HSPI_SPIHD_SD2_IO,true));
|
||||
} else {
|
||||
cJSON_AddItemToArray(list,get_gpio_entry(spiq_sd0_io,psram_dev,EFUSE_SPICONFIG_RET_SPIQ(spiconfig),true));
|
||||
cJSON_AddItemToArray(list,get_gpio_entry(spid_sd1_io,psram_dev,EFUSE_SPICONFIG_RET_SPID(spiconfig),true));
|
||||
cJSON_AddItemToArray(list,get_gpio_entry(spihd_sd2_io,psram_dev,EFUSE_SPICONFIG_RET_SPIHD(spiconfig),true));
|
||||
// If flash mode is set to QIO or QOUT, the WP pin is equal the value configured in bootloader.
|
||||
// If flash mode is set to DIO or DOUT, the WP pin should config it via menuconfig.
|
||||
#if CONFIG_ESPTOOLPY_FLASHMODE_QIO || CONFIG_FLASHMODE_QOUT
|
||||
cJSON_AddItemToArray(list,get_gpio_entry(spiwp_sd3_io,psram_dev,CONFIG_BOOTLOADER_SPI_WP_PIN,true));
|
||||
#else
|
||||
cJSON_AddItemToArray(list,get_gpio_entry(spiwp_sd3_io,psram_dev,CONFIG_SPIRAM_SPIWP_SD3_PIN,true));
|
||||
#endif
|
||||
}
|
||||
if (spiconfig == EFUSE_SPICONFIG_SPI_DEFAULTS) {
|
||||
cJSON_AddItemToArray(list,get_gpio_entry(clk,flash_dev,SPI_IOMUX_PIN_NUM_CLK,true));
|
||||
cJSON_AddItemToArray(list,get_gpio_entry(cs,flash_dev,SPI_IOMUX_PIN_NUM_CS,true));
|
||||
} else if (spiconfig == EFUSE_SPICONFIG_HSPI_DEFAULTS) {
|
||||
cJSON_AddItemToArray(list,get_gpio_entry(clk,flash_dev,FLASH_HSPI_CLK_IO,true));
|
||||
cJSON_AddItemToArray(list,get_gpio_entry(cs,flash_dev,FLASH_HSPI_CS_IO,true));
|
||||
} else {
|
||||
cJSON_AddItemToArray(list,get_gpio_entry(clk,flash_dev,EFUSE_SPICONFIG_RET_SPICLK(spiconfig),true));
|
||||
cJSON_AddItemToArray(list,get_gpio_entry(cs,flash_dev,EFUSE_SPICONFIG_RET_SPICS0(spiconfig),true));
|
||||
}
|
||||
return llist;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
cJSON * get_gpio_list(bool refresh) {
|
||||
gpio_num_t gpio_num;
|
||||
if(gpio_list && !refresh){
|
||||
return gpio_list;
|
||||
}
|
||||
|
||||
if(gpio_list){
|
||||
cJSON_Delete(gpio_list);
|
||||
}
|
||||
gpio_list= cJSON_CreateArray();
|
||||
|
||||
char *bat_config = config_alloc_get_default(NVS_TYPE_STR, "bat_config", NULL, 0);
|
||||
if (bat_config) {
|
||||
int channel = -1;
|
||||
PARSE_PARAM(bat_config, "channel", '=', channel);
|
||||
if(channel != -1){
|
||||
if(adc1_pad_get_io_num(channel,&gpio_num )==ESP_OK){
|
||||
cJSON_AddItemToArray(gpio_list,get_gpio_entry("bat","other",gpio_num,false));
|
||||
}
|
||||
}
|
||||
free(bat_config);
|
||||
}
|
||||
|
||||
gpio_list=get_GPIO_nvs_list(gpio_list);
|
||||
gpio_list=get_SPDIF_GPIO(gpio_list,is_spdif_config_locked());
|
||||
gpio_list=get_Rotary_GPIO(gpio_list);
|
||||
gpio_list=get_Display_GPIO(gpio_list);
|
||||
gpio_list=get_SPI_GPIO(gpio_list);
|
||||
gpio_list=get_I2C_GPIO(gpio_list);
|
||||
gpio_list=get_DAC_GPIO(gpio_list);
|
||||
gpio_list=get_psram_gpio_list(gpio_list);
|
||||
return gpio_list;
|
||||
}
|
||||
|
||||
@@ -10,23 +10,103 @@
|
||||
|
||||
#include "esp_system.h"
|
||||
#include "driver/i2c.h"
|
||||
#include "driver/i2s.h"
|
||||
#include "driver/spi_master.h"
|
||||
#include "gpio_exp.h"
|
||||
|
||||
extern const char *i2c_name_type;
|
||||
extern const char *spi_name_type;
|
||||
|
||||
typedef struct {
|
||||
int width;
|
||||
int height;
|
||||
int RST_pin;
|
||||
int i2c_system_port;
|
||||
int address;
|
||||
int CS_pin;
|
||||
int speed;
|
||||
const char *drivername;
|
||||
const char *type;
|
||||
int RST_pin;
|
||||
bool hflip;
|
||||
bool vflip;
|
||||
const char *drivername;
|
||||
int CS_pin;
|
||||
int speed;
|
||||
int back;
|
||||
int depth;
|
||||
const char *type;
|
||||
bool rotate;
|
||||
bool invert;
|
||||
int colorswap;
|
||||
} display_config_t;
|
||||
const display_config_t * config_display_get();
|
||||
|
||||
typedef struct {
|
||||
bool rmii;
|
||||
char model[16];
|
||||
int rst;
|
||||
int mdc, mdio;
|
||||
int host;
|
||||
int cs, mosi, miso, intr, clk;
|
||||
int speed;
|
||||
} eth_config_t;
|
||||
|
||||
typedef struct {
|
||||
i2s_pin_config_t pin;
|
||||
char model[32];
|
||||
int mute_gpio;
|
||||
int mute_level;
|
||||
int i2c_addr;
|
||||
int sda;
|
||||
int scl;
|
||||
} i2s_platform_config_t;
|
||||
|
||||
typedef struct {
|
||||
int gpio;
|
||||
int level;
|
||||
bool fixed;
|
||||
} gpio_with_level_t;
|
||||
|
||||
typedef struct {
|
||||
gpio_with_level_t vcc;
|
||||
gpio_with_level_t gnd;
|
||||
gpio_with_level_t amp;
|
||||
gpio_with_level_t ir;
|
||||
gpio_with_level_t jack;
|
||||
gpio_with_level_t green;
|
||||
gpio_with_level_t red;
|
||||
gpio_with_level_t spkfault;
|
||||
} set_GPIO_struct_t;
|
||||
|
||||
typedef struct {
|
||||
int A;
|
||||
int B;
|
||||
int SW;
|
||||
bool knobonly;
|
||||
bool volume_lock;
|
||||
bool longpress;
|
||||
int timer;
|
||||
} rotary_struct_t;
|
||||
|
||||
typedef struct {
|
||||
bool fixed;
|
||||
char * name;
|
||||
char * group;
|
||||
int gpio;
|
||||
} gpio_entry_t;
|
||||
|
||||
const display_config_t * config_display_get();
|
||||
esp_err_t config_display_set(const display_config_t * config);
|
||||
esp_err_t config_i2c_set(const i2c_config_t * config, int port);
|
||||
esp_err_t config_i2s_set(const i2s_platform_config_t * config, const char * nvs_name);
|
||||
esp_err_t config_spi_set(const spi_bus_config_t * config, int host, int dc);
|
||||
const i2c_config_t * config_i2c_get(int * i2c_port);
|
||||
const spi_bus_config_t * config_spi_get(spi_host_device_t * spi_host);
|
||||
const gpio_exp_config_t * config_gpio_exp_get(int index);
|
||||
void parse_set_GPIO(void (*cb)(int gpio, char *value));
|
||||
const i2s_platform_config_t * config_dac_get();
|
||||
const i2s_platform_config_t * config_spdif_get( );
|
||||
esp_err_t config_spdif_set(const i2s_platform_config_t * config);
|
||||
bool is_spdif_config_locked();
|
||||
esp_err_t free_gpio_entry( gpio_entry_t ** gpio);
|
||||
gpio_entry_t * get_gpio_by_name(char * name,char * group, bool refresh);
|
||||
gpio_entry_t * get_gpio_by_no(int gpionum, bool refresh);
|
||||
cJSON * get_gpio_list(bool refresh);
|
||||
bool is_dac_config_locked();
|
||||
bool are_statistics_enabled();
|
||||
const rotary_struct_t * config_rotary_get();
|
||||
esp_err_t config_rotary_set(rotary_struct_t * rotary);
|
||||
@@ -55,22 +55,24 @@ static const actrls_config_map_t actrls_config_map[] =
|
||||
};
|
||||
|
||||
// BEWARE: the actions below need to stay aligned with the corresponding enum to properly support json parsing
|
||||
// along with the actrls_t controls in LMS_controls, bt_sink and raop_sink
|
||||
#define EP(x) [x] = #x /* ENUM PRINT */
|
||||
static const char * actrls_action_s[ ] = { EP(ACTRLS_VOLUP),EP(ACTRLS_VOLDOWN),EP(ACTRLS_TOGGLE),EP(ACTRLS_PLAY),
|
||||
static const char * actrls_action_s[ ] = { EP(ACTRLS_POWER),EP(ACTRLS_VOLUP),EP(ACTRLS_VOLDOWN),EP(ACTRLS_TOGGLE),EP(ACTRLS_PLAY),
|
||||
EP(ACTRLS_PAUSE),EP(ACTRLS_STOP),EP(ACTRLS_REW),EP(ACTRLS_FWD),EP(ACTRLS_PREV),EP(ACTRLS_NEXT),
|
||||
EP(BCTRLS_UP),EP(BCTRLS_DOWN),EP(BCTRLS_LEFT),EP(BCTRLS_RIGHT),
|
||||
EP(BCTRLS_PS1),EP(BCTRLS_PS2),EP(BCTRLS_PS3),EP(BCTRLS_PS4),EP(BCTRLS_PS5),EP(BCTRLS_PS6),
|
||||
EP(KNOB_LEFT),EP(KNOB_RIGHT),EP(KNOB_PUSH),
|
||||
""} ;
|
||||
|
||||
static const char * TAG = "audio controls";
|
||||
static actrls_config_t *json_config;
|
||||
cJSON * control_profiles = NULL;
|
||||
static actrls_t default_controls, current_controls;
|
||||
static EXT_RAM_ATTR actrls_t default_controls, current_controls;
|
||||
static actrls_hook_t *default_hook, *current_hook;
|
||||
static bool default_raw_controls, current_raw_controls;
|
||||
static actrls_ir_handler_t *default_ir_handler, *current_ir_handler;
|
||||
|
||||
static struct {
|
||||
static EXT_RAM_ATTR struct {
|
||||
bool long_state;
|
||||
bool volume_lock;
|
||||
TimerHandle_t timer;
|
||||
@@ -135,10 +137,10 @@ esp_err_t actrls_init(const char *profile_name) {
|
||||
int A = -1, B = -1, SW = -1, longpress = 0;
|
||||
|
||||
// parse config
|
||||
if ((p = strcasestr(config, "A")) != NULL) A = atoi(strchr(p, '=') + 1);
|
||||
if ((p = strcasestr(config, "B")) != NULL) B = atoi(strchr(p, '=') + 1);
|
||||
if ((p = strcasestr(config, "SW")) != NULL) SW = atoi(strchr(p, '=') + 1);
|
||||
if ((p = strcasestr(config, "knobonly")) != NULL) {
|
||||
PARSE_PARAM(config, "A", '=', A);
|
||||
PARSE_PARAM(config, "B", '=', B);
|
||||
PARSE_PARAM(config, "SW", '=', SW);
|
||||
if ((p = strcasestr(config, "knobonly"))) {
|
||||
p = strchr(p, '=');
|
||||
int double_press = p ? atoi(p + 1) : 350;
|
||||
rotary.timer = xTimerCreate("knobTimer", double_press / portTICK_RATE_MS, pdFALSE, NULL, rotary_timer);
|
||||
@@ -155,7 +157,7 @@ esp_err_t actrls_init(const char *profile_name) {
|
||||
|
||||
// set infrared GPIO if any
|
||||
parse_set_GPIO(set_ir_gpio);
|
||||
|
||||
|
||||
if (!err) return actrls_init_json(profile_name, true);
|
||||
else return err;
|
||||
}
|
||||
@@ -506,11 +508,10 @@ static esp_err_t actrls_init_json(const char *profile_name, bool create) {
|
||||
char *config;
|
||||
const cJSON *button;
|
||||
|
||||
if (!profile_name || !*profile_name) return ESP_OK;
|
||||
|
||||
config = config_alloc_get_default(NVS_TYPE_STR, profile_name, NULL, 0);
|
||||
if(!config) return ESP_FAIL;
|
||||
|
||||
if (!profile_name) return ESP_OK;
|
||||
if ((config = config_alloc_get_str(profile_name, NULL, CONFIG_AUDIO_CONTROLS)) == NULL) return ESP_FAIL;
|
||||
if (!*config) goto exit;
|
||||
|
||||
ESP_LOGD(TAG,"Parsing JSON structure %s", config);
|
||||
cJSON *buttons = cJSON_Parse(config);
|
||||
if (buttons == NULL) {
|
||||
@@ -524,7 +525,8 @@ static esp_err_t actrls_init_json(const char *profile_name, bool create) {
|
||||
if(!cur_config) {
|
||||
ESP_LOGE(TAG,"Config buffer was empty. ");
|
||||
cJSON_Delete(buttons);
|
||||
return ESP_FAIL;
|
||||
err = ESP_FAIL;
|
||||
goto exit;
|
||||
}
|
||||
ESP_LOGD(TAG,"Processing button definitions. ");
|
||||
cJSON_ArrayForEach(button, buttons){
|
||||
@@ -555,6 +557,8 @@ static esp_err_t actrls_init_json(const char *profile_name, bool create) {
|
||||
// the last init that completes will assigh the first json config object found, which will match
|
||||
// the default config from nvs.
|
||||
json_config = config_root;
|
||||
exit:
|
||||
free(config);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,9 +11,10 @@
|
||||
#include "buttons.h"
|
||||
|
||||
// BEWARE: this is the index of the array of action below (change actrls_action_s as well!)
|
||||
typedef enum { ACTRLS_NONE = -1, ACTRLS_VOLUP, ACTRLS_VOLDOWN, ACTRLS_TOGGLE, ACTRLS_PLAY,
|
||||
typedef enum { ACTRLS_NONE = -1, ACTRLS_POWER,ACTRLS_VOLUP, ACTRLS_VOLDOWN, ACTRLS_TOGGLE, ACTRLS_PLAY,
|
||||
ACTRLS_PAUSE, ACTRLS_STOP, ACTRLS_REW, ACTRLS_FWD, ACTRLS_PREV, ACTRLS_NEXT,
|
||||
BCTRLS_UP, BCTRLS_DOWN, BCTRLS_LEFT, BCTRLS_RIGHT,
|
||||
BCTRLS_PS1,BCTRLS_PS2,BCTRLS_PS3,BCTRLS_PS4,BCTRLS_PS5,BCTRLS_PS6,
|
||||
KNOB_LEFT, KNOB_RIGHT, KNOB_PUSH,
|
||||
ACTRLS_REMAP, ACTRLS_MAX
|
||||
} actrls_action_e;
|
||||
|
||||
@@ -33,17 +33,19 @@ static struct {
|
||||
int channel;
|
||||
float sum, avg, scale;
|
||||
int count;
|
||||
int cells;
|
||||
int cells, attenuation;
|
||||
TimerHandle_t timer;
|
||||
} battery = {
|
||||
.channel = CONFIG_BAT_CHANNEL,
|
||||
} battery = {
|
||||
.channel = -1,
|
||||
.cells = 2,
|
||||
};
|
||||
|
||||
void (*battery_handler_svc)(float value);
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
int battery_value_svc(void) {
|
||||
float battery_value_svc(void) {
|
||||
return battery.avg;
|
||||
}
|
||||
|
||||
@@ -51,8 +53,9 @@ int battery_value_svc(void) {
|
||||
*
|
||||
*/
|
||||
uint8_t battery_level_svc(void) {
|
||||
// TODO: this is totally incorrect
|
||||
return battery.avg ? (battery.avg - (3.0 * battery.cells)) / ((4.2 - 3.0) * battery.cells) * 100 : 0;
|
||||
// TODO: this is vastly incorrect
|
||||
int level = battery.avg ? (battery.avg - (3.0 * battery.cells)) / ((4.2 - 3.0) * battery.cells) * 100 : 0;
|
||||
return level < 100 ? level : 100;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
@@ -63,6 +66,7 @@ static void battery_callback(TimerHandle_t xTimer) {
|
||||
if (++battery.count == 30) {
|
||||
battery.avg = battery.sum / battery.count;
|
||||
battery.sum = battery.count = 0;
|
||||
if (battery_handler_svc) (battery_handler_svc)(battery.avg);
|
||||
ESP_LOGI(TAG, "Voltage %.2fV", battery.avg);
|
||||
}
|
||||
}
|
||||
@@ -71,30 +75,31 @@ static void battery_callback(TimerHandle_t xTimer) {
|
||||
*
|
||||
*/
|
||||
void battery_svc_init(void) {
|
||||
#ifdef CONFIG_BAT_SCALE
|
||||
battery.scale = atof(CONFIG_BAT_SCALE);
|
||||
#endif
|
||||
|
||||
char *nvs_item = config_alloc_get_default(NVS_TYPE_STR, "bat_config", "n", 0);
|
||||
if (nvs_item) {
|
||||
char *p;
|
||||
#ifndef CONFIG_BAT_LOCKED
|
||||
if ((p = strcasestr(nvs_item, "channel")) != NULL) battery.channel = atoi(strchr(p, '=') + 1);
|
||||
if ((p = strcasestr(nvs_item, "scale")) != NULL) battery.scale = atof(strchr(p, '=') + 1);
|
||||
char *nvs_item = config_alloc_get_default(NVS_TYPE_STR, "bat_config", "", 0);
|
||||
|
||||
#ifdef CONFIG_BAT_LOCKED
|
||||
char *p = nvs_item;
|
||||
asprintf(&nvs_item, CONFIG_BAT_CONFIG ",%s", p);
|
||||
free(p);
|
||||
#endif
|
||||
if ((p = strcasestr(nvs_item, "cells")) != NULL) battery.cells = atof(strchr(p, '=') + 1);
|
||||
|
||||
if (nvs_item) {
|
||||
PARSE_PARAM(nvs_item, "channel", '=', battery.channel);
|
||||
PARSE_PARAM_FLOAT(nvs_item, "scale", '=', battery.scale);
|
||||
PARSE_PARAM(nvs_item, "atten", '=', battery.attenuation);
|
||||
PARSE_PARAM(nvs_item, "cells", '=', battery.cells);
|
||||
free(nvs_item);
|
||||
}
|
||||
|
||||
if (battery.channel != -1) {
|
||||
adc1_config_width(ADC_WIDTH_BIT_12);
|
||||
adc1_config_channel_atten(battery.channel, ADC_ATTEN_DB_0);
|
||||
adc1_config_channel_atten(battery.channel, battery.attenuation);
|
||||
|
||||
battery.avg = adc1_get_raw(battery.channel) * battery.scale / 4095.0;
|
||||
battery.timer = xTimerCreate("battery", BATTERY_TIMER / portTICK_RATE_MS, pdTRUE, NULL, battery_callback);
|
||||
xTimerStart(battery.timer, portMAX_DELAY);
|
||||
|
||||
ESP_LOGI(TAG, "Battery measure channel: %u, scale %f, cells %u, avg %.2fV", battery.channel, battery.scale, battery.cells, battery.avg);
|
||||
ESP_LOGI(TAG, "Battery measure channel: %u, scale %f, atten %d, cells %u, avg %.2fV", battery.channel, battery.scale, battery.attenuation, battery.cells, battery.avg);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "No battery");
|
||||
}
|
||||
|
||||
@@ -21,18 +21,17 @@
|
||||
#include "esp_task.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/rmt.h"
|
||||
#include "gpio_exp.h"
|
||||
#include "buttons.h"
|
||||
#include "rotary_encoder.h"
|
||||
#include "globdefs.h"
|
||||
|
||||
bool gpio36_39_used;
|
||||
|
||||
static const char * TAG = "buttons";
|
||||
|
||||
static int n_buttons = 0;
|
||||
static EXT_RAM_ATTR int n_buttons;
|
||||
|
||||
#define BUTTON_STACK_SIZE 4096
|
||||
#define MAX_BUTTONS 16
|
||||
#define MAX_BUTTONS 32
|
||||
#define DEBOUNCE 50
|
||||
#define BUTTON_QUEUE_LEN 10
|
||||
|
||||
@@ -49,7 +48,15 @@ static EXT_RAM_ATTR struct button_s {
|
||||
TimerHandle_t timer;
|
||||
} buttons[MAX_BUTTONS];
|
||||
|
||||
// can't use EXT_RAM_ATTR for initialized structure
|
||||
static struct {
|
||||
int gpio, level;
|
||||
struct button_s *button;
|
||||
} polled_gpio[] = { {36, -1, NULL}, {39, -1, NULL}, {-1, -1, NULL} };
|
||||
|
||||
static TimerHandle_t polled_timer;
|
||||
|
||||
static EXT_RAM_ATTR struct {
|
||||
QueueHandle_t queue;
|
||||
void *client;
|
||||
rotary_encoder_info_t info;
|
||||
@@ -57,15 +64,16 @@ static struct {
|
||||
rotary_handler handler;
|
||||
} rotary;
|
||||
|
||||
static struct {
|
||||
static EXT_RAM_ATTR struct {
|
||||
RingbufHandle_t rb;
|
||||
infrared_handler handler;
|
||||
} infrared;
|
||||
|
||||
static xQueueHandle button_evt_queue;
|
||||
static QueueSetHandle_t common_queue_set;
|
||||
static EXT_RAM_ATTR QueueHandle_t button_queue;
|
||||
static EXT_RAM_ATTR QueueSetHandle_t common_queue_set;
|
||||
|
||||
static void buttons_task(void* arg);
|
||||
static void buttons_handler(struct button_s *button, int level);
|
||||
|
||||
/****************************************************************************************
|
||||
* Start task needed by button,s rotaty and infrared
|
||||
@@ -76,43 +84,74 @@ static void common_task_init(void) {
|
||||
|
||||
if (!common_queue_set) {
|
||||
common_queue_set = xQueueCreateSet(BUTTON_QUEUE_LEN + 1);
|
||||
xTaskCreateStatic( (TaskFunction_t) buttons_task, "buttons_thread", BUTTON_STACK_SIZE, NULL, ESP_TASK_PRIO_MIN + 1, xStack, &xTaskBuffer);
|
||||
xTaskCreateStatic( (TaskFunction_t) buttons_task, "buttons", BUTTON_STACK_SIZE, NULL, ESP_TASK_PRIO_MIN + 2, xStack, &xTaskBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* GPIO low-level handler
|
||||
* GPIO low-level ISR handler
|
||||
*/
|
||||
static void IRAM_ATTR gpio_isr_handler(void* arg)
|
||||
{
|
||||
struct button_s *button = (struct button_s*) arg;
|
||||
BaseType_t woken = pdFALSE;
|
||||
|
||||
if (xTimerGetPeriod(button->timer) > button->debounce / portTICK_RATE_MS) xTimerChangePeriodFromISR(button->timer, button->debounce / portTICK_RATE_MS, &woken); // does that restart the timer?
|
||||
else xTimerResetFromISR(button->timer, &woken);
|
||||
if (xTimerGetPeriod(button->timer) > pdMS_TO_TICKS(button->debounce)) {
|
||||
if (button->gpio < GPIO_NUM_MAX) xTimerChangePeriodFromISR(button->timer, pdMS_TO_TICKS(button->debounce), &woken);
|
||||
else xTimerChangePeriod(button->timer, pdMS_TO_TICKS(button->debounce), pdMS_TO_TICKS(10));
|
||||
} else {
|
||||
if (button->gpio < GPIO_NUM_MAX) xTimerResetFromISR(button->timer, &woken);
|
||||
else xTimerReset(button->timer, portMAX_DELAY);
|
||||
}
|
||||
|
||||
if (woken) portYIELD_FROM_ISR();
|
||||
|
||||
ESP_EARLY_LOGD(TAG, "INT gpio %u level %u", button->gpio, button->level);
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* Buttons debounce/longpress timer
|
||||
*/
|
||||
static void buttons_timer( TimerHandle_t xTimer ) {
|
||||
static void buttons_timer_handler( TimerHandle_t xTimer ) {
|
||||
struct button_s *button = (struct button_s*) pvTimerGetTimerID (xTimer);
|
||||
// if this is an expanded GPIO, must give cache a chance
|
||||
buttons_handler(button, gpio_exp_get_level(button->gpio, (button->debounce * 3) / 2, NULL));
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* Buttons polling timer
|
||||
*/
|
||||
static void buttons_polling( TimerHandle_t xTimer ) {
|
||||
for (int i = 0; polled_gpio[i].gpio != -1; i++) {
|
||||
if (!polled_gpio[i].button) continue;
|
||||
|
||||
int level = gpio_get_level(polled_gpio[i].gpio);
|
||||
|
||||
if (level != polled_gpio[i].level) {
|
||||
polled_gpio[i].level = level;
|
||||
buttons_handler(polled_gpio[i].button, level);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* Buttons timer handler for press/longpress
|
||||
*/
|
||||
static void buttons_handler(struct button_s *button, int level) {
|
||||
button->level = level;
|
||||
|
||||
button->level = gpio_get_level(button->gpio);
|
||||
if (button->shifter && button->shifter->type == button->shifter->level) button->shifter->shifting = true;
|
||||
|
||||
if (button->long_press && !button->long_timer && button->level == button->type) {
|
||||
// detect a long press, so hold event generation
|
||||
ESP_LOGD(TAG, "setting long timer gpio:%u level:%u", button->gpio, button->level);
|
||||
xTimerChangePeriod(xTimer, button->long_press / portTICK_RATE_MS, 0);
|
||||
xTimerChangePeriod(button->timer, button->long_press / portTICK_RATE_MS, 0);
|
||||
button->long_timer = true;
|
||||
} else {
|
||||
// send a button pressed/released event (content is copied in queue)
|
||||
ESP_LOGD(TAG, "sending event for gpio:%u level:%u", button->gpio, button->level);
|
||||
// queue will have a copy of button's context
|
||||
xQueueSend(button_evt_queue, button, 0);
|
||||
xQueueSend(button_queue, button, 0);
|
||||
button->long_timer = false;
|
||||
}
|
||||
}
|
||||
@@ -129,13 +168,13 @@ static void buttons_task(void* arg) {
|
||||
// wait on button, rotary and infrared queues
|
||||
if ((xActivatedMember = xQueueSelectFromSet( common_queue_set, portMAX_DELAY )) == NULL) continue;
|
||||
|
||||
if (xActivatedMember == button_evt_queue) {
|
||||
if (xActivatedMember == button_queue) {
|
||||
struct button_s button;
|
||||
button_event_e event;
|
||||
button_press_e press;
|
||||
|
||||
// received a button event
|
||||
xQueueReceive(button_evt_queue, &button, 0);
|
||||
xQueueReceive(button_queue, &button, 0);
|
||||
|
||||
event = (button.level == button.type) ? BUTTON_PRESSED : BUTTON_RELEASED;
|
||||
|
||||
@@ -154,18 +193,18 @@ static void buttons_task(void* arg) {
|
||||
if (event == BUTTON_RELEASED) {
|
||||
// early release of a long-press button, send press/release
|
||||
if (!button.shifting) {
|
||||
(*button.handler)(button.client, BUTTON_PRESSED, press, false);
|
||||
(*button.handler)(button.client, BUTTON_RELEASED, press, false);
|
||||
button.handler(button.client, BUTTON_PRESSED, press, false);
|
||||
button.handler(button.client, BUTTON_RELEASED, press, false);
|
||||
}
|
||||
// button is a copy, so need to go to real context
|
||||
button.self->shifting = false;
|
||||
} else if (!button.shifting) {
|
||||
// normal long press and not shifting so don't discard
|
||||
(*button.handler)(button.client, BUTTON_PRESSED, press, true);
|
||||
button.handler(button.client, BUTTON_PRESSED, press, true);
|
||||
}
|
||||
} else {
|
||||
// normal press/release of a button or release of a long-press button
|
||||
if (!button.shifting) (*button.handler)(button.client, event, press, button.long_press);
|
||||
if (!button.shifting) button.handler(button.client, event, press, button.long_press);
|
||||
// button is a copy, so need to go to real context
|
||||
button.self->shifting = false;
|
||||
}
|
||||
@@ -174,12 +213,12 @@ static void buttons_task(void* arg) {
|
||||
|
||||
// received a rotary event
|
||||
xQueueReceive(rotary.queue, &event, 0);
|
||||
|
||||
|
||||
ESP_LOGD(TAG, "Event: position %d, direction %s", event.state.position,
|
||||
event.state.direction ? (event.state.direction == ROTARY_ENCODER_DIRECTION_CLOCKWISE ? "CW" : "CCW") : "NOT_SET");
|
||||
event.state.direction ? (event.state.direction == ROTARY_ENCODER_DIRECTION_CLOCKWISE ? "CW" : "CCW") : "NOT_SET");
|
||||
|
||||
rotary.handler(rotary.client, event.state.direction == ROTARY_ENCODER_DIRECTION_CLOCKWISE ?
|
||||
ROTARY_RIGHT : ROTARY_LEFT, false);
|
||||
ROTARY_RIGHT : ROTARY_LEFT, false);
|
||||
} else {
|
||||
// this is IR
|
||||
infrared_receive(infrared.rb, infrared.handler);
|
||||
@@ -203,9 +242,9 @@ void button_create(void *client, int gpio, int type, bool pull, int debounce, bu
|
||||
ESP_LOGI(TAG, "Creating button using GPIO %u, type %u, pull-up/down %u, long press %u shifter %d", gpio, type, pull, long_press, shifter_gpio);
|
||||
|
||||
if (!n_buttons) {
|
||||
button_evt_queue = xQueueCreate(BUTTON_QUEUE_LEN, sizeof(struct button_s));
|
||||
button_queue = xQueueCreate(BUTTON_QUEUE_LEN, sizeof(struct button_s));
|
||||
common_task_init();
|
||||
xQueueAddToSet( button_evt_queue, common_queue_set );
|
||||
xQueueAddToSet( button_queue, common_queue_set );
|
||||
}
|
||||
|
||||
// just in case this structure is allocated in a future release
|
||||
@@ -219,7 +258,7 @@ void button_create(void *client, int gpio, int type, bool pull, int debounce, bu
|
||||
buttons[n_buttons].long_press = long_press;
|
||||
buttons[n_buttons].shifter_gpio = shifter_gpio;
|
||||
buttons[n_buttons].type = type;
|
||||
buttons[n_buttons].timer = xTimerCreate("buttonTimer", buttons[n_buttons].debounce / portTICK_RATE_MS, pdFALSE, (void *) &buttons[n_buttons], buttons_timer);
|
||||
buttons[n_buttons].timer = xTimerCreate("buttonTimer", buttons[n_buttons].debounce / portTICK_RATE_MS, pdFALSE, (void *) &buttons[n_buttons], buttons_timer_handler);
|
||||
buttons[n_buttons].self = buttons + n_buttons;
|
||||
|
||||
for (int i = 0; i < n_buttons; i++) {
|
||||
@@ -236,30 +275,44 @@ void button_create(void *client, int gpio, int type, bool pull, int debounce, bu
|
||||
}
|
||||
}
|
||||
|
||||
gpio_pad_select_gpio(gpio);
|
||||
gpio_set_direction(gpio, GPIO_MODE_INPUT);
|
||||
|
||||
// we need any edge detection
|
||||
gpio_set_intr_type(gpio, GPIO_INTR_ANYEDGE);
|
||||
gpio_pad_select_gpio_x(gpio);
|
||||
gpio_set_direction_x(gpio, GPIO_MODE_INPUT);
|
||||
|
||||
// do we need pullup or pulldown
|
||||
if (pull) {
|
||||
if (GPIO_IS_VALID_OUTPUT_GPIO(gpio)) {
|
||||
if (type == BUTTON_LOW) gpio_set_pull_mode(gpio, GPIO_PULLUP_ONLY);
|
||||
else gpio_set_pull_mode(gpio, GPIO_PULLDOWN_ONLY);
|
||||
if (GPIO_IS_VALID_OUTPUT_GPIO(gpio) || gpio >= GPIO_NUM_MAX) {
|
||||
if (type == BUTTON_LOW) gpio_set_pull_mode_x(gpio, GPIO_PULLUP_ONLY);
|
||||
else gpio_set_pull_mode_x(gpio, GPIO_PULLDOWN_ONLY);
|
||||
} else {
|
||||
ESP_LOGW(TAG, "cannot set pull up/down for gpio %u", gpio);
|
||||
}
|
||||
}
|
||||
|
||||
// nasty ESP32 bug: fire-up constantly INT on GPIO 36/39 if ADC1, AMP, Hall used which WiFi does when PS is activated
|
||||
if (gpio == 36 || gpio == 39) gpio36_39_used = true;
|
||||
|
||||
// and initialize level ...
|
||||
buttons[n_buttons].level = gpio_get_level(gpio);
|
||||
|
||||
gpio_isr_handler_add(gpio, gpio_isr_handler, (void*) &buttons[n_buttons]);
|
||||
gpio_intr_enable(gpio);
|
||||
buttons[n_buttons].level = gpio_get_level_x(gpio);
|
||||
|
||||
// nasty ESP32 bug: fire-up constantly INT on GPIO 36/39 if ADC1, AMP, Hall used which WiFi does when PS is activated
|
||||
for (int i = 0; polled_gpio[i].gpio != -1; i++) if (polled_gpio[i].gpio == gpio) {
|
||||
if (!polled_timer) {
|
||||
polled_timer = xTimerCreate("buttonsPolling", 100 / portTICK_RATE_MS, pdTRUE, polled_gpio, buttons_polling);
|
||||
xTimerStart(polled_timer, portMAX_DELAY);
|
||||
}
|
||||
|
||||
polled_gpio[i].button = buttons + n_buttons;
|
||||
polled_gpio[i].level = gpio_get_level(gpio);
|
||||
ESP_LOGW(TAG, "creating polled gpio %u, level %u", gpio, polled_gpio[i].level);
|
||||
|
||||
gpio = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
// only create ISR if this is not a polled gpio
|
||||
if (gpio != -1) {
|
||||
// we need any edge detection
|
||||
gpio_set_intr_type_x(gpio, GPIO_INTR_ANYEDGE);
|
||||
gpio_isr_handler_add_x(gpio, gpio_isr_handler, buttons + n_buttons);
|
||||
gpio_intr_enable_x(gpio);
|
||||
}
|
||||
|
||||
n_buttons++;
|
||||
}
|
||||
@@ -326,7 +379,7 @@ void *button_remap(void *client, int gpio, button_handler handler, int long_pres
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* Create rotary encoder
|
||||
* Rotary encoder handler
|
||||
*/
|
||||
static void rotary_button_handler(void *id, button_event_e event, button_press_e mode, bool long_press) {
|
||||
ESP_LOGI(TAG, "Rotary push-button %d", event);
|
||||
@@ -337,7 +390,8 @@ static void rotary_button_handler(void *id, button_event_e event, button_press_e
|
||||
* Create rotary encoder
|
||||
*/
|
||||
bool create_rotary(void *id, int A, int B, int SW, int long_press, rotary_handler handler) {
|
||||
if (A == -1 || B == -1) {
|
||||
// nasty ESP32 bug: fire-up constantly INT on GPIO 36/39 if ADC1, AMP, Hall used which WiFi does when PS is activated
|
||||
if (A == -1 || B == -1 || A == 36 || A == 39 || B == 36 || B == 39) {
|
||||
ESP_LOGI(TAG, "Cannot create rotary %d %d", A, B);
|
||||
return false;
|
||||
}
|
||||
@@ -348,9 +402,6 @@ bool create_rotary(void *id, int A, int B, int SW, int long_press, rotary_handle
|
||||
rotary.client = id;
|
||||
rotary.handler = handler;
|
||||
|
||||
// nasty ESP32 bug: fire-up constantly INT on GPIO 36/39 if ADC1, AMP, Hall used which WiFi does when PS is activated
|
||||
if (A == 36 || A == 39 || B == 36 || B == 39 || SW == 36 || SW == 39) gpio36_39_used = true;
|
||||
|
||||
// Initialise the rotary encoder device with the GPIOs for A and B signals
|
||||
rotary_encoder_init(&rotary.info, A, B);
|
||||
|
||||
|
||||
@@ -17,16 +17,7 @@ extern int i2c_system_port;
|
||||
extern int i2c_system_speed;
|
||||
extern int spi_system_host;
|
||||
extern int spi_system_dc_gpio;
|
||||
extern bool gpio36_39_used;
|
||||
typedef struct {
|
||||
int timer, base_channel, max;
|
||||
} pwm_system_t;
|
||||
extern pwm_system_t pwm_system;
|
||||
|
||||
#ifdef CONFIG_SQUEEZEAMP
|
||||
#define ADAC dac_tas57xx
|
||||
#elif defined(CONFIG_A1S)
|
||||
#define ADAC dac_a1s
|
||||
#else
|
||||
#define ADAC dac_external
|
||||
#endif
|
||||
|
||||
737
components/services/gpio_exp.c
Normal file
737
components/services/gpio_exp.c
Normal file
@@ -0,0 +1,737 @@
|
||||
/* GDS Example
|
||||
|
||||
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 <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/timers.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "esp_task.h"
|
||||
#include "esp_log.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/i2c.h"
|
||||
#include "driver/spi_master.h"
|
||||
#include "gpio_exp.h"
|
||||
|
||||
#define GPIO_EXP_INTR 0x100
|
||||
#define GPIO_EXP_WRITE 0x200
|
||||
|
||||
/*
|
||||
shadow register is both output and input, so we assume that reading to the
|
||||
ports also reads the value set on output
|
||||
*/
|
||||
|
||||
typedef struct gpio_exp_s {
|
||||
uint32_t first, last;
|
||||
int intr;
|
||||
bool intr_pending;
|
||||
struct {
|
||||
struct gpio_exp_phy_s phy;
|
||||
spi_device_handle_t spi_handle;
|
||||
};
|
||||
uint32_t shadow, pending;
|
||||
TickType_t age;
|
||||
SemaphoreHandle_t mutex;
|
||||
uint32_t r_mask, w_mask;
|
||||
uint32_t pullup, pulldown;
|
||||
struct gpio_exp_isr_s {
|
||||
gpio_isr_t handler;
|
||||
void *arg;
|
||||
TimerHandle_t timer;
|
||||
} isr[32];
|
||||
struct gpio_exp_model_s const *model;
|
||||
} gpio_exp_t;
|
||||
|
||||
typedef struct {
|
||||
enum { ASYNC_WRITE } type;
|
||||
int gpio;
|
||||
int level;
|
||||
gpio_exp_t *expander;
|
||||
} queue_request_t;
|
||||
|
||||
static const char TAG[] = "gpio expander";
|
||||
|
||||
static void IRAM_ATTR intr_isr_handler(void* arg);
|
||||
static gpio_exp_t* find_expander(gpio_exp_t *expander, int *gpio);
|
||||
|
||||
static void pca9535_set_direction(gpio_exp_t* self);
|
||||
static uint32_t pca9535_read(gpio_exp_t* self);
|
||||
static void pca9535_write(gpio_exp_t* self);
|
||||
|
||||
static uint32_t pca85xx_read(gpio_exp_t* self);
|
||||
static void pca85xx_write(gpio_exp_t* self);
|
||||
|
||||
static esp_err_t mcp23017_init(gpio_exp_t* self);
|
||||
static void mcp23017_set_pull_mode(gpio_exp_t* self);
|
||||
static void mcp23017_set_direction(gpio_exp_t* self);
|
||||
static uint32_t mcp23017_read(gpio_exp_t* self);
|
||||
static void mcp23017_write(gpio_exp_t* self);
|
||||
|
||||
static esp_err_t mcp23s17_init(gpio_exp_t* self);
|
||||
static void mcp23s17_set_pull_mode(gpio_exp_t* self);
|
||||
static void mcp23s17_set_direction(gpio_exp_t* self);
|
||||
static uint32_t mcp23s17_read(gpio_exp_t* self);
|
||||
static void mcp23s17_write(gpio_exp_t* self);
|
||||
|
||||
static void service_handler(void *arg);
|
||||
static void debounce_handler( TimerHandle_t xTimer );
|
||||
|
||||
static esp_err_t i2c_write(uint8_t port, uint8_t addr, uint8_t reg, uint32_t data, int len);
|
||||
static uint32_t i2c_read(uint8_t port, uint8_t addr, uint8_t reg, int len);
|
||||
|
||||
static spi_device_handle_t spi_config(struct gpio_exp_phy_s *phy);
|
||||
static esp_err_t spi_write(spi_device_handle_t handle, uint8_t addr, uint8_t reg, uint32_t data, int len);
|
||||
static uint32_t spi_read(spi_device_handle_t handle, uint8_t addr, uint8_t reg, int len);
|
||||
|
||||
static const struct gpio_exp_model_s {
|
||||
char *model;
|
||||
gpio_int_type_t trigger;
|
||||
esp_err_t (*init)(gpio_exp_t* self);
|
||||
uint32_t (*read)(gpio_exp_t* self);
|
||||
void (*write)(gpio_exp_t* self);
|
||||
void (*set_direction)(gpio_exp_t* self);
|
||||
void (*set_pull_mode)(gpio_exp_t* self);
|
||||
} registered[] = {
|
||||
{ .model = "pca9535",
|
||||
.trigger = GPIO_INTR_LOW_LEVEL,
|
||||
.set_direction = pca9535_set_direction,
|
||||
.read = pca9535_read,
|
||||
.write = pca9535_write, },
|
||||
{ .model = "pca85xx",
|
||||
.trigger = GPIO_INTR_LOW_LEVEL,
|
||||
.read = pca85xx_read,
|
||||
.write = pca85xx_write, },
|
||||
{ .model = "mcp23017",
|
||||
.trigger = GPIO_INTR_LOW_LEVEL,
|
||||
.init = mcp23017_init,
|
||||
.set_direction = mcp23017_set_direction,
|
||||
.set_pull_mode = mcp23017_set_pull_mode,
|
||||
.read = mcp23017_read,
|
||||
.write = mcp23017_write, },
|
||||
{ .model = "mcp23s17",
|
||||
.trigger = GPIO_INTR_LOW_LEVEL,
|
||||
.init = mcp23s17_init,
|
||||
.set_direction = mcp23s17_set_direction,
|
||||
.set_pull_mode = mcp23s17_set_pull_mode,
|
||||
.read = mcp23s17_read,
|
||||
.write = mcp23s17_write, },
|
||||
};
|
||||
|
||||
static EXT_RAM_ATTR uint8_t n_expanders;
|
||||
static EXT_RAM_ATTR QueueHandle_t message_queue;
|
||||
static EXT_RAM_ATTR gpio_exp_t expanders[4];
|
||||
static EXT_RAM_ATTR TaskHandle_t service_task;
|
||||
|
||||
/******************************************************************************
|
||||
* Retrieve base from an expander reference
|
||||
*/
|
||||
uint32_t gpio_exp_get_base(gpio_exp_t *expander) {
|
||||
return expander->first;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Retrieve reference from a GPIO
|
||||
*/
|
||||
gpio_exp_t *gpio_exp_get_expander(int gpio) {
|
||||
int _gpio = gpio;
|
||||
return find_expander(NULL, &_gpio);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Create an I2C expander
|
||||
*/
|
||||
gpio_exp_t* gpio_exp_create(const gpio_exp_config_t *config) {
|
||||
gpio_exp_t *expander = expanders + n_expanders;
|
||||
|
||||
if (config->base < GPIO_NUM_MAX || n_expanders == sizeof(expanders)/sizeof(gpio_exp_t)) {
|
||||
ESP_LOGE(TAG, "Base %d GPIO must be at least %d for %s or too many expanders %d", config->base, GPIO_NUM_MAX, config->model, n_expanders);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// See if we know that model (expanders is zero-initialized)
|
||||
for (int i = 0; !expander->model && i < sizeof(registered)/sizeof(struct gpio_exp_model_s); i++) {
|
||||
if (strcasestr(config->model, registered[i].model)) expander->model = registered + i;
|
||||
}
|
||||
|
||||
// well... try again
|
||||
if (!expander->model) {
|
||||
ESP_LOGE(TAG, "Unknown GPIO expansion chip %s", config->model);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(&expander->phy, &config->phy, sizeof(struct gpio_exp_phy_s));
|
||||
|
||||
// try to initialize the expander if required
|
||||
if (expander->model->init && expander->model->init(expander) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Cannot create GPIO expander %s, check i2c/spi configuration", config->model);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
n_expanders++;
|
||||
expander->first = config->base;
|
||||
expander->last = config->base + config->count - 1;
|
||||
expander->intr = config->intr;
|
||||
expander->mutex = xSemaphoreCreateMutex();
|
||||
|
||||
// create a task to handle asynchronous requests (only write at this time)
|
||||
if (!message_queue) {
|
||||
// we allocate TCB but stack is static to avoid SPIRAM fragmentation
|
||||
StaticTask_t* xTaskBuffer = (StaticTask_t*) heap_caps_malloc(sizeof(StaticTask_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
|
||||
static EXT_RAM_ATTR StackType_t xStack[4*1024] __attribute__ ((aligned (4)));
|
||||
|
||||
message_queue = xQueueCreate(4, sizeof(queue_request_t));
|
||||
service_task = xTaskCreateStatic(service_handler, "gpio_expander", sizeof(xStack), NULL, ESP_TASK_PRIO_MIN + 1, xStack, xTaskBuffer);
|
||||
}
|
||||
|
||||
// set interrupt if possible
|
||||
if (config->intr >= 0) {
|
||||
gpio_pad_select_gpio(config->intr);
|
||||
gpio_set_direction(config->intr, GPIO_MODE_INPUT);
|
||||
|
||||
switch (expander->model->trigger) {
|
||||
case GPIO_INTR_NEGEDGE:
|
||||
case GPIO_INTR_LOW_LEVEL:
|
||||
gpio_set_pull_mode(config->intr, GPIO_PULLUP_ONLY);
|
||||
break;
|
||||
case GPIO_INTR_POSEDGE:
|
||||
case GPIO_INTR_HIGH_LEVEL:
|
||||
gpio_set_pull_mode(config->intr, GPIO_PULLDOWN_ONLY);
|
||||
break;
|
||||
default:
|
||||
gpio_set_pull_mode(config->intr, GPIO_PULLUP_PULLDOWN);
|
||||
break;
|
||||
}
|
||||
|
||||
gpio_set_intr_type(config->intr, expander->model->trigger);
|
||||
gpio_isr_handler_add(config->intr, intr_isr_handler, expander);
|
||||
gpio_intr_enable(config->intr);
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Create GPIO expander %s at base %u with intr %d at @%x on port/host %d/%d", config->model, config->base, config->intr, config->phy.addr, config->phy.port, config->phy.host);
|
||||
return expander;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Add ISR handler for a GPIO
|
||||
*/
|
||||
esp_err_t gpio_exp_isr_handler_add(int gpio, gpio_isr_t isr_handler, uint32_t debounce, void *arg, struct gpio_exp_s *expander) {
|
||||
if (gpio < GPIO_NUM_MAX && !expander) return gpio_isr_handler_add(gpio, isr_handler, arg);
|
||||
if ((expander = find_expander(expander, &gpio)) == NULL) return ESP_ERR_INVALID_ARG;
|
||||
|
||||
expander->isr[gpio].handler = isr_handler;
|
||||
expander->isr[gpio].arg = arg;
|
||||
if (debounce) expander->isr[gpio].timer = xTimerCreate("gpioExpDebounce", pdMS_TO_TICKS(debounce),
|
||||
pdFALSE, expander->isr + gpio, debounce_handler );
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Remove ISR handler for a GPIO
|
||||
*/
|
||||
esp_err_t gpio_exp_isr_handler_remove(int gpio, struct gpio_exp_s *expander) {
|
||||
if (gpio < GPIO_NUM_MAX && !expander) return gpio_isr_handler_remove(gpio);
|
||||
if ((expander = find_expander(expander, &gpio)) == NULL) return ESP_ERR_INVALID_ARG;
|
||||
|
||||
if (expander->isr[gpio].timer) xTimerDelete(expander->isr[gpio].timer, portMAX_DELAY);
|
||||
memset(expander->isr + gpio, 0, sizeof(struct gpio_exp_isr_s));
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Set GPIO direction
|
||||
*/
|
||||
esp_err_t gpio_exp_set_direction(int gpio, gpio_mode_t mode, gpio_exp_t *expander) {
|
||||
if (gpio < GPIO_NUM_MAX && !expander) return gpio_set_direction(gpio, mode);
|
||||
if ((expander = find_expander(expander, &gpio)) == NULL) return ESP_ERR_INVALID_ARG;
|
||||
|
||||
xSemaphoreTake(expander->mutex, pdMS_TO_TICKS(portMAX_DELAY));
|
||||
|
||||
if (mode == GPIO_MODE_INPUT) {
|
||||
expander->r_mask |= 1 << gpio;
|
||||
expander->shadow = expander->model->read(expander);
|
||||
expander->age = ~xTaskGetTickCount();
|
||||
} else {
|
||||
expander->w_mask |= 1 << gpio;
|
||||
}
|
||||
|
||||
if (expander->r_mask & expander->w_mask) {
|
||||
xSemaphoreGive(expander->mutex);
|
||||
ESP_LOGE(TAG, "GPIO %d on expander base %u can't be r/w", gpio, expander->first);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
// most expanders want unconfigured GPIO to be set to output
|
||||
if (expander->model->set_direction) expander->model->set_direction(expander);
|
||||
|
||||
xSemaphoreGive(expander->mutex);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Get GPIO level with cache
|
||||
*/
|
||||
int gpio_exp_get_level(int gpio, int age, gpio_exp_t *expander) {
|
||||
if (gpio < GPIO_NUM_MAX && !expander) return gpio_get_level(gpio);
|
||||
if ((expander = find_expander(expander, &gpio)) == NULL) return -1;
|
||||
uint32_t now = xTaskGetTickCount();
|
||||
|
||||
// return last thing we had if we can't get the mutex
|
||||
if (xSemaphoreTake(expander->mutex, pdMS_TO_TICKS(50)) == pdFALSE) {
|
||||
ESP_LOGW(TAG, "Can't get mutex for GPIO %d", expander->first + gpio);
|
||||
return (expander->shadow >> gpio) & 0x01;
|
||||
}
|
||||
|
||||
// re-read the expander if data is too old
|
||||
if (age >= 0 && now - expander->age >= pdMS_TO_TICKS(age)) {
|
||||
uint32_t value = expander->model->read(expander);
|
||||
expander->pending |= (expander->shadow ^ value) & expander->r_mask;
|
||||
expander->shadow = value;
|
||||
expander->age = now;
|
||||
}
|
||||
|
||||
// clear pending bit
|
||||
expander->pending &= ~(1 << gpio);
|
||||
|
||||
xSemaphoreGive(expander->mutex);
|
||||
|
||||
ESP_LOGD(TAG, "Get level for GPIO %u => read %x", expander->first + gpio, expander->shadow);
|
||||
return (expander->shadow >> gpio) & 0x01;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Set GPIO level with cache
|
||||
*/
|
||||
esp_err_t gpio_exp_set_level(int gpio, int level, bool direct, gpio_exp_t *expander) {
|
||||
if (gpio < GPIO_NUM_MAX && !expander) return gpio_set_level(gpio, level);
|
||||
if ((expander = find_expander(expander, &gpio)) == NULL) return ESP_ERR_INVALID_ARG;
|
||||
uint32_t mask = 1 << gpio;
|
||||
|
||||
// very limited risk with lack of semaphore here
|
||||
if ((expander->w_mask & mask) == 0) {
|
||||
ESP_LOGW(TAG, "GPIO %d is not set for output", expander->first + gpio);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (direct) {
|
||||
xSemaphoreTake(expander->mutex, pdMS_TO_TICKS(portMAX_DELAY));
|
||||
|
||||
level = level ? mask : 0;
|
||||
mask &= expander->shadow;
|
||||
|
||||
// only write if shadow not up to date
|
||||
if ((mask ^ level) && expander->model->write) {
|
||||
expander->shadow = (expander->shadow & ~(mask | level)) | level;
|
||||
expander->model->write(expander);
|
||||
}
|
||||
|
||||
xSemaphoreGive(expander->mutex);
|
||||
ESP_LOGD(TAG, "Set level %x for GPIO %u => wrote %x", level, expander->first + gpio, expander->shadow);
|
||||
} else {
|
||||
queue_request_t request = { .gpio = gpio, .level = level, .type = ASYNC_WRITE, .expander = expander };
|
||||
if (xQueueSend(message_queue, &request, 0) == pdFALSE) return ESP_ERR_INVALID_RESPONSE;
|
||||
|
||||
// notify service task that will write it when it can
|
||||
xTaskNotify(service_task, GPIO_EXP_WRITE, eSetValueWithoutOverwrite);
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Set GPIO pullmode
|
||||
*/
|
||||
esp_err_t gpio_exp_set_pull_mode(int gpio, gpio_pull_mode_t mode, gpio_exp_t *expander) {
|
||||
if (gpio < GPIO_NUM_MAX && !expander) return gpio_set_pull_mode(gpio, mode);
|
||||
if ((expander = find_expander(expander, &gpio)) != NULL && expander->model->set_pull_mode) {
|
||||
|
||||
expander->pullup &= ~(1 << gpio);
|
||||
expander->pulldown &= ~(1 << gpio);
|
||||
|
||||
if (mode == GPIO_PULLUP_ONLY || mode == GPIO_PULLUP_PULLDOWN) expander->pullup |= 1 << gpio;
|
||||
if (mode == GPIO_PULLDOWN_ONLY || mode == GPIO_PULLUP_PULLDOWN) expander->pulldown |= 1 << gpio;
|
||||
|
||||
expander->model->set_pull_mode(expander);
|
||||
return ESP_OK;
|
||||
}
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Wrapper function
|
||||
*/
|
||||
esp_err_t gpio_set_pull_mode_x(int gpio, gpio_pull_mode_t mode) {
|
||||
if (gpio < GPIO_NUM_MAX) return gpio_set_pull_mode(gpio, mode);
|
||||
return gpio_exp_set_pull_mode(gpio, mode, NULL);
|
||||
}
|
||||
|
||||
esp_err_t gpio_set_direction_x(int gpio, gpio_mode_t mode) {
|
||||
if (gpio < GPIO_NUM_MAX) return gpio_set_direction(gpio, mode);
|
||||
return gpio_exp_set_direction(gpio, mode, NULL);
|
||||
}
|
||||
|
||||
int gpio_get_level_x(int gpio) {
|
||||
if (gpio < GPIO_NUM_MAX) return gpio_get_level(gpio);
|
||||
return gpio_exp_get_level(gpio, 10, NULL);
|
||||
}
|
||||
|
||||
esp_err_t gpio_set_level_x(int gpio, int level) {
|
||||
if (gpio < GPIO_NUM_MAX) return gpio_set_level(gpio, level);
|
||||
return gpio_exp_set_level(gpio, level, false, NULL);
|
||||
}
|
||||
|
||||
esp_err_t gpio_isr_handler_add_x(int gpio, gpio_isr_t isr_handler, void* args) {
|
||||
if (gpio < GPIO_NUM_MAX) return gpio_isr_handler_add(gpio, isr_handler, args);
|
||||
return gpio_exp_isr_handler_add(gpio, isr_handler, 0, args, NULL);
|
||||
}
|
||||
|
||||
esp_err_t gpio_isr_handler_remove_x(int gpio) {
|
||||
if (gpio < GPIO_NUM_MAX) return gpio_isr_handler_remove(gpio);
|
||||
return gpio_exp_isr_handler_remove(gpio, NULL);
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************************
|
||||
* INTR low-level handler
|
||||
*/
|
||||
static void IRAM_ATTR intr_isr_handler(void* arg) {
|
||||
gpio_exp_t *self = (gpio_exp_t*) arg;
|
||||
BaseType_t woken = pdFALSE;
|
||||
|
||||
// edge interrupts do not work because of read/clear = potential short pulse
|
||||
gpio_intr_disable(self->intr);
|
||||
|
||||
// activate all, including ourselves
|
||||
for (int i = 0; i < n_expanders; i++) if (expanders[i].intr == self->intr) expanders[i].intr_pending = true;
|
||||
|
||||
xTaskNotifyFromISR(service_task, GPIO_EXP_INTR, eSetValueWithOverwrite, &woken);
|
||||
if (woken) portYIELD_FROM_ISR();
|
||||
|
||||
ESP_EARLY_LOGD(TAG, "INTR for expander base %d", gpio_exp_get_base(self));
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* INTR debounce handler
|
||||
*/
|
||||
static void debounce_handler( TimerHandle_t xTimer ) {
|
||||
struct gpio_exp_isr_s *isr = (struct gpio_exp_isr_s*) pvTimerGetTimerID (xTimer);
|
||||
isr->handler(isr->arg);
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* Service task
|
||||
*/
|
||||
void service_handler(void *arg) {
|
||||
while (1) {
|
||||
queue_request_t request;
|
||||
uint32_t notif = ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
|
||||
// we have been notified of an interrupt
|
||||
if (notif == GPIO_EXP_INTR) {
|
||||
/* If we want a smarter bitmap of expanders with a pending interrupt
|
||||
we'll have to disable interrupts while clearing that bitmap. For
|
||||
now, a loop will do */
|
||||
for (int i = 0; i < n_expanders; i++) {
|
||||
gpio_exp_t *expander = expanders + i;
|
||||
|
||||
// no interrupt for that gpio or not pending (safe as interrupt is disabled)
|
||||
if (expander->intr < 0 || !expander->intr_pending) continue;
|
||||
|
||||
xSemaphoreTake(expander->mutex, pdMS_TO_TICKS(50));
|
||||
|
||||
// read GPIOs and clear all pending status
|
||||
uint32_t value = expander->model->read(expander);
|
||||
expander->age = xTaskGetTickCount();
|
||||
|
||||
// re-enable interrupt now that it has been cleared
|
||||
expander->intr_pending = false;
|
||||
gpio_intr_enable(expander->intr);
|
||||
|
||||
uint32_t pending = expander->pending | ((expander->shadow ^ value) & expander->r_mask);
|
||||
expander->shadow = value;
|
||||
expander->pending = 0;
|
||||
|
||||
xSemaphoreGive(expander->mutex);
|
||||
ESP_LOGD(TAG, "Handling GPIO %d reads 0x%04x and has 0x%04x pending", expander->first, expander->shadow, pending);
|
||||
|
||||
for (int gpio = 31, clz = 0; pending && clz < 31; pending <<= (clz + 1)) {
|
||||
clz = __builtin_clz(pending);
|
||||
gpio -= clz;
|
||||
if (expander->isr[gpio].timer) xTimerReset(expander->isr[gpio].timer, 1); // todo 0
|
||||
else if (expander->isr[gpio].handler) expander->isr[gpio].handler(expander->isr[gpio].arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check if we have some other pending requests
|
||||
while (xQueueReceive(message_queue, &request, 0) == pdTRUE) {
|
||||
esp_err_t err = gpio_exp_set_level(request.gpio, request.level, true, request.expander);
|
||||
if (err != ESP_OK) ESP_LOGW(TAG, "Can't execute async GPIO %d write request (%d)", request.gpio, err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* Find the expander related to base
|
||||
*/
|
||||
static gpio_exp_t* find_expander(gpio_exp_t *expander, int *gpio) {
|
||||
// a mutex would be better, but risk is so small...
|
||||
for (int i = 0; !expander && i < n_expanders; i++) {
|
||||
if (*gpio >= expanders[i].first && *gpio <= expanders[i].last) expander = expanders + i;
|
||||
}
|
||||
|
||||
// normalize GPIO number
|
||||
if (expander && *gpio >= expander->first) *gpio -= expander->first;
|
||||
|
||||
return expander;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
DRIVERS
|
||||
****************************************************************************************/
|
||||
|
||||
/****************************************************************************************
|
||||
* PCA9535 family : direction, read and write
|
||||
*/
|
||||
static void pca9535_set_direction(gpio_exp_t* self) {
|
||||
i2c_write(self->phy.port, self->phy.addr, 0x06, self->r_mask, 2);
|
||||
}
|
||||
|
||||
static uint32_t pca9535_read(gpio_exp_t* self) {
|
||||
return i2c_read(self->phy.port, self->phy.addr, 0x00, 2);
|
||||
}
|
||||
|
||||
static void pca9535_write(gpio_exp_t* self) {
|
||||
i2c_write(self->phy.port, self->phy.addr, 0x02, self->shadow, 2);
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* PCA85xx family : read and write
|
||||
*/
|
||||
static uint32_t pca85xx_read(gpio_exp_t* self) {
|
||||
// must return the full set of pins, not just inputs
|
||||
uint32_t data = i2c_read(self->phy.port, self->phy.addr, 0xff, 2);
|
||||
return (data & self->r_mask) | (self->shadow & ~self->r_mask);
|
||||
}
|
||||
|
||||
static void pca85xx_write(gpio_exp_t* self) {
|
||||
/*
|
||||
There is no good option with this chip: normally, unused pin should be set to input
|
||||
to avoid any conflict but then they float and create tons of suprious. So option 1 is
|
||||
to le tthem float and option 2 is to set them as output to 0.
|
||||
In addition, setting an output pin to 1 equals is making it an input and if this is
|
||||
use to short a led (e.g.) instead of being the sink, the it generates a spurious
|
||||
*/
|
||||
// option 1
|
||||
// i2c_write(self->phy.port, self->phy.addr, 0xff, (self->shadow & self->w_mask) | ~self->w_mask, 2);
|
||||
// option 2
|
||||
i2c_write(self->phy.port, self->phy.addr, 0xff, (self->shadow & self->w_mask) | self->r_mask, 2);
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* MCP23017 family : init, direction, read and write
|
||||
*/
|
||||
static esp_err_t mcp23017_init(gpio_exp_t* self) {
|
||||
/*
|
||||
0111 x10x = same bank, mirrot single int, no sequentµial, open drain, active low
|
||||
not sure about this funny change of mapping of the control register itself, really?
|
||||
*/
|
||||
esp_err_t err = i2c_write(self->phy.port, self->phy.addr, 0x05, 0x74, 1);
|
||||
err |= i2c_write(self->phy.port, self->phy.addr, 0x0a, 0x74, 1);
|
||||
|
||||
// no interrupt on comparison or on change
|
||||
err |= i2c_write(self->phy.port, self->phy.addr, 0x04, 0x00, 2);
|
||||
err |= i2c_write(self->phy.port, self->phy.addr, 0x08, 0x00, 2);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void mcp23017_set_direction(gpio_exp_t* self) {
|
||||
// default to input and set real input to generate interrupt
|
||||
i2c_write(self->phy.port, self->phy.addr, 0x00, ~self->w_mask, 2);
|
||||
i2c_write(self->phy.port, self->phy.addr, 0x04, self->r_mask, 2);
|
||||
}
|
||||
|
||||
static void mcp23017_set_pull_mode(gpio_exp_t* self) {
|
||||
i2c_write(self->phy.port, self->phy.addr, 0x0c, self->pullup, 2);
|
||||
}
|
||||
|
||||
static uint32_t mcp23017_read(gpio_exp_t* self) {
|
||||
// read the pins value, not the stored one @interrupt
|
||||
return i2c_read(self->phy.port, self->phy.addr, 0x12, 2);
|
||||
}
|
||||
|
||||
static void mcp23017_write(gpio_exp_t* self) {
|
||||
i2c_write(self->phy.port, self->phy.addr, 0x12, self->shadow, 2);
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* MCP23s17 family : init, direction, read and write
|
||||
*/
|
||||
static esp_err_t mcp23s17_init(gpio_exp_t* self) {
|
||||
if ((self->spi_handle = spi_config(&self->phy)) == NULL) return ESP_ERR_INVALID_ARG;
|
||||
|
||||
/*
|
||||
0111 x10x = same bank, mirrot single int, no sequentµial, open drain, active low
|
||||
not sure about this funny change of mapping of the control register itself, really?
|
||||
*/
|
||||
esp_err_t err = spi_write(self->spi_handle, self->phy.addr, 0x05, 0x74, 1);
|
||||
err |= spi_write(self->spi_handle, self->phy.addr, 0x0a, 0x74, 1);
|
||||
|
||||
// no interrupt on comparison or on change
|
||||
err |= spi_write(self->spi_handle, self->phy.addr, 0x04, 0x00, 2);
|
||||
err |= spi_write(self->spi_handle, self->phy.addr, 0x08, 0x00, 2);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void mcp23s17_set_direction(gpio_exp_t* self) {
|
||||
// default to input and set real input to generate interrupt
|
||||
spi_write(self->spi_handle, self->phy.addr, 0x00, ~self->w_mask, 2);
|
||||
spi_write(self->spi_handle, self->phy.addr, 0x04, self->r_mask, 2);
|
||||
}
|
||||
|
||||
static void mcp23s17_set_pull_mode(gpio_exp_t* self) {
|
||||
spi_write(self->spi_handle, self->phy.addr, 0x0c, self->pullup, 2);
|
||||
}
|
||||
|
||||
static uint32_t mcp23s17_read(gpio_exp_t* self) {
|
||||
// read the pins value, not the stored one @interrupt
|
||||
return spi_read(self->spi_handle, self->phy.addr, 0x12, 2);
|
||||
}
|
||||
|
||||
static void mcp23s17_write(gpio_exp_t* self) {
|
||||
spi_write(self->spi_handle, self->phy.addr, 0x12, self->shadow, 2);
|
||||
}
|
||||
|
||||
/***************************************************************************************
|
||||
I2C low level
|
||||
***************************************************************************************/
|
||||
|
||||
/****************************************************************************************
|
||||
* I2C write up to 32 bits
|
||||
*/
|
||||
static esp_err_t i2c_write(uint8_t port, uint8_t addr, uint8_t reg, uint32_t data, int len) {
|
||||
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
||||
i2c_master_start(cmd);
|
||||
|
||||
i2c_master_write_byte(cmd, (addr << 1) | I2C_MASTER_WRITE, I2C_MASTER_NACK);
|
||||
if (reg != 0xff) i2c_master_write_byte(cmd, reg, I2C_MASTER_NACK);
|
||||
|
||||
// works with our endianness
|
||||
if (len > 1) i2c_master_write(cmd, (uint8_t*) &data, len, I2C_MASTER_NACK);
|
||||
else i2c_master_write_byte(cmd, data, I2C_MASTER_NACK);
|
||||
|
||||
i2c_master_stop(cmd);
|
||||
esp_err_t ret = i2c_master_cmd_begin(port, cmd, 100 / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGW(TAG, "I2C write failed");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* I2C read up to 32 bits
|
||||
*/
|
||||
static uint32_t i2c_read(uint8_t port, uint8_t addr, uint8_t reg, int len) {
|
||||
uint32_t data = 0;
|
||||
|
||||
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
||||
|
||||
i2c_master_start(cmd);
|
||||
|
||||
// when using a register, write it's value then the device address again
|
||||
if (reg != 0xff) {
|
||||
i2c_master_write_byte(cmd, (addr << 1) | I2C_MASTER_WRITE, I2C_MASTER_NACK);
|
||||
i2c_master_write_byte(cmd, reg, I2C_MASTER_NACK);
|
||||
i2c_master_start(cmd);
|
||||
i2c_master_write_byte(cmd, (addr << 1) | I2C_MASTER_READ, I2C_MASTER_NACK);
|
||||
} else {
|
||||
i2c_master_write_byte(cmd, (addr << 1) | I2C_MASTER_READ, I2C_MASTER_NACK);
|
||||
}
|
||||
|
||||
// works with our endianness
|
||||
if (len > 1) i2c_master_read(cmd, (uint8_t*) &data, len, I2C_MASTER_LAST_NACK);
|
||||
else i2c_master_read_byte(cmd, (uint8_t*) &data, I2C_MASTER_NACK);
|
||||
|
||||
i2c_master_stop(cmd);
|
||||
esp_err_t ret = i2c_master_cmd_begin(port, cmd, 100 / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGW(TAG, "I2C read failed");
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/***************************************************************************************
|
||||
SPI low level
|
||||
***************************************************************************************/
|
||||
|
||||
/****************************************************************************************
|
||||
* SPI device addition
|
||||
*/
|
||||
static spi_device_handle_t spi_config(struct gpio_exp_phy_s *phy) {
|
||||
spi_device_interface_config_t config = { };
|
||||
spi_device_handle_t handle = NULL;
|
||||
|
||||
config.command_bits = config.address_bits = 8;
|
||||
config.clock_speed_hz = phy->speed ? phy->speed : SPI_MASTER_FREQ_8M;
|
||||
config.spics_io_num = phy->cs_pin;
|
||||
config.queue_size = 1;
|
||||
config.flags = SPI_DEVICE_NO_DUMMY;
|
||||
|
||||
spi_bus_add_device( phy->host, &config, &handle );
|
||||
ESP_LOGI(TAG, "SPI expander initialized on host:%d with cs:%d and speed:%dHz", phy->host, phy->cs_pin, config.clock_speed_hz);
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* SPI write up to 32 bits
|
||||
*/
|
||||
static esp_err_t spi_write(spi_device_handle_t handle, uint8_t addr, uint8_t reg, uint32_t data, int len) {
|
||||
spi_transaction_t transaction = { };
|
||||
|
||||
// rx_buffer is NULL, nothing to receive
|
||||
transaction.flags = SPI_TRANS_USE_TXDATA;
|
||||
transaction.cmd = addr << 1;
|
||||
transaction.addr = reg;
|
||||
transaction.tx_data[0] = data; transaction.tx_data[1] = data >> 8;
|
||||
transaction.length = len * 8;
|
||||
|
||||
// only do polling as we don't have contention on SPI (otherwise DMA for transfers > 16 bytes)
|
||||
return spi_device_polling_transmit(handle, &transaction);
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* SPI read up to 32 bits
|
||||
*/
|
||||
static uint32_t spi_read(spi_device_handle_t handle, uint8_t addr, uint8_t reg, int len) {
|
||||
spi_transaction_t *transaction = heap_caps_calloc(1, sizeof(spi_transaction_t), MALLOC_CAP_DMA);
|
||||
|
||||
// tx_buffer is NULL, nothing to transmit except cmd/addr
|
||||
transaction->flags = SPI_TRANS_USE_RXDATA;
|
||||
transaction->cmd = (addr << 1) | 0x01;
|
||||
transaction->addr = reg;
|
||||
transaction->length = len * 8;
|
||||
|
||||
// only do polling as we don't have contention on SPI (otherwise DMA for transfers > 16 bytes)
|
||||
spi_device_polling_transmit(handle, transaction);
|
||||
uint32_t data = *(uint32_t*) transaction->rx_data;
|
||||
free(transaction);
|
||||
|
||||
return data;
|
||||
}
|
||||
61
components/services/gpio_exp.h
Normal file
61
components/services/gpio_exp.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/* GDS Example
|
||||
|
||||
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.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "driver/gpio.h"
|
||||
|
||||
struct gpio_exp_s;
|
||||
|
||||
typedef struct {
|
||||
char model[32];
|
||||
int intr;
|
||||
uint8_t count;
|
||||
uint32_t base;
|
||||
struct gpio_exp_phy_s {
|
||||
uint8_t addr;
|
||||
struct { // for I2C
|
||||
uint8_t port;
|
||||
};
|
||||
struct { // for SPI
|
||||
uint32_t speed;
|
||||
uint8_t host;
|
||||
uint8_t cs_pin;
|
||||
};
|
||||
} phy;
|
||||
} gpio_exp_config_t;
|
||||
|
||||
// set <intr> to -1 and <queue> to NULL if there is no interrupt
|
||||
struct gpio_exp_s* gpio_exp_create(const gpio_exp_config_t *config);
|
||||
uint32_t gpio_exp_get_base(struct gpio_exp_s *expander);
|
||||
struct gpio_exp_s* gpio_exp_get_expander(int gpio);
|
||||
#define gpio_is_expanded(gpio) (gpio < GPIO_NUM_MAX)
|
||||
|
||||
/*
|
||||
For all functions below when <expander> is provided, GPIO's can be numbered from 0. If <expander>
|
||||
is NULL, then GPIO must start from base OR be on-chip
|
||||
*/
|
||||
esp_err_t gpio_exp_set_direction(int gpio, gpio_mode_t mode, struct gpio_exp_s *expander);
|
||||
esp_err_t gpio_exp_set_pull_mode(int gpio, gpio_pull_mode_t mode, struct gpio_exp_s *expander);
|
||||
int gpio_exp_get_level(int gpio, int age, struct gpio_exp_s *expander);
|
||||
esp_err_t gpio_exp_set_level(int gpio, int level, bool direct, struct gpio_exp_s *expander);
|
||||
esp_err_t gpio_exp_isr_handler_add(int gpio, gpio_isr_t isr, uint32_t debounce, void *arg, struct gpio_exp_s *expander);
|
||||
esp_err_t gpio_exp_isr_handler_remove(int gpio, struct gpio_exp_s *expander);
|
||||
|
||||
// unified function to use either built-in or expanded GPIO
|
||||
esp_err_t gpio_set_direction_x(int gpio, gpio_mode_t mode);
|
||||
esp_err_t gpio_set_pull_mode_x(int gpio, gpio_pull_mode_t mode);
|
||||
int gpio_get_level_x(int gpio);
|
||||
esp_err_t gpio_set_level_x(int gpio, int level);
|
||||
esp_err_t gpio_isr_handler_add_x(int gpio, gpio_isr_t isr_handler, void* args);
|
||||
esp_err_t gpio_isr_handler_remove_x(int gpio);
|
||||
#define gpio_set_intr_type_x(gpio, type) do { if (gpio < GPIO_NUM_MAX) gpio_set_intr_type(gpio, type); } while (0)
|
||||
#define gpio_intr_enable_x(gpio) do { if (gpio < GPIO_NUM_MAX) gpio_intr_enable(gpio); } while (0)
|
||||
#define gpio_pad_select_gpio_x(gpio) do { if (gpio < GPIO_NUM_MAX) gpio_pad_select_gpio(gpio); } while (0)
|
||||
@@ -409,7 +409,7 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t b
|
||||
}
|
||||
|
||||
double mclk;
|
||||
int sdm0, sdm1, sdm2, odir, m_scale = 8;
|
||||
int sdm0, sdm1, sdm2, odir, m_scale = (rate > 96000 && bits > 16) ? 4 : 8;
|
||||
int fi2s_clk = rate*channel*bits*m_scale;
|
||||
if (p_i2s_obj[i2s_num]->mode & (I2S_MODE_DAC_BUILT_IN | I2S_MODE_ADC_BUILT_IN)) {
|
||||
//DAC uses bclk as sample clock, not WS. WS can be something arbitrary.
|
||||
@@ -463,7 +463,7 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t b
|
||||
double fi2s_rate = i2s_apll_get_fi2s(bits, sdm0, sdm1, sdm2, odir);
|
||||
p_i2s_obj[i2s_num]->real_rate = fi2s_rate/bits/channel/m_scale;
|
||||
ESP_LOGI(I2S_TAG, "APLL: Req RATE: %d, real rate: %0.3f, BITS: %u, CLKM: %u, BCK_M: %u, MCLK: %0.3f, SCLK: %f, diva: %d, divb: %d",
|
||||
rate, fi2s_rate/bits/channel/m_scale, bits, 1, m_scale, fi2s_rate, fi2s_rate/8, 1, 0);
|
||||
rate, fi2s_rate/bits/channel/m_scale, bits, 1, m_scale, fi2s_rate, fi2s_rate/m_scale, 1, 0);
|
||||
} else {
|
||||
I2S[i2s_num]->clkm_conf.clka_en = 0;
|
||||
I2S[i2s_num]->clkm_conf.clkm_div_a = 63;
|
||||
@@ -928,8 +928,8 @@ static esp_err_t i2s_param_config(i2s_port_t i2s_num, const i2s_config_t *i2s_co
|
||||
|
||||
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_msb_right = i2s_config->bits_per_sample == 32 ? 0 : 1;
|
||||
I2S[i2s_num]->conf.tx_right_first = ~I2S[i2s_num]->conf.tx_msb_right;
|
||||
|
||||
I2S[i2s_num]->conf.tx_slave_mod = 0; // Master
|
||||
I2S[i2s_num]->fifo_conf.tx_fifo_mod_force_en = 1;
|
||||
@@ -940,8 +940,7 @@ static esp_err_t i2s_param_config(i2s_port_t i2s_num, const i2s_config_t *i2s_co
|
||||
}
|
||||
|
||||
if (i2s_config->mode & I2S_MODE_RX) {
|
||||
// PATCH
|
||||
I2S[i2s_num]->conf.rx_msb_right = 1;
|
||||
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;
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/ledc.h"
|
||||
#include "platform_config.h"
|
||||
#include "gpio_exp.h"
|
||||
#include "led.h"
|
||||
#include "globdefs.h"
|
||||
#include "accessors.h"
|
||||
@@ -28,7 +29,7 @@
|
||||
|
||||
static const char *TAG = "led";
|
||||
|
||||
static struct led_s {
|
||||
static EXT_RAM_ATTR struct led_s {
|
||||
gpio_num_t gpio;
|
||||
bool on;
|
||||
int onstate;
|
||||
@@ -40,6 +41,7 @@ static struct led_s {
|
||||
TimerHandle_t timer;
|
||||
} leds[MAX_LED];
|
||||
|
||||
// can't use EXT_RAM_ATTR for initialized structure
|
||||
static struct {
|
||||
int gpio;
|
||||
int active;
|
||||
@@ -53,7 +55,7 @@ static int led_max = 2;
|
||||
*
|
||||
*/
|
||||
static void set_level(struct led_s *led, bool on) {
|
||||
if (led->pwm < 0) gpio_set_level(led->gpio, on ? led->onstate : !led->onstate);
|
||||
if (led->pwm < 0 || led->gpio >= GPIO_NUM_MAX) gpio_set_level_x(led->gpio, on ? led->onstate : !led->onstate);
|
||||
else {
|
||||
ledc_set_duty(LEDC_HIGH_SPEED_MODE, led->channel, on ? led->pwm : (led->onstate ? 0 : pwm_system.max));
|
||||
ledc_update_duty(LEDC_HIGH_SPEED_MODE, led->channel);
|
||||
@@ -85,7 +87,7 @@ static void vCallbackFunction( TimerHandle_t xTimer ) {
|
||||
bool led_blink_core(int idx, int ontime, int offtime, bool pushed) {
|
||||
if (!leds[idx].gpio || leds[idx].gpio < 0 ) return false;
|
||||
|
||||
ESP_LOGD(TAG,"led_blink_core");
|
||||
ESP_LOGD(TAG,"led_blink_core %d on:%d off:%d, pushed:%u", idx, ontime, offtime, pushed);
|
||||
if (leds[idx].timer) {
|
||||
// normal requests waits if a pop is pending
|
||||
if (!pushed && leds[idx].pushed) {
|
||||
@@ -179,9 +181,9 @@ bool led_config(int idx, gpio_num_t gpio, int onstate, int pwm) {
|
||||
leds[idx].onstate = onstate;
|
||||
leds[idx].pwm = -1;
|
||||
|
||||
if (pwm < 0) {
|
||||
gpio_pad_select_gpio(gpio);
|
||||
gpio_set_direction(gpio, GPIO_MODE_OUTPUT);
|
||||
if (pwm < 0 || gpio >= GPIO_NUM_MAX) {
|
||||
gpio_pad_select_gpio_x(gpio);
|
||||
gpio_set_direction_x(gpio, GPIO_MODE_OUTPUT);
|
||||
} else {
|
||||
leds[idx].channel = pwm_system.base_channel++;
|
||||
leds[idx].pwm = pwm_system.max * powf(pwm / 100.0, 3);
|
||||
@@ -231,15 +233,16 @@ void led_svc_init(void) {
|
||||
#ifndef CONFIG_LED_LOCKED
|
||||
parse_set_GPIO(set_led_gpio);
|
||||
#endif
|
||||
ESP_LOGI(TAG,"Configuring LEDs green:%d (active:%d %d%%), red:%d (active:%d %d%%)", green.gpio, green.active, green.pwm, green.gpio, green.active, green.pwm );
|
||||
|
||||
char *nvs_item = config_alloc_get(NVS_TYPE_STR, "led_brightness"), *p;
|
||||
|
||||
char *nvs_item = config_alloc_get(NVS_TYPE_STR, "led_brightness");
|
||||
if (nvs_item) {
|
||||
if ((p = strcasestr(nvs_item, "green")) != NULL) green.pwm = atoi(strchr(p, '=') + 1);
|
||||
if ((p = strcasestr(nvs_item, "red")) != NULL) red.pwm = atoi(strchr(p, '=') + 1);
|
||||
PARSE_PARAM(nvs_item, "green", '=', green.pwm);
|
||||
PARSE_PARAM(nvs_item, "red", '=', red.pwm);
|
||||
free(nvs_item);
|
||||
}
|
||||
|
||||
led_config(LED_GREEN, green.gpio, green.active, green.pwm);
|
||||
led_config(LED_RED, red.gpio, red.active, red.pwm);
|
||||
|
||||
ESP_LOGI(TAG,"Configuring LEDs green:%d (active:%d %d%%), red:%d (active:%d %d%%)", green.gpio, green.active, green.pwm, red.gpio, red.active, red.pwm );
|
||||
}
|
||||
|
||||
@@ -119,6 +119,8 @@ const char * messaging_get_class_desc(messaging_classes msg_class){
|
||||
CASE_TO_STR(MESSAGING_CLASS_OTA);
|
||||
CASE_TO_STR(MESSAGING_CLASS_SYSTEM);
|
||||
CASE_TO_STR(MESSAGING_CLASS_STATS);
|
||||
CASE_TO_STR(MESSAGING_CLASS_CFGCMD);
|
||||
CASE_TO_STR(MESSAGING_CLASS_BT);
|
||||
default:
|
||||
return "Unknown";
|
||||
break;
|
||||
@@ -141,12 +143,12 @@ cJSON * messaging_retrieve_messages(RingbufHandle_t buf_handle){
|
||||
else {
|
||||
json_message = cJSON_CreateObject();
|
||||
cJSON_AddStringToObject(json_message, "message", message->message);
|
||||
vRingbufferReturnItem(buf_handle, (void *)message);
|
||||
cJSON_AddStringToObject(json_message, "type", messaging_get_type_desc(message->type));
|
||||
cJSON_AddStringToObject(json_message, "class", messaging_get_class_desc(message->msg_class));
|
||||
cJSON_AddNumberToObject(json_message,"sent_time",message->sent_time);
|
||||
cJSON_AddNumberToObject(json_message,"current_time",esp_timer_get_time() / 1000);
|
||||
cJSON_AddItemToArray(json_messages,json_message);
|
||||
vRingbufferReturnItem(buf_handle, (void *)message);
|
||||
}
|
||||
}
|
||||
return json_messages;
|
||||
@@ -260,5 +262,23 @@ void log_send_messaging(messaging_types msgtype,const char *fmt, ...) {
|
||||
else{
|
||||
ESP_LOGE(tag, "Memory allocation failed while sending message");
|
||||
}
|
||||
|
||||
}
|
||||
void cmd_send_messaging(const char * cmdname,messaging_types msgtype, const char *fmt, ...){
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
size_t cmd_len = strlen(cmdname)+1;
|
||||
size_t ln = vsnprintf(NULL, 0, fmt, va)+1;
|
||||
char * message_txt = malloc(ln+cmd_len);
|
||||
if(message_txt){
|
||||
strcpy(message_txt,cmdname);
|
||||
strcat(message_txt,"\n");
|
||||
vsprintf((message_txt+cmd_len), fmt, va);
|
||||
va_end(va);
|
||||
ESP_LOG_LEVEL_LOCAL(messaging_type_to_err_type(msgtype),tag, "%s",message_txt);
|
||||
messaging_post_message(msgtype, MESSAGING_CLASS_CFGCMD, message_txt );
|
||||
free(message_txt);
|
||||
}
|
||||
else{
|
||||
ESP_LOGE(tag, "Memory allocation failed while sending message");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "sdkconfig.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/ringbuf.h"
|
||||
#include "cJSON.h"
|
||||
#pragma once
|
||||
@@ -10,7 +11,9 @@ typedef enum {
|
||||
typedef enum {
|
||||
MESSAGING_CLASS_OTA,
|
||||
MESSAGING_CLASS_SYSTEM,
|
||||
MESSAGING_CLASS_STATS
|
||||
MESSAGING_CLASS_STATS,
|
||||
MESSAGING_CLASS_CFGCMD,
|
||||
MESSAGING_CLASS_BT
|
||||
} messaging_classes;
|
||||
|
||||
typedef struct messaging_list_t *messaging_handle_t;
|
||||
@@ -30,6 +33,7 @@ void messaging_post_message(messaging_types type,messaging_classes msg_class, co
|
||||
cJSON * messaging_retrieve_messages(RingbufHandle_t buf_handle);
|
||||
single_message_t * messaging_retrieve_message(RingbufHandle_t buf_handle);
|
||||
void log_send_messaging(messaging_types msgtype,const char *fmt, ...);
|
||||
void cmd_send_messaging(const char * cmdname,messaging_types msgtype, const char *fmt, ...);
|
||||
esp_err_t messaging_type_to_err_type(messaging_types type);
|
||||
void messaging_service_init();
|
||||
|
||||
|
||||
@@ -32,11 +32,8 @@ static const char *TAG = "monitor";
|
||||
|
||||
static TimerHandle_t monitor_timer;
|
||||
|
||||
static struct {
|
||||
int gpio;
|
||||
int active;
|
||||
} jack = { CONFIG_JACK_GPIO, 0 },
|
||||
spkfault = { CONFIG_SPKFAULT_GPIO, 0 };
|
||||
static monitor_gpio_t jack = { CONFIG_JACK_GPIO, 0 };
|
||||
static monitor_gpio_t spkfault = { CONFIG_SPKFAULT_GPIO, 0 };
|
||||
|
||||
void (*jack_handler_svc)(bool inserted);
|
||||
bool jack_inserted_svc(void);
|
||||
@@ -44,11 +41,13 @@ bool jack_inserted_svc(void);
|
||||
void (*spkfault_handler_svc)(bool inserted);
|
||||
bool spkfault_svc(void);
|
||||
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
static void task_stats( cJSON* top ) {
|
||||
#ifdef CONFIG_FREERTOS_USE_TRACE_FACILITY
|
||||
#pragma message("Compiled with trace facility")
|
||||
static struct {
|
||||
TaskStatus_t *tasks;
|
||||
uint32_t total, n;
|
||||
@@ -63,6 +62,7 @@ static void task_stats( cJSON* top ) {
|
||||
*scratch = '\0';
|
||||
|
||||
#ifdef CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS
|
||||
#pragma message("Compiled with runtime stats")
|
||||
uint32_t elapsed = current.total - previous.total;
|
||||
|
||||
for(int i = 0, n = 0; i < current.n; i++ ) {
|
||||
@@ -90,6 +90,8 @@ static void task_stats( cJSON* top ) {
|
||||
}
|
||||
}
|
||||
#else
|
||||
#pragma message("Compiled WITHOUT runtime stats")
|
||||
|
||||
for (int i = 0, n = 0; i < current.n; i ++) {
|
||||
n += sprintf(scratch + n, "%16s s:%5u\t", current.tasks[i].pcTaskName, current.tasks[i].usStackHighWaterMark);
|
||||
cJSON * t=cJSON_CreateObject();
|
||||
@@ -109,6 +111,8 @@ static void task_stats( cJSON* top ) {
|
||||
cJSON_AddItemToObject(top,"tasks",tlist);
|
||||
if (previous.tasks) free(previous.tasks);
|
||||
previous = current;
|
||||
#else
|
||||
#pragma message("Compiled WITHOUT trace facility")
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -141,8 +145,7 @@ static void monitor_callback(TimerHandle_t xTimer) {
|
||||
*
|
||||
*/
|
||||
static void jack_handler_default(void *id, button_event_e event, button_press_e mode, bool long_press) {
|
||||
ESP_LOGD(TAG, "Jack %s", event == BUTTON_PRESSED ? "inserted" : "removed");
|
||||
messaging_post_message(MESSAGING_INFO, MESSAGING_CLASS_SYSTEM,"jack is %s",BUTTON_PRESSED ? "inserted" : "removed");
|
||||
ESP_LOGI(TAG, "Jack %s", event == BUTTON_PRESSED ? "inserted" : "removed");
|
||||
if (jack_handler_svc) (*jack_handler_svc)(event == BUTTON_PRESSED);
|
||||
}
|
||||
|
||||
@@ -181,6 +184,9 @@ static void set_jack_gpio(int gpio, char *value) {
|
||||
jack.gpio = gpio;
|
||||
if ((p = strchr(value, ':')) != NULL) jack.active = atoi(p + 1);
|
||||
}
|
||||
else {
|
||||
jack.gpio = -1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -194,6 +200,9 @@ static void set_spkfault_gpio(int gpio, char *value) {
|
||||
spkfault.gpio = gpio;
|
||||
if ((p = strchr(value, ':')) != NULL) spkfault.active = atoi(p + 1);
|
||||
}
|
||||
else {
|
||||
spkfault.gpio = -1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -237,7 +246,7 @@ void monitor_svc_init(void) {
|
||||
monitor_timer = xTimerCreate("monitor", MONITOR_TIMER / portTICK_RATE_MS, pdTRUE, NULL, monitor_callback);
|
||||
xTimerStart(monitor_timer, portMAX_DELAY);
|
||||
}
|
||||
free(p);
|
||||
FREE_AND_NULL(p);
|
||||
|
||||
ESP_LOGI(TAG, "Heap internal:%zu (min:%zu) external:%zu (min:%zu)",
|
||||
heap_caps_get_free_size(MALLOC_CAP_INTERNAL),
|
||||
@@ -245,3 +254,17 @@ void monitor_svc_init(void) {
|
||||
heap_caps_get_free_size(MALLOC_CAP_SPIRAM),
|
||||
heap_caps_get_minimum_free_size(MALLOC_CAP_SPIRAM));
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
monitor_gpio_t * get_spkfault_gpio(){
|
||||
return &spkfault ;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
monitor_gpio_t * get_jack_insertion_gpio(){
|
||||
return &jack;
|
||||
}
|
||||
@@ -9,6 +9,10 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
typedef struct {
|
||||
int gpio;
|
||||
int active;
|
||||
} monitor_gpio_t;
|
||||
|
||||
extern void (*jack_handler_svc)(bool inserted);
|
||||
extern bool jack_inserted_svc(void);
|
||||
@@ -16,6 +20,10 @@ extern bool jack_inserted_svc(void);
|
||||
extern void (*spkfault_handler_svc)(bool inserted);
|
||||
extern bool spkfault_svc(void);
|
||||
|
||||
extern int battery_value_svc(void);
|
||||
extern uint8_t battery_level_svc(void);
|
||||
extern void (*battery_handler_svc)(float value);
|
||||
extern float battery_value_svc(void);
|
||||
extern uint16_t battery_level_svc(void);
|
||||
|
||||
extern monitor_gpio_t * get_spkfault_gpio();
|
||||
extern monitor_gpio_t * get_jack_insertion_gpio();
|
||||
|
||||
|
||||
@@ -91,6 +91,7 @@
|
||||
|
||||
#include "esp_log.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "gpio_exp.h"
|
||||
|
||||
#define TAG "rotary_encoder"
|
||||
|
||||
@@ -148,7 +149,7 @@ static uint8_t _process(rotary_encoder_info_t * info)
|
||||
if (info != NULL)
|
||||
{
|
||||
// Get state of input pins.
|
||||
uint8_t pin_state = (gpio_get_level(info->pin_b) << 1) | gpio_get_level(info->pin_a);
|
||||
uint8_t pin_state = (gpio_get_level_x(info->pin_b) << 1) | gpio_get_level_x(info->pin_a);
|
||||
|
||||
// Determine new state from the pins and state table.
|
||||
#ifdef ROTARY_ENCODER_DEBUG
|
||||
@@ -198,12 +199,18 @@ static void _isr_rotenc(void * args)
|
||||
.direction = info->state.direction,
|
||||
},
|
||||
};
|
||||
BaseType_t task_woken = pdFALSE;
|
||||
xQueueOverwriteFromISR(info->queue, &queue_event, &task_woken);
|
||||
if (task_woken)
|
||||
{
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
if (info->pin_a < GPIO_NUM_MAX) {
|
||||
BaseType_t task_woken = pdFALSE;
|
||||
xQueueOverwriteFromISR(info->queue, &queue_event, &task_woken);
|
||||
if (task_woken)
|
||||
{
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
xQueueOverwrite(info->queue, &queue_event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -220,19 +227,19 @@ esp_err_t rotary_encoder_init(rotary_encoder_info_t * info, gpio_num_t pin_a, gp
|
||||
info->state.direction = ROTARY_ENCODER_DIRECTION_NOT_SET;
|
||||
|
||||
// configure GPIOs
|
||||
gpio_pad_select_gpio(info->pin_a);
|
||||
gpio_set_pull_mode(info->pin_a, GPIO_PULLUP_ONLY);
|
||||
gpio_set_direction(info->pin_a, GPIO_MODE_INPUT);
|
||||
gpio_set_intr_type(info->pin_a, GPIO_INTR_ANYEDGE);
|
||||
gpio_pad_select_gpio_x(info->pin_a);
|
||||
gpio_set_pull_mode_x(info->pin_a, GPIO_PULLUP_ONLY);
|
||||
gpio_set_direction_x(info->pin_a, GPIO_MODE_INPUT);
|
||||
gpio_set_intr_type_x(info->pin_a, GPIO_INTR_ANYEDGE);
|
||||
|
||||
gpio_pad_select_gpio(info->pin_b);
|
||||
gpio_set_pull_mode(info->pin_b, GPIO_PULLUP_ONLY);
|
||||
gpio_set_direction(info->pin_b, GPIO_MODE_INPUT);
|
||||
gpio_set_intr_type(info->pin_b, GPIO_INTR_ANYEDGE);
|
||||
gpio_pad_select_gpio_x(info->pin_b);
|
||||
gpio_set_pull_mode_x(info->pin_b, GPIO_PULLUP_ONLY);
|
||||
gpio_set_direction_x(info->pin_b, GPIO_MODE_INPUT);
|
||||
gpio_set_intr_type_x(info->pin_b, GPIO_INTR_ANYEDGE);
|
||||
|
||||
// install interrupt handlers
|
||||
gpio_isr_handler_add(info->pin_a, _isr_rotenc, info);
|
||||
gpio_isr_handler_add(info->pin_b, _isr_rotenc, info);
|
||||
gpio_isr_handler_add_x(info->pin_a, _isr_rotenc, info);
|
||||
gpio_isr_handler_add_x(info->pin_b, _isr_rotenc, info);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -280,8 +287,8 @@ esp_err_t rotary_encoder_uninit(rotary_encoder_info_t * info)
|
||||
esp_err_t err = ESP_OK;
|
||||
if (info)
|
||||
{
|
||||
gpio_isr_handler_remove(info->pin_a);
|
||||
gpio_isr_handler_remove(info->pin_b);
|
||||
gpio_isr_handler_remove_x(info->pin_a);
|
||||
gpio_isr_handler_remove_x(info->pin_b);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "driver/ledc.h"
|
||||
#include "driver/i2c.h"
|
||||
#include "platform_config.h"
|
||||
#include "gpio_exp.h"
|
||||
#include "battery.h"
|
||||
#include "led.h"
|
||||
#include "monitor.h"
|
||||
@@ -38,8 +39,11 @@ static const char *TAG = "services";
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
void set_power_gpio(int gpio, char *value) {
|
||||
void set_chip_power_gpio(int gpio, char *value) {
|
||||
bool parsed = true;
|
||||
|
||||
// we only parse on-chip GPIOs
|
||||
if (gpio >= GPIO_NUM_MAX) return;
|
||||
|
||||
if (!strcasecmp(value, "vcc") ) {
|
||||
gpio_pad_select_gpio(gpio);
|
||||
@@ -49,9 +53,26 @@ void set_power_gpio(int gpio, char *value) {
|
||||
gpio_pad_select_gpio(gpio);
|
||||
gpio_set_direction(gpio, GPIO_MODE_OUTPUT);
|
||||
gpio_set_level(gpio, 0);
|
||||
} else parsed = false ;
|
||||
} else parsed = false;
|
||||
|
||||
if (parsed) ESP_LOGI(TAG, "set GPIO %u to %s", gpio, value);
|
||||
}
|
||||
|
||||
void set_exp_power_gpio(int gpio, char *value) {
|
||||
bool parsed = true;
|
||||
|
||||
// we only parse on-chip GPIOs
|
||||
if (gpio < GPIO_NUM_MAX) return;
|
||||
|
||||
if (!strcasecmp(value, "vcc") ) {
|
||||
gpio_exp_set_direction(gpio, GPIO_MODE_OUTPUT, NULL);
|
||||
gpio_exp_set_level(gpio, 1, true, NULL);
|
||||
} else if (!strcasecmp(value, "gnd")) {
|
||||
gpio_exp_set_direction(gpio, GPIO_MODE_OUTPUT, NULL);
|
||||
gpio_exp_set_level(gpio, 0, true, NULL);
|
||||
} else parsed = false;
|
||||
|
||||
if (parsed) ESP_LOGI(TAG, "set expanded GPIO %u to %s", gpio, value);
|
||||
}
|
||||
|
||||
|
||||
@@ -69,8 +90,8 @@ void services_init(void) {
|
||||
}
|
||||
#endif
|
||||
|
||||
// set potential power GPIO
|
||||
parse_set_GPIO(set_power_gpio);
|
||||
// set potential power GPIO on chip first in case expanders are power using these
|
||||
parse_set_GPIO(set_chip_power_gpio);
|
||||
|
||||
// shared I2C bus
|
||||
const i2c_config_t * i2c_config = config_i2c_get(&i2c_system_port);
|
||||
@@ -85,7 +106,7 @@ void services_init(void) {
|
||||
}
|
||||
|
||||
const spi_bus_config_t * spi_config = config_spi_get((spi_host_device_t*) &spi_system_host);
|
||||
ESP_LOGI(TAG,"Configuring SPI data:%d clk:%d host:%u dc:%d", spi_config->mosi_io_num, spi_config->sclk_io_num, spi_system_host, spi_system_dc_gpio);
|
||||
ESP_LOGI(TAG,"Configuring SPI mosi:%d miso:%d clk:%d host:%u dc:%d", spi_config->mosi_io_num, spi_config->miso_io_num, spi_config->sclk_io_num, spi_system_host, spi_system_dc_gpio);
|
||||
|
||||
if (spi_config->mosi_io_num != -1 && spi_config->sclk_io_num != -1) {
|
||||
spi_bus_initialize( spi_system_host, spi_config, 1 );
|
||||
@@ -100,6 +121,13 @@ void services_init(void) {
|
||||
ESP_LOGW(TAG, "no SPI configured");
|
||||
}
|
||||
|
||||
// create GPIO expanders
|
||||
const gpio_exp_config_t* gpio_exp_config;
|
||||
for (int count = 0; (gpio_exp_config = config_gpio_exp_get(count)); count++) gpio_exp_create(gpio_exp_config);
|
||||
|
||||
// now set potential power GPIO on expander
|
||||
parse_set_GPIO(set_exp_power_gpio);
|
||||
|
||||
// system-wide PWM timer configuration
|
||||
ledc_timer_config_t pwm_timer = {
|
||||
.duty_resolution = LEDC_TIMER_13_BIT,
|
||||
|
||||
@@ -38,6 +38,8 @@
|
||||
#include "gds_text.h"
|
||||
#include "gds_draw.h"
|
||||
#include "platform_esp32.h"
|
||||
#include "lwip/sockets.h"
|
||||
|
||||
|
||||
extern const char * get_certificate();
|
||||
#define IF_DISPLAY(x) if(display) { x; }
|
||||
@@ -92,6 +94,7 @@ ota_status_t * ota_status;
|
||||
struct timeval tv;
|
||||
static esp_http_client_config_t http_client_config;
|
||||
|
||||
|
||||
void _printMemStats(){
|
||||
ESP_LOGD(TAG,"Heap internal:%zu (min:%zu) external:%zu (min:%zu)",
|
||||
heap_caps_get_free_size(MALLOC_CAP_INTERNAL),
|
||||
@@ -276,8 +279,8 @@ esp_err_t _http_event_handler(esp_http_client_event_t *evt)
|
||||
// int data_len - data length of data
|
||||
// void *user_data -- user_data context, from esp_http_client_config_t user_data
|
||||
|
||||
// char *header_key For HTTP_EVENT_ON_HEADER event_id, it<69>s store current http header key
|
||||
// char *header_value For HTTP_EVENT_ON_HEADER event_id, it<69>s store current http header value
|
||||
// char *header_key For HTTP_EVENT_ON_HEADER event_id, it<69>s store current http header key
|
||||
// char *header_value For HTTP_EVENT_ON_HEADER event_id, it<69>s store current http header value
|
||||
// --------------
|
||||
switch (evt->event_id) {
|
||||
case HTTP_EVENT_ERROR:
|
||||
@@ -630,7 +633,7 @@ void ota_task(void *pvParameter)
|
||||
gettimeofday(&tv, NULL);
|
||||
uint32_t elapsed_ms= (tv.tv_sec-ota_status->OTA_start.tv_sec )*1000+(tv.tv_usec-ota_status->OTA_start.tv_usec)/1000;
|
||||
ESP_LOGI(TAG,"OTA progress : %d/%.0f (%d pct), %d KB/s", ota_status->actual_image_len, ota_status->total_image_len, ota_status->newpct, elapsed_ms>0?ota_status->actual_image_len*1000/elapsed_ms/1024:0);
|
||||
sendMessaging(MESSAGING_INFO,"Writing binary file %%%3d.",ota_status->newpct);
|
||||
sendMessaging(MESSAGING_INFO,"Writing binary file %3d %%.",ota_status->newpct);
|
||||
ota_status->lastpct=ota_status->newpct;
|
||||
}
|
||||
taskYIELD();
|
||||
@@ -659,7 +662,7 @@ void ota_task(void *pvParameter)
|
||||
ESP_LOGI(TAG,"OTA Process completed successfully!");
|
||||
sendMessaging(MESSAGING_INFO,"Success!");
|
||||
IF_DISPLAY(GDS_TextLine(display, 2, GDS_TEXT_LEFT, GDS_TEXT_CLEAR | GDS_TEXT_UPDATE, "Success!"));
|
||||
vTaskDelay(1500/ portTICK_PERIOD_MS); // wait here to give the UI a chance to refresh
|
||||
vTaskDelay(3500/ portTICK_PERIOD_MS); // wait here to give the UI a chance to refresh
|
||||
IF_DISPLAY(GDS_Clear(display,GDS_COLOR_BLACK));
|
||||
esp_restart();
|
||||
} else {
|
||||
@@ -721,5 +724,66 @@ esp_err_t process_recovery_ota(const char * bin_url, char * bin_buffer, uint32_t
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
extern void set_lms_server_details(in_addr_t ip, u16_t hport, u16_t cport);
|
||||
|
||||
in_addr_t discover_ota_server(int max) {
|
||||
struct sockaddr_in d;
|
||||
struct sockaddr_in s;
|
||||
char buf[32], port_d[] = "JSON", clip_d[] = "CLIP";
|
||||
struct pollfd pollinfo;
|
||||
uint8_t len;
|
||||
uint16_t hport=9000;
|
||||
uint16_t cport=9090;
|
||||
|
||||
int disc_sock = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
|
||||
socklen_t enable = 1;
|
||||
setsockopt(disc_sock, SOL_SOCKET, SO_BROADCAST, (const void *)&enable, sizeof(enable));
|
||||
|
||||
len = sprintf(buf,"e%s%c%s", port_d, '\0', clip_d) + 1;
|
||||
|
||||
memset(&d, 0, sizeof(d));
|
||||
d.sin_family = AF_INET;
|
||||
d.sin_port = htons(3483);
|
||||
d.sin_addr.s_addr = htonl(INADDR_BROADCAST);
|
||||
|
||||
pollinfo.fd = disc_sock;
|
||||
pollinfo.events = POLLIN;
|
||||
|
||||
do {
|
||||
|
||||
ESP_LOGI(TAG,"sending LMS discovery");
|
||||
memset(&s, 0, sizeof(s));
|
||||
|
||||
if (sendto(disc_sock, buf, len, 0, (struct sockaddr *)&d, sizeof(d)) < 0) {
|
||||
ESP_LOGE(TAG,"error sending discovery");
|
||||
}
|
||||
else {
|
||||
|
||||
if (poll(&pollinfo, 1, 5000) == 1) {
|
||||
char readbuf[64], *p;
|
||||
socklen_t slen = sizeof(s);
|
||||
memset(readbuf, 0, sizeof(readbuf));
|
||||
recvfrom(disc_sock, readbuf, sizeof(readbuf) - 1, 0, (struct sockaddr *)&s, &slen);
|
||||
ESP_LOGI(TAG,"got response from: %s:%d - %s", inet_ntoa(s.sin_addr), ntohs(s.sin_port),readbuf);
|
||||
|
||||
if ((p = strstr(readbuf, port_d)) != NULL) {
|
||||
p += strlen(port_d);
|
||||
hport = atoi(p + 1);
|
||||
}
|
||||
|
||||
if ((p = strstr(readbuf, clip_d)) != NULL) {
|
||||
p += strlen(clip_d);
|
||||
cport = atoi(p + 1);
|
||||
}
|
||||
server_notify(s.sin_addr.s_addr, hport, cport);
|
||||
}
|
||||
}
|
||||
|
||||
} while (s.sin_addr.s_addr == 0 && (!max || --max));
|
||||
|
||||
closesocket(disc_sock);
|
||||
|
||||
return s.sin_addr.s_addr;
|
||||
}
|
||||
|
||||
|
||||
@@ -31,4 +31,4 @@ const char * ota_get_status();
|
||||
uint8_t ota_get_pct_complete();
|
||||
|
||||
esp_err_t start_ota(const char * bin_url, char * bin_buffer, uint32_t length);
|
||||
|
||||
in_addr_t discover_ota_server(int max);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user