mirror of
https://github.com/espressif/esp-idf.git
synced 2026-06-13 04:32:16 +02:00
Compare commits
1282 Commits
master
...
release/v5.5
| Author | SHA1 | Date | |
|---|---|---|---|
| f1a1df9b2e | |||
| 3f3525ee14 | |||
| 729b28e6a8 | |||
| cd742a30ef | |||
| 31bae90a13 | |||
| 025e5f2d99 | |||
| 8ac60192dc | |||
| d4a52b13f2 | |||
| efa485be61 | |||
| 166e12ce30 | |||
| bf41c8045e | |||
| eee4837542 | |||
| 1a6bc9685a | |||
| a317db1622 | |||
| ea36c4f609 | |||
| f63e81c044 | |||
| 53a1c66d41 | |||
| b4854cab63 | |||
| fb8d0336ae | |||
| 193b5c92d1 | |||
| 71e14b5688 | |||
| 0be2fcb3f6 | |||
| 731ff4bcf7 | |||
| ccb8b960a3 | |||
| 944e2527d1 | |||
| 1688aa29e0 | |||
| 39b9662258 | |||
| 38694c3362 | |||
| 1e538c13b7 | |||
| 042f29dd66 | |||
| 4cc95c4a71 | |||
| df900f4b7b | |||
| b490bc0613 | |||
| cd793de75a | |||
| 181cd0bee9 | |||
| 126b8f8789 | |||
| 817dec8bbb | |||
| d28a8a0d11 | |||
| a5735b3252 | |||
| 65bd466f70 | |||
| f079a572f6 | |||
| 419e91d1d3 | |||
| e0d22a5c18 | |||
| 5652984db9 | |||
| 38917f3435 | |||
| a61f93b05c | |||
| 2ec0dc5ae8 | |||
| f4f4bce739 | |||
| 50d2ecd93f | |||
| 73d0dadd6b | |||
| 22fe84bf91 | |||
| 78737a757a | |||
| d49055e307 | |||
| 26014bb404 | |||
| 4aafa4d11b | |||
| 9e487873c9 | |||
| 12ab50dc54 | |||
| 508a659001 | |||
| 1815e2e4f2 | |||
| 0847a85040 | |||
| 9f9eebf9fc | |||
| 66e07dc78c | |||
| b9f704df74 | |||
| 2b53c3c2af | |||
| 55076fd3a6 | |||
| 05de8c44ec | |||
| 27b5c25fd4 | |||
| 41c25b9716 | |||
| 91a068076f | |||
| 799e347522 | |||
| e7dd48e800 | |||
| 5e481987ea | |||
| 082ba1450f | |||
| 8d17bf99c6 | |||
| 821ce86a09 | |||
| 86352f9d1f | |||
| 572bbf84f5 | |||
| 42e7e40f2f | |||
| b4e35f30be | |||
| e6d4eec507 | |||
| a6514c5ec1 | |||
| 819ab972a5 | |||
| 233ea11ab0 | |||
| 294abc6302 | |||
| fc2f26e957 | |||
| 7c29420e45 | |||
| 6ab5a2f883 | |||
| 175a6510f5 | |||
| bd0c21fef0 | |||
| 70a8b4d842 | |||
| d902072d80 | |||
| 067faa25c2 | |||
| 690e83d456 | |||
| 1f4e41d2ac | |||
| 83361447aa | |||
| c64b751c50 | |||
| a58bae6812 | |||
| c4aa4d47fc | |||
| 3c0e283930 | |||
| 6e6b88a587 | |||
| 45bb82af49 | |||
| dec62e60f4 | |||
| cfc05166c0 | |||
| cdeedc57b1 | |||
| fa5203de21 | |||
| 7d342d49f7 | |||
| c96d41d436 | |||
| ce66ed4309 | |||
| 3d7a2d32e3 | |||
| f83d1937a1 | |||
| 4d9b3c87a0 | |||
| 8c92cb3281 | |||
| 76823b60cf | |||
| 61d4f44293 | |||
| c3da9f070b | |||
| c5a8693174 | |||
| ca81e6fe5d | |||
| 0c733c2018 | |||
| efd5dbbe45 | |||
| 5dae61d817 | |||
| fab3655753 | |||
| 9664e406cc | |||
| 1e61bc53d3 | |||
| e9e7aaf54c | |||
| 594de5dd36 | |||
| ad608d254c | |||
| 4475b138af | |||
| b6017364cd | |||
| 7aee10fc67 | |||
| 2b533e88ce | |||
| ad73a70997 | |||
| e8ff0a5656 | |||
| 39fed94da5 | |||
| a378b52bbb | |||
| 8e82dab8da | |||
| f194e0d58d | |||
| b923cc34ab | |||
| 02b6df3653 | |||
| 70ee6ed7e8 | |||
| adf5b7fc91 | |||
| 69c31289ad | |||
| 93603cd3a3 | |||
| 13614adbda | |||
| 54de9c4aa5 | |||
| 5658200d25 | |||
| 3fd8a6e320 | |||
| 438e207e45 | |||
| 36dd0034ab | |||
| d5161cb2a0 | |||
| a4004031bd | |||
| 1a3e0ebc35 | |||
| 67003b5630 | |||
| f5edf57e9f | |||
| e2b2a4d841 | |||
| 07e9bf4970 | |||
| ad1aa5dbd4 | |||
| 9fd0d5dd1a | |||
| 80ab4fbea1 | |||
| fa86aac235 | |||
| 207ad3972e | |||
| f7bad9f0c3 | |||
| 3a6614bf8e | |||
| 445c732ff3 | |||
| f75e0a49d1 | |||
| 95d2e964b5 | |||
| 82ed0c7cd3 | |||
| 2f3eccd25a | |||
| 4009e8a5c2 | |||
| d14ce1f4ce | |||
| c3efac4608 | |||
| 71c3f70245 | |||
| 999710fccf | |||
| da21126583 | |||
| 7eec1cadf1 | |||
| 83de1aac60 | |||
| e1f5ff551b | |||
| e29891552c | |||
| f6fa885492 | |||
| f0b6e3e9d6 | |||
| cda5d90ad1 | |||
| b8bd070517 | |||
| 6b0796b2a4 | |||
| 965e2e47d4 | |||
| 636daf109c | |||
| e93f0e56b6 | |||
| 0313a369ea | |||
| e0a34a5253 | |||
| 45dafc0587 | |||
| da54e34dbb | |||
| 95da85651e | |||
| 4fcab14568 | |||
| e902243477 | |||
| 6ea055c1b9 | |||
| 7b9046c5a4 | |||
| e317af3c9e | |||
| b2bca25a98 | |||
| e5222e01ec | |||
| 26c3b0b83c | |||
| dd003fb051 | |||
| 0f2d8416b5 | |||
| 5d6573cf0c | |||
| bb027dafd7 | |||
| c2c23e620a | |||
| f37f57bbe1 | |||
| 5ca84429c9 | |||
| bfd84a6a0c | |||
| 7e25412983 | |||
| d2006c6399 | |||
| 9167dcc6b2 | |||
| bc288d999d | |||
| 0b7af82488 | |||
| 0854212af7 | |||
| 2f35b047b6 | |||
| e3dd190c25 | |||
| 56bef4d352 | |||
| 23ea610fa0 | |||
| ded0c3fec6 | |||
| eafff2552b | |||
| 5de4d2e3ba | |||
| 2d2ec6c34e | |||
| fa08f239c0 | |||
| 8a4f0c597a | |||
| 63312aa64d | |||
| 1970cc7a40 | |||
| 4014385d8d | |||
| cbbcae32c1 | |||
| 4ae8b7d993 | |||
| d625405ecb | |||
| d564f728ed | |||
| 42e7c93104 | |||
| 0d9afecc5c | |||
| b5dbc7f3a1 | |||
| d41e9bc280 | |||
| cdf8419103 | |||
| a2c5d88320 | |||
| 03450d3846 | |||
| b0e0b4ddb9 | |||
| bb9cdd61ce | |||
| 727224920c | |||
| bb70fdaa12 | |||
| dc4381d0b0 | |||
| 2d83b8f422 | |||
| 85d2c81f70 | |||
| 8e1b0c23a7 | |||
| 49bcc44e76 | |||
| 954e370bc0 | |||
| 67a511abc6 | |||
| bc5b61b56c | |||
| b2ec317d96 | |||
| a2206083c8 | |||
| 4b2b5d7baf | |||
| e9cae6c805 | |||
| e73cbacd10 | |||
| 9bcf41fa6e | |||
| 9c257c4f0b | |||
| b0713ffe08 | |||
| d8eae6c80d | |||
| 7538ae7052 | |||
| f1ac614c06 | |||
| 08b798afa5 | |||
| a0f071f7ff | |||
| c84e48ec6d | |||
| cc0efd88c0 | |||
| 6e2db679da | |||
| 6cd7f74877 | |||
| 3631cb1a38 | |||
| e0151944ff | |||
| ae7d7542e0 | |||
| b0ec8feaa1 | |||
| cfbbf271a8 | |||
| c09bb9fe46 | |||
| f0ab806e7e | |||
| 847ceb6301 | |||
| 9d01ecf71b | |||
| 5e7c32897f | |||
| 84ae3f8aec | |||
| 4a53e1f581 | |||
| ac0676d6c7 | |||
| a62dc1d4dd | |||
| 2550e531d1 | |||
| 0feebfce2c | |||
| 767014b382 | |||
| ee5f84e64d | |||
| 1c39449555 | |||
| e1694c6ade | |||
| 6b7d55aeba | |||
| ba4300c226 | |||
| e463a364cc | |||
| 4f52b6028e | |||
| c092365299 | |||
| e797515680 | |||
| e45ab3764f | |||
| 6961221d28 | |||
| 96118438da | |||
| c994c2203d | |||
| f69550bc4e | |||
| 00571fe874 | |||
| 326f10b89f | |||
| bf1fe556ee | |||
| b99c81ee93 | |||
| d64a453929 | |||
| 2982305b0d | |||
| ef35d002b1 | |||
| eef2fef386 | |||
| aa82f52273 | |||
| 7d73f5edc6 | |||
| b966e396d3 | |||
| d0ffafb71f | |||
| 55cd1f3cc9 | |||
| 7d8bed20f2 | |||
| ac38a274e5 | |||
| 742d38b051 | |||
| c59ec8a330 | |||
| 4066858f5c | |||
| af2d980f57 | |||
| 79834396ae | |||
| e9790c04fa | |||
| 317eda0d91 | |||
| 37385bf4d5 | |||
| 5665e9da8f | |||
| b55eab5faf | |||
| a511f3bebb | |||
| 6e7dab576f | |||
| d0872ec138 | |||
| b0918d7a25 | |||
| d3177152b3 | |||
| 9244d4b6cc | |||
| 6adb0e5fd4 | |||
| 9991b1f6e4 | |||
| a7dbebf9da | |||
| 87793a2a21 | |||
| 752e4e89c2 | |||
| 184f2a40e7 | |||
| d421c9963e | |||
| 3e9d20f6d5 | |||
| 37eaa4cc36 | |||
| 9f1603d8b8 | |||
| 52e9e02852 | |||
| 8f6e654773 | |||
| 129cd0d247 | |||
| 5306cddaec | |||
| fcae32885b | |||
| ca77450feb | |||
| 6049a4a1c2 | |||
| d544ed0d21 | |||
| 23628f149c | |||
| 19f91cfad9 | |||
| 88165f9735 | |||
| 1a2a5f4d5b | |||
| c9e4a1c382 | |||
| 7f4dd43626 | |||
| 92feb8c4f8 | |||
| d1b727b564 | |||
| 86a9b4ff9e | |||
| 955d842213 | |||
| 3b95b50703 | |||
| c8b67b732c | |||
| 191a231e37 | |||
| 84dac281cf | |||
| 9247fa00a3 | |||
| 1480e4077a | |||
| dae216df2f | |||
| be1687d8b9 | |||
| 7844d11734 | |||
| a2e44fffc8 | |||
| 9b99477852 | |||
| 109c028fa7 | |||
| 0eab2d88b8 | |||
| c2bb9881e6 | |||
| 76c3b8fcf3 | |||
| 50e3195472 | |||
| 80b26b6c2b | |||
| ae2b5af875 | |||
| ec71bd189f | |||
| 0ef3fb4961 | |||
| 5714153832 | |||
| 17a23d1ddb | |||
| 92df7573a4 | |||
| 492c534d49 | |||
| 8267f0a460 | |||
| 76f3aea6ea | |||
| 02c5f2dbb9 | |||
| 8fe3d573d2 | |||
| d20fb2604a | |||
| 12e1db7753 | |||
| bde461f09e | |||
| e90c50d66b | |||
| 1cd73de8d9 | |||
| 7b478f3ec8 | |||
| 4f8f9748f6 | |||
| 4213e41bbd | |||
| 0f07209abb | |||
| b26c24ac02 | |||
| 10d07d1a2b | |||
| 290a454500 | |||
| de8d13360a | |||
| 90856941bf | |||
| 389a1ab280 | |||
| 16a51184ee | |||
| eece7ee86b | |||
| cf5067b329 | |||
| e747988af0 | |||
| dc65aefb72 | |||
| 1af0fb257d | |||
| c32d337203 | |||
| b88cc1724f | |||
| 320041a560 | |||
| 272e652b45 | |||
| 590cb66669 | |||
| ee777b0387 | |||
| a3ca8669f2 | |||
| 2be55b580c | |||
| 333858e57b | |||
| 14dcf57fb1 | |||
| 9c2b36b0c1 | |||
| 91ef2747b6 | |||
| ad6904db25 | |||
| 335bfd874e | |||
| 511e970d07 | |||
| e1eae237a3 | |||
| 6891970c49 | |||
| 83ea01f61b | |||
| d9b99c42b3 | |||
| 723a926b26 | |||
| 22bec9eed7 | |||
| 9fa874b1ce | |||
| e159e69c56 | |||
| 733d68532e | |||
| ba376fa81c | |||
| 1b48a697c4 | |||
| f6f15bf91a | |||
| f941ce5f1b | |||
| ab60739814 | |||
| 2292bd6473 | |||
| 4571d2756a | |||
| 54534c8637 | |||
| 831a0e8193 | |||
| c726799df4 | |||
| 15b0ff3c2b | |||
| df8533a46e | |||
| 4eee831831 | |||
| a65a86cf54 | |||
| 29df7286c8 | |||
| 2829481eb6 | |||
| 27fee88e26 | |||
| 8f51e06ae3 | |||
| 1191f4c4f9 | |||
| 950ac4cff4 | |||
| 6d012bbefe | |||
| dbc243657d | |||
| 79ce2ccd07 | |||
| ccd0d369aa | |||
| d1f47fba23 | |||
| d5fc1a61fa | |||
| c3f0eceffa | |||
| d18a5f2ddc | |||
| 865fe36a1d | |||
| 65f0804deb | |||
| ceb11cd57e | |||
| a8721f74cf | |||
| 201b9178bd | |||
| 6acf4e3ae5 | |||
| 32b4723cb2 | |||
| de8e1c7c06 | |||
| 5a2c7b2180 | |||
| a33bff6773 | |||
| 521c7fb951 | |||
| 01481f08f9 | |||
| 942a9bfbe4 | |||
| 2795fae32c | |||
| c582193add | |||
| 388ffa8818 | |||
| 6a5a2fa92a | |||
| cafe454113 | |||
| ab6fdc801f | |||
| 7c17a0e1e8 | |||
| 2357ae7621 | |||
| fec78adc92 | |||
| 3132e50cc9 | |||
| 422c123124 | |||
| 87f45cb56a | |||
| 2ac79a842c | |||
| a1a9bf60ae | |||
| 2fa78fa42e | |||
| 43b5d206aa | |||
| 415a05a6a5 | |||
| a3a1b42577 | |||
| c011bcb0dc | |||
| c64d9bc3e3 | |||
| adfa52c442 | |||
| 250f248421 | |||
| 14ae516680 | |||
| 27452eac70 | |||
| 0f9ce655c6 | |||
| 6fd9c5414c | |||
| 27bd10f821 | |||
| 0be09bc38e | |||
| cd86b976f9 | |||
| 8a8d01565e | |||
| b543181384 | |||
| e5ccbe2e58 | |||
| ab1e547429 | |||
| 6c34b02356 | |||
| 995c2f38ee | |||
| 4ed18496c4 | |||
| aa4faf57ef | |||
| 148c36d8aa | |||
| 1f132a7460 | |||
| 7704a9e93e | |||
| f66e21cdfc | |||
| c8251d3800 | |||
| 160883a48f | |||
| 032b6d802d | |||
| 59af142586 | |||
| 5b05fe3495 | |||
| 7a317c8d17 | |||
| eb784e3021 | |||
| 6b6d193b36 | |||
| 49079d23b6 | |||
| 686af2df4f | |||
| c02e1edce4 | |||
| dafdf1205d | |||
| f0f7ec705e | |||
| 7bd5212e09 | |||
| 45c26fd5a4 | |||
| f997e42e56 | |||
| f365dbe2ac | |||
| 7b1c92d371 | |||
| c5893aac53 | |||
| 6e9fca80c8 | |||
| 3fcd7b1ba5 | |||
| 4d19e6be9c | |||
| 64e9fb0b88 | |||
| 050620c264 | |||
| 94ea741e2d | |||
| 1b6d3194d1 | |||
| 801c578926 | |||
| a59065d07c | |||
| 803a94f574 | |||
| 1665cac638 | |||
| cfe8d1fb66 | |||
| b28bc7aeae | |||
| 4b36b0a1ff | |||
| e18f17cc9f | |||
| 6deb6d9727 | |||
| 13c4f14bbc | |||
| 0421e10396 | |||
| 1a6798ee7b | |||
| 6428e942dd | |||
| f405d019a6 | |||
| a4e40465c9 | |||
| 0bab63a1f1 | |||
| 4275a70d61 | |||
| a063764468 | |||
| 6e7751482e | |||
| 92a09ce7f0 | |||
| d74a625d20 | |||
| 7bc929997e | |||
| 315cc8f503 | |||
| 360a813524 | |||
| 18ff6750cc | |||
| cff75e2960 | |||
| e6e0f672ec | |||
| e2929b78ef | |||
| a5bf227ff3 | |||
| 9da2594b68 | |||
| ac941daa4e | |||
| 4b46a16922 | |||
| 8f36e23cc4 | |||
| 731f11766c | |||
| c5383e2718 | |||
| e00fa1de52 | |||
| 5cf3be2eae | |||
| e95dfc2964 | |||
| 24ea9693ce | |||
| 7c757b7f45 | |||
| cc2147238b | |||
| b9d7aacd1d | |||
| 9316e840a7 | |||
| 8840072320 | |||
| 6041ee302d | |||
| 31a72abd57 | |||
| b5944c8f34 | |||
| 9c18324a72 | |||
| a49402e12c | |||
| 72c92aaebd | |||
| bc79dc06a3 | |||
| 268af25a10 | |||
| 7bde153d0a | |||
| 01f8074a3d | |||
| ff5fea1186 | |||
| 12393745c2 | |||
| 6a03c8ffee | |||
| 3d6423a251 | |||
| c473b3deee | |||
| 9822c6f199 | |||
| 96f11e01bf | |||
| 476f8f6f51 | |||
| 55f693d4dd | |||
| 1b3eb8f93e | |||
| ddbf8391d9 | |||
| d4a67c9957 | |||
| 96836ab1f3 | |||
| c930763a8a | |||
| db72fac86b | |||
| aa2c410b62 | |||
| 1bce41e63f | |||
| 33936f0064 | |||
| bad80d35ee | |||
| 05fd283bb5 | |||
| a69266ec8b | |||
| 7b6a6531a4 | |||
| 6896432dca | |||
| 61b0b072f9 | |||
| 05a22bfd80 | |||
| ae97379c9a | |||
| ff7830f45b | |||
| 947e79f03d | |||
| 6f4ec5f3a6 | |||
| e70bf20bba | |||
| 4b347bc75a | |||
| dbb5069423 | |||
| e313f56b30 | |||
| 6d5aa29358 | |||
| ad7c681583 | |||
| a091cb0046 | |||
| 957104bb31 | |||
| 28eee20b5b | |||
| f7d3562271 | |||
| 3fa646e58a | |||
| e34b8ecf8f | |||
| 7af79ac92c | |||
| 60d0aa3cb8 | |||
| 81c01383e7 | |||
| 9aa8a1674f | |||
| 1c0b86e00c | |||
| 6434f7f82e | |||
| c2c08767db | |||
| 1e8b07ecc6 | |||
| 9987ce610b | |||
| 62b9e1620d | |||
| c9f92e84a4 | |||
| 5faf1a0ceb | |||
| 75e4f8dbb4 | |||
| 8842c6577b | |||
| 2b1ce17ea6 | |||
| 1d3cd76432 | |||
| 9c0903a5e8 | |||
| aafabaf854 | |||
| e184fe297b | |||
| 479346ff1f | |||
| ad53477921 | |||
| 3e008eac89 | |||
| 6e6bea3967 | |||
| 06b9e8804f | |||
| 93b2cf899a | |||
| 5deab445d3 | |||
| 5a94539374 | |||
| 502b26e2cd | |||
| cc54f04f96 | |||
| 89f919a96f | |||
| 47917e7a01 | |||
| e30d7143ce | |||
| 0b87e896b0 | |||
| a8d4196a3b | |||
| 59274a818f | |||
| 5d946e6ec0 | |||
| e72ea712e7 | |||
| a33995c0e9 | |||
| 9c4aa443b0 | |||
| a002a04332 | |||
| 4272a54397 | |||
| 48336d423b | |||
| c93ef4ecd9 | |||
| 628ba3aa3c | |||
| c01e1a7153 | |||
| f4db15bc60 | |||
| 9b8e989a16 | |||
| 6ec881a5c7 | |||
| 67bf1e1bb8 | |||
| 2ae3455d12 | |||
| e9b7c632a6 | |||
| a519699588 | |||
| c4ac82fc3a | |||
| 8c21713e25 | |||
| 8657cb7fc5 | |||
| 4eb565defb | |||
| f8935bd088 | |||
| ee975ba05d | |||
| 97e07a01e3 | |||
| 050ca52e1c | |||
| f9ce2bf598 | |||
| e72a3de4b9 | |||
| 95e3ea8f50 | |||
| 8d0b576c1e | |||
| aea3d880d7 | |||
| 97e6f4ab0f | |||
| b410db2b63 | |||
| 9f523adfe9 | |||
| 210c667848 | |||
| dd511077e1 | |||
| adfb879541 | |||
| 0291ab0dfb | |||
| 32a7b6a30c | |||
| 6dcd234495 | |||
| 79d842dfa1 | |||
| ec5d4c5959 | |||
| 3a242eae01 | |||
| fddb9be1e3 | |||
| cff19bffbf | |||
| f1c646a3c5 | |||
| 7d9ee328d9 | |||
| 41cb6701ad | |||
| 813b67082a | |||
| 0f043029e8 | |||
| b8936385d3 | |||
| 0b0e7b23ff | |||
| 71eeea29bc | |||
| fa02f84c3e | |||
| b458016805 | |||
| c76d8c49ee | |||
| ff0afa250f | |||
| 536a807665 | |||
| c4d3791311 | |||
| 3e94cf120e | |||
| a18fb75839 | |||
| 5bfd50ca37 | |||
| a83147ddb0 | |||
| 08d1c5d696 | |||
| a5c374c88e | |||
| 350da2b11a | |||
| da257a9690 | |||
| 338dc154dc | |||
| 23aab0fda3 | |||
| c2e1405362 | |||
| 5ec370b75c | |||
| c25d78180d | |||
| a6b0f61822 | |||
| 415aae12c7 | |||
| 0ad62114a4 | |||
| 6c56c4d584 | |||
| 3b21679be9 | |||
| f794af38c2 | |||
| 4c38f2c864 | |||
| 307c3f0ee6 | |||
| 74ffc556cb | |||
| 696d65c7b4 | |||
| 9c2e03ba74 | |||
| f3d0418fc5 | |||
| 87e8895083 | |||
| bcd56c749b | |||
| 79aedfd229 | |||
| 5e1cb0fcaa | |||
| 05db51c485 | |||
| 31fd483c25 | |||
| 75848acbd9 | |||
| 2045b1206b | |||
| 031ed78aa1 | |||
| 1d9e3dfaf9 | |||
| 73bdf0acc8 | |||
| 66f5d2653b | |||
| e2d5f85804 | |||
| be8feb977f | |||
| cbf01d9e29 | |||
| 8b0ce97f4e | |||
| c168ca3fd7 | |||
| 8d5203d4ae | |||
| 4bb1ad7246 | |||
| 941d98710b | |||
| ebc3390df3 | |||
| 76a7dd5aa4 | |||
| 570ecdc1cc | |||
| 782ffe1a7a | |||
| 5c02c6fc1e | |||
| ae561069b0 | |||
| 784547465f | |||
| 589c8b82d9 | |||
| 3c39b32195 | |||
| b66b5448e0 | |||
| ae1914398a | |||
| 5ff3d1f32b | |||
| a42532c3d7 | |||
| 163db6a8a5 | |||
| 5f4eb68c79 | |||
| 8226972997 | |||
| 8c750b088c | |||
| 25c7c11970 | |||
| 280a2f9307 | |||
| 570bc5e02e | |||
| 94c643ba87 | |||
| 51b3ff46f9 | |||
| df57c2de6c | |||
| ab8770fe5a | |||
| 3d3731965c | |||
| b43b2001a2 | |||
| bf0c01434c | |||
| ddfb59657c | |||
| e67274f0ff | |||
| 7bed0d3937 | |||
| b8f555c16b | |||
| 34a7996314 | |||
| f7bd635a5a | |||
| 4ab1ec36ea | |||
| f6826dda7e | |||
| da2c5b1228 | |||
| 11bbb25dc4 | |||
| 67fe133b3c | |||
| b585ee174e | |||
| 4c4c954dd6 | |||
| bcdb78ab13 | |||
| 8755edfb3a | |||
| 8f6e0f4cc3 | |||
| 9f19124bd8 | |||
| 50fd0a7006 | |||
| ad8f2a7547 | |||
| 8317419aed | |||
| 915610e0b6 | |||
| 9a7bd0fb1a | |||
| 71fb89eb85 | |||
| 6104d8dfe0 | |||
| 665338d526 | |||
| d98d21423a | |||
| ccf23d3da7 | |||
| 1b98cf48b1 | |||
| 0582ee32dc | |||
| 557308bf3a | |||
| e9814452bc | |||
| 2157ab84e2 | |||
| e9f096a079 | |||
| 9e286cb5c3 | |||
| 8d2710c3b6 | |||
| 8f586ecfd9 | |||
| 6501cea942 | |||
| 1d0be054ec | |||
| be801fab66 | |||
| 83db5c722e | |||
| fe6be04970 | |||
| 3d99a1d8b1 | |||
| 5b0776ab2d | |||
| c33b69e073 | |||
| 26a592f8a2 | |||
| 79f8537eb2 | |||
| e8052de6b4 | |||
| c66052e5dd | |||
| 12191f266f | |||
| b7887b052e | |||
| a441cad4b7 | |||
| d5ff5d3f46 | |||
| 4451649760 | |||
| 66ddf66e64 | |||
| a3af8972ae | |||
| b124ac7455 | |||
| 3a9cce2a92 | |||
| 7a329d5e91 | |||
| ebaece4dff | |||
| 97888e2152 | |||
| 8588446859 | |||
| cf8dad0746 | |||
| 71956c72e0 | |||
| 577d650d83 | |||
| c844ba4f7f | |||
| 7cef1a5720 | |||
| fc7f5bed4c | |||
| 78c8434d4e | |||
| d7ac3c7c80 | |||
| b6d0a8a24e | |||
| 986a55c3d2 | |||
| c910986317 | |||
| c8c10214f8 | |||
| 1ad41e589f | |||
| 7905dad525 | |||
| 4035c8418a | |||
| 917755af70 | |||
| 7bb638c946 | |||
| ab5e48b026 | |||
| 0644f453be | |||
| 65d4e3f06f | |||
| 28fff33de3 | |||
| adb3f2a580 | |||
| d2299ef3c6 | |||
| aae5e12d77 | |||
| d468522078 | |||
| a6f092516a | |||
| 3fcb964577 | |||
| 9e1b2d1741 | |||
| dc5b3de0ea | |||
| f77271e701 | |||
| 58b5a76153 | |||
| 51c803915e | |||
| 43232d25d8 | |||
| 1ce5e59715 | |||
| df0243732f | |||
| e5d17a7f8e | |||
| af84a63d6b | |||
| f3579cee33 | |||
| a714eb84b5 | |||
| 7c79d6e663 | |||
| fbc18b2c1d | |||
| 39ea58f5a2 | |||
| 4e6f18cfe2 | |||
| da939fa729 | |||
| 359cc34720 | |||
| 68d4a55205 | |||
| a787505813 | |||
| 70bb876802 | |||
| 1b698f0997 | |||
| 4ef1493355 | |||
| 7d61ed7c51 | |||
| b9aedbb1c2 | |||
| 020941c943 | |||
| cbe9388f45 | |||
| 44eba53113 | |||
| 2a484d8b43 | |||
| 40a3b0cb23 | |||
| 52badb9186 | |||
| 1313fe8edc | |||
| 820a7fd21c | |||
| 70d12d61e9 | |||
| ccfb41895d | |||
| b710539e3f | |||
| a43ce166d5 | |||
| 1d9e0ac834 | |||
| a70fa7804e | |||
| d33e716a32 | |||
| dee75b97e2 | |||
| d46f3f8801 | |||
| bbb810e70b | |||
| 8521ce42c3 | |||
| b37d4b338c | |||
| 5986566708 | |||
| 20ec15edff | |||
| 60e884b438 | |||
| 589c2516c8 | |||
| 5210e576d5 | |||
| e7a76ff71e | |||
| 2bfeb41d90 | |||
| 8694f893ea | |||
| 5c6701aad0 | |||
| 278a26213d | |||
| b6dd6f1b93 | |||
| dd13871b8a | |||
| 4d06a6ec9d | |||
| 6cb9214520 | |||
| b62e55db0b | |||
| 8ac432ec0a | |||
| 6fd5f51432 | |||
| 0eb2407a26 | |||
| 85c77bdb82 | |||
| 391c39414e | |||
| df19d0421f | |||
| 5558a08c07 | |||
| 8aa235a9a5 | |||
| 9c61e31be4 | |||
| f0d7baae5e | |||
| 9189406b05 | |||
| 30c24b2f31 | |||
| 23bc0a51fb | |||
| 16985bfd3c | |||
| e454c9be2d | |||
| 4fd109860b | |||
| 88f234f1ef | |||
| 8b06985fdf | |||
| d43f18a278 | |||
| 6076037bd5 | |||
| 20d1fdec15 | |||
| e44e7ce2f9 | |||
| 06268a4efc | |||
| e1faf670b2 | |||
| 4684d3dffc | |||
| d8f3e05201 | |||
| 0104bcde1a | |||
| aac26c847e | |||
| 4a21060839 | |||
| 9671a5d3b0 | |||
| 2f3351f1a9 | |||
| 39ebd0b143 | |||
| cfe6cbaaa0 | |||
| c7990e649e | |||
| adc3a80381 | |||
| e0f7f4e539 | |||
| 42a3c9b024 | |||
| a468bbcadd | |||
| d0d04bd986 | |||
| 7b1cbb89e0 | |||
| e17993b175 | |||
| 36749445f4 | |||
| a644e9073e | |||
| 191a24cb6d | |||
| 24e323685a | |||
| 7bbaba909f | |||
| f7046307a5 | |||
| cd7c97e6eb | |||
| 624175fc01 | |||
| 8cf17632c2 | |||
| 9a74093e98 | |||
| fa889bf5b6 | |||
| c4747aae02 | |||
| 0ea73a9273 | |||
| 80d191e797 | |||
| ba0da6f2a6 | |||
| c943797004 | |||
| 1a40b106b4 | |||
| 10a210d08a | |||
| 56a4c70c31 | |||
| 5a04cfded1 | |||
| 3fe9252c3f | |||
| c837712306 | |||
| 80abd1c7e4 | |||
| 3da3f6f2e2 | |||
| 210f3a4e38 | |||
| a17bc0ef44 | |||
| 9ba46035c8 | |||
| f9e4d9504e | |||
| 472baa7525 | |||
| 8d7aefa890 | |||
| ef71aad834 | |||
| 73058bfca0 | |||
| d5323cfaaa | |||
| 6e82c7a061 | |||
| 6cf1a6f297 | |||
| 95b7c023da | |||
| f4669e3377 | |||
| 7e28275ac1 | |||
| da534bf462 | |||
| 59434db045 | |||
| 2e7a9174fc | |||
| fc77b58ced | |||
| 770052e859 | |||
| 71f83ca625 | |||
| 156ead0cd5 | |||
| 5555ef7425 | |||
| 4b93bde59b | |||
| 04f5e591c0 | |||
| 2d5d7b819f | |||
| 908ff6e5df | |||
| 0dd5b0b979 | |||
| e536aa670b | |||
| 1df4f13b2e | |||
| bb72c42611 | |||
| d8fa0886b0 | |||
| 08d78dcd7e | |||
| 849c74b2b9 | |||
| e32bd2502d | |||
| 666f3db1a3 | |||
| 79da851a4c | |||
| 3f8da22ae0 | |||
| f523943972 | |||
| fc71a8643e | |||
| 0e585a2994 | |||
| f5be149eb2 | |||
| ccef14fad2 | |||
| bb8338b17a | |||
| 53534bc5ce | |||
| ace361e7e1 | |||
| ec2f1c0023 | |||
| 5584880376 | |||
| ebdafe8e0c | |||
| addc2101dc | |||
| 6078213bcd | |||
| 4869e83855 | |||
| 37f017585d | |||
| 8f57d672d2 | |||
| 881c5a9795 | |||
| 2e760d374e | |||
| e22c523b55 | |||
| 7c2734dc02 | |||
| 9e7325a3d6 | |||
| 29ba5469ef | |||
| 20d66da972 | |||
| 4c3d086c13 | |||
| d0e0c188fb | |||
| 19b0d6c13c | |||
| e9e995bd0a | |||
| 7914e75525 | |||
| c2f551d87a | |||
| 90b3d29223 | |||
| 30d77f494e | |||
| 7557ec0951 | |||
| e29823cfe0 | |||
| f0a4d73ea1 | |||
| 22aeb00462 | |||
| fd3178eb6b | |||
| 7cf59adc0c | |||
| 96b43c9797 | |||
| 168808248d | |||
| fc72303490 | |||
| 6b74032d2e | |||
| 39c6c703b1 | |||
| ce09a8c037 | |||
| 370ac37623 | |||
| 98cd765953 | |||
| 73747da716 | |||
| 18b6997e32 | |||
| 693a5393b2 | |||
| 23892d857a | |||
| 087727a693 | |||
| 49b5cc9e50 | |||
| 33c71ea033 | |||
| 5961670d06 | |||
| 07ae83249a | |||
| fa75a4dd67 | |||
| b002e50857 | |||
| f19263a97c | |||
| 7f8290e911 | |||
| 0170c56e04 | |||
| 7b66ed489f | |||
| 35876be5e6 | |||
| e2b524c609 | |||
| 30859ceaff | |||
| 99e5203d89 | |||
| c48b74805f | |||
| a2cd564044 | |||
| ad5d36257b | |||
| 52e3d9bb5f | |||
| d881dda91c | |||
| ecb5fc3075 | |||
| cd1601f408 | |||
| 4d83f1b8af | |||
| 0fe8891e3a | |||
| b1a379d574 | |||
| 84973428b2 | |||
| 41a17b71ad | |||
| 253ca4267a | |||
| 60ab2598c5 | |||
| b9c586ebd1 | |||
| 3d09da9251 | |||
| fddf34d7b0 | |||
| 2e761da92a | |||
| b045635cea | |||
| 3b596bb602 | |||
| 45fed1d225 | |||
| d7216d221b | |||
| 80c5fd1836 | |||
| b3843ea09a | |||
| 6687749fae | |||
| 2b0c548593 | |||
| 59496b4927 | |||
| b977a13796 | |||
| 0a3cc83a86 | |||
| d5d713cff2 | |||
| 80c92bae34 | |||
| 0904640409 | |||
| b0f107b69a | |||
| 1c81d11ec3 | |||
| 059a675e5c | |||
| 4c7a13b570 | |||
| 5be9ac3d93 | |||
| e100fc790c | |||
| a73197e886 | |||
| 9e0c4d226a | |||
| 68dd2c9a3c | |||
| 3d3b7caf95 | |||
| 0e59feac9d | |||
| c0f77d8993 | |||
| 3092578b4a | |||
| fafc25b8b9 | |||
| e7c8f555e7 | |||
| 5f71d958c3 | |||
| e26be2be8f | |||
| e8475d7796 | |||
| 31149354a9 | |||
| 833df30063 | |||
| 1cc377a373 | |||
| a74197c552 | |||
| d482206483 | |||
| 27496e47f0 | |||
| eca7c7296c | |||
| 039cc1ac80 | |||
| ee3baa4ca7 | |||
| ba70c7f3d1 | |||
| c5b725fc50 | |||
| 10a690fe10 | |||
| 758da73338 | |||
| 27b85137c7 | |||
| 06ee44ef46 | |||
| f4add076a8 | |||
| 5e6ecd81b5 | |||
| 45fb5fb793 | |||
| 63f72f659d | |||
| 7910ea8571 | |||
| 7f46f6152e | |||
| 5da8865f9b | |||
| c771e4508e | |||
| 375d675cdc | |||
| 2252a4166a | |||
| 1f4fbd060c | |||
| f97fd7490f | |||
| dbfb663b66 | |||
| 429183de1e | |||
| 1ba8abd8b7 | |||
| 5b1588e0db | |||
| 3ded40b276 | |||
| a6db9d402f | |||
| 693dfe6b0e | |||
| d738d889d8 | |||
| ce340fcce7 | |||
| b1218adfae | |||
| aff86ba14b | |||
| c85c74f54b | |||
| 0778748506 | |||
| 8a54378b95 | |||
| 43ff2531ab | |||
| a3edce572a | |||
| 4aa47aacc3 | |||
| 379f4de500 | |||
| 048d03e94d | |||
| 29520e982c | |||
| 527e2f38b8 | |||
| 9cf4ddf797 | |||
| 3052ad53e7 | |||
| 1adbeceb27 | |||
| d1c131f649 | |||
| 7b52c11661 | |||
| 5bb83afac7 | |||
| 669e677ba3 | |||
| 1909105acf | |||
| afcb8199b0 | |||
| 0a17f79cc7 | |||
| de17b6ff94 | |||
| 046479c23f | |||
| 79d2bedbf9 | |||
| 6514df1ba9 | |||
| 692f7df5aa | |||
| f6cb4422db | |||
| 60adcc5980 | |||
| a544a33131 | |||
| 4f56bba225 | |||
| 5273ba9731 | |||
| eb0cf524c0 | |||
| 6ba1a3a427 | |||
| f9597a06f4 | |||
| f056662cd5 | |||
| e1aee3ff2b | |||
| 2e02c26b81 | |||
| f5748f3d9b | |||
| 8a138cbd22 | |||
| c18e53b672 | |||
| 28ac0243bb | |||
| c61f36de13 | |||
| 6fdcf9efc1 | |||
| a652a8473e | |||
| 6f82f332fd | |||
| b095331a51 | |||
| 084dfefd6f | |||
| 04d83433c3 | |||
| dd1a331f4f | |||
| 0f7b621d47 | |||
| 72ae023a42 | |||
| 84e62daedc | |||
| 0d5d31b343 | |||
| 05617e458b | |||
| f8284e1733 | |||
| b9e03c3cf4 | |||
| 4498eea285 | |||
| af9e528409 | |||
| d35923141d | |||
| 81f5d899f6 | |||
| 2eac57a1da | |||
| 2fd71413f0 | |||
| b8badb85d1 | |||
| f8cdf02b55 | |||
| ac12d560a2 | |||
| 18cd0fa030 | |||
| 269f1d110d | |||
| f03b0fe0c5 | |||
| a0fc3e68a8 | |||
| 0993f1e67b | |||
| 45831351fa | |||
| 37e28522c2 | |||
| 8ea6b3170b | |||
| 2de265b3e7 | |||
| 953fe222ec | |||
| 70f19793f8 | |||
| 0b2f639c62 | |||
| a3cb7f4404 | |||
| b264d7f89b | |||
| 14c29c467e | |||
| 3b7f4e2341 | |||
| 3a6e5dba88 | |||
| 27e1a30acc | |||
| c0d91e33d0 | |||
| a4d0ab04c5 |
@@ -8,10 +8,11 @@ on:
|
||||
jobs:
|
||||
release_zips:
|
||||
name: Create release zip file
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Create a recursive clone source zip
|
||||
uses: espressif/github-actions/release_zips@master
|
||||
env:
|
||||
RELEASE_PROJECT_NAME: ESP-IDF
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
uses: espressif/release-zips-action@v1
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
release_project_name: ESP-IDF
|
||||
git_extra_args: --shallow-since="1 year ago"
|
||||
|
||||
+1
-249
@@ -2,253 +2,5 @@
|
||||
#
|
||||
# https://docs.gitlab.com/ee/user/project/code_owners.html#the-syntax-of-code-owners-files
|
||||
#
|
||||
# If more than one rule matches a given file, the latest rule is used.
|
||||
# The file should be generally kept sorted, except when it is necessary
|
||||
# to use a different order due to the fact above. In that case, use
|
||||
# '# sort-order-reset' comment line to reset the sort order.
|
||||
#
|
||||
# Recipes for a few common cases:
|
||||
#
|
||||
# 1. Specific directory with all its contents:
|
||||
#
|
||||
# /components/app_trace/
|
||||
#
|
||||
# Note the trailing slash!
|
||||
#
|
||||
# 2. File with certain extension in any subdirectory of a certain directory:
|
||||
#
|
||||
# /examples/**/*.py
|
||||
#
|
||||
# This includes an *.py files in /examples/ directory as well.
|
||||
#
|
||||
# 3. Contents of a directory with a certain name, anywhere in the tree:
|
||||
#
|
||||
# test_*_host/
|
||||
#
|
||||
# Will match everything under components/efuse/test_efuse_host/,
|
||||
# components/heap/test_multi_heap_host/, components/lwip/test_afl_host/, etc.
|
||||
#
|
||||
# 4. Same as above, except limited to a specific place in the tree:
|
||||
#
|
||||
# /components/esp32*/
|
||||
#
|
||||
# Matches everything under /components/esp32, /components/esp32s2, etc.
|
||||
# Doesn't match /tools/some-test/components/esp32s5.
|
||||
#
|
||||
# 5. Specific file:
|
||||
#
|
||||
# /tools/tools.json
|
||||
#
|
||||
# 6. File with a certain name anywhere in the tree
|
||||
#
|
||||
# .gitignore
|
||||
#
|
||||
|
||||
* @esp-idf-codeowners/other
|
||||
|
||||
/.* @esp-idf-codeowners/tools
|
||||
/.codespellrc @esp-idf-codeowners/ci
|
||||
/.github/workflows/ @esp-idf-codeowners/ci
|
||||
/.gitlab-ci.yml @esp-idf-codeowners/ci
|
||||
/.gitlab/ci/ @esp-idf-codeowners/ci
|
||||
/.pre-commit-config.yaml @esp-idf-codeowners/ci
|
||||
/.readthedocs.yml @esp-idf-codeowners/docs
|
||||
/.vale.ini @esp-idf-codeowners/docs
|
||||
/CMakeLists.txt @esp-idf-codeowners/build-config
|
||||
/COMPATIBILITY*.md @esp-idf-codeowners/peripherals
|
||||
/CONTRIBUTING.md @esp-idf-codeowners/docs
|
||||
/Kconfig @esp-idf-codeowners/build-config
|
||||
/README*.md @esp-idf-codeowners/docs
|
||||
/ROADMAP*.md @esp-idf-codeowners/docs
|
||||
/SUPPORT_POLICY*.md @esp-idf-codeowners/docs
|
||||
/add_path.sh @esp-idf-codeowners/tools
|
||||
/conftest.py @esp-idf-codeowners/ci
|
||||
/export.* @esp-idf-codeowners/tools
|
||||
/install.* @esp-idf-codeowners/tools
|
||||
/pytest.ini @esp-idf-codeowners/ci
|
||||
/ruff.toml @esp-idf-codeowners/tools
|
||||
/sdkconfig.rename @esp-idf-codeowners/build-config
|
||||
/sonar-project.properties @esp-idf-codeowners/ci
|
||||
|
||||
# sort-order-reset
|
||||
|
||||
/components/app_trace/ @esp-idf-codeowners/debugging
|
||||
/components/app_update/ @esp-idf-codeowners/system @esp-idf-codeowners/app-utilities
|
||||
/components/bootloader*/ @esp-idf-codeowners/system @esp-idf-codeowners/security
|
||||
/components/bootloader_support/bootloader_flash/ @esp-idf-codeowners/peripherals
|
||||
/components/bt/ @esp-idf-codeowners/bluetooth
|
||||
/components/cmock/ @esp-idf-codeowners/system
|
||||
/components/console/ @esp-idf-codeowners/system @esp-idf-codeowners/app-utilities/console
|
||||
/components/cxx/ @esp-idf-codeowners/system
|
||||
/components/driver/ @esp-idf-codeowners/peripherals
|
||||
/components/efuse/ @esp-idf-codeowners/system
|
||||
/components/esp_adc/ @esp-idf-codeowners/peripherals
|
||||
/components/esp_app_format/ @esp-idf-codeowners/system @esp-idf-codeowners/app-utilities
|
||||
/components/esp_bootloader_format/ @esp-idf-codeowners/system @esp-idf-codeowners/app-utilities
|
||||
/components/esp_coex/ @esp-idf-codeowners/wifi @esp-idf-codeowners/bluetooth @esp-idf-codeowners/ieee802154
|
||||
/components/esp_common/ @esp-idf-codeowners/system
|
||||
/components/esp_driver_*/ @esp-idf-codeowners/peripherals
|
||||
/components/esp_driver_sdmmc/ @esp-idf-codeowners/peripherals @esp-idf-codeowners/storage
|
||||
/components/esp_eth/ @esp-idf-codeowners/network
|
||||
/components/esp_event/ @esp-idf-codeowners/system
|
||||
/components/esp_gdbstub/ @esp-idf-codeowners/debugging
|
||||
/components/esp_hid/ @esp-idf-codeowners/bluetooth
|
||||
/components/esp_http_client/ @esp-idf-codeowners/app-utilities
|
||||
/components/esp_http_server/ @esp-idf-codeowners/app-utilities
|
||||
/components/esp_https_ota/ @esp-idf-codeowners/app-utilities
|
||||
/components/esp_https_server/ @esp-idf-codeowners/app-utilities
|
||||
/components/esp_hw_support/ @esp-idf-codeowners/system @esp-idf-codeowners/peripherals
|
||||
/components/esp_hw_support/lowpower/ @esp-idf-codeowners/power-management
|
||||
/components/esp_lcd/ @esp-idf-codeowners/peripherals
|
||||
/components/esp_local_ctrl/ @esp-idf-codeowners/app-utilities
|
||||
/components/esp_mm/ @esp-idf-codeowners/peripherals
|
||||
/components/esp_netif/ @esp-idf-codeowners/network
|
||||
/components/esp_netif_stack/ @esp-idf-codeowners/network
|
||||
/components/esp_partition/ @esp-idf-codeowners/storage
|
||||
/components/esp_phy/ @esp-idf-codeowners/bluetooth @esp-idf-codeowners/wifi @esp-idf-codeowners/ieee802154
|
||||
/components/esp_pm/ @esp-idf-codeowners/power-management @esp-idf-codeowners/bluetooth @esp-idf-codeowners/wifi @esp-idf-codeowners/system
|
||||
/components/esp_psram/ @esp-idf-codeowners/peripherals
|
||||
/components/esp_psram/system_layer/ @esp-idf-codeowners/peripherals @esp-idf-codeowners/system
|
||||
/components/esp_ringbuf/ @esp-idf-codeowners/system
|
||||
/components/esp_rom/ @esp-idf-codeowners/system @esp-idf-codeowners/bluetooth @esp-idf-codeowners/wifi
|
||||
/components/esp_security/ @esp-idf-codeowners/security
|
||||
/components/esp_system/ @esp-idf-codeowners/system
|
||||
/components/esp_tee/ @esp-idf-codeowners/security
|
||||
/components/esp_timer/ @esp-idf-codeowners/system
|
||||
/components/esp-tls/ @esp-idf-codeowners/app-utilities
|
||||
/components/esp_vfs_*/ @esp-idf-codeowners/storage
|
||||
/components/esp_vfs_console/ @esp-idf-codeowners/storage @esp-idf-codeowners/system
|
||||
/components/esp_wifi/ @esp-idf-codeowners/wifi
|
||||
/components/espcoredump/ @esp-idf-codeowners/debugging
|
||||
/components/esptool_py/ @esp-idf-codeowners/tools
|
||||
/components/fatfs/ @esp-idf-codeowners/storage
|
||||
/components/freertos/ @esp-idf-codeowners/system
|
||||
/components/hal/ @esp-idf-codeowners/peripherals
|
||||
/components/hal/test_apps/crypto/ @esp-idf-codeowners/peripherals @esp-idf-codeowners/security
|
||||
/components/heap/ @esp-idf-codeowners/system
|
||||
/components/http_parser/ @esp-idf-codeowners/app-utilities
|
||||
/components/idf_test/ @esp-idf-codeowners/peripherals @esp-idf-codeowners/system
|
||||
/components/ieee802154/ @esp-idf-codeowners/ieee802154
|
||||
/components/json/ @esp-idf-codeowners/app-utilities
|
||||
/components/linux/ @esp-idf-codeowners/system
|
||||
/components/log/ @esp-idf-codeowners/system
|
||||
/components/lwip/ @esp-idf-codeowners/lwip
|
||||
/components/mbedtls/ @esp-idf-codeowners/app-utilities/mbedtls @esp-idf-codeowners/security
|
||||
/components/mqtt/ @esp-idf-codeowners/network
|
||||
/components/newlib/ @esp-idf-codeowners/system @esp-idf-codeowners/toolchain
|
||||
/components/nvs_flash/ @esp-idf-codeowners/storage
|
||||
/components/nvs_sec_provider/ @esp-idf-codeowners/storage @esp-idf-codeowners/security
|
||||
/components/openthread/ @esp-idf-codeowners/ieee802154
|
||||
/components/partition_table/ @esp-idf-codeowners/system
|
||||
/components/perfmon/ @esp-idf-codeowners/debugging
|
||||
/components/protobuf-c/ @esp-idf-codeowners/app-utilities
|
||||
/components/protocomm/ @esp-idf-codeowners/app-utilities/provisioning
|
||||
/components/pthread/ @esp-idf-codeowners/system
|
||||
/components/riscv/ @esp-idf-codeowners/system
|
||||
/components/rt/ @esp-idf-codeowners/system
|
||||
/components/sdmmc/ @esp-idf-codeowners/storage
|
||||
/components/soc/ @esp-idf-codeowners/peripherals @esp-idf-codeowners/system
|
||||
/components/spi_flash/ @esp-idf-codeowners/peripherals
|
||||
/components/spiffs/ @esp-idf-codeowners/storage
|
||||
/components/tcp_transport/ @esp-idf-codeowners/network
|
||||
/components/touch_element/ @esp-idf-codeowners/peripherals
|
||||
/components/ulp/ @esp-idf-codeowners/system
|
||||
/components/unity/ @esp-idf-codeowners/peripherals @esp-idf-codeowners/system
|
||||
/components/usb/ @esp-idf-codeowners/peripherals/usb
|
||||
/components/vfs/ @esp-idf-codeowners/storage
|
||||
/components/wear_levelling/ @esp-idf-codeowners/storage
|
||||
/components/wifi_provisioning/ @esp-idf-codeowners/app-utilities/provisioning
|
||||
/components/wpa_supplicant/ @esp-idf-codeowners/wifi @esp-idf-codeowners/app-utilities/mbedtls
|
||||
/components/xtensa/ @esp-idf-codeowners/system
|
||||
|
||||
/docs/ @esp-idf-codeowners/docs
|
||||
/docs/docs_not_updated/ @esp-idf-codeowners/all-maintainers
|
||||
/docs/**/api-guides/tools/ @esp-idf-codeowners/tools
|
||||
/docs/en/api-guides/core_dump.rst @esp-idf-codeowners/debugging
|
||||
/docs/**/api-guides/wifi* @esp-idf-codeowners/wifi
|
||||
/docs/**/api-guides/esp-wifi-mesh.rst @esp-idf-codeowners/wifi
|
||||
/docs/en/api-guides/jtag-debugging/ @esp-idf-codeowners/debugging
|
||||
/docs/**/api-reference/bluetooth/ @esp-idf-codeowners/bluetooth
|
||||
/docs/**/api-reference/network/ @esp-idf-codeowners/network @esp-idf-codeowners/wifi
|
||||
/docs/**/api-reference/peripherals/ @esp-idf-codeowners/peripherals
|
||||
/docs/**/api-reference/peripherals/usb* @esp-idf-codeowners/peripherals @esp-idf-codeowners/peripherals/usb
|
||||
/docs/**/api-reference/peripherals/usb*/ @esp-idf-codeowners/peripherals @esp-idf-codeowners/peripherals/usb
|
||||
/docs/**/api-reference/protocols/ @esp-idf-codeowners/network @esp-idf-codeowners/app-utilities
|
||||
/docs/**/api-reference/provisioning/ @esp-idf-codeowners/app-utilities/provisioning
|
||||
/docs/**/api-reference/storage/ @esp-idf-codeowners/storage
|
||||
/docs/**/api-reference/system/ @esp-idf-codeowners/system
|
||||
/docs/**/security/ @esp-idf-codeowners/security
|
||||
/docs/**/migration-guides/ @esp-idf-codeowners/docs @esp-idf-codeowners/all-maintainers
|
||||
/docs/**/contribute/install-pre-commit-hook.rst @esp-idf-codeowners/ci @esp-idf-codeowners/tools
|
||||
|
||||
/examples/README.md @esp-idf-codeowners/docs @esp-idf-codeowners/ci
|
||||
/examples/**/*.py @esp-idf-codeowners/ci @esp-idf-codeowners/tools
|
||||
/examples/bluetooth/ @esp-idf-codeowners/bluetooth
|
||||
/examples/build_system/ @esp-idf-codeowners/build-config
|
||||
/examples/common_components/ @esp-idf-codeowners/system @esp-idf-codeowners/wifi @esp-idf-codeowners/lwip @esp-idf-codeowners/network
|
||||
/examples/custom_bootloader/ @esp-idf-codeowners/system
|
||||
/examples/cxx/ @esp-idf-codeowners/system
|
||||
/examples/ethernet/ @esp-idf-codeowners/network
|
||||
/examples/get-started/ @esp-idf-codeowners/system
|
||||
/examples/ieee802154/ @esp-idf-codeowners/ieee802154
|
||||
/examples/lowpower/ @esp-idf-codeowners/power-management @esp-idf-codeowners/system
|
||||
/examples/mesh/ @esp-idf-codeowners/wifi
|
||||
/examples/network/ @esp-idf-codeowners/network @esp-idf-codeowners/wifi
|
||||
/examples/openthread/ @esp-idf-codeowners/ieee802154
|
||||
/examples/peripherals/ @esp-idf-codeowners/peripherals
|
||||
/examples/peripherals/usb/ @esp-idf-codeowners/peripherals @esp-idf-codeowners/peripherals/usb
|
||||
/examples/phy/ @esp-idf-codeowners/bluetooth @esp-idf-codeowners/wifi @esp-idf-codeowners/ieee802154
|
||||
/examples/protocols/ @esp-idf-codeowners/network @esp-idf-codeowners/app-utilities
|
||||
/examples/provisioning/ @esp-idf-codeowners/app-utilities/provisioning
|
||||
/examples/security/ @esp-idf-codeowners/security
|
||||
/examples/storage/ @esp-idf-codeowners/storage
|
||||
/examples/system/ @esp-idf-codeowners/system
|
||||
/examples/system/ota/ @esp-idf-codeowners/app-utilities
|
||||
/examples/wifi/ @esp-idf-codeowners/wifi
|
||||
/examples/zigbee/ @esp-idf-codeowners/ieee802154
|
||||
|
||||
/tools/ @esp-idf-codeowners/tools
|
||||
/tools/ble/ @esp-idf-codeowners/app-utilities
|
||||
/tools/bt/ @esp-idf-codeowners/bluetooth
|
||||
/tools/catch/ @esp-idf-codeowners/ci
|
||||
/tools/ci/ @esp-idf-codeowners/ci
|
||||
/tools/cmake/ @esp-idf-codeowners/build-config
|
||||
/tools/cmake/toolchain-*.cmake @esp-idf-codeowners/toolchain
|
||||
/tools/esp_app_trace/ @esp-idf-codeowners/debugging
|
||||
/tools/esp_prov/ @esp-idf-codeowners/app-utilities
|
||||
/tools/gdb_panic_server.py @esp-idf-codeowners/debugging
|
||||
/tools/kconfig*/ @esp-idf-codeowners/build-config
|
||||
/tools/ldgen/ @esp-idf-codeowners/build-config
|
||||
/tools/mass_mfg/ @esp-idf-codeowners/app-utilities
|
||||
/tools/mocks/ @esp-idf-codeowners/system
|
||||
|
||||
/tools/test_apps/ @esp-idf-codeowners/ci
|
||||
/tools/test_apps/README.md @esp-idf-codeowners/docs @esp-idf-codeowners/ci
|
||||
|
||||
## Note: owners here should be the same as the owners for the same example subdir, above
|
||||
/tools/test_apps/build_system/ @esp-idf-codeowners/build-config
|
||||
/tools/test_apps/configs/ @esp-idf-codeowners/system
|
||||
/tools/test_apps/linux_compatible/ @esp-idf-codeowners/system
|
||||
/tools/test_apps/peripherals/ @esp-idf-codeowners/peripherals
|
||||
/tools/test_apps/phy/ @esp-idf-codeowners/bluetooth @esp-idf-codeowners/wifi @esp-idf-codeowners/ieee802154
|
||||
/tools/test_apps/protocols/ @esp-idf-codeowners/network @esp-idf-codeowners/app-utilities
|
||||
/tools/test_apps/security/ @esp-idf-codeowners/security
|
||||
/tools/test_apps/storage/ @esp-idf-codeowners/storage
|
||||
/tools/test_apps/system/ @esp-idf-codeowners/system
|
||||
|
||||
/tools/test_apps/**/*.py @esp-idf-codeowners/ci @esp-idf-codeowners/tools
|
||||
|
||||
/tools/test_build_system/ @esp-idf-codeowners/tools @esp-idf-codeowners/build-config
|
||||
|
||||
/tools/tools.json @esp-idf-codeowners/tools @esp-idf-codeowners/toolchain @esp-idf-codeowners/debugging
|
||||
|
||||
/tools/unit-test-app/ @esp-idf-codeowners/system @esp-idf-codeowners/tools
|
||||
|
||||
# sort-order-reset
|
||||
|
||||
/components/**/test_apps/**/*.py @esp-idf-codeowners/ci @esp-idf-codeowners/tools
|
||||
|
||||
# ignore lists
|
||||
/tools/ci/check_copyright_config.yaml @esp-idf-codeowners/all-maintainers
|
||||
/tools/ci/check_copyright_ignore.txt @esp-idf-codeowners/all-maintainers
|
||||
/tools/ci/mypy_ignore_list.txt @esp-idf-codeowners/tools
|
||||
* @esp-idf-codeowners/all-maintainers
|
||||
|
||||
@@ -237,7 +237,7 @@ pytest_build_system_macos:
|
||||
PYENV_VERSION: "3.9"
|
||||
# CCACHE_DIR: "/cache/idf_ccache". On macOS, you cannot write to this folder due to insufficient permissions.
|
||||
CCACHE_DIR: "" # ccache will use "$HOME/Library/Caches/ccache".
|
||||
CCACHE_MAXSIZE: "5G" # To preserve the limited Macbook storage. CCACHE automatically prunes old caches to fit the set limit.
|
||||
|
||||
build_docker:
|
||||
extends:
|
||||
- .before_script:minimal
|
||||
@@ -245,17 +245,11 @@ build_docker:
|
||||
stage: host_test
|
||||
needs: []
|
||||
image: espressif/docker-builder:1
|
||||
tags:
|
||||
- build_docker_amd64_brno
|
||||
tags: [shiny, dind]
|
||||
variables:
|
||||
DOCKER_TMP_IMAGE_NAME: "idf_tmp_image"
|
||||
script:
|
||||
- export LOCAL_CI_REPOSITORY_URL=$CI_REPOSITORY_URL
|
||||
- if [ -n "$LOCAL_GITLAB_HTTPS_HOST" ]; then export LOCAL_CI_REPOSITORY_URL="https://gitlab-ci-token:${CI_JOB_TOKEN}@${LOCAL_GITLAB_HTTPS_HOST}/${CI_PROJECT_PATH}"; fi
|
||||
- if [ -n "$LOCAL_GIT_MIRROR" ]; then export LOCAL_CI_REPOSITORY_URL="${LOCAL_GIT_MIRROR}/${CI_PROJECT_PATH}"; fi
|
||||
- echo "Using repository at $LOCAL_CI_REPOSITORY_URL"
|
||||
- export DOCKER_BUILD_ARGS="--build-arg IDF_CLONE_URL=${LOCAL_CI_REPOSITORY_URL} --build-arg IDF_CLONE_BRANCH_OR_TAG=${CI_COMMIT_REF_NAME} --build-arg IDF_CHECKOUT_REF=${CI_COMMIT_TAG:-$PIPELINE_COMMIT_SHA}"
|
||||
# Build
|
||||
- export DOCKER_BUILD_ARGS="--build-arg IDF_CLONE_URL=${CI_REPOSITORY_URL} --build-arg IDF_CLONE_BRANCH_OR_TAG=${CI_COMMIT_REF_NAME} --build-arg IDF_CHECKOUT_REF=${CI_COMMIT_TAG:-$CI_COMMIT_SHA} --build-arg IDF_CLONE_SHALLOW=1 --build-arg IDF_GITHUB_ASSETS=${INTERNAL_GITHUB_ASSETS}"
|
||||
- docker build --tag ${DOCKER_TMP_IMAGE_NAME} ${DOCKER_BUILD_ARGS} tools/docker/
|
||||
# We can't mount $PWD/examples/get-started/blink into the container, see https://gitlab.com/gitlab-org/gitlab-ce/issues/41227.
|
||||
# The workaround mentioned there works, but leaves around directories which need to be cleaned up manually.
|
||||
|
||||
+17
-9
@@ -40,7 +40,7 @@ variables:
|
||||
GIT_FETCH_EXTRA_FLAGS: "--no-recurse-submodules --prune --prune-tags"
|
||||
# we're using .cache folder for caches
|
||||
GIT_CLEAN_FLAGS: -ffdx -e .cache/
|
||||
LATEST_GIT_TAG: v5.5-dev
|
||||
LATEST_GIT_TAG: v5.5.1
|
||||
|
||||
SUBMODULE_FETCH_TOOL: "tools/ci/ci_fetch_submodule.py"
|
||||
# by default we will fetch all submodules
|
||||
@@ -56,7 +56,7 @@ variables:
|
||||
|
||||
# Docker images
|
||||
ESP_ENV_IMAGE: "${CI_DOCKER_REGISTRY}/esp-env-v5.5:3"
|
||||
ESP_IDF_DOC_ENV_IMAGE: "${CI_DOCKER_REGISTRY}/esp-idf-doc-env-v5.5:2-1"
|
||||
ESP_IDF_DOC_ENV_IMAGE: "${CI_DOCKER_REGISTRY}/esp-idf-doc-env-v5.5:3-1"
|
||||
TARGET_TEST_ENV_IMAGE: "${CI_DOCKER_REGISTRY}/target-test-env-v5.5:2"
|
||||
SONARQUBE_SCANNER_IMAGE: "${CI_DOCKER_REGISTRY}/sonarqube-scanner:5"
|
||||
PRE_COMMIT_IMAGE: "${CI_DOCKER_REGISTRY}/esp-idf-pre-commit:1"
|
||||
@@ -191,13 +191,21 @@ variables:
|
||||
fi
|
||||
|
||||
# Custom OpenOCD
|
||||
if [[ ! -z "$OOCD_DISTRO_URL" && "$CI_JOB_STAGE" == "target_test" ]]; then
|
||||
echo "Using custom OpenOCD from ${OOCD_DISTRO_URL}"
|
||||
wget $OOCD_DISTRO_URL
|
||||
ARCH_NAME=$(basename $OOCD_DISTRO_URL)
|
||||
tar -x -f $ARCH_NAME
|
||||
export OPENOCD_SCRIPTS=$PWD/openocd-esp32/share/openocd/scripts
|
||||
export PATH=$PWD/openocd-esp32/bin:$PATH
|
||||
if [[ "$CI_JOB_STAGE" == "target_test" ]]; then
|
||||
machine="$(uname -m)"
|
||||
if [[ "$machine" == "armv7l" ]] ; then
|
||||
OOCD_DISTRO_URL="$OOCD_DISTRO_URL_ARMHF"
|
||||
elif [[ "$machine" == "aarch64" ]] ; then
|
||||
OOCD_DISTRO_URL="$OOCD_DISTRO_URL_ARM64"
|
||||
fi
|
||||
if [[ ! -z "$OOCD_DISTRO_URL" ]]; then
|
||||
echo "Using custom OpenOCD from ${OOCD_DISTRO_URL}"
|
||||
wget $OOCD_DISTRO_URL
|
||||
ARCH_NAME=$(basename $OOCD_DISTRO_URL)
|
||||
tar -x -f $ARCH_NAME
|
||||
export OPENOCD_SCRIPTS=$PWD/openocd-esp32/share/openocd/scripts
|
||||
export PATH=$PWD/openocd-esp32/bin:$PATH
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ -n "$CI_PYTHON_TOOL_REPO" ]]; then
|
||||
|
||||
@@ -19,6 +19,7 @@ check_submodule_sync:
|
||||
dependencies: []
|
||||
script:
|
||||
- git submodule deinit --force .
|
||||
- rm -rf .git/modules # remove all the cached metadata
|
||||
# setting the default remote URL to the public one, to resolve relative location URLs
|
||||
- git config remote.origin.url ${PUBLIC_IDF_URL}
|
||||
# check if all submodules are correctly synced to public repository
|
||||
|
||||
@@ -113,7 +113,8 @@ test_cli_installer:
|
||||
script:
|
||||
# Tools must be downloaded for testing
|
||||
# We could use "idf_tools.py download all", but we don't want to install clang because of its huge size
|
||||
- python3 ${IDF_PATH}/tools/idf_tools.py download required qemu-riscv32 qemu-xtensa cmake
|
||||
# cmake@version that is supported
|
||||
- python3 ${IDF_PATH}/tools/idf_tools.py download required qemu-riscv32 qemu-xtensa cmake cmake@3.16.3
|
||||
- cd ${IDF_PATH}/tools/test_idf_tools
|
||||
- python3 -m pip install jsonschema
|
||||
- python3 ./test_idf_tools.py -v
|
||||
|
||||
@@ -165,6 +165,8 @@ pipeline_variables:
|
||||
if [ -n "$CI_PYTHON_CONSTRAINT_BRANCH" ]; then
|
||||
echo "BUILD_AND_TEST_ALL_APPS=1" >> pipeline.env
|
||||
fi
|
||||
- echo "OOCD_DISTRO_URL_ARMHF=$OOCD_DISTRO_URL_ARMHF" >> pipeline.env
|
||||
- echo "OOCD_DISTRO_URL_ARM64=$OOCD_DISTRO_URL_ARM64" >> pipeline.env
|
||||
- python tools/ci/ci_process_description.py
|
||||
- cat pipeline.env
|
||||
- python tools/ci/artifacts_handler.py upload --type modified_files_and_components_report
|
||||
|
||||
+11
-2
@@ -14,10 +14,17 @@
|
||||
- job: upload-submodules-cache
|
||||
optional: true
|
||||
artifacts: false
|
||||
before_script: []
|
||||
variables:
|
||||
GIT_STRATEGY: fetch # use brew local mirror first
|
||||
before_script:
|
||||
- if ($env:IDF_DONT_USE_MIRRORS) {
|
||||
$env:IDF_MIRROR_PREFIX_MAP = ""
|
||||
}
|
||||
after_script: []
|
||||
|
||||
test_cli_installer_win:
|
||||
rules:
|
||||
- when: never
|
||||
extends:
|
||||
- .host_test_win_template
|
||||
- .rules:labels:windows_pytest_build_system
|
||||
@@ -30,9 +37,11 @@ test_cli_installer_win:
|
||||
variables:
|
||||
IDF_PATH: "$CI_PROJECT_DIR"
|
||||
timeout: 3h
|
||||
allow_failure: true
|
||||
script:
|
||||
# Tools must be downloaded for testing
|
||||
- python ${IDF_PATH}\tools\idf_tools.py download required qemu-riscv32 qemu-xtensa cmake
|
||||
# cmake@version that is supported
|
||||
- python ${IDF_PATH}\tools\idf_tools.py download required qemu-riscv32 qemu-xtensa cmake cmake@3.16.3
|
||||
- cd ${IDF_PATH}\tools\test_idf_tools
|
||||
- python -m pip install jsonschema
|
||||
- python .\test_idf_tools.py
|
||||
|
||||
+3
-3
@@ -49,13 +49,13 @@
|
||||
[submodule "components/json/cJSON"]
|
||||
path = components/json/cJSON
|
||||
url = ../../DaveGamble/cJSON.git
|
||||
sbom-version = 1.7.18
|
||||
sbom-version = 1.7.19
|
||||
sbom-cpe = cpe:2.3:a:cjson_project:cjson:{}:*:*:*:*:*:*:*
|
||||
sbom-cpe = cpe:2.3:a:davegamble:cjson:{}:*:*:*:*:*:*:*
|
||||
sbom-supplier = Person: Dave Gamble
|
||||
sbom-url = https://github.com/DaveGamble/cJSON
|
||||
sbom-description = Ultralightweight JSON parser in ANSI C
|
||||
sbom-hash = acc76239bee01d8e9c858ae2cab296704e52d916
|
||||
sbom-cve-exclude-list = CVE-2024-31755 Resolved in v1.7.18
|
||||
sbom-hash = c859b25da02955fef659d658b8f324b5cde87be3
|
||||
|
||||
[submodule "components/mbedtls/mbedtls"]
|
||||
path = components/mbedtls/mbedtls
|
||||
|
||||
@@ -51,7 +51,8 @@ repos:
|
||||
.*.pb-c.c|
|
||||
.*.yuv|
|
||||
.*.rgb|
|
||||
.*COPYING.*
|
||||
.*COPYING.*|
|
||||
docs/sphinx-known-warnings\.txt
|
||||
)$
|
||||
- id: end-of-file-fixer
|
||||
exclude: *whitespace_excludes
|
||||
@@ -69,6 +70,7 @@ repos:
|
||||
rev: v2.3.0
|
||||
hooks:
|
||||
- id: codespell
|
||||
exclude: ^docs/sphinx-known-warnings\.txt$
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: check-executables
|
||||
|
||||
@@ -233,7 +233,7 @@ mainmenu "Espressif IoT Development Framework Configuration"
|
||||
|
||||
CONFIG_APP_BUILD_TYPE_RAM=y
|
||||
CONFIG_VFS_SUPPORT_TERMIOS=
|
||||
CONFIG_NEWLIB_NANO_FORMAT=y
|
||||
CONFIG_LIBC_NEWLIB_NANO_FORMAT=y
|
||||
CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT=y
|
||||
CONFIG_ESP_DEBUG_STUBS_ENABLE=
|
||||
CONFIG_ESP_ERR_TO_NAME_LOOKUP=
|
||||
|
||||
@@ -15,18 +15,18 @@ ESP-IDF is the development framework for Espressif SoCs supported on Windows, Li
|
||||
|
||||
The following table shows ESP-IDF support of Espressif SoCs where ![alt text][preview] and ![alt text][supported] denote preview status and support, respectively. The preview support is usually limited in time and intended for beta versions of chips. Please use an ESP-IDF release where the desired SoC is already supported.
|
||||
|
||||
|Chip | v5.0 | v5.1 | v5.2 | v5.3 | v5.4 | |
|
||||
|:----------- | :---------------------:| :--------------------: | :--------------------: | :--------------------: | :--------------------: |:------------------------------------------------------------------- |
|
||||
|ESP32 | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | |
|
||||
|ESP32-S2 | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | |
|
||||
|ESP32-C3 | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | |
|
||||
|ESP32-S3 | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] |[Announcement](https://www.espressif.com/en/news/ESP32_S3) |
|
||||
|ESP32-C2 | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] |[Announcement](https://www.espressif.com/en/news/ESP32-C2) |
|
||||
|ESP32-C6 | | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] |[Announcement](https://www.espressif.com/en/news/ESP32_C6) |
|
||||
|ESP32-H2 | | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] |[Announcement](https://www.espressif.com/en/news/ESP32_H2) |
|
||||
|ESP32-P4 | | | | ![alt text][supported] | ![alt text][supported] |[Announcement](https://www.espressif.com/en/news/ESP32-P4) |
|
||||
|ESP32-C5 | | | | | ![alt text][preview] |[Announcement](https://www.espressif.com/en/news/ESP32-C5) |
|
||||
|ESP32-C61 | | | | | ![alt text][preview] |[Announcement](https://www.espressif.com/en/products/socs/esp32-c61) |
|
||||
|Chip | v5.1 | v5.2 | v5.3 | v5.4 | v5.5 | |
|
||||
|:----------- |:--------------------: | :--------------------: | :--------------------: | :--------------------: | :--------------------: |:------------------------------------------------------------------- |
|
||||
|ESP32 | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | |
|
||||
|ESP32-S2 |![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | |
|
||||
|ESP32-C3 | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | |
|
||||
|ESP32-S3 | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] |[Announcement](https://www.espressif.com/en/news/ESP32_S3) |
|
||||
|ESP32-C2 | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] |[Announcement](https://www.espressif.com/en/news/ESP32-C2) |
|
||||
|ESP32-C6 | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] |[Announcement](https://www.espressif.com/en/news/ESP32_C6) |
|
||||
|ESP32-H2 |![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] |[Announcement](https://www.espressif.com/en/news/ESP32_H2) |
|
||||
|ESP32-P4 | | | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] |[Announcement](https://www.espressif.com/en/news/ESP32-P4) |
|
||||
|ESP32-C5 | | | | |![alt text][supported] |since v5.5.1, [Announcement](https://www.espressif.com/en/news/ESP32-C5) |
|
||||
|ESP32-C61 | | | | |![alt text][supported] |since v5.5.1, [Announcement](https://www.espressif.com/en/products/socs/esp32-c61) |
|
||||
|
||||
[supported]: https://img.shields.io/badge/-supported-green "supported"
|
||||
[preview]: https://img.shields.io/badge/-preview-orange "preview"
|
||||
|
||||
+13
-12
@@ -15,18 +15,19 @@ ESP-IDF 是乐鑫官方推出的物联网开发框架,支持 Windows、Linux
|
||||
|
||||
下表总结了乐鑫芯片在 ESP-IDF 各版本中的支持状态,其中 ![alt text][supported] 代表已支持,![alt text][preview] 代表目前处于预览支持状态。预览支持状态通常有时间限制,而且仅适用于测试版芯片。请确保使用与芯片相匹配的 ESP-IDF 版本。
|
||||
|
||||
|芯片 | v5.0 | v5.1 | v5.2 | v5.3 | v5.4 | |
|
||||
|:----------- | :---------------------:| :--------------------: | :--------------------: | :--------------------: | :--------------------: | :------------------------------------------------------------------------ |
|
||||
|ESP32 | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | |
|
||||
|ESP32-S2 | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | |
|
||||
|ESP32-C3 | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | |
|
||||
|ESP32-S3 | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | [芯片发布公告](https://www.espressif.com/zh-hans/news/ESP32_S3) |
|
||||
|ESP32-C2 | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | [芯片发布公告](https://www.espressif.com/zh-hans/news/ESP32-C2) |
|
||||
|ESP32-C6 | | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | [芯片发布公告](https://www.espressif.com/zh-hans/news/ESP32_C6) |
|
||||
|ESP32-H2 | | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | [芯片发布公告](https://www.espressif.com/zh-hans/news/ESP32_H2) |
|
||||
|ESP32-P4 | | | | ![alt text][supported] | ![alt text][supported] | [芯片发布公告](https://www.espressif.com/zh-hans/news/ESP32-P4) |
|
||||
|ESP32-C5 | | | | | ![alt text][preview] | [芯片发布公告](https://www.espressif.com/zh-hans/news/ESP32-C5) |
|
||||
|ESP32-C61 | | | | | ![alt text][preview] | [芯片发布公告](https://www.espressif.com/zh-hans/products/socs/esp32-c61) |
|
||||
芯片 | v5.1 | v5.2 | v5.3 | v5.4 | v5.5 | |
|
||||
|:----------- | :--------------------: | :--------------------: | :--------------------: | :--------------------: | :--------------------: |:------------------------------------------------------------------------ |
|
||||
|ESP32 |![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] |![alt text][supported] | |
|
||||
|ESP32-S2 |![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | |
|
||||
|ESP32-C3 |![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | |
|
||||
|ESP32-S3 |![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] |![alt text][supported] | [芯片发布公告](https://www.espressif.com/zh-hans/news/ESP32_S3) |
|
||||
|ESP32-C2 |![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] |![alt text][supported] | [芯片发布公告](https://www.espressif.com/zh-hans/news/ESP32-C2) |
|
||||
|ESP32-C6 |![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] |![alt text][supported] | [芯片发布公告](https://www.espressif.com/zh-hans/news/ESP32_C6) |
|
||||
|ESP32-H2 |![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] |![alt text][supported] | [芯片发布公告](https://www.espressif.com/zh-hans/news/ESP32_H2) |
|
||||
|ESP32-P4 | | | ![alt text][supported] | ![alt text][supported] |![alt text][supported] | [芯片发布公告](https://www.espressif.com/zh-hans/news/ESP32-P4) |
|
||||
|ESP32-C5 | | | | |![alt text][supported] | 自 v5.5.1 开始,[芯片发布公告](https://www.espressif.com/zh-hans/news/ESP32-C5) |
|
||||
|ESP32-C61 | | | | |![alt text][supported] | 自 v5.5.1 开始,[芯片发布公告](https://www.espressif.com/zh-hans/products/socs/esp32-c61) |
|
||||
|
||||
|
||||
[supported]: https://img.shields.io/badge/-%E6%94%AF%E6%8C%81-green "supported"
|
||||
[preview]: https://img.shields.io/badge/-%E9%A2%84%E8%A7%88-orange "preview"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*/
|
||||
@@ -92,7 +92,7 @@ static esp_err_t esp_apptrace_membufs_swap(esp_apptrace_membufs_proto_data_t *pr
|
||||
// switch to new block
|
||||
proto->state.in_block++;
|
||||
|
||||
proto->hw->swap(new_block_num);
|
||||
proto->hw->swap(new_block_num, proto->state.markers[prev_block_num]);
|
||||
|
||||
// handle data from host
|
||||
esp_hostdata_hdr_t *hdr = (esp_hostdata_hdr_t *)proto->blocks[new_block_num].start;
|
||||
@@ -148,6 +148,18 @@ static esp_err_t esp_apptrace_membufs_swap_waitus(esp_apptrace_membufs_proto_dat
|
||||
if (res != ESP_OK) {
|
||||
break;
|
||||
}
|
||||
#if CONFIG_IDF_TARGET_ESP32S3
|
||||
/*
|
||||
* ESP32S3 has a serious data corruption issue with the transferred data to host.
|
||||
* This delay helps reduce the failure rate by temporarily reducing heavy memory writes
|
||||
* from RTOS-level tracing and giving OpenOCD more time to read trace memory before
|
||||
* the current thread continues execution. While this doesn't completely prevent
|
||||
* memory access from other threads/cores/ISRs, it has shown to significantly improve
|
||||
* reliability when combined with CRC checks in OpenOCD. In practice, this reduces the
|
||||
* number of retries needed to read an entire block without corruption.
|
||||
*/
|
||||
esp_rom_delay_us(100);
|
||||
#endif
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@@ -339,7 +351,7 @@ uint8_t *esp_apptrace_membufs_up_buffer_get(esp_apptrace_membufs_proto_data_t *p
|
||||
esp_err_t esp_apptrace_membufs_up_buffer_put(esp_apptrace_membufs_proto_data_t *proto, uint8_t *ptr, esp_apptrace_tmo_t *tmo)
|
||||
{
|
||||
esp_apptrace_membufs_pkt_end(ptr);
|
||||
// TODO: mark block as busy in order not to re-use it for other tracing calls until it is completely written
|
||||
// TODO: mark block as busy in order not to reuse it for other tracing calls until it is completely written
|
||||
// TODO: avoid potential situation when all memory is consumed by low prio tasks which can not complete writing due to
|
||||
// higher prio tasks and the latter can not allocate buffers at all
|
||||
// this is abnormal situation can be detected on host which will receive only uncompleted buffers
|
||||
|
||||
@@ -50,7 +50,7 @@ static uint8_t *esp_apptrace_riscv_down_buffer_get(esp_apptrace_riscv_data_t *hw
|
||||
static esp_err_t esp_apptrace_riscv_down_buffer_put(esp_apptrace_riscv_data_t *hw_data, uint8_t *ptr, esp_apptrace_tmo_t *tmo);
|
||||
static bool esp_apptrace_riscv_host_is_connected(esp_apptrace_riscv_data_t *hw_data);
|
||||
static esp_err_t esp_apptrace_riscv_buffer_swap_start(uint32_t curr_block_id);
|
||||
static esp_err_t esp_apptrace_riscv_buffer_swap(uint32_t new_block_id);
|
||||
static esp_err_t esp_apptrace_riscv_buffer_swap(uint32_t new_block_id, uint32_t prev_block_len);
|
||||
static esp_err_t esp_apptrace_riscv_buffer_swap_end(uint32_t new_block_id, uint32_t prev_block_len);
|
||||
static bool esp_apptrace_riscv_host_data_pending(void);
|
||||
|
||||
@@ -353,7 +353,7 @@ static esp_err_t esp_apptrace_riscv_buffer_swap_end(uint32_t new_block_id, uint3
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t esp_apptrace_riscv_buffer_swap(uint32_t new_block_id)
|
||||
static esp_err_t esp_apptrace_riscv_buffer_swap(uint32_t new_block_id, uint32_t prev_block_len)
|
||||
{
|
||||
/* do nothing */
|
||||
return ESP_OK;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*/
|
||||
@@ -12,7 +12,7 @@
|
||||
// ======================
|
||||
|
||||
// Xtensa has useful feature: TRAX debug module. It allows recording program execution flow at run-time without disturbing CPU.
|
||||
// Exectution flow data are written to configurable Trace RAM block. Besides accessing Trace RAM itself TRAX module also allows to read/write
|
||||
// Execution flow data are written to configurable Trace RAM block. Besides accessing Trace RAM itself TRAX module also allows to read/write
|
||||
// trace memory via its registers by means of JTAG, APB or ERI transactions.
|
||||
// ESP32 has two Xtensa cores with separate TRAX modules on them and provides two special memory regions to be used as trace memory.
|
||||
// Chip allows muxing access to those trace memory blocks in such a way that while one block is accessed by CPUs another one can be accessed by host
|
||||
@@ -47,7 +47,7 @@
|
||||
// 2. TRAX Registers layout
|
||||
// ========================
|
||||
|
||||
// This module uses two TRAX HW registers to communicate with host SW (OpenOCD).
|
||||
// This module uses two TRAX HW registers and one Performance Monitor register to communicate with host SW (OpenOCD).
|
||||
// - Control register uses TRAX_DELAYCNT as storage. Only lower 24 bits of TRAX_DELAYCNT are writable. Control register has the following bitfields:
|
||||
// | 31..XXXXXX..24 | 23 .(host_connect). 23| 22..(block_id)..15 | 14..(block_len)..0 |
|
||||
// 14..0 bits - actual length of user data in trace memory block. Target updates it every time it fills memory block and exposes it to host.
|
||||
@@ -55,9 +55,15 @@
|
||||
// 21..15 bits - trace memory block transfer ID. Block counter. It can overflow. Updated by target, host should not modify it. Actually can be 2 bits;
|
||||
// 22 bit - 'host data present' flag. If set to one there is data from host, otherwise - no host data;
|
||||
// 23 bit - 'host connected' flag. If zero then host is not connected and tracing module works in post-mortem mode, otherwise in streaming mode;
|
||||
// - Status register uses TRAX_TRIGGERPC as storage. If this register is not zero then current CPU is changing TRAX registers and
|
||||
// this register holds address of the instruction which application will execute when it finishes with those registers modifications.
|
||||
// See 'Targets Connection' setion for details.
|
||||
// - Status register uses TRAX_TRIGGERPC as storage. If this register is not zero then current CPU is changing TRAX registers and
|
||||
// this register holds address of the instruction which application will execute when it finishes with those registers modifications.
|
||||
// See 'Targets Connection' section for details.
|
||||
// - CRC16 register uses ERI_PERFMON_PM1 as storage. This register is used to store CRC16 checksum of the exposed trace memory block.
|
||||
// The register has the following format:
|
||||
// | 31..16 (CRC indicator) | 15..0 (CRC16 value) |
|
||||
// CRC indicator (0xA55A) is used to distinguish valid CRC values from other data that might be in the register.
|
||||
// CRC16 is calculated over the entire exposed block and is updated every time a block is exposed to the host.
|
||||
// This allows the host to verify data integrity of the received trace data.
|
||||
|
||||
// 3. Modes of operation
|
||||
// =====================
|
||||
@@ -127,7 +133,7 @@
|
||||
|
||||
// Access to internal module's data is synchronized with custom mutex. Mutex is a wrapper for portMUX_TYPE and uses almost the same sync mechanism as in
|
||||
// vPortCPUAcquireMutex/vPortCPUReleaseMutex. The mechanism uses S32C1I Xtensa instruction to implement exclusive access to module's data from tasks and
|
||||
// ISRs running on both cores. Also custom mutex allows specifying timeout for locking operation. Locking routine checks underlaying mutex in cycle until
|
||||
// ISRs running on both cores. Also custom mutex allows specifying timeout for locking operation. Locking routine checks underlying mutex in cycle until
|
||||
// it gets its ownership or timeout expires. The differences of application tracing module's mutex implementation from vPortCPUAcquireMutex/vPortCPUReleaseMutex are:
|
||||
// - Support for timeouts.
|
||||
// - Local IRQs for CPU which owns the mutex are disabled till the call to unlocking routine. This is made to avoid possible task's prio inversion.
|
||||
@@ -142,9 +148,9 @@
|
||||
|
||||
// Timeout mechanism is based on xthal_get_ccount() routine and supports timeout values in microseconds.
|
||||
// There are two situations when task/ISR can be delayed by tracing API call. Timeout mechanism takes into account both conditions:
|
||||
// - Trace data are locked by another task/ISR. When wating on trace data lock.
|
||||
// - Trace data are locked by another task/ISR. When waiting on trace data lock.
|
||||
// - Current TRAX memory input block is full when working in streaming mode (host is connected). When waiting for host to complete previous block reading.
|
||||
// When wating for any of above conditions xthal_get_ccount() is called periodically to calculate time elapsed from trace API routine entry. When elapsed
|
||||
// When waiting for any of above conditions xthal_get_ccount() is called periodically to calculate time elapsed from trace API routine entry. When elapsed
|
||||
// time exceeds specified timeout value operation is canceled and ESP_ERR_TIMEOUT code is returned.
|
||||
#include "sdkconfig.h"
|
||||
#include "soc/soc.h"
|
||||
@@ -159,11 +165,15 @@
|
||||
#include "esp_log.h"
|
||||
#include "esp_app_trace_membufs_proto.h"
|
||||
#include "esp_app_trace_port.h"
|
||||
#include "esp_rom_crc.h"
|
||||
|
||||
// TRAX is disabled, so we use its registers for our own purposes
|
||||
// | 31..XXXXXX..24 | 23 .(host_connect). 23 | 22 .(host_data). 22| 21..(block_id)..15 | 14..(block_len)..0 |
|
||||
#define ESP_APPTRACE_TRAX_CTRL_REG ERI_TRAX_DELAYCNT
|
||||
#define ESP_APPTRACE_TRAX_STAT_REG ERI_TRAX_TRIGGERPC
|
||||
#define ESP_APPTRACE_TRAX_CRC16_REG ERI_PERFMON_PM1
|
||||
|
||||
#define ESP_APPTRACE_CRC_INDICATOR (0xA55AU << 16)
|
||||
|
||||
#define ESP_APPTRACE_TRAX_BLOCK_LEN_MSK 0x7FFFUL
|
||||
#define ESP_APPTRACE_TRAX_BLOCK_LEN(_l_) ((_l_) & ESP_APPTRACE_TRAX_BLOCK_LEN_MSK)
|
||||
@@ -198,7 +208,7 @@ static uint8_t *esp_apptrace_trax_down_buffer_get(esp_apptrace_trax_data_t *hw_d
|
||||
static esp_err_t esp_apptrace_trax_down_buffer_put(esp_apptrace_trax_data_t *hw_data, uint8_t *ptr, esp_apptrace_tmo_t *tmo);
|
||||
static bool esp_apptrace_trax_host_is_connected(esp_apptrace_trax_data_t *hw_data);
|
||||
static esp_err_t esp_apptrace_trax_buffer_swap_start(uint32_t curr_block_id);
|
||||
static esp_err_t esp_apptrace_trax_buffer_swap(uint32_t new_block_id);
|
||||
static esp_err_t esp_apptrace_trax_buffer_swap(uint32_t new_block_id, uint32_t prev_block_len);
|
||||
static esp_err_t esp_apptrace_trax_buffer_swap_end(uint32_t new_block_id, uint32_t prev_block_len);
|
||||
static bool esp_apptrace_trax_host_data_pending(void);
|
||||
|
||||
@@ -498,7 +508,8 @@ static esp_err_t esp_apptrace_trax_buffer_swap_start(uint32_t curr_block_id)
|
||||
uint32_t acked_block = ESP_APPTRACE_TRAX_BLOCK_ID_GET(ctrl_reg);
|
||||
uint32_t host_to_read = ESP_APPTRACE_TRAX_BLOCK_LEN_GET(ctrl_reg);
|
||||
if (host_to_read != 0 || acked_block != (curr_block_id & ESP_APPTRACE_TRAX_BLOCK_ID_MSK)) {
|
||||
ESP_APPTRACE_LOGD("HC[%d]: Can not switch %" PRIx32 " %" PRIu32 " %" PRIx32 " %" PRIx32 "/%" PRIx32, esp_cpu_get_core_id(), ctrl_reg, host_to_read, acked_block,
|
||||
ESP_APPTRACE_LOGD("HC[%d]: Can not switch %" PRIx32 " %" PRIu32 " %" PRIx32 " %" PRIx32 "/%" PRIx32,
|
||||
esp_cpu_get_core_id(), ctrl_reg, host_to_read, acked_block,
|
||||
curr_block_id & ESP_APPTRACE_TRAX_BLOCK_ID_MSK, curr_block_id);
|
||||
res = ESP_ERR_NO_MEM;
|
||||
goto _on_err;
|
||||
@@ -514,14 +525,22 @@ static esp_err_t esp_apptrace_trax_buffer_swap_end(uint32_t new_block_id, uint32
|
||||
{
|
||||
uint32_t ctrl_reg = eri_read(ESP_APPTRACE_TRAX_CTRL_REG);
|
||||
uint32_t host_connected = ESP_APPTRACE_TRAX_HOST_CONNECT & ctrl_reg;
|
||||
|
||||
eri_write(ESP_APPTRACE_TRAX_CTRL_REG, ESP_APPTRACE_TRAX_BLOCK_ID(new_block_id) |
|
||||
host_connected | ESP_APPTRACE_TRAX_BLOCK_LEN(prev_block_len));
|
||||
esp_apptrace_trax_buffer_swap_unlock();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t esp_apptrace_trax_buffer_swap(uint32_t new_block_id)
|
||||
static esp_err_t esp_apptrace_trax_buffer_swap(uint32_t new_block_id, uint32_t prev_block_len)
|
||||
{
|
||||
/* Before switching to the new block, calculate CRC16 of the current block */
|
||||
if (prev_block_len > 0) {
|
||||
const uint8_t *prev_block_start = s_trax_blocks[!((new_block_id % 2))];
|
||||
uint16_t crc16 = esp_rom_crc16_le(0, prev_block_start, prev_block_len);
|
||||
eri_write(ESP_APPTRACE_TRAX_CRC16_REG, crc16 | ESP_APPTRACE_CRC_INDICATOR);
|
||||
ESP_APPTRACE_LOGD("CRC16:%x %d @%x", crc16, prev_block_len, prev_block_start);
|
||||
}
|
||||
esp_apptrace_trax_select_memory_block(new_block_id);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ typedef struct {
|
||||
|
||||
typedef struct {
|
||||
esp_err_t (*swap_start)(uint32_t curr_block_id);
|
||||
esp_err_t (*swap)(uint32_t new_block_id);
|
||||
esp_err_t (*swap)(uint32_t new_block_id, uint32_t prev_block_len);
|
||||
esp_err_t (*swap_end)(uint32_t new_block_id, uint32_t prev_block_len);
|
||||
bool (*host_data_pending)(void);
|
||||
} esp_apptrace_membufs_proto_hw_t;
|
||||
|
||||
+15
-13
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-1-Clause
|
||||
*
|
||||
* SPDX-FileContributor: 2017-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileContributor: 2017-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*/
|
||||
/*********************************************************************
|
||||
* SEGGER Microcontroller GmbH *
|
||||
@@ -65,6 +65,7 @@ Revision: $Rev: 7745 $
|
||||
#include "esp_app_trace.h"
|
||||
#include "esp_app_trace_util.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "esp_clk_tree.h"
|
||||
#include "esp_cpu.h"
|
||||
#include "soc/soc.h"
|
||||
#include "soc/interrupts.h"
|
||||
@@ -84,11 +85,7 @@ extern const SEGGER_SYSVIEW_OS_API SYSVIEW_X_OS_TraceAPI;
|
||||
// The target device name
|
||||
#define SYSVIEW_DEVICE_NAME CONFIG_IDF_TARGET
|
||||
// The target core name
|
||||
#if CONFIG_IDF_TARGET_ARCH_XTENSA
|
||||
#define SYSVIEW_CORE_NAME "xtensa"
|
||||
#elif CONFIG_IDF_TARGET_ARCH_RISCV
|
||||
#define SYSVIEW_CORE_NAME "riscv"
|
||||
#endif
|
||||
#define SYSVIEW_CORE_NAME "core0" // In dual core, this will be renamed by OpenOCD as core1
|
||||
|
||||
// Determine which timer to use as timestamp source
|
||||
#if CONFIG_APPTRACE_SV_TS_SOURCE_CCOUNT
|
||||
@@ -105,9 +102,6 @@ extern const SEGGER_SYSVIEW_OS_API SYSVIEW_X_OS_TraceAPI;
|
||||
// Timer group timer divisor
|
||||
#define SYSVIEW_TIMER_DIV 2
|
||||
|
||||
// Frequency of the timestamp, using APB as GPTimer source clock
|
||||
#define SYSVIEW_TIMESTAMP_FREQ (esp_clk_apb_freq() / SYSVIEW_TIMER_DIV)
|
||||
|
||||
// GPTimer handle
|
||||
gptimer_handle_t s_sv_gptimer;
|
||||
|
||||
@@ -177,30 +171,38 @@ static void _cbSendSystemDesc(void) {
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
static void SEGGER_SYSVIEW_TS_Init(void)
|
||||
static int SEGGER_SYSVIEW_TS_Init(void)
|
||||
{
|
||||
/* We only need to initialize something if we use Timer Group.
|
||||
* esp_timer and ccount can be used as is.
|
||||
*/
|
||||
#if TS_USE_TIMERGROUP
|
||||
// get clock source frequency
|
||||
uint32_t counter_src_hz = 0;
|
||||
ESP_ERROR_CHECK(esp_clk_tree_src_get_freq_hz(
|
||||
(soc_module_clk_t)GPTIMER_CLK_SRC_DEFAULT,
|
||||
ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &counter_src_hz));
|
||||
gptimer_config_t config = {
|
||||
.clk_src = GPTIMER_CLK_SRC_DEFAULT,
|
||||
.direction = GPTIMER_COUNT_UP,
|
||||
.resolution_hz = SYSVIEW_TIMESTAMP_FREQ,
|
||||
.resolution_hz = counter_src_hz / SYSVIEW_TIMER_DIV,
|
||||
};
|
||||
// pick any free GPTimer instance
|
||||
ESP_ERROR_CHECK(gptimer_new_timer(&config, &s_sv_gptimer));
|
||||
/* Start counting */
|
||||
gptimer_enable(s_sv_gptimer);
|
||||
gptimer_start(s_sv_gptimer);
|
||||
return config.resolution_hz;
|
||||
#else
|
||||
return SYSVIEW_TIMESTAMP_FREQ;
|
||||
#endif // TS_USE_TIMERGROUP
|
||||
}
|
||||
|
||||
void SEGGER_SYSVIEW_Conf(void) {
|
||||
U32 disable_evts = 0;
|
||||
|
||||
SEGGER_SYSVIEW_TS_Init();
|
||||
SEGGER_SYSVIEW_Init(SYSVIEW_TIMESTAMP_FREQ, SYSVIEW_CPU_FREQ,
|
||||
int timestamp_freq = SEGGER_SYSVIEW_TS_Init();
|
||||
SEGGER_SYSVIEW_Init(timestamp_freq, SYSVIEW_CPU_FREQ,
|
||||
&SYSVIEW_X_OS_TraceAPI, _cbSendSystemDesc);
|
||||
SEGGER_SYSVIEW_SetRAMBase(SYSVIEW_RAM_BASE);
|
||||
|
||||
|
||||
@@ -108,7 +108,7 @@ static void _cbSendTaskList(void) {
|
||||
* Called from SystemView when asked by the host, returns the
|
||||
* current system time in micro seconds.
|
||||
*/
|
||||
static U64 _cbGetTime(void) {
|
||||
__attribute__((unused)) static U64 _cbGetTime(void) {
|
||||
U64 Time;
|
||||
|
||||
Time = xTaskGetTickCountFromISR();
|
||||
@@ -260,7 +260,10 @@ void SYSVIEW_SendTaskInfo(U32 TaskID, const char* sName, unsigned Prio, U32 Stac
|
||||
*/
|
||||
// Callbacks provided to SYSTEMVIEW by FreeRTOS
|
||||
const SEGGER_SYSVIEW_OS_API SYSVIEW_X_OS_TraceAPI = {
|
||||
_cbGetTime,
|
||||
/* Callback _cbGetTime locks xKernelLock inside xTaskGetTickCountFromISR, this can cause deadlock on multi-core.
|
||||
To prevent deadlock, always lock xKernelLock before s_sys_view_lock. Omitting the callback here results in sending
|
||||
SYSVIEW_EVTID_SYSTIME_CYCLES events instead of SYSVIEW_EVTID_SYSTIME_US */
|
||||
NULL,
|
||||
_cbSendTaskList,
|
||||
};
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ components/app_update/test_apps:
|
||||
- if: CONFIG_NAME == "xip_psram" and SOC_SPIRAM_XIP_SUPPORTED == 1
|
||||
# S2 doesn't have ROM for flash
|
||||
- if: CONFIG_NAME == "xip_psram_with_rom_impl" and (SOC_SPIRAM_XIP_SUPPORTED == 1 and IDF_TARGET != "esp32s2")
|
||||
- if: CONFIG_NAME == "recovery_bootloader" and SOC_RECOVERY_BOOTLOADER_SUPPORTED == 1
|
||||
disable:
|
||||
- if: IDF_TARGET in ["esp32h21", "esp32h4"]
|
||||
temporary: true
|
||||
@@ -14,3 +15,7 @@ components/app_update/test_apps:
|
||||
- if: IDF_TARGET == "esp32c61" and CONFIG_NAME == "xip_psram_with_rom_impl"
|
||||
temporary: true
|
||||
reason: not supported yet # TODO: [ESP32C61] IDF-12784
|
||||
disable_test:
|
||||
- if: CONFIG_NAME == "recovery_bootloader" and SOC_RECOVERY_BOOTLOADER_SUPPORTED == 1 and IDF_TARGET == "esp32c61"
|
||||
temporary: true
|
||||
reason: lack of runners # TODO: [ESP32C61] IDF-13165
|
||||
|
||||
@@ -1,4 +1,15 @@
|
||||
idf_component_register(SRC_DIRS "."
|
||||
PRIV_INCLUDE_DIRS "."
|
||||
PRIV_REQUIRES cmock test_utils app_update bootloader_support nvs_flash driver spi_flash esp_psram
|
||||
WHOLE_ARCHIVE)
|
||||
idf_component_register(
|
||||
SRC_DIRS "."
|
||||
PRIV_INCLUDE_DIRS "."
|
||||
PRIV_REQUIRES
|
||||
cmock
|
||||
test_utils
|
||||
app_update
|
||||
bootloader_support
|
||||
nvs_flash
|
||||
driver
|
||||
spi_flash
|
||||
esp_psram
|
||||
efuse
|
||||
WHOLE_ARCHIVE
|
||||
)
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
/*
|
||||
* Tests bootloader update.
|
||||
*/
|
||||
|
||||
#include "unity.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_flash_internal.h"
|
||||
#include "esp_rom_sys.h"
|
||||
#include "utils_update.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#define BOOT_COUNT_NAMESPACE "boot_count"
|
||||
|
||||
static __attribute__((unused)) const char *TAG = "btldr_update";
|
||||
|
||||
#if CONFIG_BOOTLOADER_RECOVERY_ENABLE
|
||||
|
||||
/* @brief Checks and prepares the partition so that the factory app is launched after that.
|
||||
*/
|
||||
static void start_test(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "boot count 1 - reset");
|
||||
set_boot_count_in_nvs(1);
|
||||
erase_ota_data();
|
||||
ESP_LOGI(TAG, "ota_data erased");
|
||||
ESP_LOGI(TAG, "Bootloader offset: 0x%x", esp_rom_get_bootloader_offset());
|
||||
reboot_as_deep_sleep();
|
||||
}
|
||||
|
||||
static void test_flow1(void)
|
||||
{
|
||||
uint8_t boot_count = get_boot_count_from_nvs();
|
||||
boot_count++;
|
||||
set_boot_count_in_nvs(boot_count);
|
||||
ESP_LOGI(TAG, "boot count %d", boot_count);
|
||||
|
||||
ESP_LOGI(TAG, "Bootloader offset: 0x%x", esp_rom_get_bootloader_offset());
|
||||
|
||||
const esp_partition_t *primary_bootloader;
|
||||
TEST_ESP_OK(esp_partition_register_external(NULL, ESP_PRIMARY_BOOTLOADER_OFFSET, ESP_BOOTLOADER_SIZE, "PrimaryBTLDR", ESP_PARTITION_TYPE_BOOTLOADER, ESP_PARTITION_SUBTYPE_BOOTLOADER_PRIMARY, &primary_bootloader));
|
||||
const esp_partition_t *recovery_bootloader;
|
||||
TEST_ESP_OK(esp_partition_register_external(NULL, CONFIG_BOOTLOADER_RECOVERY_OFFSET, ESP_BOOTLOADER_SIZE, "RecoveryBTLDR", ESP_PARTITION_TYPE_BOOTLOADER, ESP_PARTITION_SUBTYPE_BOOTLOADER_RECOVERY, &recovery_bootloader));
|
||||
ESP_LOGI(TAG, "Bootloaders are registered");
|
||||
|
||||
// Remove write protection for the bootloader
|
||||
esp_flash_set_dangerous_write_protection(esp_flash_default_chip, false);
|
||||
switch (boot_count) {
|
||||
case 2:
|
||||
TEST_ASSERT_EQUAL_HEX32(ESP_PRIMARY_BOOTLOADER_OFFSET, esp_rom_get_bootloader_offset());
|
||||
|
||||
TEST_ESP_OK(esp_partition_erase_range(recovery_bootloader, 0, recovery_bootloader->size));
|
||||
ESP_LOGI(TAG, "Erase recovery bootloader");
|
||||
|
||||
TEST_ESP_OK(esp_efuse_set_recovery_bootloader_offset(CONFIG_BOOTLOADER_RECOVERY_OFFSET));
|
||||
|
||||
ESP_LOGI(TAG, "Backup, copy <%s> -> <%s>", primary_bootloader->label, recovery_bootloader->label);
|
||||
TEST_ESP_OK(esp_partition_copy(recovery_bootloader, 0, primary_bootloader, 0, primary_bootloader->size));
|
||||
|
||||
TEST_ESP_OK(esp_partition_erase_range(primary_bootloader, 0, primary_bootloader->size));
|
||||
ESP_LOGI(TAG, "Erase primary bootloader");
|
||||
reboot_as_deep_sleep();
|
||||
break;
|
||||
case 3:
|
||||
TEST_ASSERT_EQUAL_HEX32(CONFIG_BOOTLOADER_RECOVERY_OFFSET, esp_rom_get_bootloader_offset());
|
||||
|
||||
ESP_LOGI(TAG, "Return to primary bootloader...");
|
||||
ESP_LOGI(TAG, "Copy <%s> -> <%s>", recovery_bootloader->label, primary_bootloader->label);
|
||||
TEST_ESP_OK(esp_partition_copy(primary_bootloader, 0, recovery_bootloader, 0, primary_bootloader->size));
|
||||
|
||||
TEST_ESP_OK(esp_partition_erase_range(recovery_bootloader, 0, recovery_bootloader->size));
|
||||
ESP_LOGI(TAG, "Erase recovery bootloader");
|
||||
break;
|
||||
default:
|
||||
TEST_FAIL_MESSAGE("Unexpected stage");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE_MULTIPLE_STAGES("Recovery bootloader feature", "[recovery_bootloader][timeout=90][reset=DEEPSLEEP_RESET, DEEPSLEEP_RESET]", start_test, test_flow1, test_flow1);
|
||||
|
||||
#endif // CONFIG_BOOTLOADER_RECOVERY_ENABLE
|
||||
@@ -7,315 +7,16 @@
|
||||
* Tests for switching between partitions: factory, OTAx, test.
|
||||
*/
|
||||
|
||||
#include <esp_types.h>
|
||||
#include <stdio.h>
|
||||
#include "string.h"
|
||||
#include <inttypes.h>
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#include "esp_rom_spiflash.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "unity.h"
|
||||
|
||||
#include "esp_system.h"
|
||||
#include "bootloader_common.h"
|
||||
#include "../bootloader_flash/include/bootloader_flash_priv.h"
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_ota_ops.h"
|
||||
#include "esp_partition.h"
|
||||
#include "esp_flash_partitions.h"
|
||||
#include "esp_image_format.h"
|
||||
#include "nvs_flash.h"
|
||||
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_sleep.h"
|
||||
#include "test_utils.h"
|
||||
|
||||
#define BOOT_COUNT_NAMESPACE "boot_count"
|
||||
#include "unity.h"
|
||||
#include "utils_update.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
static const char *TAG = "ota_test";
|
||||
|
||||
static void set_boot_count_in_nvs(uint8_t boot_count)
|
||||
{
|
||||
nvs_handle_t boot_count_handle;
|
||||
esp_err_t err = nvs_open(BOOT_COUNT_NAMESPACE, NVS_READWRITE, &boot_count_handle);
|
||||
if (err != ESP_OK) {
|
||||
TEST_ESP_OK(nvs_flash_erase());
|
||||
TEST_ESP_OK(nvs_flash_init());
|
||||
TEST_ESP_OK(nvs_open(BOOT_COUNT_NAMESPACE, NVS_READWRITE, &boot_count_handle));
|
||||
}
|
||||
TEST_ESP_OK(nvs_set_u8(boot_count_handle, "boot_count", boot_count));
|
||||
TEST_ESP_OK(nvs_commit(boot_count_handle));
|
||||
nvs_close(boot_count_handle);
|
||||
}
|
||||
|
||||
static uint8_t get_boot_count_from_nvs(void)
|
||||
{
|
||||
nvs_handle_t boot_count_handle;
|
||||
esp_err_t err = nvs_open(BOOT_COUNT_NAMESPACE, NVS_READONLY, &boot_count_handle);
|
||||
if (err == ESP_ERR_NVS_NOT_FOUND) {
|
||||
set_boot_count_in_nvs(0);
|
||||
}
|
||||
uint8_t boot_count;
|
||||
TEST_ESP_OK(nvs_get_u8(boot_count_handle, "boot_count", &boot_count));
|
||||
nvs_close(boot_count_handle);
|
||||
return boot_count;
|
||||
}
|
||||
|
||||
/* @brief Copies a current app to next partition using handle.
|
||||
*
|
||||
* @param[in] update_handle - Handle of API ota.
|
||||
* @param[in] cur_app - Current app.
|
||||
*/
|
||||
static void copy_app_partition(esp_ota_handle_t update_handle, const esp_partition_t *curr_app)
|
||||
{
|
||||
const void *partition_bin = NULL;
|
||||
esp_partition_mmap_handle_t data_map;
|
||||
ESP_LOGI(TAG, "start the copy process");
|
||||
TEST_ESP_OK(esp_partition_mmap(curr_app, 0, curr_app->size, ESP_PARTITION_MMAP_DATA, &partition_bin, &data_map));
|
||||
TEST_ESP_OK(esp_ota_write(update_handle, (const void *)partition_bin, curr_app->size));
|
||||
esp_partition_munmap(data_map);
|
||||
ESP_LOGI(TAG, "finish the copy process");
|
||||
}
|
||||
|
||||
/* @brief Copies a current app to next partition using handle.
|
||||
*
|
||||
* @param[in] update_handle - Handle of API ota.
|
||||
* @param[in] cur_app - Current app.
|
||||
*/
|
||||
static void copy_app_partition_with_offset(esp_ota_handle_t update_handle, const esp_partition_t *curr_app)
|
||||
{
|
||||
const void *partition_bin = NULL;
|
||||
esp_partition_mmap_handle_t data_map;
|
||||
ESP_LOGI(TAG, "start the copy process");
|
||||
uint32_t offset = 0, bytes_to_write = curr_app->size;
|
||||
uint32_t write_bytes;
|
||||
while (bytes_to_write > 0) {
|
||||
write_bytes = (bytes_to_write > (4 * 1024)) ? (4 * 1024) : bytes_to_write;
|
||||
TEST_ESP_OK(esp_partition_mmap(curr_app, offset, write_bytes, ESP_PARTITION_MMAP_DATA, &partition_bin, &data_map));
|
||||
TEST_ESP_OK(esp_ota_write_with_offset(update_handle, (const void *)partition_bin, write_bytes, offset));
|
||||
esp_partition_munmap(data_map);
|
||||
bytes_to_write -= write_bytes;
|
||||
offset += write_bytes;
|
||||
}
|
||||
ESP_LOGI(TAG, "finish the copy process");
|
||||
}
|
||||
|
||||
/* @brief Get the next partition of OTA for the update.
|
||||
*
|
||||
* @return The next partition of OTA(OTA0-15).
|
||||
*/
|
||||
static const esp_partition_t * get_next_update_partition(void)
|
||||
{
|
||||
const esp_partition_t *update_partition = esp_ota_get_next_update_partition(NULL);
|
||||
TEST_ASSERT_NOT_EQUAL(NULL, update_partition);
|
||||
ESP_LOGI(TAG, "Writing to partition subtype %d at offset 0x%"PRIx32, update_partition->subtype, update_partition->address);
|
||||
return update_partition;
|
||||
}
|
||||
|
||||
/* @brief Copies a current app to next partition (OTA0-15) and then configure OTA data for a new boot partition.
|
||||
*
|
||||
* @param[in] cur_app_partition - Current app.
|
||||
* @param[in] next_app_partition - Next app for boot.
|
||||
*/
|
||||
static void copy_current_app_to_next_part(const esp_partition_t *cur_app_partition, const esp_partition_t *next_app_partition)
|
||||
{
|
||||
esp_ota_get_next_update_partition(NULL);
|
||||
TEST_ASSERT_NOT_EQUAL(NULL, next_app_partition);
|
||||
ESP_LOGI(TAG, "Writing to partition subtype %d at offset 0x%"PRIx32, next_app_partition->subtype, next_app_partition->address);
|
||||
|
||||
esp_ota_handle_t update_handle = 0;
|
||||
TEST_ESP_OK(esp_ota_begin(next_app_partition, OTA_SIZE_UNKNOWN, &update_handle));
|
||||
|
||||
copy_app_partition(update_handle, cur_app_partition);
|
||||
|
||||
TEST_ESP_OK(esp_ota_end(update_handle));
|
||||
TEST_ESP_OK(esp_ota_set_boot_partition(next_app_partition));
|
||||
}
|
||||
|
||||
/* @brief Copies a current app to next partition (OTA0-15) and then configure OTA data for a new boot partition.
|
||||
*
|
||||
* @param[in] cur_app_partition - Current app.
|
||||
* @param[in] next_app_partition - Next app for boot.
|
||||
*/
|
||||
static void copy_current_app_to_next_part_with_offset(const esp_partition_t *cur_app_partition, const esp_partition_t *next_app_partition)
|
||||
{
|
||||
esp_ota_get_next_update_partition(NULL);
|
||||
TEST_ASSERT_NOT_EQUAL(NULL, next_app_partition);
|
||||
ESP_LOGI(TAG, "Writing to partition subtype %d at offset 0x%"PRIx32, next_app_partition->subtype, next_app_partition->address);
|
||||
|
||||
esp_ota_handle_t update_handle = 0;
|
||||
TEST_ESP_OK(esp_ota_begin(next_app_partition, OTA_SIZE_UNKNOWN, &update_handle));
|
||||
|
||||
copy_app_partition_with_offset(update_handle, cur_app_partition);
|
||||
|
||||
TEST_ESP_OK(esp_ota_end(update_handle));
|
||||
TEST_ESP_OK(esp_ota_set_boot_partition(next_app_partition));
|
||||
}
|
||||
|
||||
/* @brief Erase otadata partition
|
||||
*/
|
||||
static void erase_ota_data(void)
|
||||
{
|
||||
const esp_partition_t *data_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_OTA, NULL);
|
||||
TEST_ASSERT_NOT_EQUAL(NULL, data_partition);
|
||||
TEST_ESP_OK(esp_partition_erase_range(data_partition, 0, 2 * data_partition->erase_size));
|
||||
}
|
||||
|
||||
/* @brief Reboots ESP using mode deep sleep. This mode guaranty that RTC_DATA_ATTR variables is not reset.
|
||||
*/
|
||||
static void reboot_as_deep_sleep(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "reboot as deep sleep");
|
||||
esp_deep_sleep(20000);
|
||||
TEST_FAIL_MESSAGE("Should never be reachable except when sleep is rejected, abort");
|
||||
}
|
||||
|
||||
/* @brief Copies a current app to next partition (OTA0-15), after that ESP is rebooting and run this (the next) OTAx.
|
||||
*/
|
||||
static void copy_current_app_to_next_part_and_reboot(void)
|
||||
{
|
||||
const esp_partition_t *cur_app = esp_ota_get_running_partition();
|
||||
ESP_LOGI(TAG, "copy current app to next part");
|
||||
copy_current_app_to_next_part(cur_app, get_next_update_partition());
|
||||
reboot_as_deep_sleep();
|
||||
}
|
||||
|
||||
/* @brief Copies a current app to next partition (OTA0-15) using esp_ota_write_with_offest(), after that ESP is rebooting and run this (the next) OTAx.
|
||||
*/
|
||||
static void copy_current_app_to_next_part_with_offset_and_reboot(void)
|
||||
{
|
||||
const esp_partition_t *cur_app = esp_ota_get_running_partition();
|
||||
ESP_LOGI(TAG, "copy current app to next part");
|
||||
copy_current_app_to_next_part_with_offset(cur_app, get_next_update_partition());
|
||||
reboot_as_deep_sleep();
|
||||
}
|
||||
|
||||
/* @brief Get running app.
|
||||
*
|
||||
* @return The next partition of OTA(OTA0-15).
|
||||
*/
|
||||
static const esp_partition_t* get_running_firmware(void)
|
||||
{
|
||||
const esp_partition_t *configured = esp_ota_get_boot_partition();
|
||||
const esp_partition_t *running = esp_ota_get_running_partition();
|
||||
ESP_LOGI(TAG, "Running partition type %d subtype %d (offset 0x%08"PRIx32")",
|
||||
running->type, running->subtype, running->address);
|
||||
ESP_LOGI(TAG, "Configured partition type %d subtype %d (offset 0x%08"PRIx32")",
|
||||
configured->type, configured->subtype, configured->address);
|
||||
TEST_ASSERT_NOT_EQUAL(NULL, configured);
|
||||
TEST_ASSERT_NOT_EQUAL(NULL, running);
|
||||
if (running->subtype != ESP_PARTITION_SUBTYPE_APP_TEST) {
|
||||
TEST_ASSERT_EQUAL_PTR(running, configured);
|
||||
}
|
||||
return running;
|
||||
}
|
||||
|
||||
// type of a corrupt ota_data
|
||||
typedef enum {
|
||||
CORR_CRC_1_SECTOR_OTA_DATA = (1 << 0), /*!< Corrupt CRC only 1 sector of ota_data */
|
||||
CORR_CRC_2_SECTOR_OTA_DATA = (1 << 1), /*!< Corrupt CRC only 2 sector of ota_data */
|
||||
} corrupt_ota_data_t;
|
||||
|
||||
/* @brief Get two copies ota_data from otadata partition.
|
||||
*
|
||||
* @param[in] otadata_partition - otadata partition.
|
||||
* @param[out] ota_data_0 - First copy from otadata_partition.
|
||||
* @param[out] ota_data_1 - Second copy from otadata_partition.
|
||||
*/
|
||||
static void get_ota_data(const esp_partition_t *otadata_partition, esp_ota_select_entry_t *ota_data_0, esp_ota_select_entry_t *ota_data_1)
|
||||
{
|
||||
uint32_t offset = otadata_partition->address;
|
||||
uint32_t size = otadata_partition->size;
|
||||
if (offset != 0) {
|
||||
const esp_ota_select_entry_t *ota_select_map;
|
||||
ota_select_map = bootloader_mmap(offset, size);
|
||||
TEST_ASSERT_NOT_EQUAL(NULL, ota_select_map);
|
||||
|
||||
memcpy(ota_data_0, ota_select_map, sizeof(esp_ota_select_entry_t));
|
||||
memcpy(ota_data_1, (uint8_t *)ota_select_map + otadata_partition->erase_size, sizeof(esp_ota_select_entry_t));
|
||||
bootloader_munmap(ota_select_map);
|
||||
}
|
||||
}
|
||||
|
||||
/* @brief Writes a ota_data into required sector of otadata_partition.
|
||||
*
|
||||
* @param[in] otadata_partition - Partition information otadata.
|
||||
* @param[in] ota_data - otadata structure.
|
||||
* @param[in] sec_id - Sector number 0 or 1.
|
||||
*/
|
||||
static void write_ota_data(const esp_partition_t *otadata_partition, esp_ota_select_entry_t *ota_data, int sec_id)
|
||||
{
|
||||
esp_partition_write(otadata_partition, otadata_partition->erase_size * sec_id, &ota_data[sec_id], sizeof(esp_ota_select_entry_t));
|
||||
}
|
||||
|
||||
/* @brief Makes a corrupt of ota_data.
|
||||
* @param[in] err - type error
|
||||
*/
|
||||
static void corrupt_ota_data(corrupt_ota_data_t err)
|
||||
{
|
||||
esp_ota_select_entry_t ota_data[2];
|
||||
|
||||
const esp_partition_t *otadata_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_OTA, NULL);
|
||||
TEST_ASSERT_NOT_EQUAL(NULL, otadata_partition);
|
||||
get_ota_data(otadata_partition, &ota_data[0], &ota_data[1]);
|
||||
|
||||
if (err & CORR_CRC_1_SECTOR_OTA_DATA) {
|
||||
ota_data[0].crc = 0;
|
||||
}
|
||||
if (err & CORR_CRC_2_SECTOR_OTA_DATA) {
|
||||
ota_data[1].crc = 0;
|
||||
}
|
||||
TEST_ESP_OK(esp_partition_erase_range(otadata_partition, 0, otadata_partition->size));
|
||||
write_ota_data(otadata_partition, &ota_data[0], 0);
|
||||
write_ota_data(otadata_partition, &ota_data[1], 1);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BOOTLOADER_FACTORY_RESET) || defined(CONFIG_BOOTLOADER_APP_TEST)
|
||||
/* @brief Sets the pin number to output and sets output level as low. After reboot (deep sleep) this pin keep the same level.
|
||||
*
|
||||
* The output level of the pad will be force locked and can not be changed.
|
||||
* Power down or call gpio_hold_dis will disable this function.
|
||||
*
|
||||
* @param[in] num_pin - Pin number
|
||||
*/
|
||||
static void set_output_pin(uint32_t num_pin)
|
||||
{
|
||||
TEST_ESP_OK(gpio_hold_dis(num_pin));
|
||||
|
||||
gpio_config_t io_conf;
|
||||
io_conf.intr_type = GPIO_INTR_DISABLE;
|
||||
io_conf.mode = GPIO_MODE_OUTPUT;
|
||||
io_conf.pin_bit_mask = (1ULL << num_pin);
|
||||
io_conf.pull_down_en = 0;
|
||||
io_conf.pull_up_en = 0;
|
||||
TEST_ESP_OK(gpio_config(&io_conf));
|
||||
|
||||
TEST_ESP_OK(gpio_set_level(num_pin, 0));
|
||||
TEST_ESP_OK(gpio_hold_en(num_pin));
|
||||
}
|
||||
|
||||
/* @brief Unset the pin number hold function.
|
||||
*/
|
||||
static void reset_output_pin(uint32_t num_pin)
|
||||
{
|
||||
TEST_ESP_OK(gpio_hold_dis(num_pin));
|
||||
TEST_ESP_OK(gpio_reset_pin(num_pin));
|
||||
}
|
||||
#endif
|
||||
|
||||
static void mark_app_valid(void)
|
||||
{
|
||||
#ifdef CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE
|
||||
TEST_ESP_OK(esp_ota_mark_app_valid_cancel_rollback());
|
||||
#endif
|
||||
}
|
||||
|
||||
/* @brief Checks and prepares the partition so that the factory app is launched after that.
|
||||
*/
|
||||
static void start_test(void)
|
||||
@@ -546,20 +247,6 @@ static void test_flow5(void)
|
||||
TEST_CASE_MULTIPLE_STAGES("Switching between factory, test, factory", "[app_update][timeout=90][reset=SW_CPU_RESET, SW_CPU_RESET, DEEPSLEEP_RESET]", start_test, test_flow5, test_flow5, test_flow5);
|
||||
#endif
|
||||
|
||||
static const esp_partition_t* app_update(void)
|
||||
{
|
||||
const esp_partition_t *cur_app = get_running_firmware();
|
||||
const esp_partition_t* update_partition = esp_ota_get_next_update_partition(NULL);
|
||||
TEST_ASSERT_NOT_NULL(update_partition);
|
||||
esp_ota_handle_t update_handle = 0;
|
||||
TEST_ESP_OK(esp_ota_begin(update_partition, OTA_SIZE_UNKNOWN, &update_handle));
|
||||
copy_app_partition(update_handle, cur_app);
|
||||
TEST_ESP_OK(esp_ota_end(update_handle));
|
||||
TEST_ESP_OK(esp_ota_set_boot_partition(update_partition));
|
||||
return update_partition;
|
||||
}
|
||||
|
||||
|
||||
static void test_rollback1(void)
|
||||
{
|
||||
uint8_t boot_count = get_boot_count_from_nvs();
|
||||
|
||||
@@ -0,0 +1,307 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "esp_rom_spiflash.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "esp_partition.h"
|
||||
#include "esp_flash_partitions.h"
|
||||
#include "esp_image_format.h"
|
||||
#include "../bootloader_flash/include/bootloader_flash_priv.h"
|
||||
#include "esp_sleep.h"
|
||||
#include "esp_ota_ops.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
#include "test_utils.h"
|
||||
#include "utils_update.h"
|
||||
#include "unity.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#define BOOT_COUNT_NAMESPACE "boot_count"
|
||||
|
||||
static const char *TAG = "ota_test";
|
||||
|
||||
|
||||
void set_boot_count_in_nvs(uint8_t boot_count)
|
||||
{
|
||||
nvs_handle_t boot_count_handle;
|
||||
esp_err_t err = nvs_open(BOOT_COUNT_NAMESPACE, NVS_READWRITE, &boot_count_handle);
|
||||
if (err != ESP_OK) {
|
||||
TEST_ESP_OK(nvs_flash_erase());
|
||||
TEST_ESP_OK(nvs_flash_init());
|
||||
TEST_ESP_OK(nvs_open(BOOT_COUNT_NAMESPACE, NVS_READWRITE, &boot_count_handle));
|
||||
}
|
||||
TEST_ESP_OK(nvs_set_u8(boot_count_handle, "boot_count", boot_count));
|
||||
TEST_ESP_OK(nvs_commit(boot_count_handle));
|
||||
nvs_close(boot_count_handle);
|
||||
}
|
||||
|
||||
uint8_t get_boot_count_from_nvs(void)
|
||||
{
|
||||
nvs_handle_t boot_count_handle;
|
||||
esp_err_t err = nvs_open(BOOT_COUNT_NAMESPACE, NVS_READONLY, &boot_count_handle);
|
||||
if (err == ESP_ERR_NVS_NOT_FOUND) {
|
||||
set_boot_count_in_nvs(0);
|
||||
}
|
||||
uint8_t boot_count;
|
||||
TEST_ESP_OK(nvs_get_u8(boot_count_handle, "boot_count", &boot_count));
|
||||
nvs_close(boot_count_handle);
|
||||
return boot_count;
|
||||
}
|
||||
|
||||
/* @brief Copies a current app to next partition using handle.
|
||||
*
|
||||
* @param[in] update_handle - Handle of API ota.
|
||||
* @param[in] cur_app - Current app.
|
||||
*/
|
||||
void copy_app_partition(esp_ota_handle_t update_handle, const esp_partition_t *curr_app)
|
||||
{
|
||||
const void *partition_bin = NULL;
|
||||
esp_partition_mmap_handle_t data_map;
|
||||
ESP_LOGI(TAG, "start the copy process");
|
||||
TEST_ESP_OK(esp_partition_mmap(curr_app, 0, curr_app->size, ESP_PARTITION_MMAP_DATA, &partition_bin, &data_map));
|
||||
TEST_ESP_OK(esp_ota_write(update_handle, (const void *)partition_bin, curr_app->size));
|
||||
esp_partition_munmap(data_map);
|
||||
ESP_LOGI(TAG, "finish the copy process");
|
||||
}
|
||||
|
||||
/* @brief Copies a current app to next partition using handle.
|
||||
*
|
||||
* @param[in] update_handle - Handle of API ota.
|
||||
* @param[in] cur_app - Current app.
|
||||
*/
|
||||
void copy_app_partition_with_offset(esp_ota_handle_t update_handle, const esp_partition_t *curr_app)
|
||||
{
|
||||
const void *partition_bin = NULL;
|
||||
esp_partition_mmap_handle_t data_map;
|
||||
ESP_LOGI(TAG, "start the copy process");
|
||||
uint32_t offset = 0, bytes_to_write = curr_app->size;
|
||||
uint32_t write_bytes;
|
||||
while (bytes_to_write > 0) {
|
||||
write_bytes = (bytes_to_write > (4 * 1024)) ? (4 * 1024) : bytes_to_write;
|
||||
TEST_ESP_OK(esp_partition_mmap(curr_app, offset, write_bytes, ESP_PARTITION_MMAP_DATA, &partition_bin, &data_map));
|
||||
TEST_ESP_OK(esp_ota_write_with_offset(update_handle, (const void *)partition_bin, write_bytes, offset));
|
||||
esp_partition_munmap(data_map);
|
||||
bytes_to_write -= write_bytes;
|
||||
offset += write_bytes;
|
||||
}
|
||||
ESP_LOGI(TAG, "finish the copy process");
|
||||
}
|
||||
|
||||
/* @brief Get the next partition of OTA for the update.
|
||||
*
|
||||
* @return The next partition of OTA(OTA0-15).
|
||||
*/
|
||||
const esp_partition_t * get_next_update_partition(void)
|
||||
{
|
||||
const esp_partition_t *update_partition = esp_ota_get_next_update_partition(NULL);
|
||||
TEST_ASSERT_NOT_EQUAL(NULL, update_partition);
|
||||
ESP_LOGI(TAG, "Writing to partition subtype %d at offset 0x%"PRIx32, update_partition->subtype, update_partition->address);
|
||||
return update_partition;
|
||||
}
|
||||
|
||||
/* @brief Copies a current app to next partition (OTA0-15) and then configure OTA data for a new boot partition.
|
||||
*
|
||||
* @param[in] cur_app_partition - Current app.
|
||||
* @param[in] next_app_partition - Next app for boot.
|
||||
*/
|
||||
void copy_current_app_to_next_part(const esp_partition_t *cur_app_partition, const esp_partition_t *next_app_partition)
|
||||
{
|
||||
esp_ota_get_next_update_partition(NULL);
|
||||
TEST_ASSERT_NOT_EQUAL(NULL, next_app_partition);
|
||||
ESP_LOGI(TAG, "Writing to partition subtype %d at offset 0x%"PRIx32, next_app_partition->subtype, next_app_partition->address);
|
||||
|
||||
esp_ota_handle_t update_handle = 0;
|
||||
TEST_ESP_OK(esp_ota_begin(next_app_partition, OTA_SIZE_UNKNOWN, &update_handle));
|
||||
|
||||
copy_app_partition(update_handle, cur_app_partition);
|
||||
|
||||
TEST_ESP_OK(esp_ota_end(update_handle));
|
||||
TEST_ESP_OK(esp_ota_set_boot_partition(next_app_partition));
|
||||
}
|
||||
|
||||
/* @brief Copies a current app to next partition (OTA0-15) and then configure OTA data for a new boot partition.
|
||||
*
|
||||
* @param[in] cur_app_partition - Current app.
|
||||
* @param[in] next_app_partition - Next app for boot.
|
||||
*/
|
||||
void copy_current_app_to_next_part_with_offset(const esp_partition_t *cur_app_partition, const esp_partition_t *next_app_partition)
|
||||
{
|
||||
esp_ota_get_next_update_partition(NULL);
|
||||
TEST_ASSERT_NOT_EQUAL(NULL, next_app_partition);
|
||||
ESP_LOGI(TAG, "Writing to partition subtype %d at offset 0x%"PRIx32, next_app_partition->subtype, next_app_partition->address);
|
||||
|
||||
esp_ota_handle_t update_handle = 0;
|
||||
TEST_ESP_OK(esp_ota_begin(next_app_partition, OTA_SIZE_UNKNOWN, &update_handle));
|
||||
|
||||
copy_app_partition_with_offset(update_handle, cur_app_partition);
|
||||
|
||||
TEST_ESP_OK(esp_ota_end(update_handle));
|
||||
TEST_ESP_OK(esp_ota_set_boot_partition(next_app_partition));
|
||||
}
|
||||
|
||||
/* @brief Erase otadata partition
|
||||
*/
|
||||
void erase_ota_data(void)
|
||||
{
|
||||
const esp_partition_t *data_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_OTA, NULL);
|
||||
TEST_ASSERT_NOT_EQUAL(NULL, data_partition);
|
||||
TEST_ESP_OK(esp_partition_erase_range(data_partition, 0, 2 * data_partition->erase_size));
|
||||
}
|
||||
|
||||
/* @brief Reboots ESP using mode deep sleep. This mode guaranty that RTC_DATA_ATTR variables is not reset.
|
||||
*/
|
||||
void reboot_as_deep_sleep(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "reboot as deep sleep");
|
||||
esp_deep_sleep(20000);
|
||||
TEST_FAIL_MESSAGE("Should never be reachable except when sleep is rejected, abort");
|
||||
}
|
||||
|
||||
/* @brief Copies a current app to next partition (OTA0-15), after that ESP is rebooting and run this (the next) OTAx.
|
||||
*/
|
||||
void copy_current_app_to_next_part_and_reboot(void)
|
||||
{
|
||||
const esp_partition_t *cur_app = esp_ota_get_running_partition();
|
||||
ESP_LOGI(TAG, "copy current app to next part");
|
||||
copy_current_app_to_next_part(cur_app, get_next_update_partition());
|
||||
reboot_as_deep_sleep();
|
||||
}
|
||||
|
||||
/* @brief Copies a current app to next partition (OTA0-15) using esp_ota_write_with_offest(), after that ESP is rebooting and run this (the next) OTAx.
|
||||
*/
|
||||
void copy_current_app_to_next_part_with_offset_and_reboot(void)
|
||||
{
|
||||
const esp_partition_t *cur_app = esp_ota_get_running_partition();
|
||||
ESP_LOGI(TAG, "copy current app to next part");
|
||||
copy_current_app_to_next_part_with_offset(cur_app, get_next_update_partition());
|
||||
reboot_as_deep_sleep();
|
||||
}
|
||||
|
||||
/* @brief Get running app.
|
||||
*
|
||||
* @return The next partition of OTA(OTA0-15).
|
||||
*/
|
||||
const esp_partition_t* get_running_firmware(void)
|
||||
{
|
||||
const esp_partition_t *configured = esp_ota_get_boot_partition();
|
||||
const esp_partition_t *running = esp_ota_get_running_partition();
|
||||
// If a reboot hasn't occurred after app_update(), the configured and running partitions may differ
|
||||
ESP_LOGI(TAG, "Running partition type %d subtype %d (offset 0x%08"PRIx32")",
|
||||
running->type, running->subtype, running->address);
|
||||
ESP_LOGI(TAG, "Configured partition type %d subtype %d (offset 0x%08"PRIx32")",
|
||||
configured->type, configured->subtype, configured->address);
|
||||
TEST_ASSERT_NOT_EQUAL(NULL, configured);
|
||||
TEST_ASSERT_NOT_EQUAL(NULL, running);
|
||||
return running;
|
||||
}
|
||||
|
||||
/* @brief Get two copies ota_data from otadata partition.
|
||||
*
|
||||
* @param[in] otadata_partition - otadata partition.
|
||||
* @param[out] ota_data_0 - First copy from otadata_partition.
|
||||
* @param[out] ota_data_1 - Second copy from otadata_partition.
|
||||
*/
|
||||
void get_ota_data(const esp_partition_t *otadata_partition, esp_ota_select_entry_t *ota_data_0, esp_ota_select_entry_t *ota_data_1)
|
||||
{
|
||||
uint32_t offset = otadata_partition->address;
|
||||
uint32_t size = otadata_partition->size;
|
||||
if (offset != 0) {
|
||||
const esp_ota_select_entry_t *ota_select_map;
|
||||
ota_select_map = bootloader_mmap(offset, size);
|
||||
TEST_ASSERT_NOT_EQUAL(NULL, ota_select_map);
|
||||
|
||||
memcpy(ota_data_0, ota_select_map, sizeof(esp_ota_select_entry_t));
|
||||
memcpy(ota_data_1, (uint8_t *)ota_select_map + otadata_partition->erase_size, sizeof(esp_ota_select_entry_t));
|
||||
bootloader_munmap(ota_select_map);
|
||||
}
|
||||
}
|
||||
|
||||
/* @brief Writes a ota_data into required sector of otadata_partition.
|
||||
*
|
||||
* @param[in] otadata_partition - Partition information otadata.
|
||||
* @param[in] ota_data - otadata structure.
|
||||
* @param[in] sec_id - Sector number 0 or 1.
|
||||
*/
|
||||
void write_ota_data(const esp_partition_t *otadata_partition, esp_ota_select_entry_t *ota_data, int sec_id)
|
||||
{
|
||||
esp_partition_write(otadata_partition, otadata_partition->erase_size * sec_id, &ota_data[sec_id], sizeof(esp_ota_select_entry_t));
|
||||
}
|
||||
|
||||
/* @brief Makes a corrupt of ota_data.
|
||||
* @param[in] err - type error
|
||||
*/
|
||||
void corrupt_ota_data(corrupt_ota_data_t err)
|
||||
{
|
||||
esp_ota_select_entry_t ota_data[2];
|
||||
|
||||
const esp_partition_t *otadata_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_OTA, NULL);
|
||||
TEST_ASSERT_NOT_EQUAL(NULL, otadata_partition);
|
||||
get_ota_data(otadata_partition, &ota_data[0], &ota_data[1]);
|
||||
|
||||
if (err & CORR_CRC_1_SECTOR_OTA_DATA) {
|
||||
ota_data[0].crc = 0;
|
||||
}
|
||||
if (err & CORR_CRC_2_SECTOR_OTA_DATA) {
|
||||
ota_data[1].crc = 0;
|
||||
}
|
||||
TEST_ESP_OK(esp_partition_erase_range(otadata_partition, 0, otadata_partition->size));
|
||||
write_ota_data(otadata_partition, &ota_data[0], 0);
|
||||
write_ota_data(otadata_partition, &ota_data[1], 1);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BOOTLOADER_FACTORY_RESET) || defined(CONFIG_BOOTLOADER_APP_TEST)
|
||||
/* @brief Sets the pin number to output and sets output level as low. After reboot (deep sleep) this pin keep the same level.
|
||||
*
|
||||
* The output level of the pad will be force locked and can not be changed.
|
||||
* Power down or call gpio_hold_dis will disable this function.
|
||||
*
|
||||
* @param[in] num_pin - Pin number
|
||||
*/
|
||||
void set_output_pin(uint32_t num_pin)
|
||||
{
|
||||
TEST_ESP_OK(gpio_hold_dis(num_pin));
|
||||
|
||||
gpio_config_t io_conf;
|
||||
io_conf.intr_type = GPIO_INTR_DISABLE;
|
||||
io_conf.mode = GPIO_MODE_OUTPUT;
|
||||
io_conf.pin_bit_mask = (1ULL << num_pin);
|
||||
io_conf.pull_down_en = 0;
|
||||
io_conf.pull_up_en = 0;
|
||||
TEST_ESP_OK(gpio_config(&io_conf));
|
||||
|
||||
TEST_ESP_OK(gpio_set_level(num_pin, 0));
|
||||
TEST_ESP_OK(gpio_hold_en(num_pin));
|
||||
}
|
||||
|
||||
/* @brief Unset the pin number hold function.
|
||||
*/
|
||||
void reset_output_pin(uint32_t num_pin)
|
||||
{
|
||||
TEST_ESP_OK(gpio_hold_dis(num_pin));
|
||||
TEST_ESP_OK(gpio_reset_pin(num_pin));
|
||||
}
|
||||
#endif
|
||||
|
||||
void mark_app_valid(void)
|
||||
{
|
||||
#ifdef CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE
|
||||
TEST_ESP_OK(esp_ota_mark_app_valid_cancel_rollback());
|
||||
#endif
|
||||
}
|
||||
|
||||
const esp_partition_t* app_update(void)
|
||||
{
|
||||
const esp_partition_t *cur_app = get_running_firmware();
|
||||
const esp_partition_t* update_partition = esp_ota_get_next_update_partition(NULL);
|
||||
TEST_ASSERT_NOT_NULL(update_partition);
|
||||
esp_ota_handle_t update_handle = 0;
|
||||
TEST_ESP_OK(esp_ota_begin(update_partition, OTA_SIZE_UNKNOWN, &update_handle));
|
||||
copy_app_partition(update_handle, cur_app);
|
||||
TEST_ESP_OK(esp_ota_end(update_handle));
|
||||
TEST_ESP_OK(esp_ota_set_boot_partition(update_partition));
|
||||
return update_partition;
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "esp_ota_ops.h"
|
||||
#include "esp_partition.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* @brief Enumeration for specifying which OTA data sectors' CRCs to corrupt.
|
||||
*/
|
||||
typedef enum {
|
||||
CORR_CRC_1_SECTOR_OTA_DATA = (1 << 0), /*!< Corrupt CRC only 1 sector of ota_data */
|
||||
CORR_CRC_2_SECTOR_OTA_DATA = (1 << 1), /*!< Corrupt CRC only 2 sector of ota_data */
|
||||
} corrupt_ota_data_t;
|
||||
|
||||
/**
|
||||
* @brief Set boot count value in NVS.
|
||||
* @param boot_count Value to set.
|
||||
*/
|
||||
void set_boot_count_in_nvs(uint8_t boot_count);
|
||||
|
||||
/**
|
||||
* @brief Get boot count value from NVS.
|
||||
* @return Boot count value.
|
||||
*/
|
||||
uint8_t get_boot_count_from_nvs(void);
|
||||
|
||||
/**
|
||||
* @brief Copy current app to next partition using OTA handle.
|
||||
* @param update_handle OTA update handle.
|
||||
* @param curr_app Current app partition.
|
||||
*/
|
||||
void copy_app_partition(esp_ota_handle_t update_handle, const esp_partition_t *curr_app);
|
||||
|
||||
/**
|
||||
* @brief Copy current app to next partition using OTA handle with offset.
|
||||
* @param update_handle OTA update handle.
|
||||
* @param curr_app Current app partition.
|
||||
*/
|
||||
void copy_app_partition_with_offset(esp_ota_handle_t update_handle, const esp_partition_t *curr_app);
|
||||
|
||||
/**
|
||||
* @brief Get the next OTA update partition.
|
||||
* @return Pointer to next OTA partition.
|
||||
*/
|
||||
const esp_partition_t * get_next_update_partition(void);
|
||||
|
||||
/**
|
||||
* @brief Copy current app to next partition and set boot partition.
|
||||
* @param cur_app_partition Current app partition.
|
||||
* @param next_app_partition Next app partition.
|
||||
*/
|
||||
void copy_current_app_to_next_part(const esp_partition_t *cur_app_partition, const esp_partition_t *next_app_partition);
|
||||
|
||||
/**
|
||||
* @brief Copy current app to next partition with offset and set boot partition.
|
||||
* @param cur_app_partition Current app partition.
|
||||
* @param next_app_partition Next app partition.
|
||||
*/
|
||||
void copy_current_app_to_next_part_with_offset(const esp_partition_t *cur_app_partition, const esp_partition_t *next_app_partition);
|
||||
|
||||
/**
|
||||
* @brief Erase OTA data partition.
|
||||
*/
|
||||
void erase_ota_data(void);
|
||||
|
||||
/**
|
||||
* @brief Reboot ESP using deep sleep mode.
|
||||
*/
|
||||
void reboot_as_deep_sleep(void);
|
||||
|
||||
/**
|
||||
* @brief Copy current app to next partition and reboot.
|
||||
*/
|
||||
void copy_current_app_to_next_part_and_reboot(void);
|
||||
|
||||
/**
|
||||
* @brief Copy current app to next partition with offset and reboot.
|
||||
*/
|
||||
void copy_current_app_to_next_part_with_offset_and_reboot(void);
|
||||
|
||||
/**
|
||||
* @brief Get running firmware partition.
|
||||
* @return Pointer to running firmware partition.
|
||||
*/
|
||||
const esp_partition_t* get_running_firmware(void);
|
||||
|
||||
/**
|
||||
* @brief Get two OTA data copies from OTA data partition.
|
||||
* @param otadata_partition OTA data partition.
|
||||
* @param ota_data_0 First OTA data copy.
|
||||
* @param ota_data_1 Second OTA data copy.
|
||||
*/
|
||||
void get_ota_data(const esp_partition_t *otadata_partition, esp_ota_select_entry_t *ota_data_0, esp_ota_select_entry_t *ota_data_1);
|
||||
|
||||
/**
|
||||
* @brief Write OTA data into required sector of OTA data partition.
|
||||
* @param otadata_partition OTA data partition.
|
||||
* @param ota_data OTA data structure.
|
||||
* @param sec_id Sector number (0 or 1).
|
||||
*/
|
||||
void write_ota_data(const esp_partition_t *otadata_partition, esp_ota_select_entry_t *ota_data, int sec_id);
|
||||
|
||||
/**
|
||||
* @brief Corrupt OTA data for testing.
|
||||
* @param err Type of corruption.
|
||||
*/
|
||||
void corrupt_ota_data(corrupt_ota_data_t err);
|
||||
|
||||
#if defined(CONFIG_BOOTLOADER_FACTORY_RESET) || defined(CONFIG_BOOTLOADER_APP_TEST)
|
||||
/**
|
||||
* @brief Set output pin to low and hold state.
|
||||
* @param num_pin Pin number.
|
||||
*/
|
||||
void set_output_pin(uint32_t num_pin);
|
||||
|
||||
/**
|
||||
* @brief Reset output pin hold function.
|
||||
* @param num_pin Pin number.
|
||||
*/
|
||||
void reset_output_pin(uint32_t num_pin);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Mark app as valid and cancel rollback.
|
||||
*/
|
||||
void mark_app_valid(void);
|
||||
|
||||
/**
|
||||
* @brief Perform app update and set new boot partition.
|
||||
* @return Pointer to updated partition.
|
||||
*/
|
||||
const esp_partition_t* app_update(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -60,3 +60,18 @@ def test_app_update_xip_psram_rom_impl(dut: Dut) -> None:
|
||||
@idf_parametrize('target', ['esp32', 'esp32c3', 'esp32s3', 'esp32p4'], indirect=['target'])
|
||||
def test_app_update_with_rollback(dut: Dut) -> None:
|
||||
dut.run_all_single_board_cases(timeout=90)
|
||||
|
||||
|
||||
@pytest.mark.recovery_bootloader
|
||||
@pytest.mark.parametrize(
|
||||
'config',
|
||||
['recovery_bootloader'],
|
||||
indirect=True,
|
||||
)
|
||||
@idf_parametrize('target', ['esp32c5'], indirect=['target'])
|
||||
def test_recovery_bootloader_update(dut: Dut) -> None:
|
||||
try:
|
||||
dut.run_all_single_board_cases(group='recovery_bootloader', timeout=90)
|
||||
finally:
|
||||
# Erase recovery bootloader after test because it may interfere with other tests using this runner
|
||||
dut.serial.erase_flash()
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
CONFIG_BOOTLOADER_RECOVERY_ENABLE=y
|
||||
CONFIG_BOOTLOADER_RECOVERY_OFFSET=0x3F0000
|
||||
CONFIG_PARTITION_TABLE_OFFSET=0x9000
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
# ESP32C5 supports the Recovery bootloader feature in ROM starting from v1.0 (ECO2)
|
||||
CONFIG_IDF_TARGET="esp32c5"
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
# ESP32C61 supports the Recovery bootloader feature in ROM starting from v1.0 (ECO3)
|
||||
CONFIG_IDF_TARGET="esp32c61"
|
||||
@@ -1,8 +1,37 @@
|
||||
menu "Bootloader Rollback"
|
||||
menu "Recovery Bootloader and Rollback"
|
||||
|
||||
config BOOTLOADER_RECOVERY_ENABLE
|
||||
bool "Enable Recovery Bootloader"
|
||||
depends on SOC_RECOVERY_BOOTLOADER_SUPPORTED
|
||||
default n
|
||||
help
|
||||
The recovery bootloader feature is implemented in the ROM bootloader. It is required for safe OTA
|
||||
updates of the bootloader. The feature is activated when the eFuse field
|
||||
(ESP_EFUSE_RECOVERY_BOOTLOADER_FLASH_SECTOR) is set, which defines the flash address of the
|
||||
recovery bootloader. If activated and the primary bootloader fails to load, the ROM bootloader
|
||||
will attempt to load the recovery bootloader from the address specified in eFuse.
|
||||
|
||||
config BOOTLOADER_RECOVERY_OFFSET
|
||||
hex "Recovery Bootloader Flash Offset"
|
||||
depends on BOOTLOADER_RECOVERY_ENABLE
|
||||
default 0x3F0000
|
||||
range 0x0 0xFFE000
|
||||
help
|
||||
Flash address where the recovery bootloader is stored.
|
||||
This value must be written to the eFuse field (ESP_EFUSE_RECOVERY_BOOTLOADER_FLASH_SECTOR)
|
||||
to activate the recovery bootloader in the ROM bootloader. The eFuse can be programmed
|
||||
using espefuse.py or in the user application with the API esp_efuse_set_recovery_bootloader_offset().
|
||||
Setting this value in the config allows parttool.py to verify that it does not overlap with existing
|
||||
partitions in the partition table.
|
||||
|
||||
The address must be a multiple of the flash sector size (0x1000 bytes).
|
||||
The eFuse field stores the offset in sectors.
|
||||
If the feature is no longer needed or unused, you can burn the 0xFFF value to disable this feature in
|
||||
the ROM bootloader.
|
||||
|
||||
config BOOTLOADER_ANTI_ROLLBACK_ENABLE
|
||||
bool "Enable bootloader rollback support"
|
||||
depends on SOC_RECOVERY_BOOTLOADER_SUPPORTED
|
||||
depends on BOOTLOADER_RECOVERY_ENABLE
|
||||
default n
|
||||
help
|
||||
This option prevents rollback to previous bootloader image with lower security version.
|
||||
|
||||
@@ -21,6 +21,7 @@ menu "Settings"
|
||||
config BOOTLOADER_LOG_MODE_BINARY
|
||||
bool "Binary Log Mode"
|
||||
select BOOTLOADER_LOG_MODE_BINARY_EN
|
||||
depends on BOOTLOADER_LOG_VERSION_2
|
||||
help
|
||||
Enables binary logging with host-side format string expansion. In this mode, the
|
||||
format argument of ESP_LOGx, ESP_EARLY_LOG, and ESP_DRAM_LOG macros is stored in a
|
||||
|
||||
@@ -553,12 +553,13 @@ menu "Security features"
|
||||
depends on SECURE_SIGNED_APPS_ECDSA_V2_SCHEME
|
||||
default SECURE_BOOT_ECDSA_KEY_LEN_256_BITS
|
||||
help
|
||||
Select the ECDSA key size. Two key sizes are supported
|
||||
Select the ECDSA key size. Three key sizes are supported depending upon on the target:
|
||||
|
||||
- 192 bit key using NISTP192 curve
|
||||
- 256 bit key using NISTP256 curve (Recommended)
|
||||
- 384 bit key using NISTP384 curve (Recommended)
|
||||
|
||||
The advantage of using 256 bit key is the extra randomness which makes it difficult to be
|
||||
The advantage of using 384 and 256 bit keys is the extra randomness which makes it difficult to be
|
||||
bruteforced compared to 192 bit key.
|
||||
At present, both key sizes are practically implausible to bruteforce.
|
||||
|
||||
@@ -570,6 +571,10 @@ menu "Security features"
|
||||
bool "Using ECC curve NISTP256 (Recommended)"
|
||||
depends on SECURE_SIGNED_APPS_ECDSA_V2_SCHEME
|
||||
|
||||
config SECURE_BOOT_ECDSA_KEY_LEN_384_BITS
|
||||
bool "Using ECC curve NISTP384 (Recommended)"
|
||||
depends on SECURE_SIGNED_APPS_ECDSA_V2_SCHEME && SOC_ECDSA_SUPPORT_CURVE_P384
|
||||
|
||||
endchoice
|
||||
|
||||
config SECURE_SIGNED_ON_BOOT_NO_SECURE_BOOT
|
||||
@@ -960,6 +965,24 @@ menu "Security features"
|
||||
so that the bootloader would not need to enable secure boot and thus you could avoid its revocation
|
||||
strategy.
|
||||
|
||||
config SECURE_BOOT_SKIP_WRITE_PROTECTION_SCA
|
||||
bool "Skip write-protection of SECURE_FLASH_PSEUDO_ROUND_FUNC_STRENGTH"
|
||||
default y if SECURE_FLASH_PSEUDO_ROUND_FUNC
|
||||
default n
|
||||
depends on SOC_ECDSA_SUPPORT_CURVE_P384 && SOC_FLASH_ENCRYPTION_XTS_AES_SUPPORT_PSEUDO_ROUND
|
||||
help
|
||||
If not set (default, recommended), on the first boot when Secure Boot is enabled for
|
||||
targets that support Secure Boot using ECDSA-P384, the bootloader will burn the write-protection bit of
|
||||
of SECURE_BOOT_SHA384_EN that could be shared by multiple other efuse bits like
|
||||
SECURE_FLASH_PSEUDO_ROUND_FUNC_STRENGTH / XTS_DPA_PSEUDO_LEVEL.
|
||||
|
||||
Once this efuse bit is write-protected you cannot update the values of the shared efuses, for example,
|
||||
the security strength value of XTS_DPA_PSEUDO_LEVEL or setting ECC_FORCE_CONST_TIME.
|
||||
|
||||
List of eFuses with the same write protection bit:
|
||||
|
||||
ESP32-C5: XTS_DPA_PSEUDO_LEVEL and ECC_FORCE_CONST_TIME
|
||||
|
||||
config SECURE_FLASH_UART_BOOTLOADER_ALLOW_ENC
|
||||
bool "Leave UART bootloader encryption enabled"
|
||||
depends on SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT
|
||||
@@ -1043,10 +1066,11 @@ menu "Security features"
|
||||
ESP32-S3: DIS_ICACHE, DIS_DCACHE, DIS_DOWNLOAD_ICACHE, DIS_DOWNLOAD_DCACHE,
|
||||
DIS_FORCE_DOWNLOAD, DIS_USB_OTG, DIS_TWAI, DIS_APP_CPU, DIS_PAD_JTAG,
|
||||
DIS_DOWNLOAD_MANUAL_ENCRYPT, DIS_USB_JTAG, DIS_USB_SERIAL_JTAG, STRAP_JTAG_SEL, USB_PHY_SEL.
|
||||
|
||||
endmenu # Potentially Insecure
|
||||
|
||||
config SECURE_FLASH_ENCRYPT_ONLY_IMAGE_LEN_IN_APP_PART
|
||||
bool "Encrypt only the app image that is present in the partition of type app"
|
||||
bool "Encrypt contents upto app image length in app partition"
|
||||
depends on SECURE_FLASH_ENC_ENABLED && !SECURE_FLASH_REQUIRE_ALREADY_ENABLED
|
||||
default y
|
||||
help
|
||||
@@ -1075,8 +1099,9 @@ menu "Security features"
|
||||
|
||||
config SECURE_FLASH_PSEUDO_ROUND_FUNC
|
||||
bool "Permanently enable XTS-AES's pseudo rounds function"
|
||||
default y
|
||||
depends on SECURE_FLASH_ENCRYPTION_MODE_RELEASE && SOC_FLASH_ENCRYPTION_XTS_AES_SUPPORT_PSEUDO_ROUND
|
||||
default y if SECURE_FLASH_ENCRYPTION_MODE_RELEASE
|
||||
default n
|
||||
depends on SECURE_FLASH_ENC_ENABLED && SOC_FLASH_ENCRYPTION_XTS_AES_SUPPORT_PSEUDO_ROUND
|
||||
help
|
||||
If set (default), the bootloader will permanently enable the XTS-AES peripheral's pseudo rounds function.
|
||||
Note: Enabling this config would burn an efuse.
|
||||
@@ -1089,6 +1114,12 @@ menu "Security features"
|
||||
The strength of the pseudo rounds functions can be configured to low, medium and high,
|
||||
each denoting the values that would be stored in the efuses field.
|
||||
By default the value to set to low.
|
||||
|
||||
It is recommended that the required strength of the pseudo rounds function should be set during the
|
||||
first boot itself. If your workflow needs to update the function's strength after the first boot,
|
||||
you should enable CONFIG_SECURE_BOOT_SKIP_WRITE_PROTECTION_SCA to avoid write protecting this
|
||||
bit during the boot up for targets that support Secure Boot using ECDSA-P384.
|
||||
|
||||
You can configure the strength of the pseudo rounds functions according to your use cases,
|
||||
for example, increasing the strength would provide higher security but would slow down the
|
||||
flash encryption/decryption operations.
|
||||
@@ -1162,7 +1193,7 @@ menu "Security features"
|
||||
It is also possible to enable secure download mode at runtime by calling
|
||||
esp_efuse_enable_rom_secure_download_mode()
|
||||
|
||||
Note: Secure Download mode is not available for ESP32 (includes revisions till ECO3).
|
||||
Note: Secure Download mode is not available for ESP32.
|
||||
|
||||
config SECURE_INSECURE_ALLOW_DL_MODE
|
||||
bool "UART ROM download mode (Enabled (not recommended))"
|
||||
|
||||
@@ -70,6 +70,8 @@ if(CONFIG_SECURE_SIGNED_APPS)
|
||||
set(scheme "ecdsa192")
|
||||
elseif(CONFIG_SECURE_BOOT_ECDSA_KEY_LEN_256_BITS)
|
||||
set(scheme "ecdsa256")
|
||||
elseif(CONFIG_SECURE_BOOT_ECDSA_KEY_LEN_384_BITS)
|
||||
set(scheme "ecdsa384")
|
||||
endif()
|
||||
fail_at_build_time(gen_secure_boot_signing_key
|
||||
"Secure Boot Signing Key ${CONFIG_SECURE_BOOT_SIGNING_KEY} does not exist. Generate using:"
|
||||
|
||||
@@ -67,9 +67,13 @@ idf_build_set_property(__COMPONENT_REQUIRES_COMMON "${common_req}")
|
||||
idf_build_set_property(__OUTPUT_SDKCONFIG 0)
|
||||
# Define a property for the default linker script
|
||||
set(LD_DEFAULT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/main/ld/${IDF_TARGET}")
|
||||
idf_build_set_property(BOOTLOADER_LINKER_SCRIPT "${LD_DEFAULT_PATH}/bootloader.ld" APPEND)
|
||||
idf_build_set_property(BOOTLOADER_LINKER_SCRIPT "${LD_DEFAULT_PATH}/bootloader.rom.ld" APPEND)
|
||||
project(bootloader)
|
||||
if(CONFIG_ESP32P4_REV_MIN_300)
|
||||
target_linker_script("__idf_main" INTERFACE "${LD_DEFAULT_PATH}/bootloader.rev3.ld")
|
||||
else()
|
||||
target_linker_script("__idf_main" INTERFACE "${LD_DEFAULT_PATH}/bootloader.ld")
|
||||
endif()
|
||||
|
||||
idf_build_set_property(COMPILE_DEFINITIONS "BOOTLOADER_BUILD=1" APPEND)
|
||||
idf_build_set_property(COMPILE_DEFINITIONS "NON_OS_BUILD=1" APPEND)
|
||||
|
||||
@@ -0,0 +1,324 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
/**
|
||||
* Simplified memory map for the bootloader.
|
||||
* Make sure the bootloader can load into main memory without overwriting itself.
|
||||
*
|
||||
* ESP32-P4 ROM static data usage is as follows:
|
||||
* - 0x4ff296b8 - 0x4ff3afc0: Shared buffers, used in UART/USB/SPI download mode only
|
||||
* - 0x4ff3afc0 - 0x4ff3fba4: CPU1 stack, can be reclaimed as heap after RTOS startup
|
||||
* - 0x4ff3fba4 - 0x4ff40000: ROM .bss and .data (not easily reclaimable)
|
||||
*
|
||||
* The 2nd stage bootloader can take space up to the end of ROM shared
|
||||
* buffers area (0x4087c610).
|
||||
*/
|
||||
|
||||
/* We consider 0x4087c610 to be the last usable address for 2nd stage bootloader stack overhead, dram_seg,
|
||||
* and work out iram_seg and iram_loader_seg addresses from there, backwards.
|
||||
*/
|
||||
|
||||
/* These lengths can be adjusted, if necessary: */
|
||||
bootloader_usable_dram_end = 0x4ffbcfc0;
|
||||
bootloader_stack_overhead = 0x2000; /* For safety margin between bootloader data section and startup stacks */
|
||||
bootloader_dram_seg_len = 0x5000;
|
||||
bootloader_iram_loader_seg_len = 0x7000;
|
||||
bootloader_iram_seg_len = 0x2D00;
|
||||
|
||||
/* Start of the lower region is determined by region size and the end of the higher region */
|
||||
bootloader_dram_seg_end = bootloader_usable_dram_end - bootloader_stack_overhead;
|
||||
bootloader_dram_seg_start = bootloader_dram_seg_end - bootloader_dram_seg_len;
|
||||
bootloader_iram_loader_seg_start = bootloader_dram_seg_start - bootloader_iram_loader_seg_len;
|
||||
bootloader_iram_seg_start = bootloader_iram_loader_seg_start - bootloader_iram_seg_len;
|
||||
|
||||
MEMORY
|
||||
{
|
||||
iram_seg (RWX) : org = bootloader_iram_seg_start, len = bootloader_iram_seg_len
|
||||
iram_loader_seg (RWX) : org = bootloader_iram_loader_seg_start, len = bootloader_iram_loader_seg_len
|
||||
dram_seg (RW) : org = bootloader_dram_seg_start, len = bootloader_dram_seg_len
|
||||
}
|
||||
|
||||
/* The app may use RAM for static allocations up to the start of iram_loader_seg.
|
||||
* If you have changed something above and this assert fails:
|
||||
* 1. Check what the new value of bootloader_iram_loader_seg start is.
|
||||
* 2. Update the value in this assert.
|
||||
* 3. Update SRAM_DRAM_END in components/esp_system/ld/esp32p4/memory.ld.in to the same value.
|
||||
*/
|
||||
ASSERT(bootloader_iram_loader_seg_start == 0x4FFAEFC0, "bootloader_iram_loader_seg_start inconsistent with SRAM_DRAM_END");
|
||||
|
||||
/* Default entry point: */
|
||||
ENTRY(call_start_cpu0);
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
|
||||
.iram_loader.text :
|
||||
{
|
||||
. = ALIGN (16);
|
||||
_loader_text_start = ABSOLUTE(.);
|
||||
*(.stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*)
|
||||
*(.iram1 .iram1.*) /* catch stray IRAM_ATTR */
|
||||
*liblog.a:(.literal .text .literal.* .text.*)
|
||||
*libgcc.a:(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:bootloader_clock_loader.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:bootloader_common_loader.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:bootloader_flash.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:bootloader_random.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:bootloader_random*.*(.literal.bootloader_random_disable .text.bootloader_random_disable)
|
||||
*libbootloader_support.a:bootloader_random*.*(.literal.bootloader_random_enable .text.bootloader_random_enable)
|
||||
*libbootloader_support.a:bootloader_efuse.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:bootloader_utility.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:bootloader_sha.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:bootloader_console_loader.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:bootloader_panic.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:bootloader_soc.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:esp_image_format.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:flash_encrypt.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:flash_encryption_secure_features.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:flash_partitions.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:secure_boot.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:secure_boot_secure_features.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:secure_boot_signatures_bootloader.*(.literal .text .literal.* .text.*)
|
||||
*libmicro-ecc.a:*.*(.literal .text .literal.* .text.*)
|
||||
*libspi_flash.a:*.*(.literal .text .literal.* .text.*)
|
||||
*libhal.a:wdt_hal_iram.*(.literal .text .literal.* .text.*)
|
||||
*libhal.a:mmu_hal.*(.literal .text .literal.* .text.*)
|
||||
*libhal.a:cache_hal.*(.literal .text .literal.* .text.*)
|
||||
*libhal.a:efuse_hal.*(.literal .text .literal.* .text.*)
|
||||
*libhal.a:key_mgr_hal.*(.literal.key_mgr_hal_set_key_usage .text.key_mgr_hal_set_key_usage)
|
||||
*libesp_hw_support.a:rtc_clk.*(.literal .text .literal.* .text.*)
|
||||
*libesp_hw_support.a:rtc_time.*(.literal .text .literal.* .text.*)
|
||||
*libesp_hw_support.a:regi2c_ctrl.*(.literal .text .literal.* .text.*)
|
||||
*libefuse.a:*.*(.literal .text .literal.* .text.*)
|
||||
*libriscv.a:rv_utils.*(.literal .text .literal.* .text.*)
|
||||
*(.fini.literal)
|
||||
*(.fini)
|
||||
*(.gnu.version)
|
||||
_loader_text_end = ABSOLUTE(.);
|
||||
} > iram_loader_seg
|
||||
|
||||
.iram.text :
|
||||
{
|
||||
. = ALIGN (16);
|
||||
*(.entry.text)
|
||||
*(.init.literal)
|
||||
*(.init)
|
||||
} > iram_seg
|
||||
|
||||
|
||||
/* Shared RAM */
|
||||
.dram0.bss (NOLOAD) :
|
||||
{
|
||||
. = ALIGN (8);
|
||||
_dram_start = ABSOLUTE(.);
|
||||
_bss_start = ABSOLUTE(.);
|
||||
*(.dynsbss)
|
||||
*(.sbss)
|
||||
*(.sbss.*)
|
||||
*(.gnu.linkonce.sb.*)
|
||||
*(.scommon)
|
||||
*(.sbss2)
|
||||
*(.sbss2.*)
|
||||
*(.gnu.linkonce.sb2.*)
|
||||
*(.dynbss)
|
||||
*(.bss)
|
||||
*(.bss.*)
|
||||
*(.gnu.linkonce.b.*)
|
||||
*(COMMON)
|
||||
. = ALIGN (8);
|
||||
_bss_end = ABSOLUTE(.);
|
||||
} > dram_seg
|
||||
|
||||
.dram0.bootdesc : ALIGN(0x10)
|
||||
{
|
||||
_data_start = ABSOLUTE(.);
|
||||
*(.data_bootloader_desc .data_bootloader_desc.*) /* Should be the first. Bootloader version info. DO NOT PUT ANYTHING BEFORE IT! */
|
||||
} > dram_seg
|
||||
|
||||
.dram0.data :
|
||||
{
|
||||
*(.dram1 .dram1.*) /* catch stray DRAM_ATTR */
|
||||
*(.data)
|
||||
*(.data.*)
|
||||
*(.gnu.linkonce.d.*)
|
||||
*(.data1)
|
||||
*(.sdata)
|
||||
*(.sdata.*)
|
||||
*(.gnu.linkonce.s.*)
|
||||
*(.gnu.linkonce.s2.*)
|
||||
*(.jcr)
|
||||
_data_end = ABSOLUTE(.);
|
||||
} > dram_seg
|
||||
|
||||
.dram0.rodata :
|
||||
{
|
||||
_rodata_start = ABSOLUTE(.);
|
||||
*(.rodata)
|
||||
*(.rodata.*)
|
||||
*(.gnu.linkonce.r.*)
|
||||
*(.rodata1)
|
||||
*(.sdata2 .sdata2.* .srodata .srodata.*)
|
||||
__XT_EXCEPTION_TABLE_ = ABSOLUTE(.);
|
||||
*(.xt_except_table)
|
||||
*(.gcc_except_table)
|
||||
*(.gnu.linkonce.e.*)
|
||||
*(.gnu.version_r)
|
||||
*(.eh_frame_hdr)
|
||||
*(.eh_frame)
|
||||
. = (. + 3) & ~ 3;
|
||||
/* C++ constructor and destructor tables, properly ordered: */
|
||||
__init_array_start = ABSOLUTE(.);
|
||||
KEEP (*crtbegin.*(.ctors))
|
||||
KEEP (*(EXCLUDE_FILE (*crtend.*) .ctors))
|
||||
KEEP (*(SORT(.ctors.*)))
|
||||
KEEP (*(.ctors))
|
||||
__init_array_end = ABSOLUTE(.);
|
||||
KEEP (*crtbegin.*(.dtors))
|
||||
KEEP (*(EXCLUDE_FILE (*crtend.*) .dtors))
|
||||
KEEP (*(SORT(.dtors.*)))
|
||||
KEEP (*(.dtors))
|
||||
/* C++ exception handlers table: */
|
||||
__XT_EXCEPTION_DESCS_ = ABSOLUTE(.);
|
||||
*(.xt_except_desc)
|
||||
*(.gnu.linkonce.h.*)
|
||||
__XT_EXCEPTION_DESCS_END__ = ABSOLUTE(.);
|
||||
*(.xt_except_desc_end)
|
||||
*(.dynamic)
|
||||
*(.gnu.version_d)
|
||||
_rodata_end = ABSOLUTE(.);
|
||||
/* Literals are also RO data. */
|
||||
_lit4_start = ABSOLUTE(.);
|
||||
*(*.lit4)
|
||||
*(.lit4.*)
|
||||
*(.gnu.linkonce.lit4.*)
|
||||
_lit4_end = ABSOLUTE(.);
|
||||
. = ALIGN(4);
|
||||
_dram_end = ABSOLUTE(.);
|
||||
} > dram_seg
|
||||
|
||||
.iram.text :
|
||||
{
|
||||
_stext = .;
|
||||
_text_start = ABSOLUTE(.);
|
||||
*(.literal .text .literal.* .text.* .stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*)
|
||||
*(.iram .iram.*) /* catch stray IRAM_ATTR */
|
||||
*(.fini.literal)
|
||||
*(.fini)
|
||||
*(.gnu.version)
|
||||
|
||||
/** CPU will try to prefetch up to 16 bytes of
|
||||
* of instructions. This means that any configuration (e.g. MMU, PMS) must allow
|
||||
* safe access to up to 16 bytes after the last real instruction, add
|
||||
* dummy bytes to ensure this
|
||||
*/
|
||||
. += 16;
|
||||
|
||||
_text_end = ABSOLUTE(.);
|
||||
_etext = .;
|
||||
} > iram_seg
|
||||
|
||||
.riscv.attributes 0: { *(.riscv.attributes) }
|
||||
|
||||
/* DWARF 1 */
|
||||
.debug 0 : { *(.debug) }
|
||||
.line 0 : { *(.line) }
|
||||
/* GNU DWARF 1 extensions */
|
||||
.debug_srcinfo 0 : { *(.debug_srcinfo) }
|
||||
.debug_sfnames 0 : { *(.debug_sfnames) }
|
||||
/* DWARF 1.1 and DWARF 2 */
|
||||
.debug_aranges 0 : { *(.debug_aranges) }
|
||||
.debug_pubnames 0 : { *(.debug_pubnames) }
|
||||
/* DWARF 2 */
|
||||
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
|
||||
.debug_abbrev 0 : { *(.debug_abbrev) }
|
||||
.debug_line 0 : { *(.debug_line) }
|
||||
.debug_frame 0 : { *(.debug_frame) }
|
||||
.debug_str 0 : { *(.debug_str) }
|
||||
.debug_loc 0 : { *(.debug_loc) }
|
||||
.debug_macinfo 0 : { *(.debug_macinfo) }
|
||||
.debug_pubtypes 0 : { *(.debug_pubtypes) }
|
||||
/* DWARF 3 */
|
||||
.debug_ranges 0 : { *(.debug_ranges) }
|
||||
/* SGI/MIPS DWARF 2 extensions */
|
||||
.debug_weaknames 0 : { *(.debug_weaknames) }
|
||||
.debug_funcnames 0 : { *(.debug_funcnames) }
|
||||
.debug_typenames 0 : { *(.debug_typenames) }
|
||||
.debug_varnames 0 : { *(.debug_varnames) }
|
||||
/* GNU DWARF 2 extensions */
|
||||
.debug_gnu_pubnames 0 : { *(.debug_gnu_pubnames) }
|
||||
.debug_gnu_pubtypes 0 : { *(.debug_gnu_pubtypes) }
|
||||
/* DWARF 4 */
|
||||
.debug_types 0 : { *(.debug_types) }
|
||||
/* DWARF 5 */
|
||||
.debug_addr 0 : { *(.debug_addr) }
|
||||
.debug_line_str 0 : { *(.debug_line_str) }
|
||||
.debug_loclists 0 : { *(.debug_loclists) }
|
||||
.debug_macro 0 : { *(.debug_macro) }
|
||||
.debug_names 0 : { *(.debug_names) }
|
||||
.debug_rnglists 0 : { *(.debug_rnglists) }
|
||||
.debug_str_offsets 0 : { *(.debug_str_offsets) }
|
||||
|
||||
.comment 0 : { *(.comment) }
|
||||
.note.GNU-stack 0: { *(.note.GNU-stack) }
|
||||
|
||||
/**
|
||||
* Discarding .rela.* sections results in the following mapping:
|
||||
* .rela.text.* -> .text.*
|
||||
* .rela.data.* -> .data.*
|
||||
* And so forth...
|
||||
*/
|
||||
/DISCARD/ : { *(.rela.*) }
|
||||
|
||||
/**
|
||||
* This section is not included in the binary image; it is only present in the ELF file.
|
||||
* It is used to keep certain symbols in the ELF file.
|
||||
*/
|
||||
.noload 0 (INFO) :
|
||||
{
|
||||
_noload_keep_in_elf_start = ABSOLUTE(.);
|
||||
KEEP(*(.noload_keep_in_elf .noload_keep_in_elf.*))
|
||||
_noload_keep_in_elf_end = ABSOLUTE(.);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Appendix: Memory Usage of ROM bootloader
|
||||
*
|
||||
* 0x4ffa96b8 ------------------> _dram0_0_start
|
||||
* | |
|
||||
* | |
|
||||
* | | 1. Large buffers that are only used in certain boot modes, see shared_buffers.h
|
||||
* | |
|
||||
* | |
|
||||
* 0x4ffbafc0 ------------------> __stack_sentry
|
||||
* | |
|
||||
* | | 2. Startup pro cpu stack (freed when IDF app is running)
|
||||
* | |
|
||||
* 0x4ffbcfc0 ------------------> __stack (pro cpu)
|
||||
* | |
|
||||
* | | Startup app cpu stack
|
||||
* | |
|
||||
* 0x4ffbefc0 ------------------> __stack_app (app cpu)
|
||||
* | |
|
||||
* | |
|
||||
* | | 3. Shared memory only used in startup code or nonos/early boot*
|
||||
* | | (can be freed when IDF runs)
|
||||
* | |
|
||||
* | |
|
||||
* 0x4ffbfbb0 ------------------> _dram0_rtos_reserved_start
|
||||
* | |
|
||||
* | |
|
||||
* | | 4. Shared memory used in startup code and when IDF runs
|
||||
* | |
|
||||
* | |
|
||||
* 0x4ffbffa4 ------------------> _dram0_rtos_reserved_end
|
||||
* | |
|
||||
* 0x4ffbffc8 ------------------> _data_start_interface
|
||||
* | |
|
||||
* | | 5. End of DRAM is the 'interface' data with constant addresses (ECO compatible)
|
||||
* | |
|
||||
* 0x4ffc0000 ------------------> _data_end_interface
|
||||
*/
|
||||
@@ -136,9 +136,9 @@ esp_err_t bootloader_flash_erase_range(uint32_t start_addr, uint32_t size)
|
||||
#if ESP_TEE_BUILD
|
||||
#include "esp_fault.h"
|
||||
#include "esp_flash_partitions.h"
|
||||
#include "esp32c6/rom/spi_flash.h"
|
||||
#include "rom/spi_flash.h"
|
||||
|
||||
extern bool esp_tee_flash_check_paddr_in_active_tee_part(size_t paddr);
|
||||
extern bool esp_tee_flash_check_prange_in_active_tee_part(const size_t paddr, const size_t len);
|
||||
#endif
|
||||
|
||||
static const char *TAG = "bootloader_flash";
|
||||
@@ -524,7 +524,7 @@ esp_err_t bootloader_flash_write(size_t dest_addr, void *src, size_t size, bool
|
||||
* by validating the address before proceeding.
|
||||
*/
|
||||
#if ESP_TEE_BUILD
|
||||
bool addr_chk = esp_tee_flash_check_paddr_in_active_tee_part(dest_addr);
|
||||
bool addr_chk = esp_tee_flash_check_prange_in_active_tee_part(dest_addr, size);
|
||||
if (addr_chk) {
|
||||
ESP_EARLY_LOGE(TAG, "bootloader_flash_write invalid dest_addr");
|
||||
return ESP_FAIL;
|
||||
@@ -578,7 +578,7 @@ esp_err_t bootloader_flash_erase_sector(size_t sector)
|
||||
esp_err_t bootloader_flash_erase_range(uint32_t start_addr, uint32_t size)
|
||||
{
|
||||
#if ESP_TEE_BUILD
|
||||
bool addr_chk = esp_tee_flash_check_paddr_in_active_tee_part(start_addr);
|
||||
bool addr_chk = esp_tee_flash_check_prange_in_active_tee_part(start_addr, size);
|
||||
if (addr_chk) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
+2
-1
@@ -55,7 +55,8 @@ void IRAM_ATTR bootloader_init_mspi_clock(void)
|
||||
// SPLL clock on C5 is 480MHz , and mspi_pll needs 80MHz
|
||||
// in this stage, set divider as 6
|
||||
_mspi_timing_ll_set_flash_clk_src(0, FLASH_CLK_SRC_SPLL);
|
||||
mspi_ll_fast_set_hs_divider(6);
|
||||
// MSPI0 and MSPI1 share this core clock register, but only setting to MSPI0 register is valid
|
||||
mspi_timing_ll_set_core_clock(MSPI_TIMING_LL_MSPI_ID_0, MSPI_TIMING_LL_CORE_CLOCK_MHZ_DEFAULT);
|
||||
}
|
||||
|
||||
void IRAM_ATTR bootloader_flash_clock_config(const esp_image_header_t *pfhdr)
|
||||
|
||||
+2
-1
@@ -52,7 +52,8 @@ void IRAM_ATTR bootloader_init_mspi_clock(void)
|
||||
// SPLL clock on C61 is 480MHz , and mspi_pll needs 80MHz
|
||||
// in this stage, set divider as 6
|
||||
_mspi_timing_ll_set_flash_clk_src(0, FLASH_CLK_SRC_DEFAULT);
|
||||
mspi_ll_fast_set_hs_divider(6);
|
||||
// MSPI0 and MSPI1 share this core clock register, but only setting to MSPI0 register is valid
|
||||
mspi_timing_ll_set_core_clock(MSPI_TIMING_LL_MSPI_ID_0, MSPI_TIMING_LL_CORE_CLOCK_MHZ_DEFAULT);
|
||||
}
|
||||
|
||||
void IRAM_ATTR bootloader_flash_clock_config(const esp_image_header_t *pfhdr)
|
||||
|
||||
@@ -224,6 +224,7 @@ static void bootloader_spi_flash_resume(void)
|
||||
|
||||
esp_err_t bootloader_init_spi_flash(void)
|
||||
{
|
||||
bootloader_init_mspi_clock();
|
||||
bootloader_init_flash_configure();
|
||||
|
||||
#if CONFIG_BOOTLOADER_FLASH_DC_AWARE
|
||||
|
||||
@@ -215,6 +215,10 @@ bool esp_flash_encryption_cfg_verify_release_mode(void);
|
||||
* It burns:
|
||||
* - "disable encrypt in dl mode"
|
||||
* - set FLASH_CRYPT_CNT efuse to max
|
||||
*
|
||||
* In case of the targets that support the XTS-AES peripheral's pseudo rounds function,
|
||||
* this API would configure the pseudo rounds level efuse bit to level low if the efuse bit
|
||||
* is not set already.
|
||||
*/
|
||||
void esp_flash_encryption_set_release_mode(void);
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
#if !CONFIG_IDF_TARGET_LINUX
|
||||
#include "rom/secure_boot.h"
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SECURE_BOOT_V1_ENABLED
|
||||
#if !defined(CONFIG_SECURE_SIGNED_ON_BOOT) || !defined(CONFIG_SECURE_SIGNED_ON_UPDATE) || !defined(CONFIG_SECURE_SIGNED_APPS)
|
||||
#error "internal sdkconfig error, secure boot should always enable all signature options"
|
||||
@@ -33,12 +32,20 @@ extern "C" {
|
||||
Can be compiled as part of app or bootloader code.
|
||||
*/
|
||||
|
||||
#if CONFIG_SECURE_BOOT_ECDSA_KEY_LEN_384_BITS
|
||||
#define ESP_SECURE_BOOT_DIGEST_LEN 48
|
||||
#else /* !CONFIG_SECURE_BOOT_ECDSA_KEY_LEN_384_BITS */
|
||||
#define ESP_SECURE_BOOT_DIGEST_LEN 32
|
||||
#endif /* CONFIG_SECURE_BOOT_ECDSA_KEY_LEN_384_BITS */
|
||||
|
||||
/* SHA-256 length of the public key digest */
|
||||
#define ESP_SECURE_BOOT_KEY_DIGEST_SHA_256_LEN 32
|
||||
|
||||
/* Length of the public key digest that is stored in efuses */
|
||||
#if CONFIG_IDF_TARGET_ESP32C2
|
||||
#define ESP_SECURE_BOOT_KEY_DIGEST_LEN 16
|
||||
#define ESP_SECURE_BOOT_KEY_DIGEST_LEN ESP_SECURE_BOOT_KEY_DIGEST_SHA_256_LEN / 2
|
||||
#else
|
||||
#define ESP_SECURE_BOOT_KEY_DIGEST_LEN 32
|
||||
#define ESP_SECURE_BOOT_KEY_DIGEST_LEN ESP_SECURE_BOOT_KEY_DIGEST_SHA_256_LEN
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
|
||||
@@ -193,7 +200,8 @@ esp_err_t esp_secure_boot_v2_permanently_enable(const esp_image_metadata_t *imag
|
||||
/** @brief Verify the secure boot signature appended to some binary data in flash.
|
||||
*
|
||||
* For ECDSA Scheme (Secure Boot V1) - deterministic ECDSA w/ SHA256 image
|
||||
* For RSA Scheme (Secure Boot V2) - RSA-PSS Verification of the SHA-256 image
|
||||
* For RSA Scheme (Secure Boot V2) - RSA-PSS Verification of the SHA-256 image digest
|
||||
* For ECDSA Scheme (Secure Boot V2) - ECDSA Verification of the SHA-256 / SHA-384 (in case of ECDSA-P384 secure boot key) image digest
|
||||
*
|
||||
* Public key is compiled into the calling program in the ECDSA Scheme.
|
||||
* See the apt docs/security/secure-boot-v1.rst or docs/security/secure-boot-v2.rst for details.
|
||||
@@ -217,6 +225,23 @@ typedef struct {
|
||||
uint8_t signature[64];
|
||||
} esp_secure_boot_sig_block_t;
|
||||
|
||||
/** @brief Get the size of the secure boot signature block
|
||||
*
|
||||
* This is the size of the signature block appended to a signed image.
|
||||
*
|
||||
* @return Size of the secure boot signature block in bytes
|
||||
*/
|
||||
static inline uint32_t esp_secure_boot_sig_block_size(void)
|
||||
{
|
||||
#if CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME || CONFIG_SECURE_SIGNED_APPS_ECDSA_V2_SCHEME
|
||||
return sizeof(ets_secure_boot_signature_t);
|
||||
#elif defined(CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME)
|
||||
return sizeof(esp_secure_boot_sig_block_t);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/** @brief Verify the ECDSA secure boot signature block for Secure Boot V1.
|
||||
*
|
||||
* Calculates Deterministic ECDSA w/ SHA256 based on the SHA256 hash of the image. ECDSA signature
|
||||
@@ -236,13 +261,13 @@ esp_err_t esp_secure_boot_verify_ecdsa_signature_block(const esp_secure_boot_sig
|
||||
|
||||
/** @brief Verify the secure boot signature block for Secure Boot V2.
|
||||
*
|
||||
* Performs RSA-PSS or ECDSA verification of the SHA-256 image based on the public key
|
||||
* Performs RSA-PSS or ECDSA verification of the SHA-256 / SHA-384 image based on the public key
|
||||
* in the signature block, compared against the public key digest stored in efuse.
|
||||
*
|
||||
* Similar to esp_secure_boot_verify_signature(), but can be used when the digest is precalculated.
|
||||
* @param[in] sig_block Pointer to signature block data
|
||||
* @param[in] image_digest Pointer to 32 byte buffer holding SHA-256 hash.
|
||||
* @param[out] verified_digest Pointer to 32 byte buffer that will receive verified digest if verification completes. (Used during bootloader implementation only, result is invalid otherwise.)
|
||||
* @param[in] image_digest Pointer to 32/48 byte buffer holding SHA-256/SHA-384 hash.
|
||||
* @param[out] verified_digest Pointer to 32/48 byte buffer that will receive verified digest if verification completes. (Used during bootloader implementation only, result is invalid otherwise.)
|
||||
*
|
||||
*/
|
||||
esp_err_t esp_secure_boot_verify_sbv2_signature_block(const ets_secure_boot_signature_t *sig_block, const uint8_t *image_digest, uint8_t *verified_digest);
|
||||
@@ -255,7 +280,7 @@ esp_err_t esp_secure_boot_verify_sbv2_signature_block(const ets_secure_boot_sign
|
||||
* Each image can have one or more signature blocks (up to SECURE_BOOT_NUM_BLOCKS). Each signature block includes a public key.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t key_digests[SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS][ESP_SECURE_BOOT_DIGEST_LEN]; /* SHA of the public key components in the signature block */
|
||||
uint8_t key_digests[SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS][ESP_SECURE_BOOT_KEY_DIGEST_SHA_256_LEN]; /* SHA of the public key components in the signature block */
|
||||
unsigned num_digests; /* Number of valid digests, starting at index 0 */
|
||||
} esp_image_sig_public_key_digests_t;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2017-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2017-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -12,15 +12,18 @@
|
||||
Use mbedTLS APIs or include esp32/sha.h to calculate SHA256 in IDF apps.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include "esp_err.h"
|
||||
#include "soc/soc_caps.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef void *bootloader_sha256_handle_t;
|
||||
typedef bootloader_sha256_handle_t bootloader_sha_handle_t;
|
||||
|
||||
bootloader_sha256_handle_t bootloader_sha256_start(void);
|
||||
|
||||
@@ -28,6 +31,14 @@ void bootloader_sha256_data(bootloader_sha256_handle_t handle, const void *data,
|
||||
|
||||
void bootloader_sha256_finish(bootloader_sha256_handle_t handle, uint8_t *digest);
|
||||
|
||||
#if SOC_SHA_SUPPORT_SHA512
|
||||
bootloader_sha_handle_t bootloader_sha512_start(bool is384);
|
||||
|
||||
void bootloader_sha512_data(bootloader_sha_handle_t handle, const void *data, size_t data_len);
|
||||
|
||||
void bootloader_sha512_finish(bootloader_sha_handle_t handle, uint8_t *digest);
|
||||
#endif /* SOC_SHA_SUPPORT_SHA512 */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -25,12 +25,11 @@ void bootloader_ana_super_wdt_reset_config(bool enable);
|
||||
void bootloader_ana_clock_glitch_reset_config(bool enable);
|
||||
|
||||
/**
|
||||
* @brief Configure analog power glitch reset & glitch reset dref
|
||||
* @brief Configure analog power glitch reset
|
||||
*
|
||||
* @param enable Boolean to enable or disable power glitch reset
|
||||
* @param dref voltage threshold
|
||||
*/
|
||||
void bootloader_power_glitch_reset_config(bool enable, uint8_t dref);
|
||||
void bootloader_power_glitch_reset_config(bool enable);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2018-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2018-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -138,6 +138,20 @@ void bootloader_debug_buffer(const void *buffer, size_t length, const char *labe
|
||||
*/
|
||||
esp_err_t bootloader_sha256_flash_contents(uint32_t flash_offset, uint32_t len, uint8_t *digest);
|
||||
|
||||
/** @brief Generates the digest of the data between offset & offset+length.
|
||||
*
|
||||
* This function should be used when the size of the data is larger than 3.2MB.
|
||||
* The MMU capacity is 3.2MB (50 pages - 64KB each). This function generates the SHA-384
|
||||
* of the data in chunks of 3.2MB, considering the MMU capacity.
|
||||
*
|
||||
* @param[in] flash_offset Offset of the data in flash.
|
||||
* @param[in] len Length of data in bytes.
|
||||
* @param[out] digest Pointer to buffer where the digest is written, if ESP_OK is returned.
|
||||
*
|
||||
* @return ESP_OK if secure boot digest is generated successfully.
|
||||
*/
|
||||
esp_err_t bootloader_sha384_flash_contents(uint32_t flash_offset, uint32_t len, uint8_t *digest);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -34,7 +34,11 @@ __attribute__((weak)) void bootloader_clock_configure(void)
|
||||
esp_rom_output_tx_wait_idle(0);
|
||||
|
||||
/* Set CPU to a higher certain frequency. Keep other clocks unmodified. */
|
||||
#if CONFIG_IDF_TARGET_ESP32P4 && !CONFIG_ESP32P4_SELECTS_REV_LESS_V3
|
||||
int cpu_freq_mhz = 100;
|
||||
#else
|
||||
int cpu_freq_mhz = CPU_CLK_FREQ_MHZ_BTLD;
|
||||
#endif
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
/* On ESP32 rev 0, switching to 80/160 MHz if clock was previously set to
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
#define ESP_PARTITION_HASH_LEN 32 /* SHA-256 digest length */
|
||||
#define IS_FIELD_SET(rev_full) (((rev_full) != 65535) && ((rev_full) != 0))
|
||||
#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
|
||||
|
||||
static const char* TAG = "boot_comm";
|
||||
|
||||
@@ -264,7 +265,10 @@ rtc_retain_mem_t* bootloader_common_get_rtc_retain_mem(void)
|
||||
#if ESP_ROM_HAS_LP_ROM
|
||||
#define RTC_RETAIN_MEM_ADDR (SOC_RTC_DRAM_LOW)
|
||||
#else
|
||||
#define RTC_RETAIN_MEM_ADDR (SOC_RTC_DRAM_HIGH - sizeof(rtc_retain_mem_t))
|
||||
/* Since the structure containing the retain_mem_t is aligned on 8 by the linker, make sure we align this
|
||||
* structure size here too */
|
||||
#define RETAIN_MEM_SIZE ALIGN_UP(sizeof(rtc_retain_mem_t), 8)
|
||||
#define RTC_RETAIN_MEM_ADDR (SOC_RTC_DRAM_HIGH - RETAIN_MEM_SIZE)
|
||||
#endif //ESP_ROM_HAS_LP_ROM
|
||||
static rtc_retain_mem_t *const s_bootloader_retain_mem = (rtc_retain_mem_t *)RTC_RETAIN_MEM_ADDR;
|
||||
return s_bootloader_retain_mem;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "hal/wdt_hal.h"
|
||||
#include "hal/efuse_hal.h"
|
||||
#include "esp_bootloader_desc.h"
|
||||
#include "esp_rom_sys.h"
|
||||
|
||||
static const char *TAG = "boot";
|
||||
|
||||
@@ -34,7 +35,12 @@ void bootloader_clear_bss_section(void)
|
||||
esp_err_t bootloader_read_bootloader_header(void)
|
||||
{
|
||||
/* load bootloader image header */
|
||||
if (bootloader_flash_read(ESP_BOOTLOADER_OFFSET, &bootloader_image_hdr, sizeof(esp_image_header_t), true) != ESP_OK) {
|
||||
#if SOC_RECOVERY_BOOTLOADER_SUPPORTED
|
||||
const uint32_t bootloader_flash_offset = esp_rom_get_bootloader_offset();
|
||||
#else
|
||||
const uint32_t bootloader_flash_offset = ESP_PRIMARY_BOOTLOADER_OFFSET;
|
||||
#endif
|
||||
if (bootloader_flash_read(bootloader_flash_offset, &bootloader_image_hdr, sizeof(esp_image_header_t), true) != ESP_OK) {
|
||||
ESP_EARLY_LOGE(TAG, "failed to load bootloader image header!");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
@@ -25,20 +25,19 @@ void bootloader_init_mem(void)
|
||||
* So, at boot disabling these filters. They will enable as per the
|
||||
* use case by TEE initialization code.
|
||||
*/
|
||||
#ifdef SOC_APM_CTRL_FILTER_SUPPORTED
|
||||
apm_hal_apm_ctrl_filter_enable_all(false);
|
||||
/* [APM] On power-up, only the HP CPU starts in TEE mode; others default to REE2.
|
||||
* APM blocks REE0–REE2 access by default. C5 ECO2 adds per-peripheral control
|
||||
* (default REEx blocking), but config support is pending. As a workaround,
|
||||
* all masters are set to TEE mode.
|
||||
#if SOC_APM_CTRL_FILTER_SUPPORTED
|
||||
apm_hal_enable_ctrl_filter_all(false);
|
||||
/* [APM] On power-up, only the HP CPU starts in TEE mode; others
|
||||
* default to REE2. APM blocks REE0–REE2 access by default.
|
||||
* Thus, all masters are set to TEE mode.
|
||||
*/
|
||||
#if SOC_APM_SUPPORT_TEE_PERI_ACCESS_CTRL
|
||||
apm_tee_hal_set_master_secure_mode_all(APM_LL_SECURE_MODE_TEE);
|
||||
apm_hal_set_master_sec_mode_all(APM_SEC_MODE_TEE);
|
||||
#endif // SOC_APM_SUPPORT_TEE_PERI_ACCESS_CTRL
|
||||
#endif // SOC_APM_CTRL_FILTER_SUPPORTED
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BOOTLOADER_REGION_PROTECTION_ENABLE
|
||||
#if CONFIG_BOOTLOADER_REGION_PROTECTION_ENABLE
|
||||
// protect memory region
|
||||
esp_cpu_configure_region_protection();
|
||||
#endif
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "hal/adc_ll.h"
|
||||
#include "hal/adc_types.h"
|
||||
#include "esp_private/regi2c_ctrl.h"
|
||||
#include "soc/lpperi_reg.h"
|
||||
|
||||
void bootloader_random_enable(void)
|
||||
{
|
||||
@@ -48,6 +49,9 @@ void bootloader_random_enable(void)
|
||||
adc_ll_digi_set_trigger_interval(200);
|
||||
adc_ll_digi_trigger_enable();
|
||||
|
||||
SET_PERI_REG_MASK(LPPERI_RNG_CFG_REG, LPPERI_RNG_SAMPLE_ENABLE);
|
||||
REG_SET_FIELD(LPPERI_RNG_CFG_REG, LPPERI_RTC_TIMER_EN, 0x3);
|
||||
SET_PERI_REG_MASK(LPPERI_RNG_CFG_REG, LPPERI_RNG_TIMER_EN);
|
||||
}
|
||||
|
||||
void bootloader_random_disable(void)
|
||||
|
||||
@@ -29,15 +29,6 @@ bootloader_sha256_handle_t bootloader_sha256_start()
|
||||
void bootloader_sha256_data(bootloader_sha256_handle_t handle, const void *data, size_t data_len)
|
||||
{
|
||||
assert(handle != NULL);
|
||||
|
||||
#if !SOC_SECURE_BOOT_V2_ECC
|
||||
/* For secure boot, the key field consists of 1 byte of curve identifier and 64 bytes of ECDSA public key.
|
||||
* While verifying the signature block, we need to calculate the SHA of this key field which is of 65 bytes.
|
||||
* ets_sha_update handles it cleanly so we can safely remove the check:
|
||||
*/
|
||||
assert(data_len % 4 == 0);
|
||||
#endif /* SOC_SECURE_BOOT_V2_ECC */
|
||||
|
||||
ets_sha_update(&ctx, data, data_len, false);
|
||||
}
|
||||
|
||||
@@ -51,6 +42,33 @@ void bootloader_sha256_finish(bootloader_sha256_handle_t handle, uint8_t *digest
|
||||
}
|
||||
ets_sha_finish(&ctx, digest);
|
||||
}
|
||||
|
||||
#if SOC_SHA_SUPPORT_SHA512
|
||||
bootloader_sha_handle_t bootloader_sha512_start(bool is384)
|
||||
{
|
||||
// Enable SHA hardware
|
||||
ets_sha_enable();
|
||||
ets_sha_init(&ctx, is384 ? SHA2_384 : SHA2_512);
|
||||
return &ctx; // Meaningless non-NULL value
|
||||
}
|
||||
|
||||
void bootloader_sha512_data(bootloader_sha_handle_t handle, const void *data, size_t data_len)
|
||||
{
|
||||
assert(handle != NULL);
|
||||
ets_sha_update(&ctx, data, data_len, false);
|
||||
}
|
||||
|
||||
void bootloader_sha512_finish(bootloader_sha_handle_t handle, uint8_t *digest)
|
||||
{
|
||||
assert(handle != NULL);
|
||||
|
||||
if (digest == NULL) {
|
||||
bzero(&ctx, sizeof(ctx));
|
||||
return;
|
||||
}
|
||||
ets_sha_finish(&ctx, digest);
|
||||
}
|
||||
#endif /* SOC_SHA_SUPPORT_SHA512 */
|
||||
#else /* !CONFIG_IDF_TARGET_ESP32 */
|
||||
|
||||
#include "soc/dport_reg.h"
|
||||
@@ -162,6 +180,7 @@ void bootloader_sha256_finish(bootloader_sha256_handle_t handle, uint8_t *digest
|
||||
|
||||
#include "bootloader_flash_priv.h"
|
||||
#include <mbedtls/sha256.h>
|
||||
#include <mbedtls/sha512.h>
|
||||
|
||||
bootloader_sha256_handle_t bootloader_sha256_start(void)
|
||||
{
|
||||
@@ -199,4 +218,43 @@ void bootloader_sha256_finish(bootloader_sha256_handle_t handle, uint8_t *digest
|
||||
free(handle);
|
||||
handle = NULL;
|
||||
}
|
||||
|
||||
#if SOC_SHA_SUPPORT_SHA512
|
||||
bootloader_sha_handle_t bootloader_sha512_start(bool is384)
|
||||
{
|
||||
mbedtls_sha512_context *ctx = (mbedtls_sha512_context *)malloc(sizeof(mbedtls_sha512_context));
|
||||
if (!ctx) {
|
||||
return NULL;
|
||||
}
|
||||
mbedtls_sha512_init(ctx);
|
||||
int ret = mbedtls_sha512_starts(ctx, is384);
|
||||
if (ret != 0) {
|
||||
return NULL;
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void bootloader_sha512_data(bootloader_sha_handle_t handle, const void *data, size_t data_len)
|
||||
{
|
||||
assert(handle != NULL);
|
||||
mbedtls_sha512_context *ctx = (mbedtls_sha512_context *)handle;
|
||||
int ret = mbedtls_sha512_update(ctx, data, data_len);
|
||||
assert(ret == 0);
|
||||
(void)ret;
|
||||
}
|
||||
|
||||
void bootloader_sha512_finish(bootloader_sha_handle_t handle, uint8_t *digest)
|
||||
{
|
||||
assert(handle != NULL);
|
||||
mbedtls_sha512_context *ctx = (mbedtls_sha512_context *)handle;
|
||||
if (digest != NULL) {
|
||||
int ret = mbedtls_sha512_finish(ctx, digest);
|
||||
assert(ret == 0);
|
||||
(void)ret;
|
||||
}
|
||||
mbedtls_sha512_free(ctx);
|
||||
free(handle);
|
||||
handle = NULL;
|
||||
}
|
||||
#endif /* SOC_SHA_SUPPORT_SHA512 */
|
||||
#endif /* !(NON_OS_BUILD || CONFIG_APP_BUILD_TYPE_RAM) */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2018-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2018-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "hal/cache_types.h"
|
||||
#include "hal/cache_ll.h"
|
||||
#include "hal/cache_hal.h"
|
||||
#include "hal/sha_types.h"
|
||||
|
||||
#include "esp_cpu.h"
|
||||
#include "esp_image_format.h"
|
||||
@@ -1213,18 +1214,29 @@ void bootloader_debug_buffer(const void *buffer, size_t length, const char *labe
|
||||
#endif
|
||||
}
|
||||
|
||||
esp_err_t bootloader_sha256_flash_contents(uint32_t flash_offset, uint32_t len, uint8_t *digest)
|
||||
static esp_err_t bootloader_sha_flash_contents(esp_sha_type type, uint32_t flash_offset, uint32_t len, uint8_t *digest)
|
||||
{
|
||||
|
||||
if (digest == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
/* Handling firmware images larger than MMU capacity */
|
||||
uint32_t mmu_free_pages_count = bootloader_mmap_get_free_pages();
|
||||
bootloader_sha256_handle_t sha_handle = NULL;
|
||||
bootloader_sha_handle_t sha_handle = NULL;
|
||||
|
||||
if (type == SHA2_256) {
|
||||
sha_handle = bootloader_sha256_start();
|
||||
} else
|
||||
// Using SOC_ECDSA_SUPPORT_CURVE_P384 here so that there is no flash size impact in the case of existing targets like ESP32.
|
||||
#if SOC_SHA_SUPPORT_SHA384 && SOC_ECDSA_SUPPORT_CURVE_P384
|
||||
if (type == SHA2_384) {
|
||||
sha_handle = bootloader_sha512_start(true);
|
||||
} else
|
||||
#endif /* SOC_SHA_SUPPORT_SHA384 && SOC_ECDSA_SUPPORT_CURVE_P384 */
|
||||
{
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
sha_handle = bootloader_sha256_start();
|
||||
if (sha_handle == NULL) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
@@ -1234,7 +1246,14 @@ esp_err_t bootloader_sha256_flash_contents(uint32_t flash_offset, uint32_t len,
|
||||
uint32_t max_pages = (mmu_free_pages_count > mmu_page_offset) ? (mmu_free_pages_count - mmu_page_offset) : 0;
|
||||
if (max_pages == 0) {
|
||||
ESP_LOGE(TAG, "No free MMU pages are available");
|
||||
bootloader_sha256_finish(sha_handle, NULL);
|
||||
if (type == SHA2_256) {
|
||||
bootloader_sha256_finish(sha_handle, NULL);
|
||||
}
|
||||
#if SOC_SHA_SUPPORT_SHA384 && SOC_ECDSA_SUPPORT_CURVE_P384
|
||||
else if (type == SHA2_384) {
|
||||
bootloader_sha512_finish(sha_handle, NULL);
|
||||
}
|
||||
#endif /* SOC_SHA_SUPPORT_SHA384 && SOC_ECDSA_SUPPORT_CURVE_P384 */
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
uint32_t max_image_len;
|
||||
@@ -1245,15 +1264,51 @@ esp_err_t bootloader_sha256_flash_contents(uint32_t flash_offset, uint32_t len,
|
||||
|
||||
const void * image = bootloader_mmap(flash_offset, partial_image_len);
|
||||
if (image == NULL) {
|
||||
bootloader_sha256_finish(sha_handle, NULL);
|
||||
if (type == SHA2_256) {
|
||||
bootloader_sha256_finish(sha_handle, NULL);
|
||||
}
|
||||
#if SOC_SHA_SUPPORT_SHA384 && SOC_ECDSA_SUPPORT_CURVE_P384
|
||||
else if (type == SHA2_384) {
|
||||
bootloader_sha512_finish(sha_handle, NULL);
|
||||
}
|
||||
#endif /* SOC_SHA_SUPPORT_SHA384 && SOC_ECDSA_SUPPORT_CURVE_P384 */
|
||||
return ESP_FAIL;
|
||||
}
|
||||
bootloader_sha256_data(sha_handle, image, partial_image_len);
|
||||
|
||||
if (type == SHA2_256) {
|
||||
bootloader_sha256_data(sha_handle, image, partial_image_len);
|
||||
}
|
||||
#if SOC_SHA_SUPPORT_SHA384 && SOC_ECDSA_SUPPORT_CURVE_P384
|
||||
else if (type == SHA2_384) {
|
||||
bootloader_sha512_data(sha_handle, image, partial_image_len);
|
||||
}
|
||||
#endif /* SOC_SHA_SUPPORT_SHA384 && SOC_ECDSA_SUPPORT_CURVE_P384 */
|
||||
|
||||
bootloader_munmap(image);
|
||||
|
||||
flash_offset += partial_image_len;
|
||||
len -= partial_image_len;
|
||||
}
|
||||
bootloader_sha256_finish(sha_handle, digest);
|
||||
|
||||
if (type == SHA2_256) {
|
||||
bootloader_sha256_finish(sha_handle, digest);
|
||||
}
|
||||
#if SOC_SHA_SUPPORT_SHA384 && SOC_ECDSA_SUPPORT_CURVE_P384
|
||||
else if (type == SHA2_384) {
|
||||
bootloader_sha512_finish(sha_handle, digest);
|
||||
}
|
||||
#endif /* SOC_SHA_SUPPORT_SHA384 && SOC_ECDSA_SUPPORT_CURVE_P384 */
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t bootloader_sha256_flash_contents(uint32_t flash_offset, uint32_t len, uint8_t *digest)
|
||||
{
|
||||
return bootloader_sha_flash_contents(SHA2_256, flash_offset, len, digest);
|
||||
}
|
||||
|
||||
#if SOC_SHA_SUPPORT_SHA384 && SOC_ECDSA_SUPPORT_CURVE_P384
|
||||
esp_err_t bootloader_sha384_flash_contents(uint32_t flash_offset, uint32_t len, uint8_t *digest)
|
||||
{
|
||||
return bootloader_sha_flash_contents(SHA2_384, flash_offset, len, digest);
|
||||
}
|
||||
#endif /* SOC_SHA_SUPPORT_SHA384 && SOC_ECDSA_SUPPORT_CURVE_P384 */
|
||||
|
||||
@@ -94,11 +94,7 @@ static inline void bootloader_ana_reset_config(void)
|
||||
{
|
||||
//Enable BOD reset (mode1)
|
||||
brownout_ll_ana_reset_enable(true);
|
||||
if (efuse_hal_chip_revision() == 0) {
|
||||
// decrease power glitch reset voltage to avoid start the glitch reset
|
||||
uint8_t power_glitch_dref = 0;
|
||||
bootloader_power_glitch_reset_config(true, power_glitch_dref);
|
||||
}
|
||||
bootloader_power_glitch_reset_config(true);
|
||||
}
|
||||
|
||||
esp_err_t bootloader_init(void)
|
||||
|
||||
@@ -17,18 +17,18 @@ void bootloader_ana_clock_glitch_reset_config(bool enable)
|
||||
(void)enable;
|
||||
}
|
||||
|
||||
void bootloader_power_glitch_reset_config(bool enable, uint8_t dref)
|
||||
void bootloader_power_glitch_reset_config(bool enable)
|
||||
{
|
||||
assert(dref < 8);
|
||||
REG_SET_FIELD(LP_ANA_FIB_ENABLE_REG, LP_ANA_ANA_FIB_PWR_GLITCH_ENA, 0);
|
||||
//only detect VDDPST POWER GLITCH
|
||||
SET_PERI_REG_MASK(PMU_RF_PWC_REG, PMU_PERIF_I2C_RSTB);
|
||||
SET_PERI_REG_MASK(PMU_RF_PWC_REG, PMU_XPD_PERIF_I2C);
|
||||
REGI2C_WRITE_MASK(I2C_SAR_ADC, POWER_GLITCH_XPD_VDET_PERIF, 0);
|
||||
REGI2C_WRITE_MASK(I2C_SAR_ADC, POWER_GLITCH_XPD_VDET_XTAL, 0);
|
||||
REGI2C_WRITE_MASK(I2C_SAR_ADC, POWER_GLITCH_XPD_VDET_PLL, 0);
|
||||
|
||||
REG_SET_FIELD(LP_ANA_FIB_ENABLE_REG, LP_ANA_ANA_FIB_PWR_GLITCH_ENA, 0);//default val for chip from ECO1
|
||||
if (enable) {
|
||||
SET_PERI_REG_MASK(PMU_RF_PWC_REG, PMU_PERIF_I2C_RSTB);
|
||||
SET_PERI_REG_MASK(PMU_RF_PWC_REG, PMU_XPD_PERIF_I2C);
|
||||
REGI2C_WRITE_MASK(I2C_SAR_ADC, POWER_GLITCH_DREF_VDET_PERIF, dref);
|
||||
REGI2C_WRITE_MASK(I2C_SAR_ADC, POWER_GLITCH_DREF_VDET_VDDPST, dref);
|
||||
REGI2C_WRITE_MASK(I2C_SAR_ADC, POWER_GLITCH_DREF_VDET_XTAL, dref);
|
||||
REGI2C_WRITE_MASK(I2C_SAR_ADC, POWER_GLITCH_DREF_VDET_PLL, dref);
|
||||
REG_SET_FIELD(LP_ANA_POWER_GLITCH_CNTL_REG, LP_ANA_PWR_GLITCH_RESET_ENA, 0xf);
|
||||
REG_SET_FIELD(LP_ANA_POWER_GLITCH_CNTL_REG, LP_ANA_PWR_GLITCH_RESET_ENA, 0xf);//default val for chip from ECO1
|
||||
} else {
|
||||
REG_SET_FIELD(LP_ANA_POWER_GLITCH_CNTL_REG, LP_ANA_PWR_GLITCH_RESET_ENA, 0);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -44,7 +44,7 @@ esp_err_t esp_flash_encryption_enable_secure_features(void)
|
||||
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DIRECT_BOOT);
|
||||
|
||||
#if defined(CONFIG_SECURE_FLASH_ENCRYPTION_MODE_RELEASE) && defined(SOC_FLASH_ENCRYPTION_XTS_AES_SUPPORT_PSEUDO_ROUND)
|
||||
#if CONFIG_SECURE_FLASH_PSEUDO_ROUND_FUNC
|
||||
ESP_LOGI(TAG, "Enable XTS-AES pseudo rounds function...");
|
||||
uint8_t xts_pseudo_level = CONFIG_SECURE_FLASH_PSEUDO_ROUND_FUNC_STRENGTH;
|
||||
esp_efuse_write_field_blob(ESP_EFUSE_XTS_DPA_PSEUDO_LEVEL, &xts_pseudo_level, ESP_EFUSE_XTS_DPA_PSEUDO_LEVEL[0]->bit_count);
|
||||
@@ -71,12 +71,9 @@ esp_err_t esp_flash_encryption_enable_secure_features(void)
|
||||
|
||||
esp_err_t esp_flash_encryption_enable_key_mgr(void)
|
||||
{
|
||||
// Enable and reset key manager
|
||||
// To suppress build errors about spinlock's __DECLARE_RCC_ATOMIC_ENV
|
||||
int __DECLARE_RCC_ATOMIC_ENV __attribute__ ((unused));
|
||||
key_mgr_ll_enable_bus_clock(true);
|
||||
key_mgr_ll_enable_peripheral_clock(true);
|
||||
key_mgr_ll_reset_register();
|
||||
_key_mgr_ll_enable_bus_clock(true);
|
||||
_key_mgr_ll_enable_peripheral_clock(true);
|
||||
_key_mgr_ll_reset_register();
|
||||
|
||||
while (key_mgr_ll_get_state() != ESP_KEY_MGR_STATE_IDLE) {
|
||||
};
|
||||
|
||||
@@ -49,6 +49,10 @@ esp_err_t esp_secure_boot_enable_secure_features(void)
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_AGGRESSIVE_REVOKE);
|
||||
#endif
|
||||
|
||||
#if CONFIG_SECURE_BOOT_ECDSA_KEY_LEN_384_BITS
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_SHA384_EN);
|
||||
#endif
|
||||
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_EN);
|
||||
|
||||
#ifndef CONFIG_SECURE_BOOT_V2_ALLOW_EFUSE_RD_DIS
|
||||
|
||||
@@ -95,8 +95,7 @@ static inline void bootloader_ana_reset_config(void)
|
||||
{
|
||||
//Enable BOD reset (mode1)
|
||||
brownout_ll_ana_reset_enable(true);
|
||||
uint8_t power_glitch_dref = 0;
|
||||
bootloader_power_glitch_reset_config(true, power_glitch_dref);
|
||||
bootloader_power_glitch_reset_config(true);
|
||||
}
|
||||
|
||||
esp_err_t bootloader_init(void)
|
||||
|
||||
@@ -17,18 +17,18 @@ void bootloader_ana_clock_glitch_reset_config(bool enable)
|
||||
(void)enable;
|
||||
}
|
||||
|
||||
void bootloader_power_glitch_reset_config(bool enable, uint8_t dref)
|
||||
void bootloader_power_glitch_reset_config(bool enable)
|
||||
{
|
||||
assert(dref < 8);
|
||||
REG_SET_FIELD(LP_ANA_FIB_ENABLE_REG, LP_ANA_ANA_FIB_PWR_GLITCH_ENA, 0);
|
||||
//only detect VDDPST POWER GLITCH
|
||||
SET_PERI_REG_MASK(PMU_RF_PWC_REG, PMU_PERIF_I2C_RSTB);
|
||||
SET_PERI_REG_MASK(PMU_RF_PWC_REG, PMU_XPD_PERIF_I2C);
|
||||
REGI2C_WRITE_MASK(I2C_SAR_ADC, POWER_GLITCH_XPD_VDET_PERIF, 0);
|
||||
REGI2C_WRITE_MASK(I2C_SAR_ADC, POWER_GLITCH_XPD_VDET_PLLBB, 0);
|
||||
REGI2C_WRITE_MASK(I2C_SAR_ADC, POWER_GLITCH_XPD_VDET_PLL, 0);
|
||||
|
||||
REG_SET_FIELD(LP_ANA_FIB_ENABLE_REG, LP_ANA_ANA_FIB_PWR_GLITCH_ENA, 0);//default val for chip from ECO2
|
||||
if (enable) {
|
||||
SET_PERI_REG_MASK(PMU_RF_PWC_REG, PMU_PERIF_I2C_RSTB);
|
||||
SET_PERI_REG_MASK(PMU_RF_PWC_REG, PMU_XPD_PERIF_I2C);
|
||||
REGI2C_WRITE_MASK(I2C_SAR_ADC, POWER_GLITCH_DREF_VDET_PERIF, dref);
|
||||
REGI2C_WRITE_MASK(I2C_SAR_ADC, POWER_GLITCH_DREF_VDET_VDDPST, dref);
|
||||
REGI2C_WRITE_MASK(I2C_SAR_ADC, POWER_GLITCH_DREF_VDET_PLLBB, dref);
|
||||
REGI2C_WRITE_MASK(I2C_SAR_ADC, POWER_GLITCH_DREF_VDET_PLL, dref);
|
||||
REG_SET_FIELD(LP_ANA_POWER_GLITCH_CNTL_REG, LP_ANA_POWER_GLITCH_RESET_ENA, 0xf);
|
||||
REG_SET_FIELD(LP_ANA_POWER_GLITCH_CNTL_REG, LP_ANA_POWER_GLITCH_RESET_ENA, 0xf);//default val for chip from ECO2
|
||||
} else {
|
||||
REG_SET_FIELD(LP_ANA_POWER_GLITCH_CNTL_REG, LP_ANA_POWER_GLITCH_RESET_ENA, 0);
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ esp_err_t esp_flash_encryption_enable_secure_features(void)
|
||||
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DIRECT_BOOT);
|
||||
|
||||
#if defined(CONFIG_SECURE_FLASH_ENCRYPTION_MODE_RELEASE) && defined(SOC_FLASH_ENCRYPTION_XTS_AES_SUPPORT_PSEUDO_ROUND)
|
||||
#if CONFIG_SECURE_FLASH_PSEUDO_ROUND_FUNC
|
||||
ESP_LOGI(TAG, "Enable XTS-AES pseudo rounds function...");
|
||||
uint8_t xts_pseudo_level = CONFIG_SECURE_FLASH_PSEUDO_ROUND_FUNC_STRENGTH;
|
||||
esp_efuse_write_field_blob(ESP_EFUSE_XTS_DPA_PSEUDO_LEVEL, &xts_pseudo_level, ESP_EFUSE_XTS_DPA_PSEUDO_LEVEL[0]->bit_count);
|
||||
|
||||
@@ -36,7 +36,7 @@ esp_err_t esp_flash_encryption_enable_secure_features(void)
|
||||
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DIRECT_BOOT);
|
||||
|
||||
#if defined(CONFIG_SECURE_FLASH_ENCRYPTION_MODE_RELEASE) && defined(SOC_FLASH_ENCRYPTION_XTS_AES_SUPPORT_PSEUDO_ROUND)
|
||||
#if CONFIG_SECURE_FLASH_PSEUDO_ROUND_FUNC
|
||||
if (spi_flash_encrypt_ll_is_pseudo_rounds_function_supported()) {
|
||||
ESP_LOGI(TAG, "Enable XTS-AES pseudo rounds function...");
|
||||
uint8_t xts_pseudo_level = CONFIG_SECURE_FLASH_PSEUDO_ROUND_FUNC_STRENGTH;
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <strings.h>
|
||||
#include "hal/ecdsa_ll.h"
|
||||
#include "esp_flash_encrypt.h"
|
||||
#include "esp_secure_boot.h"
|
||||
#include "esp_efuse.h"
|
||||
|
||||
@@ -36,10 +36,6 @@ esp_err_t esp_secure_boot_enable_secure_features(void)
|
||||
ESP_LOGW(TAG, "UART ROM Download mode kept enabled - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
#ifdef SOC_ECDSA_P192_CURVE_DEFAULT_DISABLED
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_ECDSA_CURVE_MODE);
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG
|
||||
ESP_LOGI(TAG, "Disable hardware & software JTAG...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_PAD_JTAG);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -53,12 +53,9 @@ esp_err_t esp_flash_encryption_enable_secure_features(void)
|
||||
|
||||
esp_err_t esp_flash_encryption_enable_key_mgr(void)
|
||||
{
|
||||
// Enable and reset key manager
|
||||
// To suppress build errors about spinlock's __DECLARE_RCC_ATOMIC_ENV
|
||||
int __DECLARE_RCC_ATOMIC_ENV __attribute__ ((unused));
|
||||
key_mgr_ll_enable_bus_clock(true);
|
||||
key_mgr_ll_enable_peripheral_clock(true);
|
||||
key_mgr_ll_reset_register();
|
||||
_key_mgr_ll_enable_bus_clock(true);
|
||||
_key_mgr_ll_enable_peripheral_clock(true);
|
||||
_key_mgr_ll_reset_register();
|
||||
|
||||
while (key_mgr_ll_get_state() != ESP_KEY_MGR_STATE_IDLE) {
|
||||
};
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "soc/soc_caps.h"
|
||||
#include "hal/cache_ll.h"
|
||||
#include "spi_flash_mmap.h"
|
||||
#include "hal/efuse_hal.h"
|
||||
|
||||
#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
|
||||
|
||||
@@ -104,7 +105,6 @@ static esp_err_t verify_segment_header(int index, const esp_image_segment_header
|
||||
static esp_err_t process_image_header(esp_image_metadata_t *data, uint32_t part_offset, bootloader_sha256_handle_t *sha_handle, bool do_verify, bool silent);
|
||||
static esp_err_t process_appended_hash_and_sig(esp_image_metadata_t *data, uint32_t part_offset, uint32_t part_len, bool do_verify, bool silent);
|
||||
static esp_err_t process_checksum(bootloader_sha256_handle_t sha_handle, uint32_t checksum_word, esp_image_metadata_t *data, bool silent, bool skip_check_checksum);
|
||||
|
||||
static esp_err_t __attribute__((unused)) verify_secure_boot_signature(bootloader_sha256_handle_t sha_handle, esp_image_metadata_t *data, uint8_t *image_digest, uint8_t *verified_digest);
|
||||
static esp_err_t __attribute__((unused)) verify_simple_hash(bootloader_sha256_handle_t sha_handle, esp_image_metadata_t *data);
|
||||
|
||||
@@ -119,11 +119,26 @@ void esp_image_bootloader_offset_set(const uint32_t offset)
|
||||
{
|
||||
s_bootloader_partition_offset = offset;
|
||||
ESP_LOGI(TAG, "Bootloader offsets for PRIMARY: 0x%x, Secondary: 0x%" PRIx32, ESP_PRIMARY_BOOTLOADER_OFFSET, s_bootloader_partition_offset);
|
||||
#if SOC_RECOVERY_BOOTLOADER_SUPPORTED
|
||||
uint32_t recovery_offset = efuse_hal_get_recovery_bootloader_address();
|
||||
if (efuse_hal_recovery_bootloader_enabled()) {
|
||||
ESP_LOGI(TAG, "Bootloader offset for RECOVERY: 0x%" PRIx32, recovery_offset);
|
||||
} else if (recovery_offset == 0) {
|
||||
ESP_LOGI(TAG, "Bootloader offset for RECOVERY: has not been set yet");
|
||||
} else {
|
||||
ESP_LOGI(TAG, "Bootloader offset for RECOVERY: is disabled");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool is_bootloader(uint32_t offset)
|
||||
{
|
||||
return ((offset == ESP_PRIMARY_BOOTLOADER_OFFSET) || (offset == s_bootloader_partition_offset));
|
||||
return ((offset == ESP_PRIMARY_BOOTLOADER_OFFSET)
|
||||
|| (offset == s_bootloader_partition_offset)
|
||||
#if SOC_RECOVERY_BOOTLOADER_SUPPORTED
|
||||
|| (efuse_hal_recovery_bootloader_enabled() ? offset == efuse_hal_get_recovery_bootloader_address() : false)
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
static esp_err_t image_load(esp_image_load_mode_t mode, const esp_partition_pos_t *part, esp_image_metadata_t *data)
|
||||
@@ -144,8 +159,8 @@ static esp_err_t image_load(esp_image_load_mode_t mode, const esp_partition_pos_
|
||||
bool verify_sha;
|
||||
#if (SECURE_BOOT_CHECK_SIGNATURE == 1)
|
||||
/* used for anti-FI checks */
|
||||
uint8_t image_digest[HASH_LEN] = { [ 0 ... 31] = 0xEE };
|
||||
uint8_t verified_digest[HASH_LEN] = { [ 0 ... 31 ] = 0x01 };
|
||||
uint8_t image_digest[ESP_SECURE_BOOT_DIGEST_LEN] = { [ 0 ... ESP_SECURE_BOOT_DIGEST_LEN - 1 ] = 0xEE };
|
||||
uint8_t verified_digest[ESP_SECURE_BOOT_DIGEST_LEN] = { [ 0 ... ESP_SECURE_BOOT_DIGEST_LEN - 1 ] = 0x01 };
|
||||
#endif
|
||||
|
||||
if (data == NULL || part == NULL) {
|
||||
@@ -221,7 +236,7 @@ static esp_err_t image_load(esp_image_load_mode_t mode, const esp_partition_pos_
|
||||
"only verify signature in bootloader" into the macro so it's tested multiple times.
|
||||
*/
|
||||
#if CONFIG_SECURE_BOOT_V2_ENABLED
|
||||
ESP_FAULT_ASSERT(!esp_secure_boot_enabled() || memcmp(image_digest, verified_digest, HASH_LEN) == 0);
|
||||
ESP_FAULT_ASSERT(!esp_secure_boot_enabled() || memcmp(image_digest, verified_digest, ESP_SECURE_BOOT_DIGEST_LEN) == 0);
|
||||
#else // Secure Boot V1 on ESP32, only verify signatures for apps not bootloaders
|
||||
ESP_FAULT_ASSERT(is_bootloader(data->start_addr) || memcmp(image_digest, verified_digest, HASH_LEN) == 0);
|
||||
#endif
|
||||
@@ -371,6 +386,11 @@ err:
|
||||
}
|
||||
|
||||
#ifdef BOOTLOADER_BUILD
|
||||
#if CONFIG_IDF_TARGET_ESP32P4 && !CONFIG_ESP32P4_SELECTS_REV_LESS_V3
|
||||
#define ROM_STACK_START (SOC_ROM_STACK_START_REV2)
|
||||
#else
|
||||
#define ROM_STACK_START (SOC_ROM_STACK_START)
|
||||
#endif
|
||||
/* Check the region load_addr - load_end doesn't overlap any memory used by the bootloader, registers, or other invalid memory
|
||||
*/
|
||||
static bool verify_load_addresses(int segment_index, intptr_t load_addr, intptr_t load_end, bool print_error, bool no_recurse)
|
||||
@@ -390,7 +410,7 @@ static bool verify_load_addresses(int segment_index, intptr_t load_addr, intptr_
|
||||
if (esp_ptr_in_dram(load_addr_p) && esp_ptr_in_dram(load_inclusive_end_p)) { /* Writing to DRAM */
|
||||
/* Check if we're clobbering the stack */
|
||||
intptr_t sp = (intptr_t)esp_cpu_get_sp();
|
||||
if (bootloader_util_regions_overlap(sp - STACK_LOAD_HEADROOM, SOC_ROM_STACK_START,
|
||||
if (bootloader_util_regions_overlap(sp - STACK_LOAD_HEADROOM, ROM_STACK_START,
|
||||
load_addr, load_end)) {
|
||||
reason = "overlaps bootloader stack";
|
||||
goto invalid;
|
||||
@@ -796,20 +816,27 @@ static esp_err_t verify_segment_header(int index, const esp_image_segment_header
|
||||
bool map_segment = should_map(load_addr);
|
||||
|
||||
#if SOC_MMU_PAGE_SIZE_CONFIGURABLE
|
||||
esp_err_t err = ESP_FAIL;
|
||||
|
||||
/* ESP APP descriptor is present in the DROM segment #0 */
|
||||
if (index == 0 && !is_bootloader(metadata->start_addr)) {
|
||||
const esp_app_desc_t *app_desc = (const esp_app_desc_t *)bootloader_mmap(segment_data_offs, sizeof(esp_app_desc_t));
|
||||
if (!app_desc || app_desc->magic_word != ESP_APP_DESC_MAGIC_WORD) {
|
||||
uint32_t mmu_page_size = 0, magic_word = 0;
|
||||
const uint32_t mmu_page_size_offset = segment_data_offs + offsetof(esp_app_desc_t, mmu_page_size);
|
||||
CHECK_ERR(bootloader_flash_read(segment_data_offs, &magic_word, sizeof(uint32_t), true));
|
||||
CHECK_ERR(bootloader_flash_read(mmu_page_size_offset, &mmu_page_size, sizeof(uint32_t), true));
|
||||
// Extract only the lowest byte from mmu_page_size (as per image format)
|
||||
mmu_page_size &= 0xFF;
|
||||
|
||||
if (magic_word != ESP_APP_DESC_MAGIC_WORD) {
|
||||
ESP_LOGE(TAG, "Failed to fetch app description header!");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
// Convert from log base 2 number to actual size while handling legacy image case (value 0)
|
||||
metadata->mmu_page_size = (app_desc->mmu_page_size > 0) ? (1UL << app_desc->mmu_page_size) : SPI_FLASH_MMU_PAGE_SIZE;
|
||||
metadata->mmu_page_size = (mmu_page_size > 0) ? (1UL << mmu_page_size) : SPI_FLASH_MMU_PAGE_SIZE;
|
||||
if (metadata->mmu_page_size != SPI_FLASH_MMU_PAGE_SIZE) {
|
||||
ESP_LOGI(TAG, "MMU page size mismatch, configured: 0x%x, found: 0x%"PRIx32, SPI_FLASH_MMU_PAGE_SIZE, metadata->mmu_page_size);
|
||||
}
|
||||
bootloader_munmap(app_desc);
|
||||
} else if (index == 0 && is_bootloader(metadata->start_addr)) {
|
||||
// Bootloader always uses the default MMU page size
|
||||
metadata->mmu_page_size = SPI_FLASH_MMU_PAGE_SIZE;
|
||||
@@ -836,6 +863,10 @@ static esp_err_t verify_segment_header(int index, const esp_image_segment_header
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
#if SOC_MMU_PAGE_SIZE_CONFIGURABLE
|
||||
err:
|
||||
return err;
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool should_map(uint32_t load_addr)
|
||||
@@ -996,43 +1027,14 @@ err:
|
||||
return err;
|
||||
}
|
||||
|
||||
static esp_err_t verify_secure_boot_signature(bootloader_sha256_handle_t sha_handle, esp_image_metadata_t *data, uint8_t *image_digest, uint8_t *verified_digest)
|
||||
{
|
||||
#if (SECURE_BOOT_CHECK_SIGNATURE == 1)
|
||||
uint32_t end = data->start_addr + data->image_len;
|
||||
|
||||
ESP_LOGI(TAG, "Verifying image signature...");
|
||||
|
||||
// For secure boot, we calculate the signature hash over the whole file, which includes any "simple" hash
|
||||
// appended to the image for corruption detection
|
||||
if (data->image.hash_appended) {
|
||||
const void *simple_hash = bootloader_mmap(end - HASH_LEN, HASH_LEN);
|
||||
bootloader_sha256_data(sha_handle, simple_hash, HASH_LEN);
|
||||
bootloader_munmap(simple_hash);
|
||||
}
|
||||
|
||||
#if CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME || CONFIG_SECURE_SIGNED_APPS_ECDSA_V2_SCHEME
|
||||
// End of the image needs to be padded all the way to a 4KB boundary, after the simple hash
|
||||
// (for apps they are usually already padded due to --secure-pad-v2, only a problem if this option was not used.)
|
||||
uint32_t padded_end = ALIGN_UP(end, FLASH_SECTOR_SIZE);
|
||||
if (padded_end > end) {
|
||||
const void *padding = bootloader_mmap(end, padded_end - end);
|
||||
bootloader_sha256_data(sha_handle, padding, padded_end - end);
|
||||
bootloader_munmap(padding);
|
||||
end = padded_end;
|
||||
}
|
||||
#endif // CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME || CONFIG_SECURE_SIGNED_APPS_ECDSA_V2_SCHEME
|
||||
|
||||
bootloader_sha256_finish(sha_handle, image_digest);
|
||||
|
||||
// Log the hash for debugging
|
||||
bootloader_debug_buffer(image_digest, HASH_LEN, "Calculated secure boot hash");
|
||||
|
||||
static esp_err_t verify_signature_and_adjust_image_len(esp_image_metadata_t *data, uint32_t end, uint8_t *image_digest, uint8_t *verified_digest)
|
||||
{
|
||||
// Use hash to verify signature block
|
||||
esp_err_t err = ESP_ERR_IMAGE_INVALID;
|
||||
#if CONFIG_SECURE_BOOT || CONFIG_SECURE_SIGNED_APPS_NO_SECURE_BOOT
|
||||
const void *sig_block;
|
||||
ESP_FAULT_ASSERT(memcmp(image_digest, verified_digest, HASH_LEN) != 0); /* sanity check that these values start differently */
|
||||
ESP_FAULT_ASSERT(memcmp(image_digest, verified_digest, ESP_SECURE_BOOT_DIGEST_LEN) != 0); /* sanity check that these values start differently */
|
||||
#if defined(CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME)
|
||||
sig_block = bootloader_mmap(data->start_addr + data->image_len, sizeof(esp_secure_boot_sig_block_t));
|
||||
err = esp_secure_boot_verify_ecdsa_signature_block(sig_block, image_digest, verified_digest);
|
||||
@@ -1049,7 +1051,7 @@ static esp_err_t verify_secure_boot_signature(bootloader_sha256_handle_t sha_han
|
||||
ESP_LOGI(TAG, "Calculating simple hash to check for corruption...");
|
||||
const void *whole_image = bootloader_mmap(data->start_addr, data->image_len - HASH_LEN);
|
||||
if (whole_image != NULL) {
|
||||
sha_handle = bootloader_sha256_start();
|
||||
bootloader_sha256_handle_t sha_handle = bootloader_sha256_start();
|
||||
bootloader_sha256_data(sha_handle, whole_image, data->image_len - HASH_LEN);
|
||||
bootloader_munmap(whole_image);
|
||||
if (verify_simple_hash(sha_handle, data) != ESP_OK) {
|
||||
@@ -1070,6 +1072,64 @@ static esp_err_t verify_secure_boot_signature(bootloader_sha256_handle_t sha_han
|
||||
}
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
#endif /* SECURE_BOOT_CHECK_SIGNATURE */
|
||||
|
||||
static esp_err_t verify_secure_boot_signature(bootloader_sha256_handle_t sha_handle, esp_image_metadata_t *data, uint8_t *image_digest, uint8_t *verified_digest)
|
||||
{
|
||||
#if (SECURE_BOOT_CHECK_SIGNATURE == 1)
|
||||
uint32_t end = data->start_addr + data->image_len;
|
||||
|
||||
ESP_LOGI(TAG, "Verifying image signature...");
|
||||
|
||||
#if CONFIG_SECURE_BOOT_ECDSA_KEY_LEN_384_BITS
|
||||
(void) sha_handle;
|
||||
/* Re-calculating image digest using SHA384 */
|
||||
const void *image_data = bootloader_mmap(data->start_addr, data->image_len - HASH_LEN);
|
||||
bootloader_sha_handle_t sha384_handle = bootloader_sha512_start(true);
|
||||
bootloader_sha512_data(sha384_handle, image_data, data->image_len - HASH_LEN);
|
||||
bootloader_munmap(image_data);
|
||||
#endif
|
||||
|
||||
// For secure boot, we calculate the signature hash over the whole file, which includes any "simple" hash
|
||||
// appended to the image for corruption detection
|
||||
if (data->image.hash_appended) {
|
||||
const void *simple_hash = bootloader_mmap(end - HASH_LEN, HASH_LEN);
|
||||
#if CONFIG_SECURE_BOOT_ECDSA_KEY_LEN_384_BITS
|
||||
bootloader_sha512_data(sha384_handle, simple_hash, HASH_LEN);
|
||||
#else
|
||||
bootloader_sha256_data(sha_handle, simple_hash, HASH_LEN);
|
||||
#endif
|
||||
bootloader_munmap(simple_hash);
|
||||
}
|
||||
|
||||
#if CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME || CONFIG_SECURE_SIGNED_APPS_ECDSA_V2_SCHEME
|
||||
// End of the image needs to be padded all the way to a 4KB boundary, after the simple hash
|
||||
// (for apps they are usually already padded due to --secure-pad-v2, only a problem if this option was not used.)
|
||||
uint32_t padded_end = ALIGN_UP(end, FLASH_SECTOR_SIZE);
|
||||
if (padded_end > end) {
|
||||
const void *padding = bootloader_mmap(end, padded_end - end);
|
||||
#if CONFIG_SECURE_BOOT_ECDSA_KEY_LEN_384_BITS
|
||||
bootloader_sha512_data(sha384_handle, padding, padded_end - end);
|
||||
#else
|
||||
bootloader_sha256_data(sha_handle, padding, padded_end - end);
|
||||
#endif
|
||||
bootloader_munmap(padding);
|
||||
end = padded_end;
|
||||
}
|
||||
#endif // CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME || CONFIG_SECURE_SIGNED_APPS_ECDSA_V2_SCHEME
|
||||
|
||||
#if CONFIG_SECURE_BOOT_ECDSA_KEY_LEN_384_BITS
|
||||
bootloader_sha512_finish(sha384_handle, image_digest);
|
||||
#else
|
||||
bootloader_sha256_finish(sha_handle, image_digest);
|
||||
#endif
|
||||
|
||||
// Log the hash for debugging
|
||||
bootloader_debug_buffer(image_digest, ESP_SECURE_BOOT_DIGEST_LEN, "Calculated secure boot hash");
|
||||
|
||||
return verify_signature_and_adjust_image_len(data, end, image_digest, verified_digest);
|
||||
#endif // SECURE_BOOT_CHECK_SIGNATURE
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@@ -212,8 +212,13 @@ void esp_flash_encryption_set_release_mode(void)
|
||||
|
||||
#ifdef SOC_FLASH_ENCRYPTION_XTS_AES_SUPPORT_PSEUDO_ROUND
|
||||
if (spi_flash_encrypt_ll_is_pseudo_rounds_function_supported()) {
|
||||
uint8_t xts_pseudo_level = ESP_XTS_AES_PSEUDO_ROUNDS_LOW;
|
||||
esp_efuse_write_field_blob(ESP_EFUSE_XTS_DPA_PSEUDO_LEVEL, &xts_pseudo_level, ESP_EFUSE_XTS_DPA_PSEUDO_LEVEL[0]->bit_count);
|
||||
uint8_t xts_pseudo_level = 0;
|
||||
esp_efuse_read_field_blob(ESP_EFUSE_XTS_DPA_PSEUDO_LEVEL, &xts_pseudo_level, ESP_EFUSE_XTS_DPA_PSEUDO_LEVEL[0]->bit_count);
|
||||
|
||||
if (xts_pseudo_level == ESP_XTS_AES_PSEUDO_ROUNDS_DISABLE) {
|
||||
xts_pseudo_level = ESP_XTS_AES_PSEUDO_ROUNDS_LOW;
|
||||
esp_efuse_write_field_blob(ESP_EFUSE_XTS_DPA_PSEUDO_LEVEL, &xts_pseudo_level, ESP_EFUSE_XTS_DPA_PSEUDO_LEVEL[0]->bit_count);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -428,6 +428,10 @@ static esp_err_t encrypt_partition(int index, const esp_partition_info_t *partit
|
||||
if (partition->type == PART_TYPE_APP && should_encrypt) {
|
||||
// Encrypt only the app image instead of encrypting the whole partition
|
||||
size = image_data.image_len;
|
||||
#if CONFIG_SECURE_SIGNED_ON_UPDATE_NO_SECURE_BOOT
|
||||
// If secure update without secure boot, also encrypt the signature block
|
||||
size += esp_secure_boot_sig_block_size();
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
} else if (partition->type == PART_TYPE_PARTITION_TABLE) {
|
||||
|
||||
@@ -12,6 +12,10 @@
|
||||
#include "esp_secure_boot.h"
|
||||
#include "hal/efuse_hal.h"
|
||||
|
||||
#ifdef SOC_ECDSA_SUPPORTED
|
||||
#include "hal/ecdsa_ll.h"
|
||||
#endif
|
||||
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
static __attribute__((unused)) const char *TAG = "secure_boot";
|
||||
|
||||
@@ -341,15 +345,17 @@ bool esp_secure_boot_cfg_verify_release_mode(void)
|
||||
}
|
||||
|
||||
#ifdef SOC_ECDSA_P192_CURVE_DEFAULT_DISABLED
|
||||
secure = esp_efuse_read_field_bit(ESP_EFUSE_WR_DIS_ECDSA_CURVE_MODE);
|
||||
if (!secure) {
|
||||
uint8_t current_curve;
|
||||
esp_err_t err = esp_efuse_read_field_blob(ESP_EFUSE_ECDSA_CURVE_MODE, ¤t_curve, ESP_EFUSE_ECDSA_CURVE_MODE[0]->bit_count);
|
||||
if (err == ESP_OK) {
|
||||
if (current_curve != ESP_EFUSE_ECDSA_CURVE_MODE_ALLOW_ONLY_P256_BIT_LOCKED) {
|
||||
// If not P256 mode
|
||||
result &= secure;
|
||||
ESP_LOGW(TAG, "Not write disabled ECDSA curve mode (set WR_DIS_ECDSA_CURVE_MODE->1)");
|
||||
if (ecdsa_ll_is_configurable_curve_supported()) {
|
||||
secure = esp_efuse_read_field_bit(ESP_EFUSE_WR_DIS_ECDSA_CURVE_MODE);
|
||||
if (!secure) {
|
||||
uint8_t current_curve;
|
||||
esp_err_t err = esp_efuse_read_field_blob(ESP_EFUSE_ECDSA_CURVE_MODE, ¤t_curve, ESP_EFUSE_ECDSA_CURVE_MODE[0]->bit_count);
|
||||
if (err == ESP_OK) {
|
||||
if (current_curve != ESP_EFUSE_ECDSA_CURVE_MODE_ALLOW_ONLY_P256_BIT_LOCKED) {
|
||||
// If not P256 mode
|
||||
result &= secure;
|
||||
ESP_LOGW(TAG, "Not write disabled ECDSA curve mode (set WR_DIS_ECDSA_CURVE_MODE->1)");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -421,7 +427,27 @@ bool esp_secure_boot_cfg_verify_release_mode(void)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#if SOC_ECDSA_SUPPORT_CURVE_P384
|
||||
#if CONFIG_SECURE_BOOT_ECDSA_KEY_LEN_384_BITS
|
||||
secure = esp_efuse_read_field_bit(ESP_EFUSE_SECURE_BOOT_SHA384_EN);
|
||||
result &= secure;
|
||||
if (!secure) {
|
||||
ESP_LOGW(TAG, "Not enabled Secure Boot using SHA-384 mode (set SECURE_BOOT_SHA384_EN->1)");
|
||||
}
|
||||
#else
|
||||
/* When using Secure Boot with SHA-384, the efuse bit representing Secure Boot with SHA-384 would already be programmed.
|
||||
* But in the case of the existing Secure Boot V2 schemes using SHA-256, the efuse bit representing
|
||||
* Secure Boot with SHA-384 needs to be write-protected, so that an attacker cannot perform a denial-of-service
|
||||
* attack by changing the existing secure boot mode using SHA-256 to SHA-384.
|
||||
*/
|
||||
secure = esp_efuse_read_field_bit(ESP_EFUSE_WR_DIS_SECURE_BOOT_SHA384_EN);
|
||||
result &= secure;
|
||||
if (!secure) {
|
||||
ESP_LOGW(TAG, "Not write-protected secure boot using SHA-384 mode (set WR_DIS_SECURE_BOOT_SHA384_EN->1)");
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
secure = (num_keys != 0);
|
||||
result &= secure;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -69,16 +69,21 @@ static esp_err_t validate_signature_block(const ets_secure_boot_sig_block_t *blo
|
||||
*/
|
||||
static esp_err_t s_calculate_image_public_key_digests(uint32_t flash_offset, uint32_t flash_size, esp_image_sig_public_key_digests_t *public_key_digests)
|
||||
{
|
||||
esp_err_t ret;
|
||||
esp_err_t ret = ESP_FAIL;
|
||||
uint8_t image_digest[ESP_SECURE_BOOT_DIGEST_LEN] = {0};
|
||||
uint8_t __attribute__((aligned(4))) key_digest[ESP_SECURE_BOOT_DIGEST_LEN] = {0};
|
||||
uint8_t __attribute__((aligned(4))) key_digest[ESP_SECURE_BOOT_KEY_DIGEST_SHA_256_LEN] = {0};
|
||||
size_t sig_block_addr = flash_offset + ALIGN_UP(flash_size, FLASH_SECTOR_SIZE);
|
||||
|
||||
ESP_LOGD(TAG, "calculating public key digests for sig blocks of image offset 0x%" PRIx32 " (sig block offset 0x%x)", flash_offset, sig_block_addr);
|
||||
|
||||
bzero(public_key_digests, sizeof(esp_image_sig_public_key_digests_t));
|
||||
|
||||
#if CONFIG_SECURE_BOOT_ECDSA_KEY_LEN_384_BITS
|
||||
ret = bootloader_sha384_flash_contents(flash_offset, sig_block_addr - flash_offset, image_digest);
|
||||
#else
|
||||
ret = bootloader_sha256_flash_contents(flash_offset, sig_block_addr - flash_offset, image_digest);
|
||||
#endif
|
||||
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "error generating image digest, %d", ret);
|
||||
return ret;
|
||||
@@ -129,7 +134,7 @@ static esp_err_t s_calculate_image_public_key_digests(uint32_t flash_offset, uin
|
||||
}
|
||||
ESP_LOGD(TAG, "Signature block (%d) is verified", i);
|
||||
/* Copy the key digest to the buffer provided by the caller */
|
||||
memcpy((void *)public_key_digests->key_digests[i], key_digest, ESP_SECURE_BOOT_DIGEST_LEN);
|
||||
memcpy((void *)public_key_digests->key_digests[i], key_digest, ESP_SECURE_BOOT_KEY_DIGEST_SHA_256_LEN);
|
||||
public_key_digests->num_digests++;
|
||||
}
|
||||
|
||||
@@ -317,7 +322,7 @@ static esp_err_t check_and_generate_secure_boot_keys(const esp_image_metadata_t
|
||||
}
|
||||
|
||||
for (unsigned j = 0; j < tee_key_digests.num_digests; j++) {
|
||||
if (!memcmp(boot_key_digests.key_digests[i], tee_key_digests.key_digests[j], ESP_SECURE_BOOT_DIGEST_LEN)) {
|
||||
if (!memcmp(boot_key_digests.key_digests[i], tee_key_digests.key_digests[j], ESP_SECURE_BOOT_KEY_DIGEST_LEN)) {
|
||||
ESP_LOGI(TAG, "TEE key(%d) matches with bootloader key(%d).", j, i);
|
||||
tee_match = true;
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ static esp_err_t calculate_image_public_key_digests(bool verify_image_digest, bo
|
||||
}
|
||||
|
||||
uint8_t image_digest[ESP_SECURE_BOOT_DIGEST_LEN] = {0};
|
||||
uint8_t __attribute__((aligned(4))) key_digest[ESP_SECURE_BOOT_DIGEST_LEN] = {0};
|
||||
uint8_t __attribute__((aligned(4))) key_digest[ESP_SECURE_BOOT_KEY_DIGEST_SHA_256_LEN] = {0};
|
||||
size_t sig_block_addr = img_metadata.start_addr + ALIGN_UP(img_metadata.image_len, FLASH_SECTOR_SIZE);
|
||||
|
||||
ESP_LOGD(TAG, "calculating public key digests for sig blocks of image offset 0x%"PRIu32" (sig block offset 0x%u)", img_metadata.start_addr, sig_block_addr);
|
||||
@@ -81,7 +81,11 @@ static esp_err_t calculate_image_public_key_digests(bool verify_image_digest, bo
|
||||
bzero(public_key_digests, sizeof(esp_image_sig_public_key_digests_t));
|
||||
|
||||
if (verify_image_digest) {
|
||||
#if CONFIG_SECURE_BOOT_ECDSA_KEY_LEN_384_BITS
|
||||
ret = bootloader_sha384_flash_contents(img_metadata.start_addr, sig_block_addr - img_metadata.start_addr, image_digest);
|
||||
#else
|
||||
ret = bootloader_sha256_flash_contents(img_metadata.start_addr, sig_block_addr - img_metadata.start_addr, image_digest);
|
||||
#endif
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "error generating image digest, %d", ret);
|
||||
return ret;
|
||||
@@ -118,7 +122,7 @@ static esp_err_t calculate_image_public_key_digests(bool verify_image_digest, bo
|
||||
ESP_LOGD(TAG, "Signature block (%d) is verified", i);
|
||||
}
|
||||
/* Copy the key digest to the buffer provided by the caller */
|
||||
memcpy((void *)public_key_digests->key_digests[public_key_digests->num_digests], key_digest, ESP_SECURE_BOOT_DIGEST_LEN);
|
||||
memcpy((void *)public_key_digests->key_digests[public_key_digests->num_digests], key_digest, ESP_SECURE_BOOT_KEY_DIGEST_SHA_256_LEN);
|
||||
}
|
||||
public_key_digests->num_digests++;
|
||||
}
|
||||
@@ -184,14 +188,19 @@ static esp_err_t get_secure_boot_key_digests(esp_image_sig_public_key_digests_t
|
||||
|
||||
esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
|
||||
{
|
||||
uint8_t digest[ESP_SECURE_BOOT_KEY_DIGEST_LEN] = {0};
|
||||
uint8_t verified_digest[ESP_SECURE_BOOT_KEY_DIGEST_LEN] = {0};
|
||||
esp_err_t err = ESP_FAIL;
|
||||
uint8_t digest[ESP_SECURE_BOOT_DIGEST_LEN] = {0};
|
||||
|
||||
/* Rounding off length to the upper 4k boundary */
|
||||
uint32_t padded_length = ALIGN_UP(length, FLASH_SECTOR_SIZE);
|
||||
ESP_LOGD(TAG, "verifying signature src_addr 0x%"PRIx32" length 0x%"PRIx32, src_addr, length);
|
||||
|
||||
esp_err_t err = bootloader_sha256_flash_contents(src_addr, padded_length, digest);
|
||||
#if CONFIG_SECURE_BOOT_ECDSA_KEY_LEN_384_BITS
|
||||
err = bootloader_sha384_flash_contents(src_addr, padded_length, digest);
|
||||
#else
|
||||
err = bootloader_sha256_flash_contents(src_addr, padded_length, digest);
|
||||
#endif
|
||||
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Digest calculation failed 0x%"PRIx32", 0x%"PRIx32, src_addr, padded_length);
|
||||
return err;
|
||||
@@ -203,7 +212,7 @@ esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
err = esp_secure_boot_verify_sbv2_signature_block(sig_block, digest, verified_digest);
|
||||
err = esp_secure_boot_verify_sbv2_signature_block(sig_block, digest, NULL);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Secure Boot V2 verification failed.");
|
||||
}
|
||||
@@ -218,9 +227,11 @@ esp_err_t esp_secure_boot_verify_sbv2_signature_block(const ets_secure_boot_sign
|
||||
{
|
||||
bool any_trusted_key = false;
|
||||
|
||||
/* Note: in IDF verification we don't add any fault injection resistance, as we don't expect this to be called
|
||||
during boot-time verification. */
|
||||
memset(verified_digest, 0, ESP_SECURE_BOOT_KEY_DIGEST_LEN);
|
||||
if (verified_digest != NULL) {
|
||||
/* Note: in IDF verification we don't add any fault injection resistance, as we don't expect this to be called
|
||||
during boot-time verification. */
|
||||
memset(verified_digest, 0, ESP_SECURE_BOOT_DIGEST_LEN);
|
||||
}
|
||||
|
||||
esp_image_sig_public_key_digests_t trusted = {0};
|
||||
|
||||
@@ -237,7 +248,7 @@ esp_err_t esp_secure_boot_verify_sbv2_signature_block(const ets_secure_boot_sign
|
||||
#endif
|
||||
|
||||
for (unsigned app_blk_idx = 0; app_blk_idx < secure_boot_num_blocks; app_blk_idx++) {
|
||||
uint8_t app_blk_digest[ESP_SECURE_BOOT_DIGEST_LEN] = { 0 };
|
||||
uint8_t app_blk_digest[ESP_SECURE_BOOT_KEY_DIGEST_SHA_256_LEN] = { 0 };
|
||||
const ets_secure_boot_sig_block_t *app_blk = &sig_block->block[app_blk_idx];
|
||||
const ets_secure_boot_sig_block_t *trusted_block = NULL;
|
||||
|
||||
|
||||
+7
-1
@@ -26,6 +26,7 @@ static const char* TAG = "secure_boot_v2";
|
||||
|
||||
esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
|
||||
{
|
||||
esp_err_t err = ESP_FAIL;
|
||||
uint8_t digest[ESP_SECURE_BOOT_DIGEST_LEN] = {0};
|
||||
uint8_t verified_digest[ESP_SECURE_BOOT_DIGEST_LEN] = { 0 }; /* Note: this function doesn't do any anti-FI checks on this buffer */
|
||||
|
||||
@@ -34,7 +35,12 @@ esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
|
||||
ESP_LOGD(TAG, "verifying signature src_addr 0x%" PRIx32 " length 0x%" PRIx32, src_addr, length);
|
||||
|
||||
/* Calculate digest of main image */
|
||||
esp_err_t err = bootloader_sha256_flash_contents(src_addr, padded_length, digest);
|
||||
#if CONFIG_SECURE_BOOT_ECDSA_KEY_LEN_384_BITS
|
||||
err = bootloader_sha384_flash_contents(src_addr, padded_length, digest);
|
||||
#else
|
||||
err = bootloader_sha256_flash_contents(src_addr, padded_length, digest);
|
||||
#endif
|
||||
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Digest calculation failed 0x%" PRIx32 ", 0x%" PRIx32, src_addr, padded_length);
|
||||
return err;
|
||||
|
||||
@@ -4,7 +4,3 @@ components/bootloader_support/test_apps/rtc_custom_section:
|
||||
enable:
|
||||
- if: SOC_RTC_MEM_SUPPORTED == 1
|
||||
reason: this feature is supported on chips that have RTC memory
|
||||
disable:
|
||||
- if: IDF_TARGET == "esp32h21"
|
||||
temporary: true
|
||||
reason: IDF-11534
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
| Supported Targets | ESP32 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- |
|
||||
| Supported Targets | ESP32 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-H21 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- |
|
||||
|
||||
+113
-26
@@ -134,8 +134,45 @@ if(CONFIG_BT_ENABLED)
|
||||
"common/osi/semaphore.c"
|
||||
"porting/mem/bt_osi_mem.c"
|
||||
"common/ble_log/ble_log_spi_out.c"
|
||||
"common/ble_log/ble_log_uhci_out.c"
|
||||
)
|
||||
|
||||
# BLE Log Module
|
||||
if(CONFIG_BLE_LOG_ENABLED)
|
||||
# Core source files
|
||||
list(APPEND srcs
|
||||
common/ble_log/src/ble_log.c
|
||||
common/ble_log/src/ble_log_lbm.c
|
||||
common/ble_log/src/ble_log_rt.c
|
||||
common/ble_log/src/ble_log_util.c
|
||||
)
|
||||
|
||||
# Includes
|
||||
list(APPEND include_dirs
|
||||
common/ble_log/include
|
||||
)
|
||||
|
||||
# Private includes
|
||||
list(APPEND priv_include_dirs
|
||||
common/ble_log/src/internal_include
|
||||
common/ble_log/src/internal_include/prph
|
||||
)
|
||||
|
||||
# Timestamp synchronization extension
|
||||
if(CONFIG_BLE_LOG_TS_ENABLED)
|
||||
list(APPEND srcs common/ble_log/src/ble_log_ts.c)
|
||||
endif()
|
||||
|
||||
# Peripheral interface implementation
|
||||
if(CONFIG_BLE_LOG_PRPH_DUMMY)
|
||||
list(APPEND srcs common/ble_log/src/prph/ble_log_prph_dummy.c)
|
||||
elseif(CONFIG_BLE_LOG_PRPH_SPI_MASTER_DMA)
|
||||
list(APPEND srcs common/ble_log/src/prph/ble_log_prph_spi_master_dma.c)
|
||||
elseif(CONFIG_BLE_LOG_PRPH_UART_DMA)
|
||||
list(APPEND srcs common/ble_log/src/prph/ble_log_prph_uart_dma.c)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Host Bluedroid
|
||||
if(CONFIG_BT_BLUEDROID_ENABLED)
|
||||
|
||||
@@ -155,9 +192,6 @@ if(CONFIG_BT_ENABLED)
|
||||
host/bluedroid/bta/sys/include
|
||||
host/bluedroid/device/include
|
||||
host/bluedroid/hci/include
|
||||
host/bluedroid/external/sbc/decoder/include
|
||||
host/bluedroid/external/sbc/encoder/include
|
||||
host/bluedroid/external/sbc/plc/include
|
||||
host/bluedroid/btc/profile/esp/include
|
||||
host/bluedroid/btc/profile/std/a2dp/include
|
||||
host/bluedroid/btc/profile/std/include
|
||||
@@ -315,29 +349,6 @@ if(CONFIG_BT_ENABLED)
|
||||
"host/bluedroid/device/bdaddr.c"
|
||||
"host/bluedroid/device/controller.c"
|
||||
"host/bluedroid/device/interop.c"
|
||||
"host/bluedroid/external/sbc/decoder/srce/alloc.c"
|
||||
"host/bluedroid/external/sbc/decoder/srce/bitalloc-sbc.c"
|
||||
"host/bluedroid/external/sbc/decoder/srce/bitalloc.c"
|
||||
"host/bluedroid/external/sbc/decoder/srce/bitstream-decode.c"
|
||||
"host/bluedroid/external/sbc/decoder/srce/decoder-oina.c"
|
||||
"host/bluedroid/external/sbc/decoder/srce/decoder-private.c"
|
||||
"host/bluedroid/external/sbc/decoder/srce/decoder-sbc.c"
|
||||
"host/bluedroid/external/sbc/decoder/srce/dequant.c"
|
||||
"host/bluedroid/external/sbc/decoder/srce/framing-sbc.c"
|
||||
"host/bluedroid/external/sbc/decoder/srce/framing.c"
|
||||
"host/bluedroid/external/sbc/decoder/srce/oi_codec_version.c"
|
||||
"host/bluedroid/external/sbc/decoder/srce/synthesis-8-generated.c"
|
||||
"host/bluedroid/external/sbc/decoder/srce/synthesis-dct8.c"
|
||||
"host/bluedroid/external/sbc/decoder/srce/synthesis-sbc.c"
|
||||
"host/bluedroid/external/sbc/encoder/srce/sbc_analysis.c"
|
||||
"host/bluedroid/external/sbc/encoder/srce/sbc_dct.c"
|
||||
"host/bluedroid/external/sbc/encoder/srce/sbc_dct_coeffs.c"
|
||||
"host/bluedroid/external/sbc/encoder/srce/sbc_enc_bit_alloc_mono.c"
|
||||
"host/bluedroid/external/sbc/encoder/srce/sbc_enc_bit_alloc_ste.c"
|
||||
"host/bluedroid/external/sbc/encoder/srce/sbc_enc_coeffs.c"
|
||||
"host/bluedroid/external/sbc/encoder/srce/sbc_encoder.c"
|
||||
"host/bluedroid/external/sbc/encoder/srce/sbc_packing.c"
|
||||
"host/bluedroid/external/sbc/plc/sbc_plc.c"
|
||||
"host/bluedroid/hci/hci_audio.c"
|
||||
"host/bluedroid/hci/hci_hal_h4.c"
|
||||
"host/bluedroid/hci/hci_layer.c"
|
||||
@@ -474,6 +485,38 @@ if(CONFIG_BT_ENABLED)
|
||||
"host/bluedroid/api/esp_ble_cte_api.c")
|
||||
endif()
|
||||
|
||||
if((CONFIG_BT_A2DP_ENABLE AND NOT CONFIG_BT_A2DP_USE_EXTERNAL_CODEC) OR
|
||||
(CONFIG_BT_HFP_ENABLE AND CONFIG_BT_HFP_AUDIO_DATA_PATH_HCI AND NOT CONFIG_BT_HFP_USE_EXTERNAL_CODEC))
|
||||
list(APPEND priv_include_dirs
|
||||
host/bluedroid/external/sbc/decoder/include
|
||||
host/bluedroid/external/sbc/encoder/include
|
||||
host/bluedroid/external/sbc/plc/include)
|
||||
|
||||
list(APPEND srcs "host/bluedroid/external/sbc/decoder/srce/alloc.c"
|
||||
"host/bluedroid/external/sbc/decoder/srce/bitalloc-sbc.c"
|
||||
"host/bluedroid/external/sbc/decoder/srce/bitalloc.c"
|
||||
"host/bluedroid/external/sbc/decoder/srce/bitstream-decode.c"
|
||||
"host/bluedroid/external/sbc/decoder/srce/decoder-oina.c"
|
||||
"host/bluedroid/external/sbc/decoder/srce/decoder-private.c"
|
||||
"host/bluedroid/external/sbc/decoder/srce/decoder-sbc.c"
|
||||
"host/bluedroid/external/sbc/decoder/srce/dequant.c"
|
||||
"host/bluedroid/external/sbc/decoder/srce/framing-sbc.c"
|
||||
"host/bluedroid/external/sbc/decoder/srce/framing.c"
|
||||
"host/bluedroid/external/sbc/decoder/srce/oi_codec_version.c"
|
||||
"host/bluedroid/external/sbc/decoder/srce/synthesis-8-generated.c"
|
||||
"host/bluedroid/external/sbc/decoder/srce/synthesis-dct8.c"
|
||||
"host/bluedroid/external/sbc/decoder/srce/synthesis-sbc.c"
|
||||
"host/bluedroid/external/sbc/encoder/srce/sbc_analysis.c"
|
||||
"host/bluedroid/external/sbc/encoder/srce/sbc_dct.c"
|
||||
"host/bluedroid/external/sbc/encoder/srce/sbc_dct_coeffs.c"
|
||||
"host/bluedroid/external/sbc/encoder/srce/sbc_enc_bit_alloc_mono.c"
|
||||
"host/bluedroid/external/sbc/encoder/srce/sbc_enc_bit_alloc_ste.c"
|
||||
"host/bluedroid/external/sbc/encoder/srce/sbc_enc_coeffs.c"
|
||||
"host/bluedroid/external/sbc/encoder/srce/sbc_encoder.c"
|
||||
"host/bluedroid/external/sbc/encoder/srce/sbc_packing.c"
|
||||
"host/bluedroid/external/sbc/plc/sbc_plc.c")
|
||||
endif()
|
||||
|
||||
endif()
|
||||
|
||||
if(CONFIG_BLE_MESH)
|
||||
@@ -703,6 +746,7 @@ if(CONFIG_BT_ENABLED)
|
||||
host/nimble/nimble/nimble/host/util/include
|
||||
host/nimble/nimble/nimble/host/store/ram/include
|
||||
host/nimble/nimble/nimble/host/store/config/include
|
||||
host/nimble/nimble/nimble/host/services/ras/include
|
||||
)
|
||||
|
||||
list(APPEND srcs "host/nimble/nimble/nimble/transport/src/transport.c"
|
||||
@@ -723,6 +767,8 @@ if(CONFIG_BT_ENABLED)
|
||||
"host/nimble/nimble/nimble/host/services/hid/src/ble_svc_hid.c"
|
||||
"host/nimble/nimble/nimble/host/services/sps/src/ble_svc_sps.c"
|
||||
"host/nimble/nimble/nimble/host/services/cte/src/ble_svc_cte.c"
|
||||
"host/nimble/nimble/nimble/host/services/ras/src/ble_svc_ras.c"
|
||||
"host/nimble/nimble/nimble/host/src/ble_cs.c"
|
||||
"host/nimble/nimble/nimble/host/src/ble_hs_conn.c"
|
||||
"host/nimble/nimble/nimble/host/src/ble_store_util.c"
|
||||
"host/nimble/nimble/nimble/host/src/ble_sm.c"
|
||||
@@ -776,6 +822,13 @@ if(CONFIG_BT_ENABLED)
|
||||
"host/nimble/nimble/nimble/host/src/ble_eatt.c"
|
||||
)
|
||||
|
||||
if(CONFIG_BT_NIMBLE_ISO)
|
||||
list(APPEND srcs
|
||||
"host/nimble/nimble/nimble/host/src/ble_hs_iso_hci.c"
|
||||
"host/nimble/nimble/nimble/host/src/ble_hs_iso.c"
|
||||
)
|
||||
endif()
|
||||
|
||||
if(CONFIG_BT_CONTROLLER_DISABLED AND CONFIG_BT_NIMBLE_TRANSPORT_UART)
|
||||
list(APPEND srcs
|
||||
"host/nimble/nimble/nimble/transport/uart_ll/src/hci_uart.c"
|
||||
@@ -904,6 +957,22 @@ set(bt_priv_requires
|
||||
esp_gdbstub
|
||||
)
|
||||
|
||||
if(CONFIG_BLE_COMPRESSED_LOG_ENABLE)
|
||||
set(BT_ROOT_PATH "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
# When log compression is enabled, selected logs are replaced
|
||||
# by auto-generated macros that emit pre-encoded data.
|
||||
# This eliminates the original format strings, reducing firmware size and
|
||||
# removing runtime formatting overhead, so logs are produced faster and
|
||||
# with less system impact.
|
||||
add_subdirectory(common/ble_log/extension/log_compression)
|
||||
if(LOG_COMPRESSION_TARGET)
|
||||
set(srcs ${LOG_COMPRESS_SRCS})
|
||||
set(include_dirs ${LOG_COMPRESS_INCLUDE_DIRS})
|
||||
else()
|
||||
list(APPEND include_dirs ${LOG_COMPRESS_INCLUDE_DIRS})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
idf_component_register(SRCS "${srcs}"
|
||||
INCLUDE_DIRS "${include_dirs}"
|
||||
PRIV_INCLUDE_DIRS "${priv_include_dirs}"
|
||||
@@ -911,6 +980,12 @@ idf_component_register(SRCS "${srcs}"
|
||||
PRIV_REQUIRES "${bt_priv_requires}"
|
||||
LDFRAGMENTS "${ldscripts}")
|
||||
|
||||
if(CONFIG_BLE_COMPRESSED_LOG_ENABLE)
|
||||
if(LOG_COMPRESSION_TARGET)
|
||||
add_dependencies(${COMPONENT_LIB} ${LOG_COMPRESSION_TARGET})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(CONFIG_BT_ENABLED)
|
||||
target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-implicit-fallthrough -Wno-unused-const-variable)
|
||||
if(CONFIG_IDF_TARGET_ESP32)
|
||||
@@ -938,6 +1013,18 @@ if(CONFIG_BT_ENABLED)
|
||||
if(CONFIG_BT_LE_CONTROLLER_LOG_WRAP_PANIC_HANDLER_ENABLE)
|
||||
target_link_libraries(${COMPONENT_LIB} INTERFACE "-Wl,--wrap=esp_panic_handler")
|
||||
endif()
|
||||
if(CONFIG_BT_BLE_LOG_UHCI_OUT_ENABLED)
|
||||
target_link_libraries(${COMPONENT_LIB} INTERFACE "-Wl,--wrap=uart_tx_chars")
|
||||
target_link_libraries(${COMPONENT_LIB} INTERFACE "-Wl,--wrap=uart_write_bytes")
|
||||
target_link_libraries(${COMPONENT_LIB} INTERFACE "-Wl,--wrap=uart_write_bytes_with_break")
|
||||
endif()
|
||||
if(DEFINED CONFIG_BLE_LOG_PRPH_UART_DMA_PORT)
|
||||
if(CONFIG_BLE_LOG_PRPH_UART_DMA_PORT EQUAL 0)
|
||||
target_link_libraries(${COMPONENT_LIB} INTERFACE "-Wl,--wrap=uart_tx_chars")
|
||||
target_link_libraries(${COMPONENT_LIB} INTERFACE "-Wl,--wrap=uart_write_bytes")
|
||||
target_link_libraries(${COMPONENT_LIB} INTERFACE "-Wl,--wrap=uart_write_bytes_with_break")
|
||||
endif()
|
||||
endif()
|
||||
if(CONFIG_IDF_TARGET_ESP32C6)
|
||||
add_prebuilt_library(libble_app
|
||||
"${CMAKE_CURRENT_LIST_DIR}/controller/lib_esp32c6/esp32c6-bt-lib/esp32c6/libble_app.a"
|
||||
|
||||
@@ -6,6 +6,10 @@ config BT_ALARM_MAX_NUM
|
||||
This option decides the maximum number of alarms which
|
||||
could be used by Bluetooth host.
|
||||
|
||||
menu "BLE Log"
|
||||
source "$IDF_PATH/components/bt/common/ble_log/Kconfig.in"
|
||||
endmenu
|
||||
|
||||
config BT_BLE_LOG_SPI_OUT_ENABLED
|
||||
bool "Output ble logs to SPI bus (Experimental)"
|
||||
default n
|
||||
@@ -27,6 +31,21 @@ config BT_BLE_LOG_SPI_OUT_HCI_ENABLED
|
||||
help
|
||||
Enable logging of HCI packets to the SPI bus when BLE SPI log output is enabled.
|
||||
|
||||
config BT_BLE_LOG_SPI_OUT_HCI_BUF_SIZE
|
||||
int "SPI transaction buffer size for HCI logs"
|
||||
depends on BT_BLE_LOG_SPI_OUT_HCI_ENABLED
|
||||
default 1024
|
||||
help
|
||||
SPI transaction buffer size for HCI logs.
|
||||
There will be 2 SPI DMA buffers with the same size.
|
||||
|
||||
config BT_BLE_LOG_SPI_OUT_HCI_TASK_CNT
|
||||
int "HCI task count"
|
||||
depends on BT_BLE_LOG_SPI_OUT_HCI_ENABLED
|
||||
default 1
|
||||
help
|
||||
HCI task count
|
||||
|
||||
config BT_BLE_LOG_SPI_OUT_HOST_ENABLED
|
||||
bool "Enable Host log output to SPI"
|
||||
depends on BT_BLE_LOG_SPI_OUT_ENABLED
|
||||
@@ -35,6 +54,21 @@ config BT_BLE_LOG_SPI_OUT_HOST_ENABLED
|
||||
This configuration applies to the logs of both Bluedroid Host and NimBLE Host.
|
||||
When BLE SPI log output is enabled, this option allows host logs to be transmitted via SPI.
|
||||
|
||||
config BT_BLE_LOG_SPI_OUT_HOST_BUF_SIZE
|
||||
int "SPI transaction buffer size for host logs"
|
||||
depends on BT_BLE_LOG_SPI_OUT_HOST_ENABLED
|
||||
default 1024
|
||||
help
|
||||
SPI transaction buffer size for host logs.
|
||||
There will be 2 SPI DMA buffers with the same size.
|
||||
|
||||
config BT_BLE_LOG_SPI_OUT_HOST_TASK_CNT
|
||||
int "Host task count"
|
||||
depends on BT_BLE_LOG_SPI_OUT_HOST_ENABLED
|
||||
default 2
|
||||
help
|
||||
Host task count.
|
||||
|
||||
config BT_BLE_LOG_SPI_OUT_LL_ENABLED
|
||||
bool "Enable Controller log output to SPI"
|
||||
depends on BT_BLE_LOG_SPI_OUT_ENABLED
|
||||
@@ -48,7 +82,7 @@ config BT_BLE_LOG_SPI_OUT_LL_TASK_BUF_SIZE
|
||||
depends on BT_BLE_LOG_SPI_OUT_LL_ENABLED
|
||||
default 1024
|
||||
help
|
||||
SPI transaction buffer size for upper layer task logs.
|
||||
SPI transaction buffer size for lower layer task logs.
|
||||
There will be 2 SPI DMA buffers with the same size.
|
||||
|
||||
config BT_BLE_LOG_SPI_OUT_LL_ISR_BUF_SIZE
|
||||
@@ -56,9 +90,17 @@ config BT_BLE_LOG_SPI_OUT_LL_ISR_BUF_SIZE
|
||||
depends on BT_BLE_LOG_SPI_OUT_LL_ENABLED
|
||||
default 512
|
||||
help
|
||||
SPI transaction buffer size for upper layer ISR logs.
|
||||
SPI transaction buffer size for lower layer ISR logs.
|
||||
There will be 2 SPI DMA buffers with the same size.
|
||||
|
||||
config BT_BLE_LOG_SPI_OUT_LL_HCI_BUF_SIZE
|
||||
int "SPI transaction buffer size for lower layer HCI logs"
|
||||
depends on BT_BLE_LOG_SPI_OUT_LL_ENABLED
|
||||
default 512
|
||||
help
|
||||
SPI transaction buffer size for upper layer HCI logs.
|
||||
There will be 2 SPI DMA buffers with the same size
|
||||
|
||||
config BT_BLE_LOG_SPI_OUT_MOSI_IO_NUM
|
||||
int "GPIO number of SPI MOSI"
|
||||
depends on BT_BLE_LOG_SPI_OUT_ENABLED
|
||||
@@ -108,3 +150,114 @@ config BT_BLE_LOG_SPI_OUT_FLUSH_TIMEOUT
|
||||
default 1000
|
||||
help
|
||||
Buffer flush out period in unit of ms
|
||||
|
||||
config BT_BLE_LOG_SPI_OUT_LE_AUDIO_ENABLED
|
||||
bool "Enable LE Audio log output to SPI"
|
||||
depends on BT_BLE_LOG_SPI_OUT_ENABLED
|
||||
default n
|
||||
help
|
||||
Enable LE Audio log output to SPI
|
||||
|
||||
config BT_BLE_LOG_SPI_OUT_LE_AUDIO_BUF_SIZE
|
||||
int "SPI transaction buffer size for LE Audio logs"
|
||||
depends on BT_BLE_LOG_SPI_OUT_LE_AUDIO_ENABLED
|
||||
default 1024
|
||||
help
|
||||
SPI transaction buffer size for LE Audio logs.
|
||||
There will be 2 SPI DMA buffers with the same size.
|
||||
|
||||
config BT_BLE_LOG_SPI_OUT_LE_AUDIO_TASK_CNT
|
||||
int "LE audio task count"
|
||||
depends on BT_BLE_LOG_SPI_OUT_LE_AUDIO_ENABLED
|
||||
default 1
|
||||
help
|
||||
LE audio task count
|
||||
|
||||
config BT_BLE_LOG_SPI_OUT_MESH_ENABLED
|
||||
bool "Enable BLE mesh log output to SPI"
|
||||
depends on BT_BLE_LOG_SPI_OUT_ENABLED
|
||||
default n
|
||||
help
|
||||
Enable BLE mesh log output to SPI
|
||||
|
||||
config BT_BLE_LOG_SPI_OUT_MESH_BUF_SIZE
|
||||
int "SPI transaction buffer size for BLE mesh logs"
|
||||
depends on BT_BLE_LOG_SPI_OUT_MESH_ENABLED
|
||||
default 1024
|
||||
help
|
||||
SPI transaction buffer size for BLE mesh logs.
|
||||
There will be 2 SPI DMA buffers with the same size.
|
||||
|
||||
config BT_BLE_LOG_SPI_OUT_MESH_TASK_CNT
|
||||
int "Mesh task count"
|
||||
depends on BT_BLE_LOG_SPI_OUT_MESH_ENABLED
|
||||
default 3
|
||||
help
|
||||
Mesh task count
|
||||
|
||||
config BT_BLE_LOG_UHCI_OUT_ENABLED
|
||||
bool "Output ble logs via UHCI (UART DMA) driver (Experimental)"
|
||||
default n
|
||||
help
|
||||
Output ble logs via UHCI (UART DMA) driver
|
||||
On enable, BT_BLE_LOG_UHCI_OUT_UART_PORT would be reinited with
|
||||
BT_BLE_LOG_UHCI_OUT_UART_BAUD_RATE as new baud rate and
|
||||
BT_BLE_LOG_UHCI_OUT_UART_IO_NUM_TX as new UART Tx IO
|
||||
|
||||
config BT_BLE_LOG_UHCI_OUT_UART_PORT
|
||||
int "UART port connected to UHCI controller"
|
||||
depends on BT_BLE_LOG_UHCI_OUT_ENABLED
|
||||
default 0
|
||||
help
|
||||
UART port connected to UHCI controller
|
||||
If UART port 0 is selected, UART VFS Driver, UART ROM Driver
|
||||
and UART Driver output would be redirected to BLE Log UHCI Out
|
||||
to solve UART Tx FIFO multi-task access issue
|
||||
|
||||
config BT_BLE_LOG_UHCI_OUT_LL_TASK_BUF_SIZE
|
||||
int "UHCI transaction buffer size for lower layer task logs"
|
||||
depends on BT_BLE_LOG_UHCI_OUT_ENABLED
|
||||
default 1024
|
||||
help
|
||||
UHCI transaction buffer size for lower layer task logs
|
||||
|
||||
config BT_BLE_LOG_UHCI_OUT_LL_ISR_BUF_SIZE
|
||||
int "UHCI transaction buffer size for lower layer ISR logs"
|
||||
depends on BT_BLE_LOG_UHCI_OUT_ENABLED
|
||||
default 1024
|
||||
help
|
||||
UHCI transaction buffer size for lower layer ISR logs
|
||||
|
||||
config BT_BLE_LOG_UHCI_OUT_LL_HCI_BUF_SIZE
|
||||
int "UHCI transaction buffer size for lower layer HCI logs"
|
||||
depends on BT_BLE_LOG_UHCI_OUT_ENABLED
|
||||
default 1024
|
||||
help
|
||||
UHCI transaction buffer size for lower layer HCI logs
|
||||
|
||||
config BT_BLE_LOG_UHCI_OUT_UART_NEED_INIT
|
||||
bool "Enable to init UART port"
|
||||
depends on BT_BLE_LOG_UHCI_OUT_ENABLED
|
||||
default y
|
||||
help
|
||||
Enable to init UART port
|
||||
|
||||
config BT_BLE_LOG_UHCI_OUT_UART_BAUD_RATE
|
||||
int "Baud rate for BT_BLE_LOG_UHCI_OUT_UART_PORT"
|
||||
depends on BT_BLE_LOG_UHCI_OUT_UART_NEED_INIT
|
||||
default 3000000
|
||||
help
|
||||
Baud rate for BT_BLE_LOG_UHCI_OUT_UART_PORT
|
||||
|
||||
config BT_BLE_LOG_UHCI_OUT_UART_IO_NUM_TX
|
||||
int "IO number for UART TX port"
|
||||
depends on BT_BLE_LOG_UHCI_OUT_UART_NEED_INIT
|
||||
default 0
|
||||
help
|
||||
IO number for UART TX port
|
||||
|
||||
config BT_LE_USED_MEM_STATISTICS_ENABLED
|
||||
bool "Enable used memory statistics"
|
||||
default n
|
||||
help
|
||||
Used in internal tests only. Enable used memory statistics.
|
||||
|
||||
@@ -0,0 +1,173 @@
|
||||
config BLE_LOG_ENABLED
|
||||
bool "Enable BLE Log Module (Experimental)"
|
||||
default n
|
||||
help
|
||||
Enable BLE Log Module
|
||||
|
||||
if BLE_LOG_ENABLED
|
||||
config BLE_LOG_LBM_TRANS_SIZE
|
||||
int "Buffer size for each peripheral transport"
|
||||
default 512
|
||||
help
|
||||
There're 2 log buffer managers (LBMs) with compare-and-swap
|
||||
(CAS) protection, 1 LBM with FreeRTOS mutex protection, 1 LBM
|
||||
without protection for critical section. Each LBM is managing
|
||||
2 ping-pong buffers, which means there will be 4 * 2 *
|
||||
BLE_LOG_LBM_TRANS_SIZE bytes buffer allocated
|
||||
|
||||
config BLE_LOG_LBM_ATOMIC_LOCK_TASK_CNT
|
||||
int "Count of log buffer managers with atomic lock protection for task context"
|
||||
default 2
|
||||
help
|
||||
BLE Log module will search for an LBM with atomic lock protection first; if
|
||||
all LBMs with atomic lock protection are unavailable, BLE Log module will
|
||||
try to use the LBM with spin lock protection. So the more LBMs with atomic
|
||||
lock protection are created, the better the logging performance will be.
|
||||
|
||||
config BLE_LOG_LBM_ATOMIC_LOCK_ISR_CNT
|
||||
int "Count of log buffer managers with atomic lock protection for ISR context"
|
||||
default 1
|
||||
help
|
||||
BLE Log module will search for an LBM with atomic lock protection first; if
|
||||
all LBMs with atomic lock protection are unavailable, BLE Log module will
|
||||
try to use the LBM with spin lock protection. So the more LBMs with atomic
|
||||
lock protection are created, the more ISRs can nest.
|
||||
|
||||
config BLE_LOG_IS_ESP_CONTROLLER
|
||||
bool "Current BLE Controller is ESP BLE Controller"
|
||||
depends on BT_CONTROLLER_ENABLED
|
||||
depends on SOC_ESP_NIMBLE_CONTROLLER
|
||||
default y
|
||||
select BT_LE_CONTROLLER_LOG_ENABLED
|
||||
select BT_LE_CONTROLLER_LOG_MODE_BLE_LOG_V2
|
||||
select BLE_LOG_LL_ENABLED
|
||||
help
|
||||
Current BLE Controller is ESP BLE Controller
|
||||
|
||||
config BLE_LOG_IS_ESP_LEGACY_CONTROLLER
|
||||
bool "Current BLE Controller is ESP BLE Legacy Controller"
|
||||
depends on BT_CONTROLLER_ENABLED
|
||||
depends on !SOC_ESP_NIMBLE_CONTROLLER
|
||||
depends on BT_CTRL_RUN_IN_FLASH_ONLY
|
||||
default y
|
||||
select BT_CTRL_LE_LOG_EN
|
||||
select BLE_LOG_LL_ENABLED
|
||||
help
|
||||
Current BLE Controller is ESP BLE Legacy Controller
|
||||
|
||||
config BLE_LOG_LL_ENABLED
|
||||
bool "Enable BLE Log for Link Layer"
|
||||
depends on BT_CONTROLLER_ENABLED
|
||||
default n
|
||||
help
|
||||
Enable BLE Log for Link Layer
|
||||
|
||||
config BLE_LOG_LBM_LL_TRANS_SIZE
|
||||
int "Buffer size for each peripheral transport of Link Layer LBM"
|
||||
depends on BLE_LOG_LL_ENABLED
|
||||
default 1024
|
||||
help
|
||||
There're 2 Link Layer dedicated log buffer managers (LBMs) with
|
||||
compare-and-swap (CAS) protection. Each LBM is managing 2 ping-
|
||||
pong buffers, which means there will be additional 2 * 2 *
|
||||
BLE_LOG_LBM_LL_TRANS_SIZE bytes buffer allocated
|
||||
|
||||
config BLE_LOG_PAYLOAD_CHECKSUM_ENABLED
|
||||
bool "Enable payload checksum for BLE Log data integrity check"
|
||||
default y
|
||||
help
|
||||
Checksum is the default method for BLE Log data integrity check,
|
||||
but for targets with slow CPU speed, it may cause significant system
|
||||
performance decrease; a compromise could be made to balance the
|
||||
realtime performance and log data integrity, which is calculating the
|
||||
checksum of frame head and payload all together by default, or only
|
||||
calculate the checksum of frame head to minimize performance decrease
|
||||
|
||||
config BLE_LOG_ENH_STAT_ENABLED
|
||||
bool "Enable enhanced statistics for BLE Log"
|
||||
default n
|
||||
help
|
||||
Enable enhanced statistics for written/lost frame/bytes count, which may
|
||||
cost additional ~100kB memory
|
||||
|
||||
config BLE_LOG_TS_ENABLED
|
||||
bool "Enable BLE Log Timestamp Synchronization (TS)"
|
||||
default n
|
||||
help
|
||||
Enable BLE Log TS with external logging module
|
||||
|
||||
config BLE_LOG_SYNC_IO_NUM
|
||||
int "GPIO number for Timestamp Synchronization (TS) toggle output"
|
||||
depends on BLE_LOG_TS_ENABLED
|
||||
default 0
|
||||
help
|
||||
GPIO number for TS toggle output
|
||||
|
||||
choice BLE_LOG_PRPH_CHOICE
|
||||
prompt "BLE Log peripheral choice"
|
||||
default BLE_LOG_PRPH_DUMMY
|
||||
help
|
||||
Choose BLE Log peripheral
|
||||
|
||||
config BLE_LOG_PRPH_DUMMY
|
||||
bool "Dummy transport"
|
||||
help
|
||||
Dummy transport (dump only)
|
||||
|
||||
config BLE_LOG_PRPH_SPI_MASTER_DMA
|
||||
bool "Utilize SPI master DMA driver as transport"
|
||||
depends on SOC_GPSPI_SUPPORTED
|
||||
help
|
||||
Utilize SPI master DMA driver as transport
|
||||
|
||||
config BLE_LOG_PRPH_UART_DMA
|
||||
bool "Utilize UART DMA driver as transport"
|
||||
depends on SOC_UHCI_SUPPORTED
|
||||
help
|
||||
Utilize UART DMA driver as transport
|
||||
endchoice
|
||||
|
||||
if BLE_LOG_PRPH_SPI_MASTER_DMA
|
||||
config BLE_LOG_PRPH_SPI_MASTER_DMA_MOSI_IO_NUM
|
||||
int "GPIO number of MOSI port for SPI master DMA transport"
|
||||
default 0
|
||||
help
|
||||
GPIO number of MOSI port for SPI master DMA transport
|
||||
|
||||
config BLE_LOG_PRPH_SPI_MASTER_DMA_SCLK_IO_NUM
|
||||
int "GPIO number of SCLK port for SPI master DMA transport"
|
||||
default 0
|
||||
help
|
||||
GPIO number of SCLK port for SPI master DMA transport
|
||||
|
||||
config BLE_LOG_PRPH_SPI_MASTER_DMA_CS_IO_NUM
|
||||
int "GPIO number of CS port for SPI master DMA transport"
|
||||
default 0
|
||||
help
|
||||
GPIO number of CS port for SPI master DMA transport
|
||||
endif
|
||||
|
||||
if BLE_LOG_PRPH_UART_DMA
|
||||
config BLE_LOG_PRPH_UART_DMA_PORT
|
||||
int "UART port number for UART DMA transport"
|
||||
default 0
|
||||
help
|
||||
UART port number for UART DMA
|
||||
|
||||
config BLE_LOG_PRPH_UART_DMA_BAUD_RATE
|
||||
int "Baud rate of UART port for UART DMA transport"
|
||||
default 921600
|
||||
help
|
||||
Determine the baud rate of UART port
|
||||
|
||||
config BLE_LOG_PRPH_UART_DMA_TX_IO_NUM
|
||||
int "GPIO number for UART TX"
|
||||
default 0
|
||||
help
|
||||
GPIO number for UART TX
|
||||
endif
|
||||
|
||||
menu "Settings of BLE Log Compression"
|
||||
source "$IDF_PATH/components/bt/common/ble_log/extension/log_compression/Kconfig.in"
|
||||
endmenu
|
||||
endif
|
||||
@@ -0,0 +1,450 @@
|
||||
# BLE Log Module
|
||||
|
||||
A high-performance, modular Bluetooth logging system that provides real-time log capture and transmission capabilities for the ESP-IDF Bluetooth stack.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Architecture Design](#architecture-design)
|
||||
- [Features](#features)
|
||||
- [Quick Start](#quick-start)
|
||||
- [Configuration Options](#configuration-options)
|
||||
- [API Reference](#api-reference)
|
||||
- [Usage Examples](#usage-examples)
|
||||
- [Performance & Memory Optimization](#performance--memory-optimization)
|
||||
- [Troubleshooting](#troubleshooting)
|
||||
- [Important Notes](#important-notes)
|
||||
|
||||
## Overview
|
||||
|
||||
The BLE Log module is an efficient logging system specifically designed for the ESP-IDF Bluetooth stack, supporting real-time log capture, multi-source log collection, and various transmission methods. This module has been refactored with a modular design, featuring high-concurrency processing capabilities and low-latency characteristics.
|
||||
|
||||
### Main Components
|
||||
|
||||
- **BLE Log Core** (`ble_log.c`): Module core responsible for initialization and coordination of sub-modules
|
||||
- **Runtime Manager** (`ble_log_rt.c`): Runtime task management for log transmission scheduling
|
||||
- **Log Buffer Manager** (`ble_log_lbm.c`): Log buffer management supporting multiple locking mechanisms
|
||||
- **Peripheral Interface** (`ble_log_prph_*.c`): Peripheral interface abstraction layer supporting various transmission methods
|
||||
- **Timestamp Sync** (`ble_log_ts.c`): Timestamp synchronization module
|
||||
- **Utility** (`ble_log_util.c`): Common utility functions
|
||||
|
||||
## Features
|
||||
|
||||
### Core Functionality
|
||||
|
||||
- **Multi-source Log Collection**: Supports multiple log sources including Link Layer, Host, HCI, etc.
|
||||
- **High Concurrency Processing**: Uses atomic and spin lock mechanisms for multi-task concurrent writing
|
||||
- **Real-time Transmission**: Asynchronous transmission mechanism based on FreeRTOS tasks
|
||||
- **Data Integrity**: Configurable checksum mechanism ensures data integrity
|
||||
- **Memory Optimization**: Ping-pong buffer design minimizes memory usage
|
||||
|
||||
### Advanced Features
|
||||
|
||||
- **Timestamp Synchronization**: Supports timestamp synchronization with external devices (optional)
|
||||
- **Enhanced Statistics**: Detailed logging statistics including loss rate analysis (optional)
|
||||
- **Link Layer Integration**: Deep integration with ESP-IDF Bluetooth Link Layer
|
||||
- **Multiple Transmission Methods**: Supports SPI DMA, UART DMA, and Dummy transmission
|
||||
|
||||
### Performance Features
|
||||
|
||||
- **IRAM Optimization**: Critical path code runs in IRAM ensuring low latency
|
||||
- **Lock-free Design**: Most operations use atomic operations reducing lock contention
|
||||
- **Buffer Reuse**: Intelligent buffer management reduces memory allocation overhead
|
||||
|
||||
## Quick Start
|
||||
|
||||
### 1. Enable Module
|
||||
|
||||
Enable the BLE Log module in `menuconfig`:
|
||||
|
||||
```
|
||||
Component config → Bluetooth → Enable BLE Log Module (Experimental)
|
||||
```
|
||||
|
||||
### 2. Basic Configuration
|
||||
|
||||
```c
|
||||
#include "ble_log.h"
|
||||
|
||||
void app_main() {
|
||||
// Initialize BLE Log module
|
||||
if (!ble_log_init()) {
|
||||
ESP_LOGE(TAG, "Failed to initialize BLE Log");
|
||||
return;
|
||||
}
|
||||
|
||||
// Write log data
|
||||
uint8_t data[] = {0x01, 0x02, 0x03, 0x04};
|
||||
ble_log_write_hex(BLE_LOG_SRC_CUSTOM, data, sizeof(data));
|
||||
|
||||
// Force flush buffers
|
||||
ble_log_flush();
|
||||
|
||||
// Cleanup resources
|
||||
ble_log_deinit();
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Link Layer Integration
|
||||
|
||||
When `CONFIG_BLE_LOG_LL_ENABLED` is enabled, Link Layer logs are automatically integrated:
|
||||
|
||||
```c
|
||||
// Link Layer logs will automatically call this function
|
||||
void ble_log_write_hex_ll(uint32_t len, const uint8_t *addr,
|
||||
uint32_t len_append, const uint8_t *addr_append,
|
||||
uint32_t flag);
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
### Basic Configuration
|
||||
|
||||
| Configuration | Default | Description |
|
||||
|---------------|---------|-------------|
|
||||
| `CONFIG_BLE_LOG_ENABLED` | n | Enable BLE Log module |
|
||||
| `CONFIG_BLE_LOG_LBM_TRANS_SIZE` | 512 | Size of each transport buffer |
|
||||
| `CONFIG_BLE_LOG_LBM_ATOMIC_LOCK_TASK_CNT` | 2 | Number of atomic lock LBMs for task context |
|
||||
| `CONFIG_BLE_LOG_LBM_ATOMIC_LOCK_ISR_CNT` | 1 | Number of atomic lock LBMs for ISR context |
|
||||
|
||||
### Link Layer Configuration
|
||||
|
||||
| Configuration | Default | Description |
|
||||
|---------------|---------|-------------|
|
||||
| `CONFIG_BLE_LOG_LL_ENABLED` | y | Enable Link Layer logging |
|
||||
| `CONFIG_BLE_LOG_LBM_LL_TRANS_SIZE` | 1024 | Link Layer transport buffer size |
|
||||
|
||||
### Advanced Features
|
||||
|
||||
| Configuration | Default | Description |
|
||||
|---------------|---------|-------------|
|
||||
| `CONFIG_BLE_LOG_PAYLOAD_CHECKSUM_ENABLED` | y | Enable payload checksum |
|
||||
| `CONFIG_BLE_LOG_ENH_STAT_ENABLED` | n | Enable enhanced statistics |
|
||||
| `CONFIG_BLE_LOG_TS_ENABLED` | n | Enable timestamp synchronization |
|
||||
|
||||
### Transport Method Configuration
|
||||
|
||||
| Transport | Configuration | Description |
|
||||
|-----------|---------------|-------------|
|
||||
| Dummy | `CONFIG_BLE_LOG_PRPH_DUMMY` | Debug dummy transport |
|
||||
| SPI Master DMA | `CONFIG_BLE_LOG_PRPH_SPI_MASTER_DMA` | SPI DMA transport |
|
||||
| UART DMA | `CONFIG_BLE_LOG_PRPH_UART_DMA` | UART DMA transport |
|
||||
|
||||
## API Reference
|
||||
|
||||
### Core API
|
||||
|
||||
#### `bool ble_log_init(void)`
|
||||
|
||||
Initialize the BLE Log module.
|
||||
|
||||
**Return Value**:
|
||||
- `true`: Initialization successful
|
||||
- `false`: Initialization failed
|
||||
|
||||
**Note**: Must be called before using any other APIs.
|
||||
|
||||
#### `void ble_log_deinit(void)`
|
||||
|
||||
Cleanup the BLE Log module and release all resources.
|
||||
|
||||
**Note**:
|
||||
- All pending logs will be lost after calling this function
|
||||
- Peripheral interface will be cleaned up first to avoid DMA transmission issues during memory release
|
||||
|
||||
#### `bool ble_log_write_hex(ble_log_src_t src_code, const uint8_t *addr, size_t len)`
|
||||
|
||||
Write hexadecimal log data.
|
||||
|
||||
**Parameters**:
|
||||
- `src_code`: Log source code
|
||||
- `addr`: Data pointer
|
||||
- `len`: Data length
|
||||
|
||||
**Return Value**:
|
||||
- `true`: Write successful
|
||||
- `false`: Write failed (module not initialized or insufficient buffer)
|
||||
|
||||
#### `void ble_log_flush(void)`
|
||||
|
||||
Force flush all buffers and send pending logs immediately.
|
||||
|
||||
**Note**: This operation is blocking and will pause module operation until all buffers are cleared.
|
||||
|
||||
#### `void ble_log_dump_to_console(void)`
|
||||
|
||||
Output all buffer contents to console in hexadecimal format for debugging.
|
||||
|
||||
### Log Source Types
|
||||
|
||||
```c
|
||||
typedef enum {
|
||||
BLE_LOG_SRC_INTERNAL = 0, // Internal system logs
|
||||
BLE_LOG_SRC_CUSTOM, // User-defined logs
|
||||
BLE_LOG_SRC_LL_TASK, // Link Layer task logs
|
||||
BLE_LOG_SRC_LL_HCI, // Link Layer HCI logs
|
||||
BLE_LOG_SRC_LL_ISR, // Link Layer interrupt logs
|
||||
BLE_LOG_SRC_HOST, // Host layer logs
|
||||
BLE_LOG_SRC_HCI, // HCI layer logs
|
||||
BLE_LOG_SRC_ENCODE, // Encoding layer logs
|
||||
BLE_LOG_SRC_MAX,
|
||||
} ble_log_src_t;
|
||||
```
|
||||
|
||||
### Link Layer API (Conditional Compilation)
|
||||
|
||||
#### `void ble_log_write_hex_ll(uint32_t len, const uint8_t *addr, uint32_t len_append, const uint8_t *addr_append, uint32_t flag)`
|
||||
|
||||
Link Layer dedicated log writing interface.
|
||||
|
||||
**Parameters**:
|
||||
- `len`: Main data length
|
||||
- `addr`: Main data pointer
|
||||
- `len_append`: Append data length
|
||||
- `addr_append`: Append data pointer
|
||||
- `flag`: Log flag bits
|
||||
|
||||
**Flag Definitions**:
|
||||
```c
|
||||
enum {
|
||||
BLE_LOG_LL_FLAG_CONTINUE = 0,
|
||||
BLE_LOG_LL_FLAG_END,
|
||||
BLE_LOG_LL_FLAG_TASK,
|
||||
BLE_LOG_LL_FLAG_ISR,
|
||||
BLE_LOG_LL_FLAG_HCI,
|
||||
BLE_LOG_LL_FLAG_RAW,
|
||||
BLE_LOG_LL_FLAG_HCI_UPSTREAM,
|
||||
};
|
||||
```
|
||||
|
||||
### Timestamp Synchronization API (Conditional Compilation)
|
||||
|
||||
#### `bool ble_log_sync_enable(bool enable)`
|
||||
|
||||
Enable or disable timestamp synchronization functionality.
|
||||
|
||||
**Parameters**:
|
||||
- `enable`: true to enable, false to disable
|
||||
|
||||
**Return Value**:
|
||||
- `true`: Operation successful
|
||||
- `false`: Operation failed (module not initialized)
|
||||
|
||||
## Usage Examples
|
||||
|
||||
### Example 1: Basic Logging
|
||||
|
||||
```c
|
||||
#include "ble_log.h"
|
||||
|
||||
void example_basic_logging() {
|
||||
// Initialize
|
||||
if (!ble_log_init()) {
|
||||
printf("BLE Log init failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Log some example data
|
||||
uint8_t hci_cmd[] = {0x01, 0x03, 0x0C, 0x00}; // HCI Reset Command
|
||||
ble_log_write_hex(BLE_LOG_SRC_HCI, hci_cmd, sizeof(hci_cmd));
|
||||
|
||||
uint8_t host_data[] = {0x02, 0x00, 0x20, 0x0B, 0x00, 0x07, 0x00, 0x04, 0x00, 0x10, 0x01, 0x00, 0xFF, 0xFF, 0x00, 0x28};
|
||||
ble_log_write_hex(BLE_LOG_SRC_HOST, host_data, sizeof(host_data));
|
||||
|
||||
// Force send
|
||||
ble_log_flush();
|
||||
|
||||
// Cleanup
|
||||
ble_log_deinit();
|
||||
}
|
||||
```
|
||||
|
||||
### Example 2: ISR Context Logging
|
||||
|
||||
```c
|
||||
void IRAM_ATTR some_isr_handler() {
|
||||
uint8_t isr_data[] = {0xDE, 0xAD, 0xBE, 0xEF};
|
||||
|
||||
// Safe to write logs in ISR context
|
||||
ble_log_write_hex(BLE_LOG_SRC_LL_ISR, isr_data, sizeof(isr_data));
|
||||
}
|
||||
```
|
||||
|
||||
### Example 3: Logging with Timestamp Synchronization
|
||||
|
||||
```c
|
||||
void example_with_timestamp_sync() {
|
||||
if (!ble_log_init()) {
|
||||
return;
|
||||
}
|
||||
|
||||
#if CONFIG_BLE_LOG_TS_ENABLED
|
||||
// Enable timestamp synchronization
|
||||
ble_log_sync_enable(true);
|
||||
#endif
|
||||
|
||||
// Log data...
|
||||
uint8_t data[] = {0x01, 0x02, 0x03};
|
||||
ble_log_write_hex(BLE_LOG_SRC_CUSTOM, data, sizeof(data));
|
||||
|
||||
// Timestamp information will be automatically included in logs
|
||||
|
||||
ble_log_deinit();
|
||||
}
|
||||
```
|
||||
|
||||
### Example 4: Performance Testing
|
||||
|
||||
```c
|
||||
void example_performance_test() {
|
||||
if (!ble_log_init()) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t test_data[100];
|
||||
for (int i = 0; i < 100; i++) {
|
||||
test_data[i] = i;
|
||||
}
|
||||
|
||||
uint32_t start_time = esp_timer_get_time();
|
||||
|
||||
// Send 1000 logs
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
ble_log_write_hex(BLE_LOG_SRC_CUSTOM, test_data, sizeof(test_data));
|
||||
}
|
||||
|
||||
ble_log_flush();
|
||||
uint32_t end_time = esp_timer_get_time();
|
||||
|
||||
printf("Time to write 1000 logs: %lu us\n", end_time - start_time);
|
||||
|
||||
ble_log_deinit();
|
||||
}
|
||||
```
|
||||
|
||||
## Performance & Memory Optimization
|
||||
|
||||
### Memory Usage Estimation
|
||||
|
||||
Memory usage under default configuration:
|
||||
|
||||
```
|
||||
Total Buffers = (Atomic Task LBMs + Atomic ISR LBMs + Spin LBMs) × 2 × Transport Buffer Size
|
||||
Default Config = (2 + 1 + 2) × 2 × 512 = 5120 bytes
|
||||
|
||||
Additional when Link Layer enabled:
|
||||
LL Buffers = 2 × 2 × 1024 = 4096 bytes
|
||||
|
||||
Additional when Enhanced Statistics enabled:
|
||||
Statistics Data = Log Source Count × sizeof(ble_log_stat_mgr_t) = 8 × 40 = 320 bytes
|
||||
```
|
||||
|
||||
### Performance Optimization Recommendations
|
||||
|
||||
1. **Adjust LBM Count**: Adjust atomic lock LBM count based on concurrency requirements
|
||||
2. **Buffer Size**: Adjust transport buffer size based on log volume
|
||||
3. **Transport Method**: Choose optimal transport method based on hardware (SPI DMA typically has best performance)
|
||||
4. **Checksum**: Consider disabling payload checksum when performance requirements are extremely high
|
||||
|
||||
### Real-time Considerations
|
||||
|
||||
- Critical code paths are marked with `BLE_LOG_IRAM_ATTR` and run in IRAM
|
||||
- Atomic operations avoid lock contention
|
||||
- Ping-pong buffers ensure continuous writing
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
#### 1. Initialization Failure
|
||||
|
||||
**Symptoms**: `ble_log_init()` returns `false`
|
||||
|
||||
**Possible Causes**:
|
||||
- Insufficient memory
|
||||
- Peripheral configuration error
|
||||
- Duplicate initialization
|
||||
|
||||
**Solutions**:
|
||||
```c
|
||||
// Check available memory
|
||||
printf("Free heap: %d bytes\n", esp_get_free_heap_size());
|
||||
|
||||
// Ensure initialization only happens once
|
||||
static bool initialized = false;
|
||||
if (!initialized) {
|
||||
initialized = ble_log_init();
|
||||
}
|
||||
```
|
||||
|
||||
#### 2. Log Loss
|
||||
|
||||
**Symptoms**: Some logs don't appear in output
|
||||
|
||||
**Possible Causes**:
|
||||
- Buffer overflow
|
||||
- Transmission speed can't keep up with write speed
|
||||
- Module not properly initialized
|
||||
|
||||
**Solutions**:
|
||||
```c
|
||||
// Enable enhanced statistics to check loss rate
|
||||
#if CONFIG_BLE_LOG_ENH_STAT_ENABLED
|
||||
// Statistics will be automatically included in logs
|
||||
#endif
|
||||
|
||||
// Adjust buffer size
|
||||
// CONFIG_BLE_LOG_LBM_TRANS_SIZE=1024
|
||||
|
||||
// Increase atomic lock LBM count
|
||||
// CONFIG_BLE_LOG_LBM_ATOMIC_LOCK_TASK_CNT=4
|
||||
```
|
||||
|
||||
#### 3. Performance Issues
|
||||
|
||||
**Symptoms**: System response becomes slow
|
||||
|
||||
**Possible Causes**:
|
||||
- Checksum calculation overhead
|
||||
- Transmission bottleneck
|
||||
- Lock contention
|
||||
|
||||
**Solutions**:
|
||||
```c
|
||||
// Disable payload checksum
|
||||
// CONFIG_BLE_LOG_PAYLOAD_CHECKSUM_ENABLED=n
|
||||
|
||||
// Use faster transmission method
|
||||
// CONFIG_BLE_LOG_PRPH_SPI_MASTER_DMA=y
|
||||
|
||||
// Adjust task priority
|
||||
#define BLE_LOG_TASK_PRIO configMAX_PRIORITIES-3
|
||||
```
|
||||
|
||||
### Debugging Techniques
|
||||
|
||||
#### 1. Use Dummy Transport for Debugging
|
||||
|
||||
```c
|
||||
// Select Dummy transport in menuconfig
|
||||
// Then use dump function to view buffer contents
|
||||
ble_log_dump_to_console();
|
||||
```
|
||||
|
||||
#### 2. Enable Enhanced Statistics
|
||||
|
||||
```c
|
||||
// Enable in menuconfig
|
||||
// CONFIG_BLE_LOG_ENH_STAT_ENABLED=y
|
||||
// Statistics will be automatically output to logs
|
||||
```
|
||||
|
||||
#### 3. Monitor Memory Usage
|
||||
|
||||
```c
|
||||
void monitor_memory() {
|
||||
printf("Free heap before init: %d\n", esp_get_free_heap_size());
|
||||
ble_log_init();
|
||||
printf("Free heap after init: %d\n", esp_get_free_heap_size());
|
||||
}
|
||||
```
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,795 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "ble_log/ble_log_uhci_out.h"
|
||||
|
||||
|
||||
#if CONFIG_BT_BLE_LOG_UHCI_OUT_ENABLED
|
||||
|
||||
// Private includes
|
||||
#include "esp_bt.h"
|
||||
|
||||
// sdkconfig defines
|
||||
#define UHCI_OUT_LL_TASK_BUF_SIZE CONFIG_BT_BLE_LOG_UHCI_OUT_LL_TASK_BUF_SIZE
|
||||
#define UHCI_OUT_LL_ISR_BUF_SIZE CONFIG_BT_BLE_LOG_UHCI_OUT_LL_ISR_BUF_SIZE
|
||||
#define UHCI_OUT_LL_HCI_BUF_SIZE CONFIG_BT_BLE_LOG_UHCI_OUT_LL_HCI_BUF_SIZE
|
||||
#define UHCI_OUT_UART_PORT CONFIG_BT_BLE_LOG_UHCI_OUT_UART_PORT
|
||||
#define UHCI_OUT_UART_NEED_INIT CONFIG_BT_BLE_LOG_UHCI_OUT_UART_NEED_INIT
|
||||
|
||||
#if UHCI_OUT_UART_NEED_INIT
|
||||
#define UHCI_OUT_UART_BAUD_RATE CONFIG_BT_BLE_LOG_UHCI_OUT_UART_BAUD_RATE
|
||||
#define UHCI_OUT_UART_IO_NUM_TX CONFIG_BT_BLE_LOG_UHCI_OUT_UART_IO_NUM_TX
|
||||
#endif // UHCI_OUT_UART_NEED_INIT
|
||||
|
||||
// Private defines
|
||||
#define UHCI_OUT_MAX_TRANSFER_SIZE (10240)
|
||||
#define UHCI_OUT_MALLOC(size) heap_caps_malloc(size, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)
|
||||
#define UHCI_OUT_FLUSH_TIMEOUT_MS (100)
|
||||
#define UHCI_OUT_FLUSH_TIMEOUT_US (UHCI_OUT_FLUSH_TIMEOUT_MS * 1000)
|
||||
#define UHCI_OUT_USER_BUF_SIZE (512)
|
||||
#define UHCI_OUT_UART_PORT0 (0)
|
||||
#define UHCI_OUT_UART_PORT1 (1)
|
||||
#define UHCI_OUT_UART_DRIVER_RX_BUF_SIZE (32)
|
||||
|
||||
// Queue size defines
|
||||
#define UHCI_OUT_PING_PONG_BUF_CNT (2)
|
||||
#define UHCI_OUT_USER_QUEUE_SIZE (UHCI_OUT_PING_PONG_BUF_CNT)
|
||||
#define UHCI_OUT_LL_QUEUE_SIZE (3 * UHCI_OUT_PING_PONG_BUF_CNT)
|
||||
#define UHCI_OUT_QUEUE_SIZE (UHCI_OUT_USER_QUEUE_SIZE + UHCI_OUT_LL_QUEUE_SIZE)
|
||||
|
||||
#if CONFIG_SOC_ESP_NIMBLE_CONTROLLER
|
||||
#include "os/os_mbuf.h"
|
||||
#endif /* CONFIG_SOC_ESP_NIMBLE_CONTROLLER */
|
||||
|
||||
// Private typedefs
|
||||
typedef struct {
|
||||
// This flag is for multithreading, must be a word, do not modify
|
||||
volatile uint32_t flag;
|
||||
uint16_t buf_size;
|
||||
uint16_t length;
|
||||
uint8_t buffer[0];
|
||||
} uhci_out_trans_cb_t;
|
||||
|
||||
typedef struct {
|
||||
uhci_out_trans_cb_t *trans_cb[2];
|
||||
uint8_t trans_cb_idx;
|
||||
uint8_t type;
|
||||
uint16_t lost_frame_cnt;
|
||||
uint32_t lost_bytes_cnt;
|
||||
uint32_t frame_sn;
|
||||
} uhci_out_log_cb_t;
|
||||
|
||||
typedef struct {
|
||||
uint16_t length;
|
||||
uint8_t source;
|
||||
uint8_t type;
|
||||
uint16_t frame_sn;
|
||||
} __attribute__((packed)) frame_head_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t type;
|
||||
uint16_t lost_frame_cnt;
|
||||
uint32_t lost_bytes_cnt;
|
||||
} __attribute__((packed)) loss_payload_t;
|
||||
|
||||
// Private enums
|
||||
enum {
|
||||
TRANS_CB_FLAG_AVAILABLE = 0,
|
||||
TRANS_CB_FLAG_NEED_QUEUE,
|
||||
TRANS_CB_FLAG_IN_QUEUE,
|
||||
};
|
||||
|
||||
enum {
|
||||
LOG_CB_TYPE_USER = 0,
|
||||
LOG_CB_TYPE_LL,
|
||||
};
|
||||
|
||||
enum {
|
||||
LOG_CB_LL_SUBTYPE_TASK = 0,
|
||||
LOG_CB_LL_SUBTYPE_ISR,
|
||||
LOG_CB_LL_SUBTYPE_HCI
|
||||
};
|
||||
|
||||
enum {
|
||||
LL_LOG_FLAG_CONTINUE = 0,
|
||||
LL_LOG_FLAG_END,
|
||||
LL_LOG_FLAG_TASK,
|
||||
LL_LOG_FLAG_ISR,
|
||||
LL_LOG_FLAG_HCI,
|
||||
LL_LOG_FLAG_RAW,
|
||||
LL_LOG_FLAG_OMDATA,
|
||||
LL_LOG_FLAG_HCI_UPSTREAM,
|
||||
};
|
||||
|
||||
enum {
|
||||
LL_EV_FLAG_ISR_APPEND = 0,
|
||||
LL_EV_FLAG_FLUSH_LOG,
|
||||
};
|
||||
|
||||
// Private variables
|
||||
static bool uhci_out_inited = false;
|
||||
static uhci_controller_handle_t uhci_handle = NULL;
|
||||
|
||||
static bool user_log_inited = false;
|
||||
static SemaphoreHandle_t user_log_mutex = NULL;
|
||||
static uhci_out_log_cb_t *user_log_cb = NULL;
|
||||
static uint32_t user_last_write_ts = 0;
|
||||
|
||||
static bool ll_log_inited = false;
|
||||
static uhci_out_log_cb_t *ll_task_log_cb = NULL;
|
||||
static uhci_out_log_cb_t *ll_isr_log_cb = NULL;
|
||||
static uhci_out_log_cb_t *ll_hci_log_cb = NULL;
|
||||
static uint32_t ll_ev_flags = 0;
|
||||
static uint32_t ll_last_write_ts = 0;
|
||||
|
||||
static esp_timer_handle_t flush_timer = NULL;
|
||||
|
||||
// Private function declarations
|
||||
extern void esp_panic_handler_feed_wdts(void);
|
||||
|
||||
static int uhci_out_init_trans(uhci_out_trans_cb_t **trans_cb, uint16_t buf_size);
|
||||
static void uhci_out_deinit_trans(uhci_out_trans_cb_t **trans_cb);
|
||||
static bool uhci_out_tx_done_cb(uhci_controller_handle_t uhci_ctrl,
|
||||
const uhci_tx_done_event_data_t *edata, void *user_ctx);
|
||||
static inline void uhci_out_append_trans(uhci_out_trans_cb_t *trans_cb);
|
||||
|
||||
static int uhci_out_log_cb_init(uhci_out_log_cb_t **log_cb, uint16_t buf_size, uint8_t type, uint8_t idx);
|
||||
static void uhci_out_log_cb_deinit(uhci_out_log_cb_t **log_cb);
|
||||
static inline bool uhci_out_log_cb_check_trans(uhci_out_log_cb_t *log_cb, uint16_t len, bool *need_append);
|
||||
static inline void uhci_out_log_cb_append_trans(uhci_out_log_cb_t *log_cb);
|
||||
static inline void uhci_out_log_cb_flush_trans(uhci_out_log_cb_t *log_cb);
|
||||
static bool uhci_out_log_cb_write(uhci_out_log_cb_t *log_cb, const uint8_t *addr, uint16_t len,
|
||||
const uint8_t *addr_append, uint16_t len_append, uint8_t source, bool omdata);
|
||||
static void uhci_out_log_cb_write_loss(uhci_out_log_cb_t *log_cb);
|
||||
static void uhci_out_log_cb_dump(uhci_out_log_cb_t *log_cb);
|
||||
|
||||
static void esp_timer_cb_log_flush(void);
|
||||
static void uhci_out_user_write_str(const uint8_t *src, uint16_t len);
|
||||
|
||||
#if UHCI_OUT_UART_PORT == UHCI_OUT_UART_PORT0
|
||||
static void uhci_out_user_write_char(char c);
|
||||
#endif // UHCI_OUT_UART_PORT == UHCI_OUT_UART_PORT0
|
||||
|
||||
static int uhci_out_user_log_init(void);
|
||||
static void uhci_out_user_log_deinit(void);
|
||||
|
||||
static int uhci_out_ll_log_init(void);
|
||||
static void uhci_out_ll_log_deinit(void);
|
||||
static void uhci_out_ll_log_flush(void);
|
||||
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32H2) || defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32C5) ||\
|
||||
defined(CONFIG_IDF_TARGET_ESP32C61) || defined(CONFIG_IDF_TARGET_ESP32H21)
|
||||
extern void r_ble_log_simple_put_ev(void);
|
||||
#define UHCI_OUT_LL_PUT_EV r_ble_log_simple_put_ev()
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32C2)
|
||||
extern void ble_log_simple_put_ev(void);
|
||||
#define UHCI_OUT_LL_PUT_EV ble_log_simple_put_ev()
|
||||
#else
|
||||
#define UHCI_OUT_LL_PUT_EV
|
||||
#endif
|
||||
|
||||
// Private macros
|
||||
#define UHCI_OUT_FRAME_HEAD_LEN (sizeof(frame_head_t))
|
||||
#define UHCI_OUT_FRAME_TAIL_LEN (sizeof(uint32_t))
|
||||
#define UHCI_OUT_FRAME_OVERHEAD (UHCI_OUT_FRAME_HEAD_LEN + UHCI_OUT_FRAME_TAIL_LEN)
|
||||
#define UHCI_OUT_GET_FRAME_SN(VAR) __atomic_fetch_add(VAR, 1, __ATOMIC_RELAXED)
|
||||
|
||||
// Private functions
|
||||
static int uhci_out_init_trans(uhci_out_trans_cb_t **trans_cb, uint16_t buf_size)
|
||||
{
|
||||
// Memory allocations
|
||||
size_t cb_size = sizeof(uhci_out_trans_cb_t) + buf_size;
|
||||
*trans_cb = (uhci_out_trans_cb_t *)UHCI_OUT_MALLOC(cb_size);
|
||||
if (!(*trans_cb)) {
|
||||
return -1;
|
||||
}
|
||||
memset(*trans_cb, 0, sizeof(uhci_out_trans_cb_t));
|
||||
|
||||
// Initialization
|
||||
(*trans_cb)->buf_size = buf_size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void uhci_out_deinit_trans(uhci_out_trans_cb_t **trans_cb)
|
||||
{
|
||||
if (!(*trans_cb)) {
|
||||
return;
|
||||
}
|
||||
|
||||
free(*trans_cb);
|
||||
*trans_cb = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
IRAM_ATTR static bool uhci_out_tx_done_cb(uhci_controller_handle_t uhci_ctrl,
|
||||
const uhci_tx_done_event_data_t *edata, void *user_ctx)
|
||||
{
|
||||
uhci_out_trans_cb_t *trans_cb = (uhci_out_trans_cb_t *)((uint8_t *)edata->buffer - sizeof(uhci_out_trans_cb_t));
|
||||
trans_cb->length = 0;
|
||||
trans_cb->flag = TRANS_CB_FLAG_AVAILABLE;
|
||||
return true;
|
||||
}
|
||||
|
||||
IRAM_ATTR static inline void uhci_out_append_trans(uhci_out_trans_cb_t *trans_cb)
|
||||
{
|
||||
if ((trans_cb->flag != TRANS_CB_FLAG_NEED_QUEUE) || !trans_cb->length) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Note: If task yield after transmission but before flag set
|
||||
// flag might be reset in tx done ISR before flag set, leading to buffer access failure
|
||||
trans_cb->flag = TRANS_CB_FLAG_IN_QUEUE;
|
||||
if (uhci_transmit(uhci_handle, trans_cb->buffer, trans_cb->length) != ESP_OK) {
|
||||
goto recycle;
|
||||
}
|
||||
return;
|
||||
|
||||
recycle:
|
||||
trans_cb->length = 0;
|
||||
trans_cb->flag = TRANS_CB_FLAG_AVAILABLE;
|
||||
return;
|
||||
}
|
||||
|
||||
static int uhci_out_log_cb_init(uhci_out_log_cb_t **log_cb, uint16_t buf_size, uint8_t type, uint8_t idx)
|
||||
{
|
||||
// Initialize log control block
|
||||
*log_cb = (uhci_out_log_cb_t *)UHCI_OUT_MALLOC(sizeof(uhci_out_log_cb_t));
|
||||
if (!(*log_cb)) {
|
||||
return -1;
|
||||
}
|
||||
memset(*log_cb, 0, sizeof(uhci_out_log_cb_t));
|
||||
|
||||
// Initialize transactions
|
||||
int ret = 0;
|
||||
for (uint8_t i = 0; i < 2; i++) {
|
||||
ret |= uhci_out_init_trans(&((*log_cb)->trans_cb[i]), buf_size);
|
||||
}
|
||||
if (ret != 0) {
|
||||
uhci_out_log_cb_deinit(log_cb);
|
||||
return -1;
|
||||
}
|
||||
|
||||
(*log_cb)->type = (type << 4) | (idx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void uhci_out_log_cb_deinit(uhci_out_log_cb_t **log_cb)
|
||||
{
|
||||
if (!(*log_cb)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < 2; i++) {
|
||||
if ((*log_cb)->trans_cb[i]) {
|
||||
uhci_out_deinit_trans(&((*log_cb)->trans_cb[i]));
|
||||
}
|
||||
}
|
||||
free(*log_cb);
|
||||
*log_cb = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
IRAM_ATTR static inline bool uhci_out_log_cb_check_trans(uhci_out_log_cb_t *log_cb, uint16_t len, bool *need_append)
|
||||
{
|
||||
uhci_out_trans_cb_t *trans_cb;
|
||||
*need_append = false;
|
||||
for (uint8_t i = 0; i < 2; i++) {
|
||||
trans_cb = log_cb->trans_cb[log_cb->trans_cb_idx];
|
||||
if (len > trans_cb->buf_size) {
|
||||
goto failed;
|
||||
}
|
||||
if (trans_cb->flag == TRANS_CB_FLAG_AVAILABLE) {
|
||||
if ((trans_cb->buf_size - trans_cb->length) >= len) {
|
||||
return true;
|
||||
} else {
|
||||
trans_cb->flag = TRANS_CB_FLAG_NEED_QUEUE;
|
||||
*need_append = true;
|
||||
}
|
||||
}
|
||||
log_cb->trans_cb_idx = !(log_cb->trans_cb_idx);
|
||||
}
|
||||
failed:
|
||||
log_cb->lost_bytes_cnt += len;
|
||||
log_cb->lost_frame_cnt++;
|
||||
return false;
|
||||
}
|
||||
|
||||
// CRITICAL: Shall not be called from ISR!
|
||||
IRAM_ATTR static inline void uhci_out_log_cb_append_trans(uhci_out_log_cb_t *log_cb)
|
||||
{
|
||||
uhci_out_trans_cb_t *trans_cb;
|
||||
uint8_t idx = !log_cb->trans_cb_idx;
|
||||
for (uint8_t i = 0; i < 2; i++) {
|
||||
trans_cb = log_cb->trans_cb[idx];
|
||||
if (trans_cb->flag == TRANS_CB_FLAG_NEED_QUEUE) {
|
||||
uhci_out_append_trans(trans_cb);
|
||||
}
|
||||
idx = !idx;
|
||||
}
|
||||
}
|
||||
|
||||
IRAM_ATTR static inline void uhci_out_log_cb_flush_trans(uhci_out_log_cb_t *log_cb)
|
||||
{
|
||||
uhci_out_trans_cb_t *trans_cb;
|
||||
for (uint8_t i = 0; i < 2; i++) {
|
||||
trans_cb = log_cb->trans_cb[i];
|
||||
if (trans_cb->length && (trans_cb->flag == TRANS_CB_FLAG_AVAILABLE)) {
|
||||
trans_cb->flag = TRANS_CB_FLAG_NEED_QUEUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return value: Need append
|
||||
IRAM_ATTR static bool uhci_out_log_cb_write(uhci_out_log_cb_t *log_cb, const uint8_t *addr, uint16_t len,
|
||||
const uint8_t *addr_append, uint16_t len_append, uint8_t source, bool omdata)
|
||||
{
|
||||
uhci_out_trans_cb_t *trans_cb = log_cb->trans_cb[log_cb->trans_cb_idx];
|
||||
|
||||
uint8_t *buf = trans_cb->buffer + trans_cb->length;
|
||||
uint16_t total_length = len + len_append;
|
||||
frame_head_t head = {
|
||||
.length = total_length,
|
||||
.source = source,
|
||||
.type = log_cb->type,
|
||||
.frame_sn = UHCI_OUT_GET_FRAME_SN(&(log_cb->frame_sn)) & 0xFFFF,
|
||||
};
|
||||
|
||||
memcpy(buf, (const uint8_t *)&head, UHCI_OUT_FRAME_HEAD_LEN);
|
||||
memcpy(buf + UHCI_OUT_FRAME_HEAD_LEN, addr, len);
|
||||
if (len_append && addr_append) {
|
||||
#if CONFIG_SOC_ESP_NIMBLE_CONTROLLER
|
||||
if (omdata) {
|
||||
os_mbuf_copydata((struct os_mbuf *)addr_append, 0,
|
||||
len_append, buf + UHCI_OUT_FRAME_HEAD_LEN + len);
|
||||
}
|
||||
else
|
||||
#endif /* CONFIG_SOC_ESP_NIMBLE_CONTROLLER */
|
||||
{
|
||||
memcpy(buf + UHCI_OUT_FRAME_HEAD_LEN + len, addr_append, len_append);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t checksum = 0;
|
||||
for (int i = 0; i < UHCI_OUT_FRAME_HEAD_LEN + total_length; i++) {
|
||||
checksum += buf[i];
|
||||
}
|
||||
memcpy(buf + UHCI_OUT_FRAME_HEAD_LEN + total_length, &checksum, UHCI_OUT_FRAME_TAIL_LEN);
|
||||
|
||||
trans_cb->length += total_length + UHCI_OUT_FRAME_OVERHEAD;
|
||||
if ((trans_cb->buf_size - trans_cb->length) <= UHCI_OUT_FRAME_OVERHEAD) {
|
||||
trans_cb->flag = TRANS_CB_FLAG_NEED_QUEUE;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
IRAM_ATTR static void uhci_out_log_cb_write_loss(uhci_out_log_cb_t *log_cb)
|
||||
{
|
||||
if (!log_cb->lost_bytes_cnt || !log_cb->lost_frame_cnt) {
|
||||
return;
|
||||
}
|
||||
bool need_append;
|
||||
uint16_t frame_len = sizeof(loss_payload_t) + UHCI_OUT_FRAME_OVERHEAD;
|
||||
if (uhci_out_log_cb_check_trans(log_cb, frame_len, &need_append)) {
|
||||
loss_payload_t payload = {
|
||||
.type = log_cb->type,
|
||||
.lost_frame_cnt = log_cb->lost_frame_cnt,
|
||||
.lost_bytes_cnt = log_cb->lost_bytes_cnt,
|
||||
};
|
||||
uhci_out_log_cb_write(log_cb, (const uint8_t *)&payload, sizeof(loss_payload_t),
|
||||
NULL, 0, BLE_LOG_UHCI_OUT_SOURCE_LOSS, false);
|
||||
|
||||
log_cb->lost_frame_cnt = 0;
|
||||
log_cb->lost_bytes_cnt = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void uhci_out_log_cb_dump(uhci_out_log_cb_t *log_cb)
|
||||
{
|
||||
uhci_out_trans_cb_t *trans_cb;
|
||||
uint8_t *buf;
|
||||
for (uint8_t i = 0; i < 2; i++) {
|
||||
// Dump the last transaction before dumping the current transaction
|
||||
log_cb->trans_cb_idx = !(log_cb->trans_cb_idx);
|
||||
trans_cb = log_cb->trans_cb[log_cb->trans_cb_idx];
|
||||
buf = (uint8_t *)trans_cb->buffer;
|
||||
for (uint16_t j = 0; j < trans_cb->buf_size; j++) {
|
||||
esp_rom_printf("%02x ", buf[j]);
|
||||
|
||||
// Feed watchdogs periodically to avoid wdts timeout
|
||||
if ((j % 100) == 0) {
|
||||
esp_panic_handler_feed_wdts();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void esp_timer_cb_log_flush(void)
|
||||
{
|
||||
uint32_t os_ts = pdTICKS_TO_MS(xTaskGetTickCount());
|
||||
|
||||
if ((os_ts - user_last_write_ts) > UHCI_OUT_FLUSH_TIMEOUT_MS) {
|
||||
xSemaphoreTake(user_log_mutex, portMAX_DELAY);
|
||||
uhci_out_log_cb_flush_trans(user_log_cb);
|
||||
uhci_out_log_cb_append_trans(user_log_cb);
|
||||
xSemaphoreGive(user_log_mutex);
|
||||
}
|
||||
|
||||
if ((esp_bt_controller_get_status() >= ESP_BT_CONTROLLER_STATUS_INITED) &&
|
||||
((os_ts - ll_last_write_ts) > UHCI_OUT_FLUSH_TIMEOUT_MS)) {
|
||||
ll_ev_flags |= BIT(LL_EV_FLAG_FLUSH_LOG);
|
||||
UHCI_OUT_LL_PUT_EV;
|
||||
}
|
||||
|
||||
esp_timer_start_once(flush_timer, UHCI_OUT_FLUSH_TIMEOUT_US);
|
||||
}
|
||||
|
||||
static void uhci_out_user_write_str(const uint8_t *src, uint16_t len)
|
||||
{
|
||||
if (!user_log_inited || !src || !len) {
|
||||
return;
|
||||
}
|
||||
|
||||
xSemaphoreTake(user_log_mutex, portMAX_DELAY);
|
||||
|
||||
bool need_append;
|
||||
if (uhci_out_log_cb_check_trans(user_log_cb, len, &need_append)) {
|
||||
uhci_out_trans_cb_t *trans_cb = user_log_cb->trans_cb[user_log_cb->trans_cb_idx];
|
||||
uint8_t *buf = trans_cb->buffer + trans_cb->length;
|
||||
|
||||
memcpy(buf, (const uint8_t *)src, len);
|
||||
trans_cb->length += len;
|
||||
}
|
||||
|
||||
if (need_append) {
|
||||
uhci_out_log_cb_append_trans(user_log_cb);
|
||||
}
|
||||
|
||||
user_last_write_ts = pdTICKS_TO_MS(xTaskGetTickCount());
|
||||
|
||||
xSemaphoreGive(user_log_mutex);
|
||||
}
|
||||
|
||||
#if UHCI_OUT_UART_PORT == UHCI_OUT_UART_PORT0
|
||||
static void uhci_out_user_write_char(char c)
|
||||
{
|
||||
uhci_out_user_write_str((const uint8_t *)&c, 1);
|
||||
}
|
||||
#endif // UHCI_OUT_UART_PORT == UHCI_OUT_UART_PORT0
|
||||
|
||||
static int uhci_out_user_log_init(void)
|
||||
{
|
||||
if (user_log_inited) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Initialize mutex
|
||||
user_log_mutex = xSemaphoreCreateMutex();
|
||||
if (!user_log_mutex) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
// Initialize log control block
|
||||
if (uhci_out_log_cb_init(&user_log_cb, UHCI_OUT_USER_BUF_SIZE, LOG_CB_TYPE_USER, 0) != 0) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
// Initialization done
|
||||
user_log_inited = true;
|
||||
return 0;
|
||||
|
||||
failed:
|
||||
uhci_out_user_log_deinit();
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void uhci_out_user_log_deinit(void)
|
||||
{
|
||||
user_log_inited = false;
|
||||
|
||||
if (!user_log_mutex) {
|
||||
return;
|
||||
}
|
||||
xSemaphoreTake(user_log_mutex, portMAX_DELAY);
|
||||
|
||||
uhci_out_log_cb_deinit(&user_log_cb);
|
||||
|
||||
xSemaphoreGive(user_log_mutex);
|
||||
vSemaphoreDelete(user_log_mutex);
|
||||
user_log_mutex = NULL;
|
||||
}
|
||||
|
||||
static int uhci_out_ll_log_init(void)
|
||||
{
|
||||
if (ll_log_inited) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (uhci_out_log_cb_init(&ll_task_log_cb, UHCI_OUT_LL_TASK_BUF_SIZE,
|
||||
LOG_CB_TYPE_LL, LOG_CB_LL_SUBTYPE_TASK) != 0) {
|
||||
goto failed;
|
||||
}
|
||||
if (uhci_out_log_cb_init(&ll_isr_log_cb, UHCI_OUT_LL_ISR_BUF_SIZE,
|
||||
LOG_CB_TYPE_LL, LOG_CB_LL_SUBTYPE_ISR) != 0) {
|
||||
goto failed;
|
||||
}
|
||||
if (uhci_out_log_cb_init(&ll_hci_log_cb, UHCI_OUT_LL_HCI_BUF_SIZE,
|
||||
LOG_CB_TYPE_LL, LOG_CB_LL_SUBTYPE_HCI) != 0) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
ll_log_inited = true;
|
||||
return 0;
|
||||
|
||||
failed:
|
||||
uhci_out_ll_log_deinit();
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void uhci_out_ll_log_deinit(void)
|
||||
{
|
||||
ll_log_inited = false;
|
||||
|
||||
uhci_out_log_cb_deinit(&ll_hci_log_cb);
|
||||
uhci_out_log_cb_deinit(&ll_isr_log_cb);
|
||||
uhci_out_log_cb_deinit(&ll_task_log_cb);
|
||||
}
|
||||
|
||||
static void uhci_out_ll_log_flush(void)
|
||||
{
|
||||
if (!ll_log_inited) {
|
||||
return;
|
||||
}
|
||||
|
||||
uhci_out_log_cb_write_loss(ll_task_log_cb);
|
||||
uhci_out_log_cb_write_loss(ll_hci_log_cb);
|
||||
|
||||
uhci_out_log_cb_flush_trans(ll_task_log_cb);
|
||||
uhci_out_log_cb_flush_trans(ll_hci_log_cb);
|
||||
|
||||
portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED;
|
||||
portENTER_CRITICAL_SAFE(&spinlock);
|
||||
uhci_out_log_cb_write_loss(ll_isr_log_cb);
|
||||
uhci_out_log_cb_flush_trans(ll_isr_log_cb);
|
||||
portEXIT_CRITICAL_SAFE(&spinlock);
|
||||
|
||||
uhci_out_log_cb_append_trans(ll_task_log_cb);
|
||||
uhci_out_log_cb_append_trans(ll_hci_log_cb);
|
||||
uhci_out_log_cb_append_trans(ll_isr_log_cb);
|
||||
}
|
||||
|
||||
// Public functions
|
||||
int ble_log_uhci_out_init(void)
|
||||
{
|
||||
// Avoid double init
|
||||
if (uhci_out_inited) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if UHCI_OUT_UART_NEED_INIT
|
||||
uart_config_t uart_config = {
|
||||
.baud_rate = UHCI_OUT_UART_BAUD_RATE,
|
||||
.data_bits = UART_DATA_8_BITS,
|
||||
.parity = UART_PARITY_DISABLE,
|
||||
.stop_bits = UART_STOP_BITS_1,
|
||||
.flow_ctrl = UART_HW_FLOWCTRL_CTS_RTS,
|
||||
.rx_flow_ctrl_thresh = 122,
|
||||
};
|
||||
// Configure UART parameters
|
||||
uart_param_config(UHCI_OUT_UART_PORT, &uart_config);
|
||||
uart_set_pin(UHCI_OUT_UART_PORT, UHCI_OUT_UART_IO_NUM_TX, -1, -1, -1);
|
||||
#endif // UHCI_OUT_UART_NEED_INIT
|
||||
|
||||
uhci_controller_config_t uhci_config = {
|
||||
.uart_port = UHCI_OUT_UART_PORT,
|
||||
.tx_trans_queue_depth = UHCI_OUT_QUEUE_SIZE,
|
||||
.max_receive_internal_mem = 1024,
|
||||
.max_transmit_size = UHCI_OUT_MAX_TRANSFER_SIZE,
|
||||
.dma_burst_size = 32,
|
||||
.rx_eof_flags.idle_eof = 1,
|
||||
};
|
||||
if (uhci_new_controller(&uhci_config, &uhci_handle) != ESP_OK) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
uhci_event_callbacks_t uhci_cbs = {
|
||||
.on_tx_trans_done = uhci_out_tx_done_cb,
|
||||
};
|
||||
uhci_register_event_callbacks(uhci_handle, &uhci_cbs, NULL);
|
||||
|
||||
if (uhci_out_user_log_init() != 0) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if (uhci_out_ll_log_init() != 0) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
esp_timer_create_args_t timer_args = {
|
||||
.callback = (esp_timer_cb_t)esp_timer_cb_log_flush,
|
||||
.dispatch_method = ESP_TIMER_TASK
|
||||
};
|
||||
if (esp_timer_create(&timer_args, &flush_timer) != ESP_OK) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
#if UHCI_OUT_UART_PORT == UHCI_OUT_UART_PORT0
|
||||
// Install UART Driver if not installed
|
||||
if (!uart_is_driver_installed(UHCI_OUT_UART_PORT0)) {
|
||||
uart_driver_install(UHCI_OUT_UART_PORT0, UHCI_OUT_UART_DRIVER_RX_BUF_SIZE, 0, 0, NULL, 0);
|
||||
}
|
||||
|
||||
// Redirect UART VFS Driver to UART Driver
|
||||
uart_vfs_dev_use_driver(UHCI_OUT_UART_PORT0);
|
||||
|
||||
// Redirect esp_rom_printf to BLE Log UHCI Out
|
||||
esp_rom_install_channel_putc(1, uhci_out_user_write_char);
|
||||
esp_rom_install_channel_putc(2, NULL);
|
||||
#endif // UHCI_OUT_UART_PORT == UHCI_OUT_UART_PORT0
|
||||
|
||||
uhci_out_inited = true;
|
||||
esp_timer_start_once(flush_timer, UHCI_OUT_FLUSH_TIMEOUT_US);
|
||||
return 0;
|
||||
|
||||
failed:
|
||||
ble_log_uhci_out_deinit();
|
||||
return -1;
|
||||
}
|
||||
|
||||
void ble_log_uhci_out_deinit(void)
|
||||
{
|
||||
uhci_out_inited = false;
|
||||
|
||||
if (flush_timer) {
|
||||
esp_timer_stop(flush_timer);
|
||||
esp_timer_delete(flush_timer);
|
||||
flush_timer = NULL;
|
||||
}
|
||||
|
||||
if (uhci_handle) {
|
||||
uhci_wait_all_tx_transaction_done(uhci_handle, portMAX_DELAY);
|
||||
uhci_del_controller(uhci_handle);
|
||||
uhci_handle = NULL;
|
||||
}
|
||||
|
||||
uhci_out_ll_log_deinit();
|
||||
uhci_out_user_log_deinit();
|
||||
}
|
||||
|
||||
IRAM_ATTR void ble_log_uhci_out_ll_write(uint32_t len, const uint8_t *addr, uint32_t len_append,
|
||||
const uint8_t *addr_append, uint32_t flag)
|
||||
{
|
||||
// Raw logs will come in case of assert, shall be printed to console directly
|
||||
if (flag & BIT(LL_LOG_FLAG_RAW)) {
|
||||
if (len && addr) {
|
||||
for (uint32_t i = 0; i < len; i++) { esp_rom_printf("%02x ", addr[i]); }
|
||||
}
|
||||
if (len_append && addr_append) {
|
||||
for (uint32_t i = 0; i < len_append; i++) { esp_rom_printf("%02x ", addr_append[i]); }
|
||||
}
|
||||
if (flag & BIT(LL_LOG_FLAG_END)) { esp_rom_printf("\n"); }
|
||||
}
|
||||
|
||||
if (!ll_log_inited) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool in_isr = false;
|
||||
uint8_t source;
|
||||
uhci_out_log_cb_t *log_cb;
|
||||
if (flag & BIT(LL_LOG_FLAG_ISR)) {
|
||||
log_cb = ll_isr_log_cb;
|
||||
source = BLE_LOG_UHCI_OUT_SOURCE_ESP_ISR;
|
||||
in_isr = true;
|
||||
} else if (flag & BIT(LL_LOG_FLAG_HCI)) {
|
||||
log_cb = ll_hci_log_cb;
|
||||
source = BLE_LOG_UHCI_OUT_SOURCE_LL_HCI;
|
||||
} else {
|
||||
log_cb = ll_task_log_cb;
|
||||
source = BLE_LOG_UHCI_OUT_SOURCE_ESP;
|
||||
}
|
||||
bool omdata = flag & BIT(LL_LOG_FLAG_OMDATA);
|
||||
|
||||
bool need_append;
|
||||
uint16_t frame_len = len + len_append + UHCI_OUT_FRAME_OVERHEAD;
|
||||
if (uhci_out_log_cb_check_trans(log_cb, frame_len, &need_append)) {
|
||||
need_append |= uhci_out_log_cb_write(log_cb, addr, len, addr_append,
|
||||
len_append, source, omdata);
|
||||
}
|
||||
|
||||
ll_last_write_ts = in_isr?\
|
||||
pdTICKS_TO_MS(xTaskGetTickCountFromISR()):\
|
||||
pdTICKS_TO_MS(xTaskGetTickCount());
|
||||
|
||||
if (need_append) {
|
||||
if (in_isr) {
|
||||
ll_ev_flags |= BIT(LL_EV_FLAG_ISR_APPEND);
|
||||
UHCI_OUT_LL_PUT_EV;
|
||||
} else {
|
||||
uhci_out_log_cb_append_trans(log_cb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IRAM_ATTR void ble_log_uhci_out_ll_log_ev_proc(void)
|
||||
{
|
||||
if (!ll_log_inited) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ll_ev_flags & BIT(LL_EV_FLAG_ISR_APPEND)) {
|
||||
uhci_out_log_cb_append_trans(ll_isr_log_cb);
|
||||
ll_ev_flags &= ~BIT(LL_EV_FLAG_ISR_APPEND);
|
||||
}
|
||||
|
||||
if (ll_ev_flags & BIT(LL_EV_FLAG_FLUSH_LOG)) {
|
||||
uhci_out_ll_log_flush();
|
||||
ll_ev_flags &= ~BIT(LL_EV_FLAG_FLUSH_LOG);
|
||||
}
|
||||
|
||||
ll_ev_flags = 0;
|
||||
}
|
||||
|
||||
// Redirect UART Driver to BLE Log UHCI Out
|
||||
int __real_uart_tx_chars(uart_port_t uart_num, const char *buffer, uint32_t len);
|
||||
int __wrap_uart_tx_chars(uart_port_t uart_num, const char *buffer, uint32_t len)
|
||||
{
|
||||
#if UHCI_OUT_UART_PORT == UHCI_OUT_UART_PORT0
|
||||
uhci_out_user_write_str((const uint8_t *)buffer, len);
|
||||
return 0;
|
||||
#else
|
||||
return __real_uart_tx_chars(uart_num, buffer, len);
|
||||
#endif // UHCI_OUT_UART_PORT == UHCI_OUT_UART_PORT0
|
||||
}
|
||||
|
||||
int __real_uart_write_bytes(uart_port_t uart_num, const void *src, size_t size);
|
||||
int __wrap_uart_write_bytes(uart_port_t uart_num, const void *src, size_t size)
|
||||
{
|
||||
#if UHCI_OUT_UART_PORT == UHCI_OUT_UART_PORT0
|
||||
uhci_out_user_write_str((const uint8_t *)src, size);
|
||||
return 0;
|
||||
#else
|
||||
return __real_uart_write_bytes(uart_num, src, size);
|
||||
#endif // UHCI_OUT_UART_PORT == UHCI_OUT_UART_PORT0
|
||||
}
|
||||
|
||||
int __real_uart_write_bytes_with_break(uart_port_t uart_num, const void *src, size_t size, int brk_len);
|
||||
int __wrap_uart_write_bytes_with_break(uart_port_t uart_num, const void *src, size_t size, int brk_len)
|
||||
{
|
||||
#if UHCI_OUT_UART_PORT == UHCI_OUT_UART_PORT0
|
||||
return __wrap_uart_write_bytes(uart_num, src, size);
|
||||
#else
|
||||
return __real_uart_write_bytes_with_break(uart_num, src, size, brk_len);
|
||||
#endif // UHCI_OUT_UART_PORT == UHCI_OUT_UART_PORT0
|
||||
}
|
||||
|
||||
void ble_log_uhci_out_dump_all(void)
|
||||
{
|
||||
if (!uhci_out_inited) {
|
||||
return;
|
||||
}
|
||||
|
||||
#if UHCI_OUT_UART_PORT == UHCI_OUT_UART_PORT0
|
||||
esp_rom_output_tx_wait_idle(UHCI_OUT_UART_PORT0);
|
||||
esp_rom_install_uart_printf();
|
||||
#endif // UHCI_OUT_UART_PORT == UHCI_OUT_UART_PORT0
|
||||
|
||||
portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED;
|
||||
portENTER_CRITICAL_SAFE(&spinlock);
|
||||
|
||||
if (ll_log_inited) {
|
||||
esp_rom_printf("[DUMP_START:\n");
|
||||
uhci_out_log_cb_dump(ll_isr_log_cb);
|
||||
uhci_out_log_cb_dump(ll_task_log_cb);
|
||||
uhci_out_log_cb_dump(ll_hci_log_cb);
|
||||
esp_rom_printf("\n:DUMP_END]\n\n");
|
||||
}
|
||||
portEXIT_CRITICAL_SAFE(&spinlock);
|
||||
|
||||
#if UHCI_OUT_UART_PORT == UHCI_OUT_UART_PORT0
|
||||
esp_rom_install_channel_putc(1, uhci_out_user_write_char);
|
||||
#endif // UHCI_OUT_UART_PORT == UHCI_OUT_UART_PORT0
|
||||
}
|
||||
#endif // CONFIG_BT_BLE_LOG_UHCI_OUT_ENABLED
|
||||
@@ -0,0 +1,202 @@
|
||||
|
||||
set(LOG_COMPRESSED_MODULE "")
|
||||
set(LOG_COMPRESSED_MODULE_CODE_PATH "")
|
||||
set(LOG_COMPRESSED_SRCS_DIR "${CMAKE_BINARY_DIR}/ble_log/.compressed_srcs")
|
||||
|
||||
# default config value for ble mesh module
|
||||
set(BLE_MESH_CODE_PATH "")
|
||||
set(BLE_MESH_LOG_INDEX_HEADER "\"\"")
|
||||
set(BLE_MESH_TAGS "")
|
||||
set(BLE_MESH_TAGS_PRESERVE "")
|
||||
|
||||
# default config value for host module
|
||||
set(HOST_CODE_PATH "")
|
||||
set(HOST_LOG_INDEX_HEADER "\"\"")
|
||||
set(BLE_HOST_TAGS "")
|
||||
set(BLE_HOST_TAGS_PRESERVE "")
|
||||
|
||||
if(CONFIG_BLE_MESH_COMPRESSED_LOG_ENABLE)
|
||||
list(APPEND LOG_COMPRESSED_MODULE "BLE_MESH")
|
||||
if(NOT EXISTS "${CMAKE_BINARY_DIR}/ble_log/include/mesh_log_index.h")
|
||||
file(WRITE "${CMAKE_BINARY_DIR}/ble_log/include/mesh_log_index.h" "")
|
||||
endif()
|
||||
list(APPEND LOG_COMPRESSED_MODULE_CODE_PATH "esp_ble_mesh")
|
||||
|
||||
# update config file
|
||||
set(BLE_MESH_CODE_PATH "esp_ble_mesh")
|
||||
set(BLE_MESH_LOG_INDEX_HEADER "mesh_log_index.h")
|
||||
# update BLE_MESH_TAGS and BLE_MESH_TAGS_PRESERVE
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/cmake/ble_mesh_log_tags.cmake)
|
||||
|
||||
endif()
|
||||
if(CONFIG_BLE_HOST_COMPRESSED_LOG_ENABLE AND CONFIG_BT_BLUEDROID_ENABLED)
|
||||
list(APPEND LOG_COMPRESSED_MODULE "BLE_HOST")
|
||||
list(APPEND LOG_COMPRESSED_MODULE_CODE_PATH "host/bluedroid/stack")
|
||||
if(NOT EXISTS "${CMAKE_BINARY_DIR}/ble_log/include/host_log_index.h")
|
||||
file(WRITE "${CMAKE_BINARY_DIR}/ble_log/include/host_log_index.h" "")
|
||||
endif()
|
||||
|
||||
set(HOST_CODE_PATH "host/bluedroid/stack")
|
||||
set(HOST_LOG_INDEX_HEADER "host_log_index.h")
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/cmake/ble_host_bluedroid_tags.cmake)
|
||||
endif()
|
||||
if(LOG_COMPRESSED_MODULE)
|
||||
list(APPEND srcs "common/ble_log/extension/log_compression/ble_log_compression.c")
|
||||
list(APPEND include_dirs "${CMAKE_BINARY_DIR}/ble_log/include")
|
||||
if(NOT CMAKE_VERSION VERSION_LESS 3.15.0)
|
||||
set(Python3_FIND_STRATEGY LOCATION)
|
||||
find_package(Python3 COMPONENTS Interpreter)
|
||||
if(Python3_Interpreter_FOUND)
|
||||
set(BLE_PYTHON_EXECUTABLE ${Python3_EXECUTABLE})
|
||||
endif()
|
||||
else()
|
||||
find_package(PythonInterp 3)
|
||||
if(PYTHONINTERP_FOUND)
|
||||
set(BLE_PYTHON_EXECUTABLE ${PYTHON_EXECUTABLE})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(BLE_PYTHON_EXECUTABLE)
|
||||
set(PYTHON_SCRIPT ${BT_ROOT_PATH}/common/ble_log/extension/log_compression/scripts/ble_log_compress.py)
|
||||
|
||||
set(compressed_srcs "")
|
||||
set(uncompressed_srcs "")
|
||||
set(compressed_srcs_with_abs_path "")
|
||||
|
||||
execute_process(COMMAND ${BLE_PYTHON_EXECUTABLE}
|
||||
${BT_ROOT_PATH}/common/ble_log/extension/log_compression/scripts/env_check.py
|
||||
RESULT_VARIABLE result
|
||||
OUTPUT_VARIABLE out
|
||||
ERROR_VARIABLE err
|
||||
)
|
||||
|
||||
if(NOT ${result} EQUAL 0)
|
||||
message(WARNING "${err}")
|
||||
message(WARNING "Exit this log compression due to failure of environment check")
|
||||
set(LOG_COMPRESS_INCLUDE_DIRS ${include_dirs} PARENT_SCOPE)
|
||||
set(LOG_COMPRESSION_TARGET "" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
set(CONFIG_FILE_PATH "${CMAKE_BINARY_DIR}/ble_log/module_info.yml")
|
||||
if(NOT EXISTS "${CONFIG_FILE_PATH}")
|
||||
file(WRITE "${CMAKE_BINARY_DIR}/ble_log/module_info.yml")
|
||||
endif()
|
||||
set(YML_IN "${BT_ROOT_PATH}/common/ble_log/extension/log_compression/scripts/configs/module_info.yml.in")
|
||||
configure_file(${YML_IN} ${CONFIG_FILE_PATH} @ONLY)
|
||||
|
||||
string(REPLACE ";" "|" MODULE_CODE_PATH "${LOG_COMPRESSED_MODULE_CODE_PATH}")
|
||||
set(MATCH_PATTERN "(${MODULE_CODE_PATH}).+\\.c")
|
||||
foreach(src ${srcs})
|
||||
if(src MATCHES ${MATCH_PATTERN})
|
||||
set(dest "${LOG_COMPRESSED_SRCS_DIR}/${src}")
|
||||
file(WRITE "${dest}" "")
|
||||
list(APPEND compressed_srcs ${src})
|
||||
list(APPEND compressed_srcs_with_abs_path "${dest}")
|
||||
else()
|
||||
list(APPEND uncompressed_srcs ${src})
|
||||
endif()
|
||||
endforeach()
|
||||
string(REPLACE "|" ";" LOG_COMPRESSED_MODULE_CODE_PATH "${MODULE_CODE_PATH}")
|
||||
|
||||
# Some header files of NIMBLE are not added to include_dirs,
|
||||
# but rely on relative path searches. This will cause the header
|
||||
# files to be found due to the change in the source code location
|
||||
# after using the log compression scheme.
|
||||
# Therefore, these paths are added to include_dirs here to avoid
|
||||
# unfinished compilation errors.
|
||||
if(CONFIG_BT_NIMBLE_ENABLED)
|
||||
list(APPEND include_dirs
|
||||
"host/nimble/nimble/nimble/host/src"
|
||||
"host/nimble/nimble/nimble/host/store/config/src")
|
||||
endif()
|
||||
|
||||
add_custom_target(ble_log_compression ALL
|
||||
COMMAND ${BLE_PYTHON_EXECUTABLE} ${PYTHON_SCRIPT}
|
||||
compress
|
||||
--compressed_srcs_path "${LOG_COMPRESSED_SRCS_DIR}"
|
||||
--build_path "${CMAKE_BINARY_DIR}"
|
||||
--module "'${LOG_COMPRESSED_MODULE}'"
|
||||
--bt_path "${BT_ROOT_PATH}"
|
||||
--srcs "'${compressed_srcs}'"
|
||||
DEPENDS ${compressed_srcs_with_abs_path} ${PYTHON_SCRIPT}
|
||||
COMMENT "Log compression is being performed, please wait..."
|
||||
WORKING_DIRECTORY ${BT_ROOT_PATH}
|
||||
USES_TERMINAL
|
||||
)
|
||||
|
||||
function(add_flags_if_in_list file file_list compile_flags)
|
||||
set(PROCESSED OFF PARENT_SCOPE)
|
||||
foreach(item IN LISTS file_list)
|
||||
if(item STREQUAL file)
|
||||
set_source_files_properties("${LOG_COMPRESSED_SRCS_DIR}/${file}"
|
||||
PROPERTIES
|
||||
GENERATED TRUE
|
||||
COMPILE_FLAGS "${compile_flags}"
|
||||
OBJECT_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/ble_log_compression"
|
||||
)
|
||||
set(PROCESSED ON PARENT_SCOPE)
|
||||
break()
|
||||
endif()
|
||||
endforeach()
|
||||
endfunction()
|
||||
|
||||
foreach(src ${compressed_srcs})
|
||||
set(PROCESSED OFF)
|
||||
if(CONFIG_BT_BLUEDROID_ENABLED)
|
||||
set(files_with_compile_flags
|
||||
"host/bluedroid/bta/gatt/bta_gattc_act.c"
|
||||
"host/bluedroid/bta/gatt/bta_gattc_cache.c"
|
||||
"host/bluedroid/btc/profile/std/gatt/btc_gatt_util.c"
|
||||
"host/bluedroid/btc/profile/std/gatt/btc_gatts.c")
|
||||
add_flags_if_in_list("${src}"
|
||||
"${files_with_compile_flags}"
|
||||
"-Wno-address-of-packed-member")
|
||||
|
||||
if(NOT CMAKE_BUILD_EARLY_EXPANSION)
|
||||
set(jump_table_opts "-fjump-tables")
|
||||
if(NOT (CMAKE_C_COMPILER_ID MATCHES "Clang") )
|
||||
set(jump_table_opts "${jump_table_opts} -ftree-switch-conversion")
|
||||
endif()
|
||||
set(files_with_compile_flags
|
||||
"host/bluedroid/bta/hf_ag/bta_ag_cmd.c"
|
||||
"host/bluedroid/btc/profile/std/gap/btc_gap_ble.c"
|
||||
)
|
||||
add_flags_if_in_list("${src}"
|
||||
"${files_with_compile_flags}"
|
||||
"${jump_table_opts}")
|
||||
endif()
|
||||
|
||||
if(CMAKE_C_COMPILER_ID MATCHES "GNU" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER 15.0)
|
||||
set(files_with_compile_flags "host/bluedroid/device/controller.c")
|
||||
add_flags_if_in_list("${src}"
|
||||
"${files_with_compile_flags}"
|
||||
"-Wno-unterminated-string-initialization")
|
||||
endif()
|
||||
endif()
|
||||
if(CONFIG_BT_NIMBLE_ENABLED)
|
||||
if(CONFIG_BT_NIMBLE_MESH)
|
||||
message(ERROR "The current log compression scheme does not support NIMBLE MESH")
|
||||
endif()
|
||||
endif()
|
||||
if(NOT PROCESSED)
|
||||
set_source_files_properties("${LOG_COMPRESSED_SRCS_DIR}/${src}"
|
||||
PROPERTIES GENERATED TRUE
|
||||
OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/ble_log_compression
|
||||
)
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
set(LOG_COMPRESSION_TARGET ble_log_compression PARENT_SCOPE)
|
||||
# set(LOG_COMPRESSION_TARGET "" PARENT_SCOPE)
|
||||
set(LOG_COMPRESS_SRCS "${compressed_srcs_with_abs_path};${uncompressed_srcs}" PARENT_SCOPE)
|
||||
list(APPEND include_dirs "common/ble_log/extension/log_compression/include")
|
||||
set(LOG_COMPRESS_INCLUDE_DIRS ${include_dirs} PARENT_SCOPE)
|
||||
else()
|
||||
set(LOG_COMPRESSION_TARGET "" PARENT_SCOPE)
|
||||
message("Python 3 used for log compressing not found")
|
||||
endif()
|
||||
else()
|
||||
set(LOG_COMPRESSION_TARGET "" PARENT_SCOPE)
|
||||
message(STATUS "No module enabled for log compress")
|
||||
endif()
|
||||
@@ -0,0 +1,692 @@
|
||||
|
||||
config BLE_COMPRESSED_LOG_ENABLE
|
||||
bool "Enable BLE log compression(Preview, Please read help information)"
|
||||
default n
|
||||
help
|
||||
Compress BLE logs during application build to reduce flash usage
|
||||
and improve output speed. When enabled, log data from Bluetooth
|
||||
Low Energy components will be compressed before storage,
|
||||
optimizing both memory footprint and transmission efficiency.
|
||||
|
||||
Note: This library depends on additional Python packages. It will
|
||||
function correctly only after these dependencies are installed;
|
||||
refer to:
|
||||
"components/bt/common/ble_log/log_compression/README.en.md"
|
||||
for installation instructions.
|
||||
|
||||
if BLE_COMPRESSED_LOG_ENABLE
|
||||
menuconfig BLE_MESH_COMPRESSED_LOG_ENABLE
|
||||
bool "Enable BLE Mesh log compression(Preview)"
|
||||
depends on BLE_COMPRESSED_LOG_ENABLE
|
||||
depends on BLE_MESH
|
||||
default n
|
||||
help
|
||||
Apply compression to ESP-BLE-MESH protocol stack logs. Requires
|
||||
base BLE compression to be enabled. Specifically optimizes log
|
||||
storage and transmission for ble mesh.
|
||||
|
||||
Note: This library depends on additional Python packages. It will
|
||||
function correctly only after these dependencies are installed;
|
||||
refer to:
|
||||
"components/bt/common/ble_log/log_compression/README.en.md"
|
||||
for installation instructions.
|
||||
|
||||
If the required packages are not installed, the log-compression
|
||||
mechanism will remain disabled even when this Config is enabled.
|
||||
|
||||
config BLE_MESH_COMPRESSED_LOG_BUFFER_LEN
|
||||
int "BLE Mesh log buffer length"
|
||||
depends on BLE_MESH_COMPRESSED_LOG_ENABLE
|
||||
default 400
|
||||
help
|
||||
Maximum output length for a single log
|
||||
|
||||
if BLE_MESH_COMPRESSED_LOG_ENABLE
|
||||
menu "Select the stack log tag to be compressed"
|
||||
config BLE_MESH_STACK_ERR_LOG_COMPRESSION
|
||||
bool "Compress ERROR log of ESP-BLE-MESH"
|
||||
default y
|
||||
help
|
||||
The error log in the BLE-MESH component will be compressed
|
||||
config BLE_MESH_STACK_ERR_LOG_PRESERVE
|
||||
bool "Keep the original error log statement"
|
||||
depends on BLE_MESH_STACK_ERR_LOG_COMPRESSION
|
||||
default y
|
||||
help
|
||||
When this option is enabled, the log data will be output
|
||||
through both the compressed log interface and the original
|
||||
UART interface at the same time, meaning that the log
|
||||
statements will appear on both paths. However, please note
|
||||
that this dual-output approach introduces additional code
|
||||
and string constants, which will increase the size of the
|
||||
firmware binary file. When this option is disabled, the
|
||||
logs will no longer be printed through the original UART
|
||||
output path; instead, they will only be output through the
|
||||
compressed log interface. As the code and strings related
|
||||
to the original UART output are omitted, the size of the
|
||||
firmware binary file can be effectively reduced.
|
||||
|
||||
config BLE_MESH_STACK_WARN_LOG_COMPRESSION
|
||||
bool "Compress warn log of ESP-BLE-MESH"
|
||||
default y
|
||||
help
|
||||
The warn log in the BLE-MESH component will be compressed
|
||||
config BLE_MESH_STACK_WARN_LOG_PRESERVE
|
||||
bool "Keep the original warn log statement"
|
||||
depends on BLE_MESH_STACK_WARN_LOG_COMPRESSION
|
||||
default y
|
||||
help
|
||||
Please refer to the help information in BLE_MESH_STACK_ERR_LOG_PRESERVE
|
||||
config BLE_MESH_STACK_INFO_LOG_COMPRESSION
|
||||
bool "Compress info log of ESP-BLE-MESH"
|
||||
default y
|
||||
help
|
||||
The info log in the BLE-MESH component will be compressed
|
||||
config BLE_MESH_STACK_INFO_LOG_PRESERVE
|
||||
bool "Keep the original info log statement"
|
||||
depends on BLE_MESH_STACK_INFO_LOG_COMPRESSION
|
||||
default n
|
||||
help
|
||||
Please refer to the help information in BLE_MESH_STACK_ERR_LOG_PRESERVE
|
||||
config BLE_MESH_STACK_DEBUG_LOG_COMPRESSION
|
||||
bool "Compress debug log of ESP-BLE-MESH"
|
||||
default y
|
||||
help
|
||||
The debug log in the BLE-MESH component will be compressed
|
||||
config BLE_MESH_STACK_DEBUG_LOG_PRESERVE
|
||||
bool "Keep the original debug log statement"
|
||||
depends on BLE_MESH_STACK_DEBUG_LOG_COMPRESSION
|
||||
default n
|
||||
help
|
||||
Please refer to the help information in BLE_MESH_STACK_ERR_LOG_PRESERVE
|
||||
endmenu
|
||||
menu "Select the net buf log tag to be compressed"
|
||||
config BLE_MESH_NET_BUF_ERR_LOG_COMPRESSION
|
||||
bool "Compress ERROR log of ESP-BLE-MESH"
|
||||
default y
|
||||
help
|
||||
The error log in the BLE-MESH component will be compressed
|
||||
config BLE_MESH_NET_BUF_ERR_LOG_PRESERVE
|
||||
bool "Keep the original error log statement"
|
||||
depends on BLE_MESH_NET_BUF_ERR_LOG_COMPRESSION
|
||||
default y
|
||||
help
|
||||
When this option is enabled, the log data will be output
|
||||
through both the compressed log interface and the original
|
||||
UART interface at the same time, meaning that the log
|
||||
statements will appear on both paths. However, please note
|
||||
that this dual-output approach introduces additional code
|
||||
and string constants, which will increase the size of the
|
||||
firmware binary file. When this option is disabled, the
|
||||
logs will no longer be printed through the original UART
|
||||
output path; instead, they will only be output through the
|
||||
compressed log interface. As the code and strings related
|
||||
to the original UART output are omitted, the size of the
|
||||
firmware binary file can be effectively reduced.
|
||||
config BLE_MESH_NET_BUF_WARN_LOG_COMPRESSION
|
||||
bool "Compress warn log of ESP-BLE-MESH"
|
||||
default y
|
||||
help
|
||||
The warn log in the BLE-MESH component will be compressed
|
||||
config BLE_MESH_NET_BUF_WARN_LOG_PRESERVE
|
||||
bool "Keep the original warn log statement"
|
||||
depends on BLE_MESH_NET_BUF_WARN_LOG_COMPRESSION
|
||||
default y
|
||||
help
|
||||
Please refer to the help information in BLE_MESH_NET_BUF_ERR_LOG_PRESERVE
|
||||
config BLE_MESH_NET_BUF_INFO_LOG_COMPRESSION
|
||||
bool "Compress info log of ESP-BLE-MESH"
|
||||
default y
|
||||
help
|
||||
The info log in the BLE-MESH component will be compressed
|
||||
config BLE_MESH_NET_BUF_INFO_LOG_PRESERVE
|
||||
bool "Keep the original info log statement"
|
||||
depends on BLE_MESH_NET_BUF_INFO_LOG_COMPRESSION
|
||||
default n
|
||||
help
|
||||
Please refer to the help information in BLE_MESH_NET_BUF_ERR_LOG_PRESERVE
|
||||
config BLE_MESH_NET_BUF_DEBUG_LOG_COMPRESSION
|
||||
bool "Compress debug log of ESP-BLE-MESH"
|
||||
default y
|
||||
help
|
||||
The debug log in the BLE-MESH component will be compressed
|
||||
config BLE_MESH_NET_BUF_DEBUG_LOG_PRESERVE
|
||||
bool "Keep the original debug log statement"
|
||||
depends on BLE_MESH_NET_BUF_DEBUG_LOG_COMPRESSION
|
||||
default n
|
||||
help
|
||||
Please refer to the help information in BLE_MESH_NET_BUF_ERR_LOG_PRESERVE
|
||||
endmenu
|
||||
endif
|
||||
|
||||
menuconfig BLE_HOST_COMPRESSED_LOG_ENABLE
|
||||
bool "Enable BLE Host log compression(Preview, only Bluedroid Host for now)"
|
||||
depends on BLE_COMPRESSED_LOG_ENABLE
|
||||
depends on BT_BLUEDROID_ENABLED
|
||||
default n
|
||||
help
|
||||
Apply compression to host logs. Requires
|
||||
base BLE compression to be enabled. Specifically optimizes log
|
||||
storage and transmission.
|
||||
|
||||
Note: This library depends on additional Python packages. It will
|
||||
function correctly only after these dependencies are installed;
|
||||
refer to:
|
||||
"components/bt/common/ble_log/log_compression/README.en.md"
|
||||
for installation instructions.
|
||||
|
||||
config BLE_HOST_COMPRESSED_LOG_BUFFER_LEN
|
||||
int "Host log buffer length"
|
||||
depends on BLE_HOST_COMPRESSED_LOG_ENABLE
|
||||
default 300
|
||||
help
|
||||
Maximum output length for a single log
|
||||
|
||||
if BLE_HOST_COMPRESSED_LOG_ENABLE
|
||||
menu "Select the BTM layer log tag to be compressed"
|
||||
config BLE_BLUEDROID_BTM_ERROR_LOG_COMPRESSION
|
||||
bool "Compress error log of Bluedroid host"
|
||||
default y
|
||||
help
|
||||
The error log in the Bluedroid host component will be compressed
|
||||
config BLE_BLUEDROID_BTM_ERROR_LOG_PRESERVE
|
||||
bool "Keep the original error log statement"
|
||||
depends on BLE_BLUEDROID_BTM_ERROR_LOG_COMPRESSION
|
||||
default y
|
||||
help
|
||||
When this option is enabled, the log data will be output
|
||||
through both the compressed log interface and the original
|
||||
UART interface at the same time, meaning that the log
|
||||
statements will appear on both paths. However, please note
|
||||
that this dual-output approach introduces additional code
|
||||
and string constants, which will increase the size of the
|
||||
firmware binary file. When this option is disabled, the
|
||||
logs will no longer be printed through the original UART
|
||||
output path; instead, they will only be output through the
|
||||
compressed log interface. As the code and strings related
|
||||
to the original UART output are omitted, the size of the
|
||||
firmware binary file can be effectively reduced.
|
||||
|
||||
config BLE_BLUEDROID_BTM_WARNING_LOG_COMPRESSION
|
||||
bool "Compress warning log of Bluedroid host"
|
||||
default y
|
||||
help
|
||||
The warning log in the Bluedroid host component will be compressed
|
||||
config BLE_BLUEDROID_BTM_WARNING_LOG_PRESERVE
|
||||
bool "Keep the original warning log statement"
|
||||
depends on BLE_BLUEDROID_BTM_WARNING_LOG_COMPRESSION
|
||||
default y
|
||||
help
|
||||
Please refer to the help information in BLE_BLUEDROID_BTM_ERROR_LOG_PRESERVE
|
||||
|
||||
config BLE_BLUEDROID_BTM_API_LOG_COMPRESSION
|
||||
bool "Compress api log of Bluedroid host"
|
||||
default y
|
||||
help
|
||||
The api log in the Bluedroid host component will be compressed
|
||||
config BLE_BLUEDROID_BTM_API_LOG_PRESERVE
|
||||
bool "Keep the original api log statement"
|
||||
depends on BLE_BLUEDROID_BTM_API_LOG_COMPRESSION
|
||||
default n
|
||||
help
|
||||
Please refer to the help information in BLE_BLUEDROID_BTM_ERROR_LOG_PRESERVE
|
||||
|
||||
config BLE_BLUEDROID_BTM_EVENT_LOG_COMPRESSION
|
||||
bool "Compress event log of Bluedroid host"
|
||||
default y
|
||||
help
|
||||
The event log in the Bluedroid host component will be compressed
|
||||
config BLE_BLUEDROID_BTM_EVENT_LOG_PRESERVE
|
||||
bool "Keep the original event log statement"
|
||||
depends on BLE_BLUEDROID_BTM_EVENT_LOG_COMPRESSION
|
||||
default n
|
||||
help
|
||||
Please refer to the help information in BLE_BLUEDROID_BTM_ERROR_LOG_PRESERVE
|
||||
|
||||
config BLE_BLUEDROID_BTM_DEBUG_LOG_COMPRESSION
|
||||
bool "Compress debug log of Bluedroid host"
|
||||
default y
|
||||
help
|
||||
The debug log in the Bluedroid host component will be compressed
|
||||
config BLE_BLUEDROID_BTM_DEBUG_LOG_PRESERVE
|
||||
bool "Keep the original debug log statement"
|
||||
depends on BLE_BLUEDROID_BTM_DEBUG_LOG_COMPRESSION
|
||||
default n
|
||||
help
|
||||
Please refer to the help information in BLE_BLUEDROID_BTM_ERROR_LOG_PRESERVE
|
||||
|
||||
config BLE_BLUEDROID_BTM_VERBOSE_LOG_COMPRESSION
|
||||
bool "Compress verbose log of Bluedroid host"
|
||||
default y
|
||||
help
|
||||
The verbose log in the Bluedroid host component will be compressed
|
||||
config BLE_BLUEDROID_BTM_VERBOSE_LOG_PRESERVE
|
||||
bool "Keep the original verbose log statement"
|
||||
depends on BLE_BLUEDROID_BTM_VERBOSE_LOG_COMPRESSION
|
||||
default n
|
||||
help
|
||||
Please refer to the help information in BLE_BLUEDROID_BTM_ERROR_LOG_PRESERVE
|
||||
|
||||
endmenu
|
||||
menu "Select the LA2CAP layer log tag to be compressed"
|
||||
config BLE_BLUEDROID_L2CAP_ERROR_LOG_COMPRESSION
|
||||
bool "Compress error log of Bluedroid host"
|
||||
default y
|
||||
help
|
||||
The error log in the Bluedroid host component will be compressed
|
||||
config BLE_BLUEDROID_L2CAP_ERROR_LOG_PRESERVE
|
||||
bool "Keep the original error log statement"
|
||||
depends on BLE_BLUEDROID_L2CAP_ERROR_LOG_COMPRESSION
|
||||
default y
|
||||
help
|
||||
When this option is enabled, the log data will be output
|
||||
through both the compressed log interface and the original
|
||||
UART interface at the same time, meaning that the log
|
||||
statements will appear on both paths. However, please note
|
||||
that this dual-output approach introduces additional code
|
||||
and string constants, which will increase the size of the
|
||||
firmware binary file. When this option is disabled, the
|
||||
logs will no longer be printed through the original UART
|
||||
output path; instead, they will only be output through the
|
||||
compressed log interface. As the code and strings related
|
||||
to the original UART output are omitted, the size of the
|
||||
firmware binary file can be effectively reduced.
|
||||
|
||||
config BLE_BLUEDROID_L2CAP_WARNING_LOG_COMPRESSION
|
||||
bool "Compress warning log of Bluedroid host"
|
||||
default y
|
||||
help
|
||||
The warning log in the Bluedroid host component will be compressed
|
||||
config BLE_BLUEDROID_L2CAP_WARNING_LOG_PRESERVE
|
||||
bool "Keep the original warning log statement"
|
||||
depends on BLE_BLUEDROID_L2CAP_WARNING_LOG_COMPRESSION
|
||||
default y
|
||||
help
|
||||
Please refer to the help information in BLE_BLUEDROID_L2CAP_ERROR_LOG_PRESERVE
|
||||
|
||||
config BLE_BLUEDROID_L2CAP_API_LOG_COMPRESSION
|
||||
bool "Compress api log of Bluedroid host"
|
||||
default y
|
||||
help
|
||||
The api log in the Bluedroid host component will be compressed
|
||||
config BLE_BLUEDROID_L2CAP_API_LOG_PRESERVE
|
||||
bool "Keep the original api log statement"
|
||||
depends on BLE_BLUEDROID_L2CAP_API_LOG_COMPRESSION
|
||||
default n
|
||||
help
|
||||
Please refer to the help information in BLE_BLUEDROID_L2CAP_ERROR_LOG_PRESERVE
|
||||
|
||||
config BLE_BLUEDROID_L2CAP_EVENT_LOG_COMPRESSION
|
||||
bool "Compress event log of Bluedroid host"
|
||||
default y
|
||||
help
|
||||
The event log in the Bluedroid host component will be compressed
|
||||
config BLE_BLUEDROID_L2CAP_EVENT_LOG_PRESERVE
|
||||
bool "Keep the original event log statement"
|
||||
depends on BLE_BLUEDROID_L2CAP_EVENT_LOG_COMPRESSION
|
||||
default n
|
||||
help
|
||||
Please refer to the help information in BLE_BLUEDROID_L2CAP_ERROR_LOG_PRESERVE
|
||||
|
||||
config BLE_BLUEDROID_L2CAP_DEBUG_LOG_COMPRESSION
|
||||
bool "Compress debug log of Bluedroid host"
|
||||
default y
|
||||
help
|
||||
The debug log in the Bluedroid host component will be compressed
|
||||
config BLE_BLUEDROID_L2CAP_DEBUG_LOG_PRESERVE
|
||||
bool "Keep the original debug log statement"
|
||||
depends on BLE_BLUEDROID_L2CAP_DEBUG_LOG_COMPRESSION
|
||||
default n
|
||||
help
|
||||
Please refer to the help information in BLE_BLUEDROID_L2CAP_ERROR_LOG_PRESERVE
|
||||
|
||||
config BLE_BLUEDROID_L2CAP_VERBOSE_LOG_COMPRESSION
|
||||
bool "Compress verbose log of Bluedroid host"
|
||||
default y
|
||||
help
|
||||
The verbose log in the Bluedroid host component will be compressed
|
||||
config BLE_BLUEDROID_L2CAP_VERBOSE_LOG_PRESERVE
|
||||
bool "Keep the original verbose log statement"
|
||||
depends on BLE_BLUEDROID_L2CAP_VERBOSE_LOG_COMPRESSION
|
||||
default n
|
||||
help
|
||||
Please refer to the help information in BLE_BLUEDROID_L2CAP_ERROR_LOG_PRESERVE
|
||||
endmenu
|
||||
menu "Select the GAP layer log tag to be compressed"
|
||||
config BLE_BLUEDROID_GAP_ERROR_LOG_COMPRESSION
|
||||
bool "Compress error log of Bluedroid host"
|
||||
default y
|
||||
help
|
||||
The error log in the Bluedroid host component will be compressed
|
||||
config BLE_BLUEDROID_GAP_ERROR_LOG_PRESERVE
|
||||
bool "Keep the original error log statement"
|
||||
depends on BLE_BLUEDROID_GAP_ERROR_LOG_COMPRESSION
|
||||
default y
|
||||
help
|
||||
When this option is enabled, the log data will be output
|
||||
through both the compressed log interface and the original
|
||||
UART interface at the same time, meaning that the log
|
||||
statements will appear on both paths. However, please note
|
||||
that this dual-output approach introduces additional code
|
||||
and string constants, which will increase the size of the
|
||||
firmware binary file. When this option is disabled, the
|
||||
logs will no longer be printed through the original UART
|
||||
output path; instead, they will only be output through the
|
||||
compressed log interface. As the code and strings related
|
||||
to the original UART output are omitted, the size of the
|
||||
firmware binary file can be effectively reduced.
|
||||
|
||||
config BLE_BLUEDROID_GAP_WARNING_LOG_COMPRESSION
|
||||
bool "Compress warning log of Bluedroid host"
|
||||
default y
|
||||
help
|
||||
The warning log in the Bluedroid host component will be compressed
|
||||
config BLE_BLUEDROID_GAP_WARNING_LOG_PRESERVE
|
||||
bool "Keep the original warning log statement"
|
||||
depends on BLE_BLUEDROID_GAP_WARNING_LOG_COMPRESSION
|
||||
default y
|
||||
help
|
||||
Please refer to the help information in BLE_BLUEDROID_GAP_ERROR_LOG_PRESERVE
|
||||
|
||||
config BLE_BLUEDROID_GAP_API_LOG_COMPRESSION
|
||||
bool "Compress api log of Bluedroid host"
|
||||
default y
|
||||
help
|
||||
The api log in the Bluedroid host component will be compressed
|
||||
config BLE_BLUEDROID_GAP_API_LOG_PRESERVE
|
||||
bool "Keep the original api log statement"
|
||||
depends on BLE_BLUEDROID_GAP_API_LOG_COMPRESSION
|
||||
default n
|
||||
help
|
||||
Please refer to the help information in BLE_BLUEDROID_GAP_ERROR_LOG_PRESERVE
|
||||
|
||||
config BLE_BLUEDROID_GAP_EVENT_LOG_COMPRESSION
|
||||
bool "Compress event log of Bluedroid host"
|
||||
default y
|
||||
help
|
||||
The event log in the Bluedroid host component will be compressed
|
||||
config BLE_BLUEDROID_GAP_EVENT_LOG_PRESERVE
|
||||
bool "Keep the original event log statement"
|
||||
depends on BLE_BLUEDROID_GAP_EVENT_LOG_COMPRESSION
|
||||
default n
|
||||
help
|
||||
Please refer to the help information in BLE_BLUEDROID_GAP_ERROR_LOG_PRESERVE
|
||||
|
||||
config BLE_BLUEDROID_GAP_DEBUG_LOG_COMPRESSION
|
||||
bool "Compress debug log of Bluedroid host"
|
||||
default y
|
||||
help
|
||||
The debug log in the Bluedroid host component will be compressed
|
||||
config BLE_BLUEDROID_GAP_DEBUG_LOG_PRESERVE
|
||||
bool "Keep the original debug log statement"
|
||||
depends on BLE_BLUEDROID_GAP_DEBUG_LOG_COMPRESSION
|
||||
default n
|
||||
help
|
||||
Please refer to the help information in BLE_BLUEDROID_GAP_ERROR_LOG_PRESERVE
|
||||
|
||||
config BLE_BLUEDROID_GAP_VERBOSE_LOG_COMPRESSION
|
||||
bool "Compress verbose log of Bluedroid host"
|
||||
default y
|
||||
help
|
||||
The verbose log in the Bluedroid host component will be compressed
|
||||
config BLE_BLUEDROID_GAP_VERBOSE_LOG_PRESERVE
|
||||
bool "Keep the original verbose log statement"
|
||||
depends on BLE_BLUEDROID_GAP_VERBOSE_LOG_COMPRESSION
|
||||
default n
|
||||
help
|
||||
Please refer to the help information in BLE_BLUEDROID_GAP_ERROR_LOG_PRESERVE
|
||||
endmenu
|
||||
menu "Select the GATT layer log tag to be compressed"
|
||||
config BLE_BLUEDROID_GATT_ERROR_LOG_COMPRESSION
|
||||
bool "Compress error log of Bluedroid host"
|
||||
default y
|
||||
help
|
||||
The error log in the Bluedroid host component will be compressed
|
||||
config BLE_BLUEDROID_GATT_ERROR_LOG_PRESERVE
|
||||
bool "Keep the original error log statement"
|
||||
depends on BLE_BLUEDROID_GATT_ERROR_LOG_COMPRESSION
|
||||
default y
|
||||
help
|
||||
When this option is enabled, the log data will be output
|
||||
through both the compressed log interface and the original
|
||||
UART interface at the same time, meaning that the log
|
||||
statements will appear on both paths. However, please note
|
||||
that this dual-output approach introduces additional code
|
||||
and string constants, which will increase the size of the
|
||||
firmware binary file. When this option is disabled, the
|
||||
logs will no longer be printed through the original UART
|
||||
output path; instead, they will only be output through the
|
||||
compressed log interface. As the code and strings related
|
||||
to the original UART output are omitted, the size of the
|
||||
firmware binary file can be effectively reduced.
|
||||
|
||||
config BLE_BLUEDROID_GATT_WARNING_LOG_COMPRESSION
|
||||
bool "Compress warning log of Bluedroid host"
|
||||
default y
|
||||
help
|
||||
The warning log in the Bluedroid host component will be compressed
|
||||
config BLE_BLUEDROID_GATT_WARNING_LOG_PRESERVE
|
||||
bool "Keep the original warning log statement"
|
||||
depends on BLE_BLUEDROID_GATT_WARNING_LOG_COMPRESSION
|
||||
default y
|
||||
help
|
||||
Please refer to the help information in BLE_BLUEDROID_GATT_ERROR_LOG_PRESERVE
|
||||
|
||||
config BLE_BLUEDROID_GATT_API_LOG_COMPRESSION
|
||||
bool "Compress api log of Bluedroid host"
|
||||
default y
|
||||
help
|
||||
The api log in the Bluedroid host component will be compressed
|
||||
config BLE_BLUEDROID_GATT_API_LOG_PRESERVE
|
||||
bool "Keep the original api log statement"
|
||||
depends on BLE_BLUEDROID_GATT_API_LOG_COMPRESSION
|
||||
default n
|
||||
help
|
||||
Please refer to the help information in BLE_BLUEDROID_GATT_ERROR_LOG_PRESERVE
|
||||
|
||||
config BLE_BLUEDROID_GATT_EVENT_LOG_COMPRESSION
|
||||
bool "Compress event log of Bluedroid host"
|
||||
default y
|
||||
help
|
||||
The event log in the Bluedroid host component will be compressed
|
||||
config BLE_BLUEDROID_GATT_EVENT_LOG_PRESERVE
|
||||
bool "Keep the original event log statement"
|
||||
depends on BLE_BLUEDROID_GATT_EVENT_LOG_COMPRESSION
|
||||
default n
|
||||
help
|
||||
Please refer to the help information in BLE_BLUEDROID_GATT_ERROR_LOG_PRESERVE
|
||||
|
||||
config BLE_BLUEDROID_GATT_DEBUG_LOG_COMPRESSION
|
||||
bool "Compress debug log of Bluedroid host"
|
||||
default y
|
||||
help
|
||||
The debug log in the Bluedroid host component will be compressed
|
||||
config BLE_BLUEDROID_GATT_DEBUG_LOG_PRESERVE
|
||||
bool "Keep the original debug log statement"
|
||||
depends on BLE_BLUEDROID_GATT_DEBUG_LOG_COMPRESSION
|
||||
default n
|
||||
help
|
||||
Please refer to the help information in BLE_BLUEDROID_GATT_ERROR_LOG_PRESERVE
|
||||
|
||||
config BLE_BLUEDROID_GATT_VERBOSE_LOG_COMPRESSION
|
||||
bool "Compress verbose log of Bluedroid host"
|
||||
default y
|
||||
help
|
||||
The verbose log in the Bluedroid host component will be compressed
|
||||
config BLE_BLUEDROID_GATT_VERBOSE_LOG_PRESERVE
|
||||
bool "Keep the original verbose log statement"
|
||||
depends on BLE_BLUEDROID_GATT_VERBOSE_LOG_COMPRESSION
|
||||
default n
|
||||
help
|
||||
Please refer to the help information in BLE_BLUEDROID_GATT_ERROR_LOG_PRESERVE
|
||||
endmenu
|
||||
menu "Select the SMP layer log tag to be compressed"
|
||||
config BLE_BLUEDROID_SMP_ERROR_LOG_COMPRESSION
|
||||
bool "Compress error log of Bluedroid host"
|
||||
default y
|
||||
help
|
||||
The error log in the Bluedroid host component will be compressed
|
||||
config BLE_BLUEDROID_SMP_ERROR_LOG_PRESERVE
|
||||
bool "Keep the original error log statement"
|
||||
depends on BLE_BLUEDROID_SMP_ERROR_LOG_COMPRESSION
|
||||
default y
|
||||
help
|
||||
When this option is enabled, the log data will be output
|
||||
through both the compressed log interface and the original
|
||||
UART interface at the same time, meaning that the log
|
||||
statements will appear on both paths. However, please note
|
||||
that this dual-output approach introduces additional code
|
||||
and string constants, which will increase the size of the
|
||||
firmware binary file. When this option is disabled, the
|
||||
logs will no longer be printed through the original UART
|
||||
output path; instead, they will only be output through the
|
||||
compressed log interface. As the code and strings related
|
||||
to the original UART output are omitted, the size of the
|
||||
firmware binary file can be effectively reduced.
|
||||
|
||||
config BLE_BLUEDROID_SMP_WARNING_LOG_COMPRESSION
|
||||
bool "Compress warning log of Bluedroid host"
|
||||
default y
|
||||
help
|
||||
The warning log in the Bluedroid host component will be compressed
|
||||
config BLE_BLUEDROID_SMP_WARNING_LOG_PRESERVE
|
||||
bool "Keep the original warning log statement"
|
||||
depends on BLE_BLUEDROID_SMP_WARNING_LOG_COMPRESSION
|
||||
default y
|
||||
help
|
||||
Please refer to the help information in BLE_BLUEDROID_SMP_ERROR_LOG_PRESERVE
|
||||
|
||||
config BLE_BLUEDROID_SMP_API_LOG_COMPRESSION
|
||||
bool "Compress api log of Bluedroid host"
|
||||
default y
|
||||
help
|
||||
The api log in the Bluedroid host component will be compressed
|
||||
config BLE_BLUEDROID_SMP_API_LOG_PRESERVE
|
||||
bool "Keep the original api log statement"
|
||||
depends on BLE_BLUEDROID_SMP_API_LOG_COMPRESSION
|
||||
default n
|
||||
help
|
||||
Please refer to the help information in BLE_BLUEDROID_SMP_ERROR_LOG_PRESERVE
|
||||
|
||||
config BLE_BLUEDROID_SMP_EVENT_LOG_COMPRESSION
|
||||
bool "Compress event log of Bluedroid host"
|
||||
default y
|
||||
help
|
||||
The event log in the Bluedroid host component will be compressed
|
||||
config BLE_BLUEDROID_SMP_EVENT_LOG_PRESERVE
|
||||
bool "Keep the original event log statement"
|
||||
depends on BLE_BLUEDROID_SMP_EVENT_LOG_COMPRESSION
|
||||
default n
|
||||
help
|
||||
Please refer to the help information in BLE_BLUEDROID_SMP_ERROR_LOG_PRESERVE
|
||||
|
||||
config BLE_BLUEDROID_SMP_DEBUG_LOG_COMPRESSION
|
||||
bool "Compress debug log of Bluedroid host"
|
||||
default y
|
||||
help
|
||||
The debug log in the Bluedroid host component will be compressed
|
||||
config BLE_BLUEDROID_SMP_DEBUG_LOG_PRESERVE
|
||||
bool "Keep the original debug log statement"
|
||||
depends on BLE_BLUEDROID_SMP_DEBUG_LOG_COMPRESSION
|
||||
default n
|
||||
help
|
||||
Please refer to the help information in BLE_BLUEDROID_SMP_ERROR_LOG_PRESERVE
|
||||
|
||||
config BLE_BLUEDROID_SMP_VERBOSE_LOG_COMPRESSION
|
||||
bool "Compress verbose log of Bluedroid host"
|
||||
default y
|
||||
help
|
||||
The verbose log in the Bluedroid host component will be compressed
|
||||
config BLE_BLUEDROID_SMP_VERBOSE_LOG_PRESERVE
|
||||
bool "Keep the original verbose log statement"
|
||||
depends on BLE_BLUEDROID_SMP_VERBOSE_LOG_COMPRESSION
|
||||
default n
|
||||
help
|
||||
Please refer to the help information in BLE_BLUEDROID_SMP_ERROR_LOG_PRESERVE
|
||||
endmenu
|
||||
menu "Select the APPL layer log tag to be compressed"
|
||||
config BLE_BLUEDROID_APPL_ERROR_LOG_COMPRESSION
|
||||
bool "Compress error log of Bluedroid host"
|
||||
default y
|
||||
help
|
||||
The error log in the Bluedroid host component will be compressed
|
||||
config BLE_BLUEDROID_APPL_ERROR_LOG_PRESERVE
|
||||
bool "Keep the original error log statement"
|
||||
depends on BLE_BLUEDROID_APPL_ERROR_LOG_COMPRESSION
|
||||
default y
|
||||
help
|
||||
When this option is enabled, the log data will be output
|
||||
through both the compressed log interface and the original
|
||||
UART interface at the same time, meaning that the log
|
||||
statements will appear on both paths. However, please note
|
||||
that this dual-output approach introduces additional code
|
||||
and string constants, which will increase the size of the
|
||||
firmware binary file. When this option is disabled, the
|
||||
logs will no longer be printed through the original UART
|
||||
output path; instead, they will only be output through the
|
||||
compressed log interface. As the code and strings related
|
||||
to the original UART output are omitted, the size of the
|
||||
firmware binary file can be effectively reduced.
|
||||
|
||||
config BLE_BLUEDROID_APPL_WARNING_LOG_COMPRESSION
|
||||
bool "Compress warning log of Bluedroid host"
|
||||
default y
|
||||
help
|
||||
The warning log in the Bluedroid host component will be compressed
|
||||
config BLE_BLUEDROID_APPL_WARNING_LOG_PRESERVE
|
||||
bool "Keep the original warning log statement"
|
||||
depends on BLE_BLUEDROID_APPL_WARNING_LOG_COMPRESSION
|
||||
default y
|
||||
help
|
||||
Please refer to the help information in BLE_BLUEDROID_APPL_ERROR_LOG_PRESERVE
|
||||
|
||||
config BLE_BLUEDROID_APPL_API_LOG_COMPRESSION
|
||||
bool "Compress api log of Bluedroid host"
|
||||
default y
|
||||
help
|
||||
The api log in the Bluedroid host component will be compressed
|
||||
config BLE_BLUEDROID_APPL_API_LOG_PRESERVE
|
||||
bool "Keep the original api log statement"
|
||||
depends on BLE_BLUEDROID_APPL_API_LOG_COMPRESSION
|
||||
default n
|
||||
help
|
||||
Please refer to the help information in BLE_BLUEDROID_APPL_ERROR_LOG_PRESERVE
|
||||
|
||||
config BLE_BLUEDROID_APPL_EVENT_LOG_COMPRESSION
|
||||
bool "Compress event log of Bluedroid host"
|
||||
default y
|
||||
help
|
||||
The event log in the Bluedroid host component will be compressed
|
||||
config BLE_BLUEDROID_APPL_EVENT_LOG_PRESERVE
|
||||
bool "Keep the original event log statement"
|
||||
depends on BLE_BLUEDROID_APPL_EVENT_LOG_COMPRESSION
|
||||
default n
|
||||
help
|
||||
Please refer to the help information in BLE_BLUEDROID_APPL_ERROR_LOG_PRESERVE
|
||||
|
||||
config BLE_BLUEDROID_APPL_DEBUG_LOG_COMPRESSION
|
||||
bool "Compress debug log of Bluedroid host"
|
||||
default y
|
||||
help
|
||||
The debug log in the Bluedroid host component will be compressed
|
||||
config BLE_BLUEDROID_APPL_DEBUG_LOG_PRESERVE
|
||||
bool "Keep the original debug log statement"
|
||||
depends on BLE_BLUEDROID_APPL_DEBUG_LOG_COMPRESSION
|
||||
default n
|
||||
help
|
||||
Please refer to the help information in BLE_BLUEDROID_APPL_ERROR_LOG_PRESERVE
|
||||
|
||||
config BLE_BLUEDROID_APPL_VERBOSE_LOG_COMPRESSION
|
||||
bool "Compress verbose log of Bluedroid host"
|
||||
default y
|
||||
help
|
||||
The verbose log in the Bluedroid host component will be compressed
|
||||
config BLE_BLUEDROID_APPL_VERBOSE_LOG_PRESERVE
|
||||
bool "Keep the original verbose log statement"
|
||||
depends on BLE_BLUEDROID_APPL_VERBOSE_LOG_COMPRESSION
|
||||
default n
|
||||
help
|
||||
Please refer to the help information in BLE_BLUEDROID_APPL_ERROR_LOG_PRESERVE
|
||||
endmenu
|
||||
endif
|
||||
endif
|
||||
@@ -0,0 +1,111 @@
|
||||
## BLE 日志压缩方案 (Preview)
|
||||
|
||||
### 一、概述
|
||||
|
||||
本方案通过在编译阶段扫描 BLE 协议栈相关组件的代码,将日志语句中的格式化字符串和参数转换为纯二进制数据,从而提升日志输出效率并减少协议栈所占用的 Flash 空间。
|
||||
|
||||
目前,该方案已支持对 BLE-MESH 和 BLE-HOST-BLUEDROID 组件的日志压缩。
|
||||
|
||||
### 二、使用方法
|
||||
该功能依赖额外的 Python 库,请按以下步骤安装所需环境。
|
||||
|
||||
#### 步骤一:验证 ESP-IDF 虚拟环境
|
||||
请确保在 ESP-IDF 的 Python 虚拟环境中执行后续操作。可通过以下命令验证当前环境是否已激活:
|
||||
```bash
|
||||
idf.py --version
|
||||
```
|
||||
若提示 `command not found`,则表示未激活 ESP-IDF 虚拟环境。
|
||||
|
||||
请参考官方文档配置并激活环境:
|
||||
[ESP-IDF 环境设置指南](https://docs.espressif.com/projects/esp-idf/zh_CN/latest/esp32/get-started/linux-macos-setup.html#get-started-linux-macos-first-steps)
|
||||
|
||||
激活后再次执行 `idf.py --version`,若显示版本信息则表明环境已就绪。
|
||||
|
||||
#### 步骤二:检查 Python 版本
|
||||
在虚拟环境中执行以下命令确认 Python 版本:
|
||||
```bash
|
||||
python --version
|
||||
```
|
||||
若版本低于 3.8,请根据同一官方文档升级 Python:
|
||||
[Python 升级指南](https://docs.espressif.com/projects/esp-idf/zh_CN/latest/esp32/get-started/linux-macos-setup.html#get-started-linux-macos-first-steps)
|
||||
|
||||
#### 步骤三:安装日志压缩依赖
|
||||
根据您的操作系统和终端环境,选择以下对应的命令安装所需依赖:
|
||||
|
||||
- **Linux 或 macOS**:
|
||||
```bash
|
||||
pip install -r $IDF_PATH/components/bt/common/ble_log/log_compression/scripts/requirements.txt
|
||||
```
|
||||
- **Windows (PowerShell)**:
|
||||
```ps
|
||||
pip install -r $Env:IDF_PATH\components\bt\common\ble_log\log_compression\scripts\requirements.txt
|
||||
```
|
||||
- **Windows (命令提示符 Cmd)**:
|
||||
```bat
|
||||
pip install -r %IDF_PATH%\components\bt\common\ble_log\log_compression\scripts\requirements.txt
|
||||
```
|
||||
|
||||
#### 步骤四:清理缓存文件
|
||||
安装日志压缩所需的依赖后,删除之前构建生成的 build 文件夹(如有)。之后重新构建应用程序即可。
|
||||
|
||||
|
||||
### 步骤五:配置 Menuconfig
|
||||
|
||||
使用命令`idf.py menuconfig`打开menuconfig, 以开启`BLE-MESH`组件的日志压缩为例:
|
||||
|
||||
通过路径`(Top) -> Component config -> Bluetooth -> Common Options -> BLE Log -> Enable BLE log compression(Preview, Please read help information)->Enable BLE Mesh log compression(Preview)`开启`BLE-MESH`组件的日志压缩功能。
|
||||
|
||||
在`Enable BLE Mesh log compression(Preview)`目录中有三个配置项目可供设置:
|
||||
1. `Mesh log buffer length` 通过该配置项来配置单条日志可能出现的最大长度。
|
||||
2. `Maximum number of tasks that can generate ble mesh logs` 通过该配置项目用来配置可能输出`BLE-MESH`组件日志的最大Task数目,(默认值为推荐值,不建议修改)。
|
||||
|
||||
|
||||
### 步骤六:构建应用程序
|
||||
|
||||
当开启配置项后,使用命令`idf.py build`构建应用程序,请注意构建过程中是否会有警告日志出现,比如出现以下日志时:
|
||||
```txt
|
||||
CMake Warning at esp/esp-idf/components/bt/common/ble_log/log_compression/CMakeLists.txt:46 (message):
|
||||
tree_sitter import failed, please check whether the package is installed
|
||||
correctly,Please refer to the
|
||||
file: esp/esp-idf/components/bt/common/ble_log/log_compression/README
|
||||
for installation instructions.
|
||||
```
|
||||
该警告表示依赖未正确安装,日志压缩构建失败,系统将自动回退至普通编译模式。请重新执行步骤一至步骤四。
|
||||
|
||||
若日志压缩成功,终端将显示如下信息:
|
||||
```
|
||||
[0/1285] Log compression is being performed, please wait...
|
||||
Log compression underway, please wait...
|
||||
Found module BLE_MESH for compression
|
||||
Found 111 source files in module BLE_MESH requiring compression
|
||||
3055 ble log(s) compressed
|
||||
Header file for compressed logs generated
|
||||
```
|
||||
出现该信息表明压缩日志构建成功,其中输出的文件数目和日志数目可能会随版本变更而略有不同。
|
||||
|
||||
构建成功后,将在 `build/ble_log/` 目录下生成如下结构::
|
||||
```
|
||||
build/ble_log/
|
||||
├── ble_log_database
|
||||
│ └── BLE_MESH_logs.json
|
||||
├── ble_script_log_{timestamp}.log
|
||||
├── .compressed_srcs
|
||||
│ └── esp_ble_mesh
|
||||
├── include
|
||||
│ └── mesh_log_index.h
|
||||
└── module_info.yml
|
||||
```
|
||||
- `.compressed_srcs`: 压缩处理后的C代码文件。
|
||||
- `mesh_log_index.h`: 生成的日志宏头文件。
|
||||
- `BLE_MESH_logs.json`: 每条日志的详细信息。
|
||||
- `ble_script_log_{timestamp}.log`: 压缩日志在运行过程中产生的日志。
|
||||
- `module_info.yml`: 压缩日志对各个模块的配置文件。
|
||||
|
||||
**注意:这些为自动生成文件,请勿手动修改。**
|
||||
|
||||
### 步骤七、接收日志
|
||||
开启日志压缩后, 被压缩组件在默认配置下, 除`ERR`、`WARN`级别的日志外,其余级别的日志将会被重定向到压缩日志接口进行输出,接收日志的方法请参考BLE Log模块的说明文档:[BLE Log Module](../../README.md)
|
||||
|
||||
|
||||
## 常见问题解决
|
||||
1. 如果出现编码后的日志导致编译错误或者找不到宏定义,请删除`build`文件夹后重新构建,如果问题持续存在,请将问题反馈给 Espressif BLE 团队。
|
||||
@@ -0,0 +1,124 @@
|
||||
## BLE Log Compression Scheme (Preview)
|
||||
|
||||
### 一、Overview
|
||||
|
||||
This scheme scans the code of BLE stack-related components during the compilation phase, converting formatted strings and parameters in log statements into pure binary data. This improves log output efficiency and reduces the Flash footprint of the protocol stack.
|
||||
|
||||
Currently, the scheme supports log compression for both `BLE-MESH` and `BLE-HOST-BLUEDROID` components.
|
||||
|
||||
---
|
||||
|
||||
### 二、How to Use
|
||||
This feature requires additional Python libraries. Please follow the steps below to set up the environment.
|
||||
|
||||
### Step 1: Verify ESP-IDF Virtual Environment
|
||||
Ensure all subsequent steps are performed within the ESP-IDF Python virtual environment.
|
||||
|
||||
Verify activation by running:
|
||||
```bash
|
||||
idf.py --version
|
||||
```
|
||||
|
||||
If the output shows `idf.py: command not found`, the virtual environment is not active.
|
||||
|
||||
Refer to the official documentation to configure and activate the environment:
|
||||
[ESP-IDF Setup Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/linux-macos-setup.html)
|
||||
|
||||
After activation, run `idf.py --version` again. A version number confirms successful setup.
|
||||
|
||||
### Step 2: Check Python Version
|
||||
|
||||
Within the virtual environment, check the Python version:
|
||||
```bash
|
||||
python --version
|
||||
```
|
||||
If the version is lower than 3.8, upgrade Python by following the same official guide:
|
||||
[Python Upgrade Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/linux-macos-setup.html)
|
||||
|
||||
### Step 3: Install Log Compression Dependencies
|
||||
|
||||
Choose the appropriate command below based on your operating system and terminal environment to install the required dependencies:
|
||||
If you are using Linux or macos, please use the following command:
|
||||
- **Linux or macOS**:
|
||||
```bash
|
||||
pip install -r $IDF_PATH/components/bt/common/ble_log/log_compression/scripts/requirements.txt
|
||||
```
|
||||
- **Windows (PowerShell)**:
|
||||
```ps
|
||||
pip install -r $Env:IDF_PATH\components\bt\common\ble_log\log_compression\scripts\requirements.txt
|
||||
```
|
||||
- **Windows (Command Prompt - Cmd)**:
|
||||
```bat
|
||||
pip install -r %IDF_PATH%\components\bt\common\ble_log\log_compression\scripts\requirements.txt
|
||||
```
|
||||
|
||||
#### Step 4: Clean Build Cache
|
||||
After installing the dependencies, it is recommended to delete the existing build folder (if any) and rebuild the application to ensure a clean environment.
|
||||
|
||||
|
||||
### Step 5: Configure via Menuconfig
|
||||
|
||||
>
|
||||
|
||||
Run `idf.py menuconfig` and navigate to the following path to enable `BLE-MESH` log compression:
|
||||
|
||||
```(Top) -> Component config -> Bluetooth -> Common Options -> BLE Log -> Enable BLE log compression(Preview, Please read help information)->Enable BLE Mesh log compression(Preview)```.
|
||||
|
||||
There are three configuration items under this submenu:
|
||||
|
||||
- Mesh log buffer length: Sets the maximum length of a single log entry.
|
||||
|
||||
- Maximum number of tasks that can generate BLE mesh logs: Sets the maximum number of tasks that can output BLE-MESH logs (the default is recommended; avoid modifying this).
|
||||
|
||||
|
||||
### Step 6: Build the Application
|
||||
|
||||
After configuration, build the application with:
|
||||
```bash
|
||||
idf.py build
|
||||
```
|
||||
|
||||
Watch for any warnings during the build process. For example:
|
||||
```txt
|
||||
CMake Warning at esp/esp-idf/components/bt/common/ble_log/log_compression/CMakeLists.txt:46 (message):
|
||||
tree_sitter import failed, please check whether the package is installed
|
||||
correctly,Please refer to the
|
||||
file: esp/esp-idf/components/bt/common/ble_log/log_compression/README
|
||||
for installation instructions.
|
||||
```
|
||||
This indicates that the dependencies were not installed correctly, and log compression has failed—falling back to a normal build. Please repeat Steps 1–4.
|
||||
|
||||
If log compression is successful, you will see output similar to:
|
||||
```
|
||||
[0/1285] Log compression is being performed, please wait...
|
||||
Log compression underway, please wait...
|
||||
Found module BLE_MESH for compression
|
||||
Found 111 source files in module BLE_MESH requiring compression
|
||||
3055 ble log(s) compressed
|
||||
Header file for compressed logs generated
|
||||
```
|
||||
After a successful build, the following structure will be generated under `build/ble_log/`:
|
||||
```
|
||||
build/ble_log/
|
||||
├── ble_log_database
|
||||
│ └── BLE_MESH_logs.json
|
||||
├── ble_script_log_{timestamp}.log
|
||||
├── .compressed_srcs
|
||||
│ └── esp_ble_mesh
|
||||
├── include
|
||||
│ └── mesh_log_index.h
|
||||
└── module_info.yml
|
||||
```
|
||||
- `.compressed_srcs`: Compressed C source files.
|
||||
- `mesh_log_index.h`: Generated header file containing log macros.
|
||||
- `BLE_MESH_logs.json`: Detailed information for each log entry.
|
||||
- `ble_script_log_{timestamp}.log`: Log generated by the compression script.
|
||||
- `module_info.yml`: Configuration file for compressed logging across modules.
|
||||
|
||||
**Do not modify these auto-generated files.**
|
||||
|
||||
### Step 7: Receive Logs
|
||||
With log compression enabled and under the default configuration, all log levels except ERR and WARN generated by the compressed component will be redirected to the compression-log interface for output. Please refer to the BLE Log module’s documentation for how to receive these logs: [BLE Log module](../../README.md).
|
||||
|
||||
## Frequently Asked Questions
|
||||
1. If encoded logs cause compilation errors or missing macro definitions, delete the build folder and rebuild. If the issue persists, please report it to the Espressif BLE team.
|
||||
@@ -0,0 +1,263 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
// Private includes
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "ble_log_util.h"
|
||||
#include "log_compression/utils.h"
|
||||
|
||||
#if CONFIG_BLE_COMPRESSED_LOG_ENABLE
|
||||
|
||||
#define BUF_NAME(name, idx) name##_buffer##idx
|
||||
#define BUF_MGMT_NAME(name) name##_log_buffer_mgmt
|
||||
|
||||
#define DECL_BUF_OP(name, len, idx) \
|
||||
static uint8_t BUF_NAME(name, idx)[len];
|
||||
|
||||
#define INIT_MAP_OP(name, _, buffer_idx) \
|
||||
{.busy = 0, \
|
||||
.idx = 0, \
|
||||
.buffer = BUF_NAME(name, buffer_idx), \
|
||||
.len = sizeof(BUF_NAME(name, buffer_idx))},
|
||||
|
||||
#define DECLARE_BUFFERS(NAME, BUF_LEN, BUF_CNT) \
|
||||
FOR_EACH_IDX(DECL_BUF_OP, NAME, BUF_LEN, GEN_INDEX(BUF_CNT));
|
||||
|
||||
#define INIT_BUFFER_MGMT(NAME, BUF_CNT) \
|
||||
ble_cp_log_buffer_mgmt_t BUF_MGMT_NAME(NAME)[BUF_CNT] = { \
|
||||
FOR_EACH_IDX(INIT_MAP_OP, NAME, 0, GEN_INDEX(BUF_CNT)) \
|
||||
};
|
||||
|
||||
#if CONFIG_BLE_MESH_COMPRESSED_LOG_ENABLE
|
||||
DECLARE_BUFFERS(mesh, CONFIG_BLE_MESH_COMPRESSED_LOG_BUFFER_LEN, LOG_CP_MAX_LOG_BUFFER_USED_SIMU);
|
||||
INIT_BUFFER_MGMT(mesh, LOG_CP_MAX_LOG_BUFFER_USED_SIMU);
|
||||
char * mesh_last_task_handle = NULL;
|
||||
#endif
|
||||
|
||||
#if CONFIG_BLE_HOST_COMPRESSED_LOG_ENABLE
|
||||
DECLARE_BUFFERS(host, CONFIG_BLE_HOST_COMPRESSED_LOG_BUFFER_LEN, LOG_CP_MAX_LOG_BUFFER_USED_SIMU);
|
||||
INIT_BUFFER_MGMT(host, LOG_CP_MAX_LOG_BUFFER_USED_SIMU);
|
||||
char * host_last_task_handle = NULL;
|
||||
#endif
|
||||
|
||||
/* The maximum number of supported parameters is 64 */
|
||||
#define LOG_HEADER(log_type, info) ((log_type << 6) | (info & 0x3f))
|
||||
|
||||
int ble_compressed_log_cb_get(uint8_t source, ble_cp_log_buffer_mgmt_t **mgmt)
|
||||
{
|
||||
ble_cp_log_buffer_mgmt_t *buffer_mgmt = NULL;
|
||||
char ** last_handle = NULL;
|
||||
char * cur_handle = pcTaskGetName(NULL);
|
||||
|
||||
switch (source)
|
||||
{
|
||||
#if CONFIG_BLE_MESH_COMPRESSED_LOG_ENABLE
|
||||
case BLE_COMPRESSED_LOG_OUT_SOURCE_MESH:
|
||||
buffer_mgmt = BUF_MGMT_NAME(mesh);
|
||||
last_handle = &mesh_last_task_handle;
|
||||
break;
|
||||
#endif
|
||||
#if CONFIG_BLE_HOST_COMPRESSED_LOG_ENABLE
|
||||
case BLE_COMPRESSED_LOG_OUT_SOURCE_HOST:
|
||||
buffer_mgmt = BUF_MGMT_NAME(host);
|
||||
last_handle = &host_last_task_handle;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
assert(0 && "Unsupported log source");
|
||||
break;
|
||||
}
|
||||
|
||||
for (int i = 0; i < LOG_CP_MAX_LOG_BUFFER_USED_SIMU; i++) {
|
||||
if (ble_log_cas_acquire(&(buffer_mgmt[i].busy))) {
|
||||
*mgmt = &buffer_mgmt[i];
|
||||
ble_log_cp_push_u8(*mgmt, source);
|
||||
if (*last_handle == NULL ||
|
||||
*last_handle != cur_handle) {
|
||||
ble_log_cp_push_u8(*mgmt, LOG_HEADER(LOG_TYPE_INFO, LOG_TYPE_INFO_TASK_SWITCH));
|
||||
*last_handle = cur_handle;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int ble_compressed_log_buffer_free(ble_cp_log_buffer_mgmt_t *mgmt)
|
||||
{
|
||||
#if BLE_LOG_CP_CONTENT_CHECK_ENBALE
|
||||
memset(mgmt->buffer, BLE_LOG_CP_CONTENT_CHECK_VAL, mgmt->idx);
|
||||
#endif
|
||||
mgmt->idx = 0;
|
||||
ble_log_cas_release(&mgmt->busy);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ble_log_compressed_hex_print(uint8_t source, uint32_t log_index, size_t args_cnt, ...)
|
||||
{
|
||||
ble_cp_log_buffer_mgmt_t *mgmt = NULL;
|
||||
uint8_t arg_type = 0;
|
||||
va_list args;
|
||||
|
||||
ble_compressed_log_cb_get(source, &mgmt);
|
||||
|
||||
if (args_cnt == 0) {
|
||||
ble_log_cp_push_u8(mgmt, LOG_HEADER(LOG_TYPE_HEX_ARGS, 0));
|
||||
ble_log_cp_push_u16(mgmt, log_index);
|
||||
ble_compressed_log_output(source, mgmt->buffer, mgmt->idx);
|
||||
ble_compressed_log_buffer_free(mgmt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
va_start(args, args_cnt);
|
||||
|
||||
ble_log_cp_push_u8(mgmt, LOG_HEADER(LOG_TYPE_HEX_ARGS, args_cnt));
|
||||
ble_log_cp_push_u16(mgmt, log_index);
|
||||
uint8_t size_info_idx = mgmt->idx;
|
||||
uint8_t *cur = &(mgmt->buffer)[mgmt->idx];
|
||||
uint8_t size_info = 0;
|
||||
|
||||
for (size_t i = 0; i < args_cnt; i++) {
|
||||
if (i % 2) {
|
||||
arg_type = va_arg(args, size_t);
|
||||
ble_log_cp_push_u8(mgmt, size_info|arg_type);
|
||||
size_info = 0;
|
||||
cur++;
|
||||
} else {
|
||||
arg_type = va_arg(args, size_t);
|
||||
if (i == args_cnt - 1) {
|
||||
ble_log_cp_push_u8(mgmt, arg_type);
|
||||
} else {
|
||||
size_info = arg_type << 4;
|
||||
}
|
||||
}
|
||||
if (arg_type >= ARG_SIZE_TYPE_MAX) {
|
||||
printf("Found invalid arg type %08lx type %d", log_index, arg_type);
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
cur = &(mgmt->buffer)[size_info_idx];
|
||||
|
||||
for (size_t i = 0; i < args_cnt; i++) {
|
||||
if (i % 2) {
|
||||
arg_type = (*cur) & 0x0f;
|
||||
cur++;
|
||||
} else {
|
||||
arg_type = (*cur) >> 4;
|
||||
}
|
||||
switch(arg_type) {
|
||||
case ARG_SIZE_TYPE_U32:
|
||||
uint32_t u32v = va_arg(args, size_t);
|
||||
if (likely(u32v)) {
|
||||
if (u32v <= 0xff) {
|
||||
ble_log_cp_push_u8(mgmt, 3);
|
||||
ble_log_cp_push_u8(mgmt, u32v);
|
||||
ble_log_cp_update_half_byte(mgmt, size_info_idx + i/2, ARG_SIZE_TYPE_LZU32, !(i%2));
|
||||
break;
|
||||
} else if (u32v <= 0xffff) {
|
||||
ble_log_cp_push_u8(mgmt, 2);
|
||||
ble_log_cp_push_u16(mgmt, u32v);
|
||||
ble_log_cp_update_half_byte(mgmt, size_info_idx + i/2, ARG_SIZE_TYPE_LZU32, !(i%2));
|
||||
break;
|
||||
} else {
|
||||
ble_log_cp_push_u32(mgmt, u32v);
|
||||
}
|
||||
} else {
|
||||
ble_log_cp_update_half_byte(mgmt, size_info_idx + i/2, ARG_SIZE_TYPE_AZU32, !(i%2));
|
||||
}
|
||||
break;
|
||||
case ARG_SIZE_TYPE_U64:
|
||||
uint64_t u64v = va_arg(args, uint64_t);
|
||||
if (likely(u64v)) {
|
||||
if (unlikely(u64v >> 48)) {
|
||||
ble_log_cp_push_u64(mgmt, u64v);
|
||||
} else {
|
||||
uint32_t tmpv = 0;
|
||||
uint8_t lz = 0;
|
||||
if (likely(u64v <= UINT32_MAX)) {
|
||||
tmpv = (uint32_t)u64v;
|
||||
lz = 4;
|
||||
} else {
|
||||
tmpv = u64v >> 32;
|
||||
}
|
||||
lz += __builtin_clz(tmpv) / 8;
|
||||
ble_log_cp_push_u8(mgmt, lz);
|
||||
switch (8-lz) {
|
||||
case 5:
|
||||
ble_log_cp_push_u32(mgmt, (uint32_t)u64v);
|
||||
[[fallthrough]];
|
||||
case 1:
|
||||
ble_log_cp_push_u8(mgmt, (uint8_t)tmpv);
|
||||
break;
|
||||
case 6:
|
||||
ble_log_cp_push_u32(mgmt, (uint32_t)u64v);
|
||||
[[fallthrough]];
|
||||
case 2:
|
||||
ble_log_cp_push_u16(mgmt, (uint16_t)tmpv);
|
||||
break;
|
||||
case 7:
|
||||
ble_log_cp_push_u32(mgmt, (uint32_t)u64v);
|
||||
[[fallthrough]];
|
||||
case 3:
|
||||
ble_log_cp_push_u8(mgmt, (uint8_t)tmpv);
|
||||
ble_log_cp_push_u16(mgmt, (uint16_t)(tmpv >> 8));
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
ble_log_cp_update_half_byte(mgmt, size_info_idx + i/2, ARG_SIZE_TYPE_LZU64, !(i%2));
|
||||
}
|
||||
} else {
|
||||
ble_log_cp_update_half_byte(mgmt, size_info_idx + i/2, ARG_SIZE_TYPE_AZU64, !(i%2));
|
||||
}
|
||||
break;
|
||||
case ARG_SIZE_TYPE_STR:
|
||||
char *str_p = (char *)va_arg(args, char *);
|
||||
ble_log_cp_push_buf(mgmt, (const uint8_t *)str_p, strlen(str_p) + 1);
|
||||
break;
|
||||
default:
|
||||
printf("Invalid size %d\n", arg_type);
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ble_compressed_log_output(source, mgmt->buffer, mgmt->idx);
|
||||
ble_compressed_log_buffer_free(mgmt);
|
||||
va_end(args);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ble_log_compressed_hex_print_buf(uint8_t source, uint32_t log_index, uint8_t buf_idx, const uint8_t *buf, size_t len)
|
||||
{
|
||||
ble_cp_log_buffer_mgmt_t *mgmt = NULL;
|
||||
|
||||
ble_compressed_log_cb_get(source, &mgmt);
|
||||
|
||||
if (buf == NULL && len != 0) {
|
||||
ble_log_cp_push_u8(mgmt, LOG_HEADER(LOG_TYPE_INFO, LOG_TYPE_INFO_NULL_BUF));
|
||||
ble_log_cp_push_u16(mgmt, log_index);
|
||||
ble_compressed_log_output(source, mgmt->buffer, mgmt->idx);
|
||||
ble_compressed_log_buffer_free(mgmt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ble_log_cp_push_u8(mgmt, LOG_HEADER(LOG_TYPE_HEX_BUF, buf_idx));
|
||||
ble_log_cp_push_u16(mgmt, log_index);
|
||||
ble_log_cp_push_buf(mgmt, buf, len);
|
||||
ble_compressed_log_output(source, mgmt->buffer, mgmt->idx);
|
||||
ble_compressed_log_buffer_free(mgmt);
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_BLE_COMPRESSED_LOG_ENABLE */
|
||||
+160
@@ -0,0 +1,160 @@
|
||||
set(_BLE_HOST_TAG_MAP
|
||||
# BTM Layer
|
||||
CONFIG_BLE_BLUEDROID_BTM_ERROR_LOG_COMPRESSION
|
||||
CONFIG_BLE_BLUEDROID_BTM_ERROR_LOG_PRESERVE
|
||||
BTM_TRACE_ERROR
|
||||
|
||||
CONFIG_BLE_BLUEDROID_BTM_WARNING_LOG_COMPRESSION
|
||||
CONFIG_BLE_BLUEDROID_BTM_WARNING_LOG_PRESERVE
|
||||
BTM_TRACE_WARNING
|
||||
|
||||
CONFIG_BLE_BLUEDROID_BTM_API_LOG_COMPRESSION
|
||||
CONFIG_BLE_BLUEDROID_BTM_API_LOG_PRESERVE
|
||||
BTM_TRACE_API
|
||||
|
||||
CONFIG_BLE_BLUEDROID_BTM_EVENT_LOG_COMPRESSION
|
||||
CONFIG_BLE_BLUEDROID_BTM_EVENT_LOG_PRESERVE
|
||||
BTM_TRACE_EVENT
|
||||
|
||||
CONFIG_BLE_BLUEDROID_BTM_DEBUG_LOG_COMPRESSION
|
||||
CONFIG_BLE_BLUEDROID_BTM_DEBUG_LOG_PRESERVE
|
||||
BTM_TRACE_DEBUG
|
||||
|
||||
CONFIG_BLE_BLUEDROID_BTM_VERBOSE_LOG_COMPRESSION
|
||||
CONFIG_BLE_BLUEDROID_BTM_VERBOSE_LOG_PRESERVE
|
||||
BTM_TRACE_VERBOSE
|
||||
|
||||
# L2CAP Layer
|
||||
CONFIG_BLE_BLUEDROID_L2CAP_ERROR_LOG_COMPRESSION
|
||||
CONFIG_BLE_BLUEDROID_L2CAP_ERROR_LOG_PRESERVE
|
||||
L2CAP_TRACE_ERROR
|
||||
|
||||
CONFIG_BLE_BLUEDROID_L2CAP_WARNING_LOG_COMPRESSION
|
||||
CONFIG_BLE_BLUEDROID_L2CAP_WARNING_LOG_PRESERVE
|
||||
L2CAP_TRACE_WARNING
|
||||
|
||||
CONFIG_BLE_BLUEDROID_L2CAP_API_LOG_COMPRESSION
|
||||
CONFIG_BLE_BLUEDROID_L2CAP_API_LOG_PRESERVE
|
||||
L2CAP_TRACE_API
|
||||
|
||||
CONFIG_BLE_BLUEDROID_L2CAP_EVENT_LOG_COMPRESSION
|
||||
CONFIG_BLE_BLUEDROID_L2CAP_EVENT_LOG_PRESERVE
|
||||
L2CAP_TRACE_EVENT
|
||||
|
||||
CONFIG_BLE_BLUEDROID_L2CAP_DEBUG_LOG_COMPRESSION
|
||||
CONFIG_BLE_BLUEDROID_L2CAP_DEBUG_LOG_PRESERVE
|
||||
L2CAP_TRACE_DEBUG
|
||||
|
||||
CONFIG_BLE_BLUEDROID_L2CAP_VERBOSE_LOG_COMPRESSION
|
||||
CONFIG_BLE_BLUEDROID_L2CAP_VERBOSE_LOG_PRESERVE
|
||||
L2CAP_TRACE_VERBOSE
|
||||
|
||||
# GAP Layer
|
||||
CONFIG_BLE_BLUEDROID_GAP_ERROR_LOG_COMPRESSION
|
||||
CONFIG_BLE_BLUEDROID_GAP_ERROR_LOG_PRESERVE
|
||||
GAP_TRACE_ERROR
|
||||
|
||||
CONFIG_BLE_BLUEDROID_GAP_WARNING_LOG_COMPRESSION
|
||||
CONFIG_BLE_BLUEDROID_GAP_WARNING_LOG_PRESERVE
|
||||
GAP_TRACE_WARNING
|
||||
|
||||
CONFIG_BLE_BLUEDROID_GAP_API_LOG_COMPRESSION
|
||||
CONFIG_BLE_BLUEDROID_GAP_API_LOG_PRESERVE
|
||||
GAP_TRACE_API
|
||||
|
||||
CONFIG_BLE_BLUEDROID_GAP_EVENT_LOG_COMPRESSION
|
||||
CONFIG_BLE_BLUEDROID_GAP_EVENT_LOG_PRESERVE
|
||||
GAP_TRACE_EVENT
|
||||
|
||||
CONFIG_BLE_BLUEDROID_GAP_DEBUG_LOG_COMPRESSION
|
||||
CONFIG_BLE_BLUEDROID_GAP_DEBUG_LOG_PRESERVE
|
||||
GAP_TRACE_DEBUG
|
||||
|
||||
CONFIG_BLE_BLUEDROID_GAP_VERBOSE_LOG_COMPRESSION
|
||||
CONFIG_BLE_BLUEDROID_GAP_VERBOSE_LOG_PRESERVE
|
||||
GAP_TRACE_VERBOSE
|
||||
|
||||
# GATT Layer
|
||||
CONFIG_BLE_BLUEDROID_GATT_ERROR_LOG_COMPRESSION
|
||||
CONFIG_BLE_BLUEDROID_GATT_ERROR_LOG_PRESERVE
|
||||
GATT_TRACE_ERROR
|
||||
|
||||
CONFIG_BLE_BLUEDROID_GATT_WARNING_LOG_COMPRESSION
|
||||
CONFIG_BLE_BLUEDROID_GATT_WARNING_LOG_PRESERVE
|
||||
GATT_TRACE_WARNING
|
||||
|
||||
CONFIG_BLE_BLUEDROID_GATT_API_LOG_COMPRESSION
|
||||
CONFIG_BLE_BLUEDROID_GATT_API_LOG_PRESERVE
|
||||
GATT_TRACE_API
|
||||
|
||||
CONFIG_BLE_BLUEDROID_GATT_EVENT_LOG_COMPRESSION
|
||||
CONFIG_BLE_BLUEDROID_GATT_EVENT_LOG_PRESERVE
|
||||
GATT_TRACE_EVENT
|
||||
|
||||
CONFIG_BLE_BLUEDROID_GATT_DEBUG_LOG_COMPRESSION
|
||||
CONFIG_BLE_BLUEDROID_GATT_DEBUG_LOG_PRESERVE
|
||||
GATT_TRACE_DEBUG
|
||||
|
||||
CONFIG_BLE_BLUEDROID_GATT_VERBOSE_LOG_COMPRESSION
|
||||
CONFIG_BLE_BLUEDROID_GATT_VERBOSE_LOG_PRESERVE
|
||||
GATT_TRACE_VERBOSE
|
||||
|
||||
# SMP Layer
|
||||
CONFIG_BLE_BLUEDROID_SMP_ERROR_LOG_COMPRESSION
|
||||
CONFIG_BLE_BLUEDROID_SMP_ERROR_LOG_PRESERVE
|
||||
SMP_TRACE_ERROR
|
||||
|
||||
CONFIG_BLE_BLUEDROID_SMP_WARNING_LOG_COMPRESSION
|
||||
CONFIG_BLE_BLUEDROID_SMP_WARNING_LOG_PRESERVE
|
||||
SMP_TRACE_WARNING
|
||||
|
||||
CONFIG_BLE_BLUEDROID_SMP_API_LOG_COMPRESSION
|
||||
CONFIG_BLE_BLUEDROID_SMP_API_LOG_PRESERVE
|
||||
SMP_TRACE_API
|
||||
|
||||
CONFIG_BLE_BLUEDROID_SMP_EVENT_LOG_COMPRESSION
|
||||
CONFIG_BLE_BLUEDROID_SMP_EVENT_LOG_PRESERVE
|
||||
SMP_TRACE_EVENT
|
||||
|
||||
CONFIG_BLE_BLUEDROID_SMP_DEBUG_LOG_COMPRESSION
|
||||
CONFIG_BLE_BLUEDROID_SMP_DEBUG_LOG_PRESERVE
|
||||
SMP_TRACE_DEBUG
|
||||
|
||||
CONFIG_BLE_BLUEDROID_SMP_VERBOSE_LOG_COMPRESSION
|
||||
CONFIG_BLE_BLUEDROID_SMP_VERBOSE_LOG_PRESERVE
|
||||
SMP_TRACE_VERBOSE
|
||||
|
||||
# APPL Layer
|
||||
CONFIG_BLE_BLUEDROID_APPL_ERROR_LOG_COMPRESSION
|
||||
CONFIG_BLE_BLUEDROID_APPL_ERROR_LOG_PRESERVE
|
||||
APPL_TRACE_ERROR
|
||||
|
||||
CONFIG_BLE_BLUEDROID_APPL_WARNING_LOG_COMPRESSION
|
||||
CONFIG_BLE_BLUEDROID_APPL_WARNING_LOG_PRESERVE
|
||||
APPL_TRACE_WARNING
|
||||
|
||||
CONFIG_BLE_BLUEDROID_APPL_API_LOG_COMPRESSION
|
||||
CONFIG_BLE_BLUEDROID_APPL_API_LOG_PRESERVE
|
||||
APPL_TRACE_API
|
||||
|
||||
CONFIG_BLE_BLUEDROID_APPL_EVENT_LOG_COMPRESSION
|
||||
CONFIG_BLE_BLUEDROID_APPL_EVENT_LOG_PRESERVE
|
||||
APPL_TRACE_EVENT
|
||||
|
||||
CONFIG_BLE_BLUEDROID_APPL_DEBUG_LOG_COMPRESSION
|
||||
CONFIG_BLE_BLUEDROID_APPL_DEBUG_LOG_PRESERVE
|
||||
APPL_TRACE_DEBUG
|
||||
|
||||
CONFIG_BLE_BLUEDROID_APPL_VERBOSE_LOG_COMPRESSION
|
||||
CONFIG_BLE_BLUEDROID_APPL_VERBOSE_LOG_PRESERVE
|
||||
APPL_TRACE_VERBOSE
|
||||
|
||||
)
|
||||
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/tag_table_function.cmake)
|
||||
|
||||
set(BLE_HOST_TAGS "")
|
||||
set(BLE_HOST_TAGS_PRESERVE "")
|
||||
tag_table_to_lists(_BLE_HOST_TAG_MAP BLE_HOST_TAGS BLE_HOST_TAGS_PRESERVE)
|
||||
set(BLE_HOST_TAGS "${BLE_HOST_TAGS}" PARENT_SCOPE)
|
||||
set(BLE_HOST_TAGS_PRESERVE "${BLE_HOST_TAGS_PRESERVE}" PARENT_SCOPE)
|
||||
@@ -0,0 +1,41 @@
|
||||
set(_BLE_MESH_TAG_MAP
|
||||
CONFIG_BLE_MESH_STACK_ERR_LOG_COMPRESSION
|
||||
CONFIG_BLE_MESH_STACK_ERR_LOG_PRESERVE
|
||||
BT_ERR
|
||||
|
||||
CONFIG_BLE_MESH_STACK_WARN_LOG_COMPRESSION
|
||||
CONFIG_BLE_MESH_STACK_WARN_LOG_PRESERVE
|
||||
BT_WARN
|
||||
|
||||
CONFIG_BLE_MESH_STACK_INFO_LOG_COMPRESSION
|
||||
CONFIG_BLE_MESH_STACK_INFO_LOG_PRESERVE
|
||||
BT_INFO
|
||||
|
||||
CONFIG_BLE_MESH_STACK_DEBUG_LOG_COMPRESSION
|
||||
CONFIG_BLE_MESH_STACK_DEBUG_LOG_PRESERVE
|
||||
BT_DBG
|
||||
|
||||
CONFIG_BLE_MESH_NET_BUF_ERR_LOG_COMPRESSION
|
||||
CONFIG_BLE_MESH_NET_BUF_ERR_LOG_PRESERVE
|
||||
NET_BUF_ERR
|
||||
|
||||
CONFIG_BLE_MESH_NET_BUF_WARN_LOG_COMPRESSION
|
||||
CONFIG_BLE_MESH_NET_BUF_WARN_LOG_PRESERVE
|
||||
NET_BUF_WARN
|
||||
|
||||
CONFIG_BLE_MESH_NET_BUF_INFO_LOG_COMPRESSION
|
||||
CONFIG_BLE_MESH_NET_BUF_INFO_LOG_PRESERVE
|
||||
NET_BUF_INFO
|
||||
|
||||
CONFIG_BLE_MESH_NET_BUF_DEBUG_LOG_COMPRESSION
|
||||
CONFIG_BLE_MESH_NET_BUF_DEBUG_LOG_PRESERVE
|
||||
NET_BUF_DBG
|
||||
)
|
||||
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/tag_table_function.cmake)
|
||||
|
||||
set(BLE_MESH_TAGS "")
|
||||
set(BLE_MESH_TAGS_PRESERVE "")
|
||||
tag_table_to_lists(_BLE_MESH_TAG_MAP BLE_MESH_TAGS BLE_MESH_TAGS_PRESERVE)
|
||||
set(BLE_MESH_TAGS "${BLE_MESH_TAGS}" PARENT_SCOPE)
|
||||
set(BLE_MESH_TAGS_PRESERVE "${BLE_MESH_TAGS_PRESERVE}" PARENT_SCOPE)
|
||||
@@ -0,0 +1,33 @@
|
||||
# Usage:
|
||||
# set(MY_TABLE CONFIG_FOO_ON CONFIG_FOO_KEEP TAG_FOO ...)
|
||||
# tag_table_to_lists(MY_TABLE OUT_TAGS OUT_PRESERVE)
|
||||
function(tag_table_to_lists TABLE_NAME OUT_TAGS OUT_PRESERVE)
|
||||
set(_tags "")
|
||||
set(_preserve "")
|
||||
set(_map ${${TABLE_NAME}})
|
||||
|
||||
list(LENGTH _map _len)
|
||||
math(EXPR _stop "${_len} - 1")
|
||||
|
||||
foreach(i RANGE 0 ${_stop} 3)
|
||||
math(EXPR _i1 "${i} + 1")
|
||||
math(EXPR _i2 "${i} + 2")
|
||||
|
||||
list(GET _map ${i} _comp)
|
||||
list(GET _map ${_i1} _pres)
|
||||
list(GET _map ${_i2} _tag)
|
||||
|
||||
if(${_comp})
|
||||
list(APPEND _tags "${_tag}")
|
||||
if(${_pres})
|
||||
list(APPEND _preserve "${_tag}")
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
list(JOIN _tags ", " _tags_str)
|
||||
list(JOIN _preserve ", " _preserve_str)
|
||||
|
||||
set(${OUT_TAGS} "${_tags_str}" PARENT_SCOPE)
|
||||
set(${OUT_PRESERVE} "${_preserve_str}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
+189
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef _BLE_LOG_COMPRESSION_UTILS_H
|
||||
#define _BLE_LOG_COMPRESSION_UTILS_H
|
||||
|
||||
#include "ble_log.h"
|
||||
|
||||
#define CONCAT(a, b) a##b
|
||||
#define _CONCAT(a, b) CONCAT(a, b)
|
||||
|
||||
#define _0 0
|
||||
#define _1 1
|
||||
#define _2 2
|
||||
#define _3 3
|
||||
#define _4 4
|
||||
#define _5 5
|
||||
#define _6 6
|
||||
#define _7 7
|
||||
#define _8 8
|
||||
#define _9 9
|
||||
|
||||
#define __COUNT_ARGS(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _n, X...) _n
|
||||
#define COUNT_ARGS(X...) __COUNT_ARGS(, ##X, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
|
||||
|
||||
#define FOR_EACH_IDX(macro, name, len, ...) \
|
||||
_CONCAT(_FOR_EACH_, COUNT_ARGS(__VA_ARGS__))(macro, name, len, __VA_ARGS__)
|
||||
|
||||
#define _FOR_EACH_0(m, n, l, ...)
|
||||
#define _FOR_EACH_1(m, n, l, i1, ...) m(n, l, i1)
|
||||
#define _FOR_EACH_2(m, n, l, i1, ...) m(n, l, i1) _FOR_EACH_1(m, n, l, __VA_ARGS__)
|
||||
#define _FOR_EACH_3(m, n, l, i1, ...) m(n, l, i1) _FOR_EACH_2(m, n, l, __VA_ARGS__)
|
||||
#define _FOR_EACH_4(m, n, l, i1, ...) m(n, l, i1) _FOR_EACH_3(m, n, l, __VA_ARGS__)
|
||||
#define _FOR_EACH_5(m, n, l, i1, ...) m(n, l, i1) _FOR_EACH_4(m, n, l, __VA_ARGS__)
|
||||
|
||||
#define _GEN_INDEX_0()
|
||||
#define _GEN_INDEX_1() _0
|
||||
#define _GEN_INDEX_2() _0, _1
|
||||
#define _GEN_INDEX_3() _0, _1, _2
|
||||
#define _GEN_INDEX_4() _0, _1, _2, _3
|
||||
#define _GEN_INDEX_5() _0, _1, _2, _3, _4
|
||||
#define GEN_INDEX(n) _CONCAT(_GEN_INDEX_, n)()
|
||||
|
||||
|
||||
enum {
|
||||
BLE_COMPRESSED_LOG_OUT_SOURCE_HOST,
|
||||
BLE_COMPRESSED_LOG_OUT_SOURCE_MESH,
|
||||
};
|
||||
|
||||
enum {
|
||||
ARG_SIZE_TYPE_U32, /* argument type with 4 bytes */
|
||||
ARG_SIZE_TYPE_STR, /* argument type with strings */
|
||||
ARG_SIZE_TYPE_U64, /* argument type with 8 bytes */
|
||||
ARG_SIZE_TYPE_LZU32, /* argument type with 4 bytes but with leading zeros */
|
||||
ARG_SIZE_TYPE_LZU64, /* argument type with 8 bytes but with leading zeros */
|
||||
ARG_SIZE_TYPE_AZU32, /* argument type with 4 bytes but all zeros */
|
||||
ARG_SIZE_TYPE_AZU64, /* argument type with 8 bytes but all zeros */
|
||||
ARG_SIZE_TYPE_MAX,
|
||||
};
|
||||
|
||||
/* The maximum number of buffers used simultaneously */
|
||||
#define LOG_CP_MAX_LOG_BUFFER_USED_SIMU 3
|
||||
|
||||
#define LOG_TYPE_ZERO_ARGS 0
|
||||
#define LOG_TYPE_HEX_ARGS 1
|
||||
#define LOG_TYPE_HEX_BUF 2
|
||||
/* This type of message is used to update log information,
|
||||
* such as there is currently a new task log */
|
||||
#define LOG_TYPE_INFO 3
|
||||
|
||||
#define LOG_TYPE_INFO_TASK_ID_UPDATE 0
|
||||
#define LOG_TYPE_INFO_NULL_BUF 1
|
||||
#define LOG_TYPE_INFO_TASK_SWITCH 2
|
||||
|
||||
typedef struct {
|
||||
volatile bool busy;
|
||||
uint8_t *buffer;
|
||||
uint16_t idx;
|
||||
uint16_t len;
|
||||
} ble_cp_log_buffer_mgmt_t;
|
||||
|
||||
#define CONTENT_CHECK(idx, buf, except_val, len)
|
||||
#define LENGTH_CHECK(idx, pbuffer_mgmt) do ( if(unlikely((idx) > (pbuffer_mgmt->len))) assert(0 && "Maximum log buffer length exceeded");) while(0)
|
||||
|
||||
#define BLE_LOG_CP_CONTENT_CHECK_ENBALE 0
|
||||
#define BLE_LOG_CP_CONTENT_CHECK_VAL 0x00
|
||||
|
||||
static inline int ble_log_cp_buffer_safe_check(ble_cp_log_buffer_mgmt_t *pbuf_mgmt, uint16_t write_len)
|
||||
{
|
||||
if ((pbuf_mgmt->idx + write_len) > pbuf_mgmt->len) {
|
||||
printf("Maximum length of buffer(%p) idx %d write_len %d exceed\n", pbuf_mgmt, pbuf_mgmt->idx, write_len);
|
||||
return -1;
|
||||
}
|
||||
#if BLE_LOG_CP_CONTENT_CHECK_ENBALE
|
||||
for (int i = pbuf_mgmt->idx; i < pbuf_mgmt->idx + write_len; i++) {
|
||||
if (pbuf_mgmt->buffer[i] != BLE_LOG_CP_CONTENT_CHECK_VAL) {
|
||||
printf("The value(%02x) in the buffer does not match the expected(%02x)\n", pbuf_mgmt->buffer[i], BLE_LOG_CP_CONTENT_CHECK_VAL);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int ble_log_cp_push_u8(ble_cp_log_buffer_mgmt_t *pbuf_mgmt, uint8_t val)
|
||||
{
|
||||
if (ble_log_cp_buffer_safe_check(pbuf_mgmt, 1)) {
|
||||
return -1;
|
||||
}
|
||||
pbuf_mgmt->buffer[pbuf_mgmt->idx] = val;
|
||||
pbuf_mgmt->idx++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int ble_log_cp_push_u16(ble_cp_log_buffer_mgmt_t *pbuf_mgmt, uint16_t val)
|
||||
{
|
||||
if (ble_log_cp_buffer_safe_check(pbuf_mgmt, 2)) {
|
||||
return -1;
|
||||
}
|
||||
uint16_t *p = (uint16_t *)&(pbuf_mgmt->buffer[pbuf_mgmt->idx]);
|
||||
*p = val;
|
||||
pbuf_mgmt->idx+=2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int ble_log_cp_push_u32(ble_cp_log_buffer_mgmt_t *pbuf_mgmt, uint32_t val)
|
||||
{
|
||||
if (ble_log_cp_buffer_safe_check(pbuf_mgmt, 4)) {
|
||||
return -1;
|
||||
}
|
||||
uint32_t *p = (uint32_t *)&(pbuf_mgmt->buffer[pbuf_mgmt->idx]);
|
||||
*p = val;
|
||||
pbuf_mgmt->idx+=4;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int ble_log_cp_push_u64(ble_cp_log_buffer_mgmt_t *pbuf_mgmt, uint64_t val)
|
||||
{
|
||||
if (ble_log_cp_buffer_safe_check(pbuf_mgmt, 8)) {
|
||||
return -1;
|
||||
}
|
||||
uint64_t *p = (uint64_t *)&(pbuf_mgmt->buffer[pbuf_mgmt->idx]);
|
||||
*p = val;
|
||||
pbuf_mgmt->idx+=8;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int ble_log_cp_push_buf(ble_cp_log_buffer_mgmt_t *pbuf_mgmt, const uint8_t *buf, uint16_t len)
|
||||
{
|
||||
if (ble_log_cp_buffer_safe_check(pbuf_mgmt, len)) {
|
||||
return -1;
|
||||
}
|
||||
uint8_t *p = (uint8_t *)&(pbuf_mgmt->buffer[pbuf_mgmt->idx]);
|
||||
memcpy(p, buf, len);
|
||||
pbuf_mgmt->idx+=len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int ble_log_cp_update_half_byte(ble_cp_log_buffer_mgmt_t *pbuf_mgmt,
|
||||
uint16_t idx, uint8_t new_data, uint8_t high)
|
||||
{
|
||||
if (pbuf_mgmt->idx <= idx) {
|
||||
return -1;
|
||||
}
|
||||
uint8_t old_val = pbuf_mgmt->buffer[idx];
|
||||
if (high) {
|
||||
pbuf_mgmt->buffer[idx] = (old_val & 0x0f) | (new_data << 4);
|
||||
} else {
|
||||
pbuf_mgmt->buffer[idx] = (old_val & 0xf0) | (new_data & 0x0f);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int ble_log_cp_buffer_print(ble_cp_log_buffer_mgmt_t *pbuf_mgmt)
|
||||
{
|
||||
for (size_t i = 0; i < pbuf_mgmt->idx; i++) {
|
||||
printf("%02x ", pbuf_mgmt->buffer[i]);
|
||||
}
|
||||
printf("\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int ble_compressed_log_output(uint8_t source, uint8_t *data, uint16_t len)
|
||||
{
|
||||
return ble_log_write_hex(BLE_LOG_SRC_ENCODE, data, len);
|
||||
}
|
||||
#endif /* _BLE_LOG_COMPRESSION_UTILS_H */
|
||||
@@ -0,0 +1,440 @@
|
||||
# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# ruff: noqa: UP007
|
||||
"""
|
||||
Log Database Manager
|
||||
====================
|
||||
Manages the storage and retrieval of compressed log metadata using a multiprocessing-safe database.
|
||||
"""
|
||||
|
||||
import atexit
|
||||
import hashlib
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import tempfile
|
||||
import threading
|
||||
from collections.abc import Mapping
|
||||
from pathlib import Path
|
||||
from types import TracebackType
|
||||
from typing import Any
|
||||
from typing import Union
|
||||
|
||||
LOGGER = logging.getLogger('log_db_manager')
|
||||
|
||||
|
||||
class LogDBManager:
|
||||
"""Manages log compression metadata in a multiprocessing-safe manner."""
|
||||
|
||||
# Operation result codes
|
||||
SUCCESS = 0
|
||||
LOG_EXISTS = 1
|
||||
OPERATION_FAILED = 2
|
||||
|
||||
SOURCE_LOG_UPDATE_FULL = 0
|
||||
SOURCE_LOG_UPDATE_PARTIAL = 1
|
||||
SOURCE_LOG_UPDATE_NONE = 2
|
||||
|
||||
def __init__(self, data_dir: str, sources: Mapping[str, str], logger: Union[logging.Logger, None] = None):
|
||||
"""
|
||||
Initialize the log database manager.
|
||||
|
||||
Args:
|
||||
data_dir: Directory for database files
|
||||
sources: List of log sources/modules
|
||||
logger: Optional logger instance
|
||||
"""
|
||||
self.logger = logger or LOGGER
|
||||
self.data_dir = Path(data_dir)
|
||||
self.sources = [s.upper() for s in sources.keys()]
|
||||
self.source_cfg = sources
|
||||
self.sources_exist: dict[str, bool] = {s.upper(): False for s in sources.keys()}
|
||||
self.sources_updated: dict[str, int] = {s.upper(): 0 for s in sources.keys()}
|
||||
|
||||
# Create database directory
|
||||
self.data_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# Setup multiprocessing infrastructure
|
||||
self.shared_data: dict[str, Any] = dict()
|
||||
self.locks: dict[str, Any] = dict()
|
||||
self.global_lock = threading.Lock()
|
||||
|
||||
# Initialize sources
|
||||
self._initialize_sources()
|
||||
|
||||
self._closed = False
|
||||
self.stop_event = threading.Event()
|
||||
atexit.register(self.safe_close)
|
||||
|
||||
self.logger.info(f'LogDB initialized for {len(self.sources)} sources in {self.data_dir}')
|
||||
|
||||
def _initialize_sources(self) -> None:
|
||||
"""Initialize database structures for all sources."""
|
||||
with self.global_lock:
|
||||
for source in self.sources:
|
||||
# Create source-specific structures
|
||||
self.shared_data[source] = dict(
|
||||
{
|
||||
'config': '',
|
||||
'files': dict(), # file_path -> {src_hash, compressed_hash}
|
||||
'logs': dict(), # log_id -> log_data
|
||||
'index': dict(), # unique_key -> log_id
|
||||
'max_id': 0,
|
||||
}
|
||||
)
|
||||
|
||||
# Create source-specific lock
|
||||
self.locks[source] = threading.Lock()
|
||||
|
||||
# Load existing data
|
||||
self._load_source(source)
|
||||
|
||||
def _source_file_path(self, source: str) -> Path:
|
||||
"""Get file path for a source's database file."""
|
||||
return self.data_dir / f'{source}_logs.json'
|
||||
|
||||
def _file_hash(self, file_path: Union[str, Path]) -> str:
|
||||
"""Compute SHA256 hash of a file's contents."""
|
||||
hasher = hashlib.sha256()
|
||||
file_path = Path(file_path)
|
||||
try:
|
||||
with file_path.open('rb') as f:
|
||||
while chunk := f.read(8192):
|
||||
hasher.update(chunk)
|
||||
return hasher.hexdigest()
|
||||
except OSError as e:
|
||||
self.logger.error(f'Failed to compute hash for {file_path}: {e}')
|
||||
return ''
|
||||
|
||||
def is_config_updated(self, source: str) -> bool:
|
||||
return bool(self.source_cfg[source] != self.shared_data[source]['config'])
|
||||
|
||||
def is_file_processed(self, source: str, src_path: Union[str, Path], compressed_path: Union[str, Path]) -> bool:
|
||||
"""
|
||||
Check if a file has already been processed.
|
||||
|
||||
Args:
|
||||
source: Log source/module
|
||||
src_path: Original source file path
|
||||
compressed_path: Compressed version path
|
||||
|
||||
Returns:
|
||||
True if file has been processed, False otherwise
|
||||
"""
|
||||
source = source.upper()
|
||||
if source not in self.shared_data:
|
||||
self.logger.error(f'Unknown source: {source}')
|
||||
return False
|
||||
|
||||
src_hash = self._file_hash(src_path)
|
||||
compressed_hash = self._file_hash(compressed_path) if Path(compressed_path).exists() else ''
|
||||
|
||||
with self.locks[source]:
|
||||
files = self.shared_data[source]['files']
|
||||
file_info = files.get(str(src_path))
|
||||
|
||||
# Check if file is registered and hashes match
|
||||
if file_info:
|
||||
if file_info.get('src_hash') == src_hash and file_info.get('compressed_hash') == compressed_hash:
|
||||
return True
|
||||
|
||||
# Update hashes if changed
|
||||
file_info['src_hash'] = src_hash
|
||||
if compressed_hash:
|
||||
file_info['compressed_hash'] = compressed_hash
|
||||
return False
|
||||
|
||||
# New file
|
||||
files[str(src_path)] = dict({'src_hash': src_hash, 'compressed_hash': compressed_hash})
|
||||
return False
|
||||
|
||||
def mark_file_processed(self, source: str, src_path: Union[str, Path], compressed_path: Union[str, Path]) -> None:
|
||||
"""
|
||||
Mark a file as successfully processed.
|
||||
|
||||
Args:
|
||||
source: Log source/module
|
||||
src_path: Original source file path
|
||||
compressed_path: Compressed version path
|
||||
"""
|
||||
source = source.upper()
|
||||
if source not in self.shared_data:
|
||||
return
|
||||
|
||||
src_hash = self._file_hash(src_path)
|
||||
compressed_hash = self._file_hash(compressed_path)
|
||||
|
||||
with self.locks[source]:
|
||||
files = self.shared_data[source]['files']
|
||||
file_info = files.get(str(src_path), dict())
|
||||
file_info.update({'src_hash': src_hash, 'compressed_hash': compressed_hash})
|
||||
files[str(src_path)] = file_info
|
||||
|
||||
def _load_source(self, source: str) -> None:
|
||||
"""Load source data from JSON file."""
|
||||
db_file = self._source_file_path(source)
|
||||
|
||||
# Create empty database if not exists
|
||||
if not db_file.exists():
|
||||
with db_file.open('w') as f:
|
||||
json.dump({'config': '', 'files': {}, 'logs': {}}, f)
|
||||
return
|
||||
|
||||
try:
|
||||
with db_file.open('r') as f:
|
||||
data = json.load(f)
|
||||
except (OSError, json.JSONDecodeError) as e:
|
||||
self.logger.error(f'Error loading {source} database: {e}')
|
||||
return
|
||||
|
||||
files = {}
|
||||
logs = {}
|
||||
indexes = {}
|
||||
|
||||
with self.locks[source]:
|
||||
source_db = self.shared_data[source]
|
||||
|
||||
# Load config
|
||||
source_db['config'] = data.get('config', '')
|
||||
|
||||
# Load files
|
||||
source_db['files'].clear()
|
||||
for path, info in data.get('files', {}).items():
|
||||
files[path] = dict(info)
|
||||
|
||||
source_db['files'].update(files)
|
||||
|
||||
# Load logs
|
||||
source_db['logs'].clear()
|
||||
source_db['index'].clear()
|
||||
max_id = 0
|
||||
|
||||
for log_id, log_data in data.get('logs', {}).items():
|
||||
log_id = int(log_id)
|
||||
logs[log_id] = dict(log_data)
|
||||
unique_key = self._log_unique_key(log_data)
|
||||
indexes[unique_key] = log_id
|
||||
if log_id > max_id:
|
||||
max_id = log_id
|
||||
source_db['logs'].update(logs)
|
||||
source_db['index'].update(indexes)
|
||||
source_db['max_id'] = max_id
|
||||
self.sources_updated[source] = len(logs)
|
||||
self.sources_exist[source] = bool(data.get('logs'))
|
||||
|
||||
self.logger.info(f'Loaded {len(data.get("logs", {}))} logs for {source}')
|
||||
|
||||
def _save_source(self, source: str) -> bool:
|
||||
"""Save source data to JSON file using atomic write."""
|
||||
db_file = self._source_file_path(source)
|
||||
|
||||
# Prepare data
|
||||
with self.locks[source]:
|
||||
source_db = self.shared_data[source]
|
||||
config = self.source_cfg[source]
|
||||
files_data = {path: dict(info) for path, info in source_db['files'].items()}
|
||||
logs_data = {log_id: dict(data) for log_id, data in source_db['logs'].items()}
|
||||
|
||||
data = {'config': config, 'files': files_data, 'logs': logs_data}
|
||||
|
||||
# Atomic write
|
||||
tmp_path = None
|
||||
try:
|
||||
with tempfile.NamedTemporaryFile(mode='w', dir=self.data_dir, delete=False) as tmp_file:
|
||||
json.dump(data, tmp_file, indent=2)
|
||||
tmp_path = tmp_file.name
|
||||
|
||||
# Replace original file
|
||||
os.replace(tmp_path, db_file)
|
||||
return True
|
||||
except (OSError, TypeError) as e:
|
||||
self.logger.error(f'Error saving {source} database: {e}')
|
||||
if tmp_path and Path(tmp_path).exists():
|
||||
Path(tmp_path).unlink()
|
||||
return False
|
||||
|
||||
def _log_unique_key(self, log_data: dict) -> tuple:
|
||||
"""
|
||||
Create a unique key for a log entry.
|
||||
|
||||
Args:
|
||||
log_data: Log entry dictionary
|
||||
|
||||
Returns:
|
||||
Unique key tuple
|
||||
"""
|
||||
return (log_data['tag'], log_data['format'], log_data['caller'], log_data['file'], log_data['line_number'])
|
||||
|
||||
def add_log(
|
||||
self,
|
||||
source: str,
|
||||
log_tag: str,
|
||||
log_format: str,
|
||||
log_line_number: int,
|
||||
hexify: bool,
|
||||
caller_func: str,
|
||||
caller_line: int,
|
||||
file_name: str,
|
||||
) -> tuple[int, int]:
|
||||
"""
|
||||
Add a new log entry to the database if it doesn't exist.
|
||||
|
||||
Args:
|
||||
source: Log source/module
|
||||
log_tag: Log tag
|
||||
log_format: Log format string
|
||||
log_line_number: Log Line number
|
||||
hexify: Whether the log can be hexified
|
||||
caller_func: Calling function name
|
||||
caller_line: Calling function line number
|
||||
file_name: Source file name
|
||||
|
||||
Returns:
|
||||
Tuple (result_code, log_id)
|
||||
"""
|
||||
if self._closed:
|
||||
return self.OPERATION_FAILED, 0
|
||||
|
||||
source = source.upper()
|
||||
if source not in self.shared_data:
|
||||
self.logger.error(f'Unknown source: {source}')
|
||||
return self.OPERATION_FAILED, 0
|
||||
|
||||
log_data = {
|
||||
'tag': log_tag,
|
||||
'format': log_format,
|
||||
'line_number': log_line_number,
|
||||
'hexify': hexify,
|
||||
'caller': caller_func,
|
||||
'caller_line': caller_line,
|
||||
'file': file_name,
|
||||
}
|
||||
|
||||
unique_key = self._log_unique_key(log_data)
|
||||
|
||||
with self.locks[source]:
|
||||
source_db = self.shared_data[source]
|
||||
|
||||
# Check if log exists
|
||||
if unique_key in source_db['index']:
|
||||
existing_id = source_db['index'][unique_key]
|
||||
return self.LOG_EXISTS, existing_id
|
||||
|
||||
# Create new log entry
|
||||
new_id = source_db['max_id'] + 1
|
||||
log_data['id'] = new_id
|
||||
|
||||
source_db['logs'][new_id] = dict(log_data)
|
||||
source_db['index'][unique_key] = new_id
|
||||
source_db['max_id'] = new_id
|
||||
|
||||
self.logger.info(f'Added new log [{source}]: ID={new_id}, Tag={log_tag}')
|
||||
return self.SUCCESS, new_id
|
||||
|
||||
def remove_log(self, source: str, log_id: int) -> bool:
|
||||
"""
|
||||
Remove a log entry from the database.
|
||||
|
||||
Args:
|
||||
source: Log source/module
|
||||
log_id: ID of log to remove
|
||||
|
||||
Returns:
|
||||
True if successful, False otherwise
|
||||
"""
|
||||
source = source.upper()
|
||||
if source not in self.shared_data:
|
||||
return False
|
||||
|
||||
with self.locks[source]:
|
||||
source_db = self.shared_data[source]
|
||||
|
||||
if log_id not in source_db['logs']:
|
||||
return False
|
||||
|
||||
# Remove from indexes
|
||||
log_data = dict(source_db['logs'][log_id])
|
||||
unique_key = self._log_unique_key(log_data)
|
||||
|
||||
if unique_key in source_db['index']:
|
||||
del source_db['index'][unique_key]
|
||||
del source_db['logs'][log_id]
|
||||
|
||||
if log_id == source_db['max_id']:
|
||||
source_db['max_id'] = max(source_db['logs'].keys()) if source_db['logs'] else 0
|
||||
|
||||
return True
|
||||
|
||||
def source_update_state(self, source: str) -> int:
|
||||
if self.is_config_updated(source):
|
||||
return self.SOURCE_LOG_UPDATE_FULL
|
||||
if self.sources_updated[source] == len(self.shared_data[source]['logs']):
|
||||
return self.SOURCE_LOG_UPDATE_NONE
|
||||
elif self.sources_updated[source] == 0 and len(self.shared_data[source]['logs']) != 0:
|
||||
return self.SOURCE_LOG_UPDATE_FULL
|
||||
else:
|
||||
return self.SOURCE_LOG_UPDATE_PARTIAL
|
||||
|
||||
def save_source(self, source: str) -> bool:
|
||||
"""Save a single source's data to file."""
|
||||
return self._save_source(source.upper())
|
||||
|
||||
def save_all(self) -> int:
|
||||
"""Save all sources' data to files."""
|
||||
self.logger.debug('Saving all sources...')
|
||||
success_count = 0
|
||||
|
||||
for source in self.sources:
|
||||
if (not self.is_config_updated(source)) and self.sources_updated[source] == len(
|
||||
self.shared_data[source]['logs']
|
||||
):
|
||||
self.logger.info(f'{source} has not updated data')
|
||||
continue
|
||||
if self._save_source(source):
|
||||
success_count += 1
|
||||
|
||||
self.logger.info(f'Saved {success_count}/{len(self.sources)} sources')
|
||||
return success_count
|
||||
|
||||
def safe_close(self) -> None:
|
||||
"""Safe close method that handles atexit callbacks."""
|
||||
if not self._closed:
|
||||
try:
|
||||
self.close()
|
||||
except Exception as e:
|
||||
# Log to stderr as logging may be shutdown
|
||||
print(f'Error during safe_close: {e}', flush=True)
|
||||
|
||||
def close(self) -> None:
|
||||
"""Cleanup resources."""
|
||||
if self._closed:
|
||||
return
|
||||
|
||||
self._closed = True
|
||||
|
||||
try:
|
||||
if not self.stop_event.is_set():
|
||||
self.stop_event.set()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
self.logger.info('Closing database manager...')
|
||||
self.stop_event.set()
|
||||
|
||||
# Final save
|
||||
self.logger.info('Performing final save...')
|
||||
self.save_all()
|
||||
|
||||
# Shutdown manager
|
||||
self.logger.info('Database manager closed')
|
||||
|
||||
def __enter__(self) -> 'LogDBManager':
|
||||
return self
|
||||
|
||||
def __exit__(
|
||||
self,
|
||||
exc_type: Union[type[BaseException], None],
|
||||
exc_val: Union[BaseException, None],
|
||||
exc_tb: Union[TracebackType, None],
|
||||
) -> None:
|
||||
self.close()
|
||||
@@ -0,0 +1,967 @@
|
||||
# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# The current project needs to support environments before Python 3.9,
|
||||
# and UP007 will prohibit the use of Tuple, Union, etc.
|
||||
# ruff: noqa: UP007
|
||||
|
||||
# The current project needs to support environments before Python 3.9,
|
||||
# Therefore, it is necessary to prohibit UP006 from automatically
|
||||
# changing the annotation type
|
||||
# ruff: noqa: UP006
|
||||
# ruff: noqa: UP035
|
||||
|
||||
"""
|
||||
BLE Log Compression Utility
|
||||
===========================
|
||||
This script processes Bluetooth source files to compress logging statements.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import enum
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import sys
|
||||
import textwrap
|
||||
import traceback
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
from typing import Dict
|
||||
from typing import List
|
||||
from typing import Tuple
|
||||
from typing import Union
|
||||
|
||||
import tree_sitter_c as tsc
|
||||
import yaml
|
||||
from c_format_parse import parse_format_string
|
||||
from inttypes_map import TYPES_MACRO_MAP
|
||||
from LogDBManager import LogDBManager
|
||||
|
||||
try:
|
||||
import importlib.metadata as meta
|
||||
|
||||
_TS_VER = tuple(map(int, meta.version('tree-sitter').split('.')[:2]))
|
||||
except Exception:
|
||||
_TS_VER = (0, 20)
|
||||
|
||||
if _TS_VER >= (0, 21):
|
||||
from tree_sitter import Language
|
||||
from tree_sitter import Node
|
||||
from tree_sitter import Parser
|
||||
from tree_sitter import Query
|
||||
from tree_sitter import Tree
|
||||
|
||||
if _TS_VER >= (0, 25):
|
||||
from tree_sitter import QueryCursor
|
||||
else:
|
||||
from tree_sitter import Language
|
||||
from tree_sitter import Parser
|
||||
from tree_sitter import Tree
|
||||
|
||||
# Initialize logger
|
||||
LOGGER = logging.getLogger('ble_log_compression')
|
||||
|
||||
# Global parser instances
|
||||
C_LANGUAGE: Union[Language, None] = None
|
||||
CLANG_PARSER: Union[Parser, None] = None
|
||||
|
||||
# Log source enumeration
|
||||
SOURCE_ENUM_MAP = {
|
||||
'BLE_HOST': 0,
|
||||
'BLE_MESH': 1,
|
||||
}
|
||||
|
||||
# Functions that require hex formatting
|
||||
HEX_FUNCTIONS = ['bt_hex'] # Used in Mesh and Audio modules
|
||||
|
||||
# C keywords to exclude from function names
|
||||
C_KEYWORDS = {
|
||||
'auto',
|
||||
'break',
|
||||
'case',
|
||||
'char',
|
||||
'const',
|
||||
'continue',
|
||||
'default',
|
||||
'do',
|
||||
'double',
|
||||
'else',
|
||||
'enum',
|
||||
'extern',
|
||||
'float',
|
||||
'for',
|
||||
'goto',
|
||||
'if',
|
||||
'int',
|
||||
'long',
|
||||
'register',
|
||||
'return',
|
||||
'short',
|
||||
'signed',
|
||||
'sizeof',
|
||||
'static',
|
||||
'struct',
|
||||
'switch',
|
||||
'typedef',
|
||||
'union',
|
||||
'unsigned',
|
||||
'void',
|
||||
'volatile',
|
||||
'while',
|
||||
}
|
||||
|
||||
FUNC_MACROS = {'__func__', '__FUNCTION__'}
|
||||
|
||||
LINE_MACROS = {
|
||||
'__LINE__',
|
||||
}
|
||||
|
||||
BLUEDROID_LOG_MODE_LEVEL_GET = {
|
||||
'BTM': 'btm_cb.trace_level',
|
||||
'L2CAP': 'l2cb.l2cap_trace_level',
|
||||
'GAP': 'gap_cb.trace_level',
|
||||
'GATT': 'gatt_cb.trace_level',
|
||||
'SMP': 'smp_cb.trace_level',
|
||||
'APPL': 'appl_trace_level',
|
||||
}
|
||||
|
||||
|
||||
class ARG_SIZE_TYPE(enum.IntEnum):
|
||||
U32 = 0
|
||||
STR = 1
|
||||
U64 = 2
|
||||
LZU32 = 3
|
||||
LZU64 = 4
|
||||
AZU32 = 5
|
||||
AZU64 = 6
|
||||
|
||||
|
||||
def TsInit() -> Tuple[Language, Parser]:
|
||||
if _TS_VER > (0, 21):
|
||||
lang = Language(tsc.language())
|
||||
parser = Parser(lang)
|
||||
return lang, parser
|
||||
else:
|
||||
lang = Language(tsc.language(), 'c')
|
||||
parser = Parser()
|
||||
parser.set_language(lang)
|
||||
return lang, parser
|
||||
|
||||
|
||||
def TsQueryByTree(language: Language, tree: Tree, query_str: str) -> Dict[str, List[Node]]:
|
||||
if _TS_VER == (0, 21):
|
||||
captures_res = language.query(query_str).captures(tree.root_node)
|
||||
elif _TS_VER > (0, 21) and _TS_VER < (0, 25):
|
||||
captures_res = Query(language, (query_str)).captures(tree.root_node)
|
||||
else:
|
||||
captures_res = QueryCursor(Query(language, (query_str))).captures(tree.root_node)
|
||||
|
||||
captures: Dict[str, List[Node]] = {}
|
||||
if isinstance(captures_res, list):
|
||||
for node, node_type in captures_res:
|
||||
if node_type not in captures:
|
||||
captures[node_type] = []
|
||||
captures[node_type].append(node)
|
||||
else:
|
||||
captures = captures_res
|
||||
return captures
|
||||
|
||||
|
||||
class LogCompressor:
|
||||
"""Main class for BLE log compression."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.bt_component_path = Path()
|
||||
self.build_dir = Path()
|
||||
self.bt_compressed_srcs_path = Path()
|
||||
self.config: dict[str, Any] = {}
|
||||
self.module_info: dict[str, Any] = {}
|
||||
|
||||
def init_parser(self) -> Parser:
|
||||
"""Initialize tree-sitter parser for C."""
|
||||
global C_LANGUAGE, CLANG_PARSER
|
||||
|
||||
C_LANGUAGE, CLANG_PARSER = TsInit()
|
||||
|
||||
return CLANG_PARSER
|
||||
|
||||
def extract_log_calls(self, code_content: bytes, log_tags: list[str]) -> list[dict]:
|
||||
"""
|
||||
Extract log statements from C source code.
|
||||
|
||||
Args:
|
||||
code_content: Source code as bytes
|
||||
log_tags: List of log tags to search for
|
||||
|
||||
Returns:
|
||||
List of dictionaries containing log information
|
||||
"""
|
||||
parser = self.init_parser()
|
||||
tree = parser.parse(code_content)
|
||||
function_map = self._get_function_boundaries(tree)
|
||||
return self._find_log_statements(tree, log_tags, function_map)
|
||||
|
||||
def _get_function_boundaries(self, tree: Tree) -> list[tuple[str, int, int, int]]:
|
||||
"""
|
||||
Identify function boundaries in the AST.
|
||||
|
||||
Returns:
|
||||
List of tuples (function_name, start_byte, end_byte, line_number)
|
||||
"""
|
||||
function_query = """
|
||||
[
|
||||
(function_declarator
|
||||
(identifier) @func_name
|
||||
)
|
||||
(declaration
|
||||
(function_declarator
|
||||
(identifier) @func_decls
|
||||
)
|
||||
)
|
||||
]
|
||||
"""
|
||||
captures: dict[str, list[Node]] = TsQueryByTree(C_LANGUAGE, tree, function_query)
|
||||
|
||||
# Filter valid function names
|
||||
func_names = [
|
||||
node
|
||||
for node in captures.get('func_name', [])
|
||||
if node not in captures.get('func_decls', []) and node.text.decode('utf-8') not in C_KEYWORDS
|
||||
]
|
||||
|
||||
# Sort by start byte
|
||||
func_names.sort(key=lambda node: node.start_byte)
|
||||
boundaries = []
|
||||
|
||||
for i, node in enumerate(func_names):
|
||||
func_name = node.text.decode('utf-8')
|
||||
start_byte = node.start_byte
|
||||
end_byte = func_names[i + 1].start_byte if i < len(func_names) - 1 else len(tree.root_node.text)
|
||||
line_number = node.start_point[0] + 1
|
||||
boundaries.append((func_name, start_byte, end_byte, line_number))
|
||||
|
||||
return boundaries
|
||||
|
||||
def _find_log_statements(
|
||||
self, tree: Tree, log_tags: list[str], function_boundaries: list[tuple[str, int, int, int]]
|
||||
) -> list[dict]:
|
||||
"""
|
||||
Find log statements in the AST.
|
||||
|
||||
Args:
|
||||
tree: Parsed AST tree
|
||||
log_tags: List of log tags to search for
|
||||
function_boundaries: Function boundaries list
|
||||
|
||||
Returns:
|
||||
List of log information dictionaries
|
||||
"""
|
||||
# Build pattern for matching log tags
|
||||
tag_pattern = '|'.join(log_tags)
|
||||
log_query = f"""
|
||||
(expression_statement
|
||||
(call_expression
|
||||
function: (identifier) @fname
|
||||
arguments: (argument_list) @args
|
||||
(#match? @fname "^({tag_pattern})$")
|
||||
) @log_stmt
|
||||
)
|
||||
"""
|
||||
captures: dict[str, list[Node]] = TsQueryByTree(C_LANGUAGE, tree, log_query)
|
||||
log_nodes = captures.get('log_stmt', [])
|
||||
|
||||
# It is necessary to ensure that the nodes
|
||||
# are sorted according to the starting bytes,
|
||||
# because only the nodes are ordered can ensure
|
||||
# that the subsequent calculation offset is correct.
|
||||
log_nodes.sort(key=lambda node: node.start_byte)
|
||||
logs = []
|
||||
|
||||
for node in log_nodes:
|
||||
try:
|
||||
log_info = self._process_log_node(node, function_boundaries)
|
||||
if log_info:
|
||||
logs.append(log_info)
|
||||
except Exception as e:
|
||||
LOGGER.error(f'Error processing log node: {e}\n{traceback.format_exc()}')
|
||||
raise
|
||||
|
||||
return logs
|
||||
|
||||
def _process_log_node(self, node: Node, function_boundaries: list[tuple[str, int, int, int]]) -> Union[dict, None]:
|
||||
"""
|
||||
Process a log AST node and extract information.
|
||||
|
||||
Args:
|
||||
node: Log statement AST node
|
||||
function_boundaries: Function boundaries list
|
||||
|
||||
Returns:
|
||||
Log information dictionary or None if invalid
|
||||
"""
|
||||
# Extract basic information
|
||||
tag_node = node.child_by_field_name('function')
|
||||
if not tag_node:
|
||||
return None
|
||||
|
||||
tag = tag_node.text.decode('utf-8')
|
||||
|
||||
args_node = node.child_by_field_name('arguments')
|
||||
if not args_node or args_node.type != 'argument_list':
|
||||
return None
|
||||
|
||||
# Initialize log info
|
||||
log_info = {
|
||||
'tag': (tag, tag_node.start_byte, tag_node.end_byte),
|
||||
'line_number': node.start_point[0] + 1,
|
||||
'arguments': [],
|
||||
'hexify': True,
|
||||
}
|
||||
|
||||
# Process format string (first argument)
|
||||
valid_arg_childrn: list[Node] = [n for n in args_node.named_children if n.type != 'comment']
|
||||
fmt_node = valid_arg_childrn[0] if len(valid_arg_childrn) > 0 else None
|
||||
if not fmt_node:
|
||||
return None
|
||||
|
||||
if fmt_node.type == 'concatenated_string':
|
||||
log_fmt = self._process_concatenated_string(fmt_node)
|
||||
elif fmt_node.type == 'string_literal':
|
||||
log_fmt = fmt_node.text.decode('utf-8')[1:-1] # Remove quotes
|
||||
else:
|
||||
return None
|
||||
|
||||
log_info['arguments'].append((f'"{log_fmt}"', fmt_node.start_byte, fmt_node.end_byte))
|
||||
|
||||
# Parse format tokens
|
||||
tokens = parse_format_string(f'"{log_fmt}"')
|
||||
tokens_tuple_map: list[int] = []
|
||||
for idx, tk in enumerate(tokens):
|
||||
if isinstance(tk, tuple):
|
||||
tokens_tuple_map.append(idx)
|
||||
|
||||
arguments: list[Node] = valid_arg_childrn[1:]
|
||||
|
||||
if len(arguments) != len(tokens_tuple_map):
|
||||
raise SyntaxError(f'LogSyntaxError:{node.text.decode("utf-8")}')
|
||||
|
||||
# Process each argument
|
||||
for i, (token, arg_node) in enumerate(zip([t for t in tokens if isinstance(t, tuple)], arguments)):
|
||||
arg_text = arg_node.text.decode('utf-8')
|
||||
log_info['arguments'].append((arg_text, arg_node.start_byte, arg_node.end_byte))
|
||||
|
||||
# Check if argument can be hexified
|
||||
# if not self._can_be_hexified(token, arg_node):
|
||||
# log_info['hexify'] = False
|
||||
|
||||
# Handle special identifiers
|
||||
if arg_text in FUNC_MACROS:
|
||||
token_list = list(token)
|
||||
token_list[6] = '@func' # Modify conversion char to special marker
|
||||
tokens[tokens_tuple_map[i]] = tuple(token_list)
|
||||
elif arg_text in LINE_MACROS:
|
||||
token_list = list(token)
|
||||
token_list[6] = '@line'
|
||||
tokens[tokens_tuple_map[i]] = tuple(token_list)
|
||||
|
||||
# Handle hex functions
|
||||
if (
|
||||
arg_node.type == 'call_expression'
|
||||
and arg_node.child_by_field_name('function')
|
||||
and arg_node.child_by_field_name('function').text.decode('utf-8') in HEX_FUNCTIONS
|
||||
):
|
||||
# Extract arguments of the hex function
|
||||
hex_args = arg_node.child_by_field_name('arguments')
|
||||
if hex_args and hex_args.named_child_count >= 2:
|
||||
buf_node = hex_args.named_children[0]
|
||||
len_node = hex_args.named_children[1]
|
||||
token_list = list(token)
|
||||
token_list[6] = f'@hex_func@{buf_node.text.decode("utf-8")}@{len_node.text.decode("utf-8")}'
|
||||
tokens[tokens_tuple_map[i]] = tuple(token_list)
|
||||
|
||||
log_info['argu_tokens'] = tokens
|
||||
|
||||
# Find calling function
|
||||
caller_info = self._find_calling_function(node.start_byte, function_boundaries)
|
||||
if not caller_info:
|
||||
return None
|
||||
|
||||
log_info.update(caller_info)
|
||||
return log_info
|
||||
|
||||
def _process_concatenated_string(self, node: Node) -> str:
|
||||
"""Process a concatenated string node into a single string."""
|
||||
parts = []
|
||||
for child in node.named_children:
|
||||
if child.type == 'identifier':
|
||||
identifier = child.text.decode('utf-8')
|
||||
if identifier in TYPES_MACRO_MAP:
|
||||
parts.append(TYPES_MACRO_MAP[identifier])
|
||||
else:
|
||||
raise ValueError(f'Unknown format macro: {identifier}')
|
||||
elif child.type == 'string_literal':
|
||||
parts.append(child.text.decode('utf-8')[1:-1]) # Remove quotes
|
||||
else:
|
||||
raise ValueError(f'Unsupported node in concatenated string: {child.type}')
|
||||
return ''.join(parts)
|
||||
|
||||
def _can_be_hexified(self, token: tuple[int, int, str, str, str, str, str], node: Node) -> bool:
|
||||
"""Determine if a node can be represented in hex format."""
|
||||
if token[-1] != 's':
|
||||
return True
|
||||
|
||||
if node.type == 'identifier' and node.text.decode('utf-8') in FUNC_MACROS:
|
||||
return True
|
||||
|
||||
if (
|
||||
node.type == 'call_expression'
|
||||
and node.child_by_field_name('function')
|
||||
and node.child_by_field_name('function').text.decode('utf-8') in HEX_FUNCTIONS
|
||||
):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def _find_calling_function(
|
||||
self, log_start: int, function_boundaries: list[tuple[str, int, int, int]]
|
||||
) -> Union[dict, None]:
|
||||
"""
|
||||
Find the function containing the log statement.
|
||||
|
||||
Args:
|
||||
log_start: Start byte of the log statement
|
||||
function_boundaries: List of function boundaries
|
||||
|
||||
Returns:
|
||||
Dictionary with caller information or None if not found
|
||||
"""
|
||||
for name, start, end, line in function_boundaries:
|
||||
if start <= log_start < end:
|
||||
return {'caller_name': name, 'caller_line_number': line}
|
||||
return None
|
||||
|
||||
def generate_compressed_macro(
|
||||
self, source: str, log_idx: int, tag: str, print_fmt: Union[str, None], log_info: dict
|
||||
) -> str:
|
||||
"""
|
||||
Generate a compressed log macro definition.
|
||||
|
||||
Args:
|
||||
source: Log source module
|
||||
log_idx: Unique log index
|
||||
tag: Original log tag
|
||||
print_fmt: Simplified format string
|
||||
log_info: Log information dictionary
|
||||
|
||||
Returns:
|
||||
Macro definition string
|
||||
"""
|
||||
if not log_idx:
|
||||
return ''
|
||||
|
||||
def generate_mesh_log_prefix(source: str, tag: str, print_statm: str) -> str:
|
||||
level = tag.split('_')[-1]
|
||||
mod = tag.split('_')[0]
|
||||
if level == 'ERR':
|
||||
level = 'ERROR'
|
||||
log_level = 'BLE_MESH_LOG_LEVEL_ERROR'
|
||||
elif level == 'WARN':
|
||||
level = 'WARN'
|
||||
log_level = 'BLE_MESH_LOG_LEVEL_WARN'
|
||||
elif level == 'INFO':
|
||||
level = 'INFO'
|
||||
log_level = 'BLE_MESH_LOG_LEVEL_INFO'
|
||||
elif level == 'DBG':
|
||||
level = 'DEBUG'
|
||||
log_level = 'BLE_MESH_LOG_LEVEL_DEBUG'
|
||||
else:
|
||||
LOGGER.error(f'Invalid log level {level}')
|
||||
return ''
|
||||
if mod == 'NET':
|
||||
used_log_levl = 'BLE_MESH_NET_BUF_LOG_LEVEL'
|
||||
used_log_mod = 'BLE_MESH_NET_BUF'
|
||||
else:
|
||||
used_log_levl = 'BLE_MESH_LOG_LEVEL'
|
||||
used_log_mod = 'BLE_MESH'
|
||||
return (
|
||||
f'{{do {{ if (({used_log_levl} >= {log_level}) &&'
|
||||
f' BLE_MESH_LOG_LEVEL_CHECK({used_log_mod}, {level})) {print_statm};}} while (0);}}\\\n'
|
||||
)
|
||||
|
||||
def generate_bluedroid_log_prefix(source: str, tag: str, print_statm: str) -> str:
|
||||
tag_info = tag.split('_')
|
||||
mod = tag_info[0]
|
||||
|
||||
return (
|
||||
f'{{if ({BLUEDROID_LOG_MODE_LEVEL_GET[mod]} >= BT_TRACE_LEVEL_{tag_info[-1]} &&'
|
||||
f' BT_LOG_LEVEL_CHECK({mod}, {tag_info[-1]})) {print_statm};}}\\\n'
|
||||
)
|
||||
|
||||
def generate_log_lvl_prefix(source: str, tag: str, print_statm: str) -> str:
|
||||
if source == 'BLE_MESH':
|
||||
return ' ' + generate_mesh_log_prefix(source, tag, print_statm)
|
||||
elif source == 'BLE_HOST': # only bluedroid host supported for now
|
||||
return ' ' + generate_bluedroid_log_prefix(source, tag, print_statm)
|
||||
else:
|
||||
LOGGER.error(f'Unknown source {source}')
|
||||
return ''
|
||||
|
||||
source_value = SOURCE_ENUM_MAP.get(source.upper())
|
||||
if source_value is None:
|
||||
raise ValueError(f'Invalid source: {source}')
|
||||
|
||||
macro = f'#define {tag}_{log_idx}(fmt, ...) {{\\\n'
|
||||
|
||||
if log_info['hexify']:
|
||||
# Count of arguments that are not special (__func__, __LINE__, etc.)
|
||||
arg_tokens = [t for t in log_info['argu_tokens'] if isinstance(t, tuple)]
|
||||
arg_count = len(arg_tokens)
|
||||
arguments = []
|
||||
sizes = []
|
||||
hex_func: list[str] = []
|
||||
|
||||
LOGGER.info(f'{arg_tokens}:{[a[0] for a in log_info["arguments"]]}')
|
||||
|
||||
for token, argument in zip(
|
||||
arg_tokens,
|
||||
[a[0] for a in log_info['arguments'][1:]],
|
||||
):
|
||||
# Skip special tokens
|
||||
if token[6] in ('@func', '@line'):
|
||||
arg_count -= 1
|
||||
continue
|
||||
|
||||
# Handle hex function
|
||||
if token[6].startswith('@hex_func'):
|
||||
if not hex_func:
|
||||
hex_func = []
|
||||
hex_func.append(token[6])
|
||||
arg_count -= 1
|
||||
continue
|
||||
|
||||
arguments.append(argument)
|
||||
|
||||
if token[6] == 'f' or token[5] == 'll': # float or long long
|
||||
sizes.append(f'{int(ARG_SIZE_TYPE.U64)}')
|
||||
elif token[6] == 's':
|
||||
sizes.append(f'{int(ARG_SIZE_TYPE.STR)}')
|
||||
else:
|
||||
sizes.append(f'{int(ARG_SIZE_TYPE.U32)}')
|
||||
|
||||
if arg_count > 0:
|
||||
size_str = ', '.join(sizes)
|
||||
arg_str = ', '.join(arguments).replace('\n', '')
|
||||
macro += generate_log_lvl_prefix(
|
||||
source,
|
||||
tag,
|
||||
(f'BLE_LOG_COMPRESSED_HEX_PRINT({source_value}, {log_idx}, {arg_count}, {size_str}, {arg_str})'),
|
||||
)
|
||||
|
||||
for idx, item in enumerate(hex_func):
|
||||
# hex_func format: @hex_func@buf@len
|
||||
parts = item.split('@')
|
||||
if len(parts) >= 4:
|
||||
buf = parts[2]
|
||||
buf_len = parts[3]
|
||||
macro += generate_log_lvl_prefix(
|
||||
source,
|
||||
tag,
|
||||
(f'BLE_LOG_COMPRESSED_HEX_PRINT_BUF({source_value}, {log_idx}, {idx}, {buf}, {buf_len})'),
|
||||
)
|
||||
else:
|
||||
macro += generate_log_lvl_prefix(
|
||||
source, tag, f'BLE_LOG_COMPRESSED_HEX_PRINT_WITH_ZERO_ARGUMENTS({source_value}, {log_idx})'
|
||||
)
|
||||
for idx, item in enumerate(hex_func):
|
||||
# hex_func format: @hex_func@buf@len
|
||||
parts = item.split('@')
|
||||
if len(parts) >= 4:
|
||||
buf = parts[2]
|
||||
buf_len = parts[3]
|
||||
macro += generate_log_lvl_prefix(
|
||||
source,
|
||||
tag,
|
||||
(f'BLE_LOG_COMPRESSED_HEX_PRINT_BUF({source_value}, {log_idx}, {idx}, {buf}, {buf_len})'),
|
||||
)
|
||||
if (
|
||||
'tags_with_preserve' in self.module_info[source]
|
||||
and tag in self.module_info[source]['tags_with_preserve']
|
||||
):
|
||||
macro += f' {tag}(fmt, ##__VA_ARGS__);\\\n'
|
||||
else:
|
||||
# Non-hexified log
|
||||
print_fmt = print_fmt or 'NULL'
|
||||
macro += f' BLE_LOG_COMPRESSED_PRINT({source_value}, {log_idx}, "{print_fmt}", ##__VA_ARGS__); \\\n'
|
||||
|
||||
macro += '}\n'
|
||||
return macro
|
||||
|
||||
def compress_file(self, file_info: tuple[str, str]) -> list[tuple[str, int, str]]:
|
||||
"""
|
||||
Process a single file for log compression.
|
||||
|
||||
Args:
|
||||
file_info: Tuple of (module_name, file_path)
|
||||
|
||||
Returns:
|
||||
List of generated macros (module, log_id, macro)
|
||||
"""
|
||||
module, file_path = file_info
|
||||
generated_macros = []
|
||||
|
||||
try:
|
||||
with open(file_path, 'rb') as f:
|
||||
content = f.read()
|
||||
|
||||
new_content = bytearray(content)
|
||||
logs = self.extract_log_calls(content, self.module_info[module]['tags'])
|
||||
LOGGER.info(f'Processing {file_path} - found {len(logs)} logs')
|
||||
offset = 0 # Track cumulative changes due to tag replacements
|
||||
|
||||
for log in logs:
|
||||
tag = log['tag'][0]
|
||||
|
||||
# Extract existing index if present
|
||||
if match := re.fullmatch(r'(.+)_([0-9A-F]{8})', tag):
|
||||
tag_base = match.group(1)
|
||||
file_index = match.group(2)
|
||||
else:
|
||||
tag_base = tag
|
||||
file_index = None
|
||||
|
||||
# Generate simplified format string
|
||||
no_buf_fmt: str = ''
|
||||
simple_fmt_list: list[str] = []
|
||||
hex_buffer_cnt = 0
|
||||
for token in log['argu_tokens']:
|
||||
if isinstance(token, tuple):
|
||||
if '@func' in token[6] or '@line' in token[6]:
|
||||
continue
|
||||
if '@hex_func' in token[6]:
|
||||
simple_fmt_list.append(f'@hex_buffer{hex_buffer_cnt}')
|
||||
no_buf_fmt += f'@hex_buffer{hex_buffer_cnt}'
|
||||
hex_buffer_cnt += 1
|
||||
continue
|
||||
simple_fmt_list.append(token[2])
|
||||
no_buf_fmt += token[2]
|
||||
else:
|
||||
no_buf_fmt += token
|
||||
simple_fmt_str = ' '.join(simple_fmt_list) if simple_fmt_list else None
|
||||
|
||||
# Add to database
|
||||
result, db_index = self.db_manager.add_log(
|
||||
source=module,
|
||||
log_tag=tag_base,
|
||||
log_format=no_buf_fmt if log['hexify'] else log['arguments'][0][0],
|
||||
log_line_number=log['line_number'],
|
||||
hexify=log['hexify'],
|
||||
caller_func=log['caller_name'],
|
||||
caller_line=log['caller_line_number'],
|
||||
file_name=os.path.basename(file_path),
|
||||
)
|
||||
|
||||
LOGGER.info(f'Got log tag {tag}, generated or quired idx {db_index}')
|
||||
|
||||
if result == LogDBManager.SUCCESS:
|
||||
LOGGER.info(f'Added new log: {db_index} - {tag_base}')
|
||||
elif result == LogDBManager.LOG_EXISTS:
|
||||
if file_index:
|
||||
if int(file_index, 16) != db_index:
|
||||
LOGGER.info(f'Updating index: {file_index} -> {db_index}')
|
||||
else:
|
||||
LOGGER.info(f'duplicate index: {file_index} == {db_index}')
|
||||
continue
|
||||
else:
|
||||
LOGGER.info(f'Recovery log index {db_index}')
|
||||
else:
|
||||
LOGGER.error(f'Database error for log: {tag_base}')
|
||||
continue
|
||||
|
||||
# Update tag in content
|
||||
new_tag_bytes = f'{tag_base}_{db_index}'.encode()
|
||||
tag_start, tag_end = log['tag'][1], log['tag'][2]
|
||||
new_content[offset + tag_start : offset + tag_end] = new_tag_bytes
|
||||
offset += len(new_tag_bytes) - (tag_end - tag_start)
|
||||
|
||||
# Generate macro if this is a new log or index changed
|
||||
if result == LogDBManager.SUCCESS or file_index or self.db_manager.is_config_updated(module):
|
||||
macro = self.generate_compressed_macro(module, db_index, tag_base, simple_fmt_str, log)
|
||||
generated_macros.append((module, db_index, macro))
|
||||
|
||||
# Write updated content
|
||||
with open(file_path, 'wb') as f_out:
|
||||
f_out.write(new_content)
|
||||
|
||||
except Exception as e:
|
||||
LOGGER.error(f'Error processing {file_path}: {e}\n{traceback.format_exc()}')
|
||||
raise
|
||||
|
||||
return generated_macros
|
||||
|
||||
def prepare_source_files(self, srcs: list[str]) -> None:
|
||||
"""
|
||||
Prepare source files for processing.
|
||||
|
||||
Args:
|
||||
srcs: List of source file paths
|
||||
"""
|
||||
for module, info in self.module_info.items():
|
||||
code_dirs = '|'.join(info['code_path'])
|
||||
pattern = re.compile(f'({code_dirs}).*\\.c$')
|
||||
info['files_to_process'] = []
|
||||
compressed_file_cnt = 0
|
||||
total_cnt = 0
|
||||
for src in srcs:
|
||||
if pattern.match(src):
|
||||
src_path = self.bt_component_path / src
|
||||
dest_path = self.bt_compressed_srcs_path / src
|
||||
temp_path = f'{dest_path}.tmp'
|
||||
total_cnt += 1
|
||||
# Skip if already processed
|
||||
if self.db_manager.is_file_processed(
|
||||
module, src_path, temp_path
|
||||
) and not self.db_manager.is_config_updated(module):
|
||||
compressed_file_cnt += 1
|
||||
continue
|
||||
|
||||
# Ensure directory exists
|
||||
os.makedirs(os.path.dirname(temp_path), exist_ok=True)
|
||||
shutil.copy2(src_path, temp_path)
|
||||
info['files_to_process'].append(temp_path)
|
||||
LOGGER.info(f'Prepared: {src}')
|
||||
LOGGER.info(f'Compressed cnt {compressed_file_cnt} {total_cnt}')
|
||||
if compressed_file_cnt == total_cnt:
|
||||
print(
|
||||
f'All source files in module {module} have been compressed\n', flush=True, end='', file=sys.stdout
|
||||
)
|
||||
else:
|
||||
print(
|
||||
f'Found {len(info["files_to_process"])} source files in module {module} requiring compression\n',
|
||||
flush=True,
|
||||
end='',
|
||||
file=sys.stdout,
|
||||
)
|
||||
LOGGER.info('Source file preparation complete')
|
||||
|
||||
def generate_log_index_header(self, module: str, macros: list[tuple[int, str]]) -> None:
|
||||
"""
|
||||
Generate or update the log index header file.
|
||||
|
||||
Args:
|
||||
module: Module name
|
||||
macros: List of (log_id, macro_definition)
|
||||
"""
|
||||
# header_path = self.bt_component_path / self.module_info[module]['log_index_path']
|
||||
header_path = self.build_dir / Path('ble_log') / Path('include') / self.module_info[module]['log_index_file']
|
||||
# Create directory if needed
|
||||
header_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
update_state = self.db_manager.source_update_state(source=module)
|
||||
if update_state == self.db_manager.SOURCE_LOG_UPDATE_NONE:
|
||||
return
|
||||
elif update_state == self.db_manager.SOURCE_LOG_UPDATE_FULL:
|
||||
# Header template
|
||||
header_content = (
|
||||
textwrap.dedent(f"""
|
||||
/*
|
||||
* SPDX-FileCopyrightText: {datetime.now().year} Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef __{module.upper()}_INTERNAL_LOG_INDEX_H
|
||||
#define __{module.upper()}_INTERNAL_LOG_INDEX_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// Compression function declarations
|
||||
extern int ble_log_compressed_hex_print
|
||||
(uint32_t source, uint32_t log_index, size_t args_size_cnt, ...);
|
||||
extern int ble_log_compressed_hex_print_buf
|
||||
(uint8_t source, uint32_t log_index, uint8_t buf_idx, const uint8_t *buf, size_t len);
|
||||
|
||||
// Compression macros
|
||||
#define BLE_LOG_COMPRESSED_HEX_PRINT(source, log_index, args_cnt, ...) \\
|
||||
ble_log_compressed_hex_print(source, log_index, args_cnt, ##__VA_ARGS__)
|
||||
#define BLE_LOG_COMPRESSED_HEX_PRINT_BUF(source, log_index, buf_idx, buf, len) \\
|
||||
ble_log_compressed_hex_print_buf(source, log_index, buf_idx, (const uint8_t *)buf, len)
|
||||
#define BLE_LOG_COMPRESSED_HEX_PRINT_WITH_ZERO_ARGUMENTS(source, log_index) \\
|
||||
ble_log_compressed_hex_print(source, log_index, 0)
|
||||
""").strip()
|
||||
+ '\n\n'
|
||||
)
|
||||
# Add sorted macros
|
||||
for log_id, macro_def in sorted(macros, key=lambda x: x[0]):
|
||||
header_content += macro_def + '\n'
|
||||
|
||||
header_content += f'#endif // __{module.upper()}_INTERNAL_LOG_INDEX_H\n'
|
||||
|
||||
with open(header_path, 'w') as f:
|
||||
f.write(header_content)
|
||||
else:
|
||||
append_content = ''
|
||||
log_idx_set: dict[int, int] = dict()
|
||||
for log_id, macro_def in sorted(macros, key=lambda x: x[0]):
|
||||
append_content += macro_def + '\n'
|
||||
log_idx_set[log_id] = 1
|
||||
with open(header_path, encoding='utf-8') as f:
|
||||
lines = f.readlines()
|
||||
log_idx_pattern = re.compile(r'#define .+(\d+)\(fmt,')
|
||||
for idx, line in enumerate(lines):
|
||||
if line.strip().startswith('#define'):
|
||||
res = log_idx_pattern.match(line)
|
||||
if res:
|
||||
li = int(res.group(1))
|
||||
if li in log_idx_set:
|
||||
raise ValueError(
|
||||
f'The generated log index{li} andlog_index in the header file have duplicates'
|
||||
)
|
||||
|
||||
if line.strip().startswith('#endif'):
|
||||
break
|
||||
else:
|
||||
raise RuntimeError('#endif not found')
|
||||
lines.insert(idx, append_content)
|
||||
with open(header_path, 'w', encoding='utf-8') as f:
|
||||
f.writelines(lines)
|
||||
LOGGER.info(f'Generated log index header: {header_path}')
|
||||
|
||||
def load_config(self, config_path: str, module_names: list[str]) -> None:
|
||||
"""
|
||||
Load and validate log configuration.
|
||||
|
||||
Args:
|
||||
config_path: Path to configuration file
|
||||
module_names: List of module names to load
|
||||
"""
|
||||
with open(config_path, encoding='utf-8') as f:
|
||||
config = yaml.safe_load(f)
|
||||
|
||||
# Extract global config
|
||||
log_config = config.get('log_config', {})
|
||||
for key, value in log_config.items():
|
||||
if key != 'modules':
|
||||
self.config[key] = value
|
||||
|
||||
# Extract module configs
|
||||
modules = log_config.get('modules', {})
|
||||
for module in module_names:
|
||||
if module in modules:
|
||||
self.module_info[module] = modules[module]
|
||||
print(f'Found module {module} for compression\n', flush=True, end='', file=sys.stdout)
|
||||
else:
|
||||
LOGGER.warning(f"Skipping module '{module}' - config not found")
|
||||
|
||||
def main(self) -> int:
|
||||
"""Main entry point for the compression utility."""
|
||||
parser = argparse.ArgumentParser(description='BLE Log Compression Utility')
|
||||
subparsers = parser.add_subparsers(dest='command', required=True)
|
||||
|
||||
compress_parser = subparsers.add_parser('compress')
|
||||
compress_parser.add_argument('--srcs', required=True, help='Semicolon-separated source file paths')
|
||||
compress_parser.add_argument('--bt_path', required=True, help='Bluetooth component root path')
|
||||
compress_parser.add_argument('--module', required=True, help='Semicolon-separated module names')
|
||||
compress_parser.add_argument('--build_path', required=True, help='Build output directory')
|
||||
compress_parser.add_argument('--compressed_srcs_path', required=True, help='Directory for processed sources')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# Setup paths
|
||||
self.bt_component_path = Path(args.bt_path)
|
||||
self.build_dir = Path(args.build_path)
|
||||
self.bt_compressed_srcs_path = Path(args.compressed_srcs_path)
|
||||
|
||||
# Create directories
|
||||
(self.build_dir / 'ble_log').mkdir(parents=True, exist_ok=True)
|
||||
self.bt_compressed_srcs_path.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# Configure logging
|
||||
log_file = self.build_dir / 'ble_log' / f'ble_script_log_{datetime.now().strftime("%y%m%d_%H%M%S")}.log'
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
||||
handlers=[logging.FileHandler(log_file, mode='w')],
|
||||
)
|
||||
|
||||
# Load configuration
|
||||
modules = args.module.split(';')
|
||||
config_path = self.build_dir / 'ble_log/module_info.yml'
|
||||
self.load_config(str(config_path), modules)
|
||||
|
||||
# Initialize database
|
||||
db_path = self.build_dir / self.config.get('db_path', 'log_db')
|
||||
db_manager = LogDBManager(
|
||||
data_dir=str(db_path),
|
||||
sources={source: str(config) for source, config in self.module_info.items()},
|
||||
logger=LOGGER,
|
||||
)
|
||||
|
||||
self.db_manager = db_manager
|
||||
|
||||
# Prepare source files
|
||||
src_list = args.srcs.split(';')
|
||||
self.prepare_source_files(src_list)
|
||||
|
||||
# Collect files to process
|
||||
files_to_process = []
|
||||
for module, info in self.module_info.items():
|
||||
files_to_process.extend([(module, path) for path in info['files_to_process']])
|
||||
|
||||
if not files_to_process:
|
||||
LOGGER.info('No files to process')
|
||||
print('No source files require compression; exiting log compression\n', flush=True, end='', file=sys.stdout)
|
||||
for root, _, files in os.walk(self.bt_compressed_srcs_path):
|
||||
for name in files:
|
||||
if name.endswith('.tmp'):
|
||||
file_src = os.path.join(root, name)
|
||||
dst_path = os.path.join(root, name[: -len('.tmp')])
|
||||
shutil.copy2(file_src, dst_path)
|
||||
LOGGER.info(f'Recovery src {file_src} dst {dst_path}')
|
||||
db_manager.close()
|
||||
return 0
|
||||
|
||||
all_macros: dict[str, list[tuple[int, str]]] = {}
|
||||
files_to_process.sort(key=lambda x: x[1])
|
||||
try:
|
||||
compressed_log_count = 0
|
||||
for needs_compressed_file in files_to_process:
|
||||
file_macros = self.compress_file(needs_compressed_file)
|
||||
compressed_log_count += len(file_macros)
|
||||
for module, log_id, macro in file_macros:
|
||||
all_macros.setdefault(module, []).append((log_id, macro))
|
||||
print(f'{compressed_log_count} ble log(s) compressed\n', flush=True, end='', file=sys.stdout)
|
||||
except Exception as e:
|
||||
LOGGER.error(f'Processing failed: {e}')
|
||||
db_manager.close()
|
||||
return 1
|
||||
|
||||
# Generate headers
|
||||
for module, macros in all_macros.items():
|
||||
self.generate_log_index_header(module, macros)
|
||||
print('Header file for compressed logs generated\n', flush=True, end='', file=sys.stdout)
|
||||
|
||||
# Mark files as processed
|
||||
for module, info in self.module_info.items():
|
||||
for temp_path in info['files_to_process']:
|
||||
src_path = self.bt_component_path / os.path.relpath(temp_path[:-4], self.bt_compressed_srcs_path)
|
||||
db_manager.mark_file_processed(module, src_path, temp_path)
|
||||
for root, _, files in os.walk(self.bt_compressed_srcs_path):
|
||||
for name in files:
|
||||
if name.endswith('.tmp'):
|
||||
file_src = os.path.join(root, name)
|
||||
dst_path = os.path.join(root, name[: -len('.tmp')])
|
||||
shutil.copy2(file_src, dst_path)
|
||||
LOGGER.info(f'Recovery src {file_src} dst {dst_path}')
|
||||
db_manager.close()
|
||||
LOGGER.info('Compression completed successfully')
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
print('Log compression underway, please wait...\n', flush=True, end='', file=sys.stdout)
|
||||
compressor = LogCompressor()
|
||||
exit(compressor.main())
|
||||
@@ -0,0 +1,268 @@
|
||||
# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# ruff: noqa: UP007
|
||||
"""
|
||||
Format String Parser
|
||||
====================
|
||||
Parses C-style format strings and handles argument formatting for log compression.
|
||||
"""
|
||||
|
||||
import struct
|
||||
from typing import Union
|
||||
|
||||
|
||||
def parse_format_string(format_str: str) -> list[Union[str, tuple[int, int, str, str, str, str, str]]]:
|
||||
"""
|
||||
Parse a format string into tokens.
|
||||
|
||||
Args:
|
||||
format_str: C-style format string
|
||||
|
||||
Returns:
|
||||
List of tokens (strings or format spec tuples)
|
||||
"""
|
||||
tokens: list[Union[str, tuple[int, int, str, str, str, str, str]]] = []
|
||||
i = 0
|
||||
n = len(format_str)
|
||||
|
||||
while i < n:
|
||||
if format_str[i] == '%':
|
||||
start = i
|
||||
i += 1
|
||||
|
||||
# Handle escaped %
|
||||
if i < n and format_str[i] == '%':
|
||||
tokens.append('%')
|
||||
i += 1
|
||||
continue
|
||||
|
||||
# Parse flags
|
||||
flags = ''
|
||||
while i < n and format_str[i] in '-+ #0':
|
||||
flags += format_str[i]
|
||||
i += 1
|
||||
|
||||
# Parse width
|
||||
width = ''
|
||||
while i < n and format_str[i].isdigit():
|
||||
width += format_str[i]
|
||||
i += 1
|
||||
|
||||
# Parse precision
|
||||
precision = ''
|
||||
if i < n and format_str[i] == '.':
|
||||
i += 1
|
||||
while i < n and format_str[i].isdigit():
|
||||
precision += format_str[i]
|
||||
i += 1
|
||||
|
||||
# Parse length modifier
|
||||
length = ''
|
||||
if i < n and format_str[i] in 'zhl':
|
||||
length += format_str[i]
|
||||
i += 1
|
||||
# Handle double length (e.g., ll)
|
||||
if i < n and format_str[i] == 'l' and length == 'l':
|
||||
length += 'l'
|
||||
i += 1
|
||||
|
||||
if i < n and format_str[i] in 'diuoxXfcsplL':
|
||||
conv_char = format_str[i]
|
||||
i += 1
|
||||
full_spec = format_str[start:i]
|
||||
tokens.append((start, i, full_spec, flags, width, length, conv_char))
|
||||
else:
|
||||
tokens.append(format_str[start:i])
|
||||
else:
|
||||
# Regular text
|
||||
start = i
|
||||
while i < n and format_str[i] != '%':
|
||||
i += 1
|
||||
tokens.append(format_str[start:i])
|
||||
|
||||
return tokens
|
||||
|
||||
|
||||
def format_integer(value: int, conv_char: str, flags: str, width: str, length_mod: str) -> str:
|
||||
"""
|
||||
Format an integer value according to format specifiers.
|
||||
|
||||
Args:
|
||||
value: Integer value
|
||||
conv_char: Conversion character (d, i, u, o, x, X)
|
||||
flags: Format flags
|
||||
width: Minimum width
|
||||
length_mod: Length modifier
|
||||
|
||||
Returns:
|
||||
Formatted string
|
||||
"""
|
||||
# Determine base
|
||||
base = 10
|
||||
uppercase = False
|
||||
if conv_char in 'xX':
|
||||
base = 16
|
||||
uppercase = conv_char == 'X'
|
||||
elif conv_char == 'o':
|
||||
base = 8
|
||||
|
||||
# Generate number string
|
||||
if base == 16:
|
||||
num_str = format(value, 'X' if uppercase else 'x')
|
||||
elif base == 8:
|
||||
num_str = format(value, 'o')
|
||||
else: # decimal
|
||||
num_str = str(value)
|
||||
|
||||
# Add prefix
|
||||
prefix = ''
|
||||
if '#' in flags and value != 0:
|
||||
if base == 16:
|
||||
prefix = '0X' if uppercase else '0x'
|
||||
elif base == 8:
|
||||
prefix = '0'
|
||||
|
||||
# Apply width and padding
|
||||
total_len = len(prefix) + len(num_str)
|
||||
width_val = int(width) if width else 0
|
||||
|
||||
if width_val > total_len:
|
||||
padding = width_val - total_len
|
||||
if '0' in flags and '-' not in flags:
|
||||
num_str = num_str.zfill(padding + len(num_str))
|
||||
else:
|
||||
pad_char = ' ' * padding
|
||||
if '-' in flags:
|
||||
num_str = prefix + num_str + pad_char
|
||||
prefix = ''
|
||||
else:
|
||||
num_str = pad_char + prefix + num_str
|
||||
prefix = ''
|
||||
|
||||
return prefix + num_str
|
||||
|
||||
|
||||
def parse_compressed_arguments(byte_sequence: bytes, format_str: str) -> str:
|
||||
"""
|
||||
Parse compressed log arguments into formatted string.
|
||||
|
||||
Args:
|
||||
byte_sequence: Compressed argument bytes
|
||||
format_str: Original format string
|
||||
|
||||
Returns:
|
||||
Formatted log string
|
||||
|
||||
Raises:
|
||||
ValueError: If the input is invalid
|
||||
"""
|
||||
if len(byte_sequence) < 2:
|
||||
raise ValueError('Insufficient bytes for header')
|
||||
|
||||
# Parse header
|
||||
header = (byte_sequence[0] << 8) | byte_sequence[1]
|
||||
type_flag = (header >> 15) & 0x01
|
||||
arg_count = header & 0x7FFF
|
||||
|
||||
if type_flag != 1:
|
||||
raise ValueError(f'Unsupported type flag: {type_flag}')
|
||||
|
||||
# Parse size list
|
||||
size_bytes_needed = (arg_count + 1) // 2
|
||||
if len(byte_sequence) < 2 + size_bytes_needed:
|
||||
raise ValueError('Insufficient bytes for size list')
|
||||
|
||||
size_bytes = byte_sequence[2 : 2 + size_bytes_needed]
|
||||
arg_sizes = []
|
||||
|
||||
for i in range(arg_count):
|
||||
byte_index = i // 2
|
||||
if i % 2 == 0:
|
||||
size = (size_bytes[byte_index] >> 4) & 0x0F
|
||||
else:
|
||||
size = size_bytes[byte_index] & 0x0F
|
||||
arg_sizes.append(size)
|
||||
|
||||
# Parse arguments
|
||||
args = []
|
||||
pos = 2 + size_bytes_needed
|
||||
|
||||
for size in arg_sizes:
|
||||
if pos + size > len(byte_sequence):
|
||||
raise ValueError('Insufficient bytes for arguments')
|
||||
|
||||
args.append(byte_sequence[pos : pos + size])
|
||||
pos += size
|
||||
|
||||
# Parse format string
|
||||
tokens = parse_format_string(format_str)
|
||||
output = []
|
||||
arg_index = 0
|
||||
|
||||
for token in tokens:
|
||||
if isinstance(token, tuple):
|
||||
start, end, flags, width, precision, length_mod, conv_char = token
|
||||
|
||||
if conv_char == '%':
|
||||
output.append('%')
|
||||
else:
|
||||
if arg_index >= len(args):
|
||||
raise ValueError('Not enough arguments for format string')
|
||||
|
||||
arg_bytes = args[arg_index]
|
||||
arg_index += 1
|
||||
|
||||
# Character type
|
||||
if conv_char == 'c':
|
||||
# Pad to 4 bytes for unpacking
|
||||
padded = arg_bytes.ljust(4, b'\x00')
|
||||
char_code = struct.unpack('>I', padded)[0]
|
||||
output.append(chr(char_code))
|
||||
|
||||
# Pointer type
|
||||
elif conv_char == 'p':
|
||||
ptr_value = int.from_bytes(arg_bytes, 'big', signed=False)
|
||||
output.append(hex(ptr_value))
|
||||
|
||||
# Floating point types
|
||||
elif conv_char in 'fFeEgGaA':
|
||||
if len(arg_bytes) == 4:
|
||||
float_value = struct.unpack('>f', arg_bytes)[0]
|
||||
elif len(arg_bytes) == 8:
|
||||
float_value = struct.unpack('>d', arg_bytes)[0]
|
||||
else:
|
||||
raise ValueError(f'Unsupported float size: {len(arg_bytes)} bytes')
|
||||
output.append(str(float_value))
|
||||
|
||||
# Integer types
|
||||
elif conv_char in 'diuoxX':
|
||||
signed = conv_char in 'di'
|
||||
|
||||
# Determine expected size
|
||||
if length_mod == 'll':
|
||||
expected_size = 8
|
||||
elif length_mod in ('l', 'z', 'j', 't') or conv_char == 'p':
|
||||
expected_size = 4
|
||||
else:
|
||||
expected_size = len(arg_bytes)
|
||||
|
||||
# Pad to expected size
|
||||
if len(arg_bytes) < expected_size:
|
||||
if signed and arg_bytes and (arg_bytes[0] & 0x80):
|
||||
# Sign extension for negative numbers
|
||||
pad = b'\xff' * (expected_size - len(arg_bytes))
|
||||
else:
|
||||
pad = b'\x00' * (expected_size - len(arg_bytes))
|
||||
arg_bytes = pad + arg_bytes
|
||||
elif len(arg_bytes) > expected_size:
|
||||
arg_bytes = arg_bytes[:expected_size]
|
||||
|
||||
# Convert to integer
|
||||
int_value = int.from_bytes(arg_bytes, 'big', signed=signed)
|
||||
output.append(format_integer(int_value, conv_char, flags, width, length_mod))
|
||||
else:
|
||||
raise ValueError(f'Unsupported conversion: {conv_char}')
|
||||
else:
|
||||
output.append(token)
|
||||
|
||||
return ''.join(output)
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
log_config:
|
||||
db_path: "ble_log/ble_log_database"
|
||||
|
||||
modules:
|
||||
BLE_MESH:
|
||||
description: "BLE Mesh"
|
||||
code_path: [@BLE_MESH_CODE_PATH@]
|
||||
log_index_file: @BLE_MESH_LOG_INDEX_HEADER@
|
||||
tags: [@BLE_MESH_TAGS@]
|
||||
tags_with_preserve: [@BLE_MESH_TAGS_PRESERVE@]
|
||||
|
||||
BLE_HOST:
|
||||
description: "BLE Host"
|
||||
code_path: [@HOST_CODE_PATH@]
|
||||
log_index_file: @HOST_LOG_INDEX_HEADER@
|
||||
tags: [@BLE_HOST_TAGS@]
|
||||
tags_with_preserve: [@BLE_HOST_TAGS_PRESERVE@]
|
||||
@@ -0,0 +1,139 @@
|
||||
# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
try:
|
||||
import tree_sitter_c
|
||||
except ModuleNotFoundError:
|
||||
tree_sitter_c = None
|
||||
try:
|
||||
import tree_sitter
|
||||
except ModuleNotFoundError:
|
||||
tree_sitter = None
|
||||
import platform
|
||||
import sys
|
||||
from importlib.metadata import version
|
||||
from pathlib import Path
|
||||
|
||||
from ble_log_compress import TsInit
|
||||
from ble_log_compress import TsQueryByTree
|
||||
|
||||
IDF_PATH = Path(Path(__file__).resolve().parent / Path('../../../../../../')).resolve()
|
||||
|
||||
TEST_C_STR = b"""
|
||||
void test_func(void);
|
||||
int main(void) {
|
||||
printf("Hello world\n");
|
||||
return 0;
|
||||
}
|
||||
"""
|
||||
|
||||
TEST_FUNCTION_QUERY = """
|
||||
[
|
||||
(function_declarator
|
||||
(identifier) @func_name
|
||||
)
|
||||
(declaration
|
||||
(function_declarator
|
||||
(identifier) @func_decls
|
||||
)
|
||||
)
|
||||
]
|
||||
"""
|
||||
TEST_LOG_QUERY = """
|
||||
(expression_statement
|
||||
(call_expression
|
||||
function: (identifier) @fname
|
||||
arguments: (argument_list) @args
|
||||
(#match? @fname "^(printf)$")
|
||||
) @log_stmt
|
||||
)
|
||||
"""
|
||||
|
||||
|
||||
def check_py_version(min_version: str = '3.8.0') -> None:
|
||||
cur_str = platform.python_version()
|
||||
cur_tuple = tuple(map(int, cur_str.split('.')))
|
||||
min_tuple = tuple(map(int, min_version.split('.')))
|
||||
|
||||
if min_tuple > cur_tuple:
|
||||
print(
|
||||
('Please use Python 3.8 or above'),
|
||||
file=sys.stderr,
|
||||
)
|
||||
exit(1)
|
||||
|
||||
|
||||
def validate() -> None:
|
||||
if tree_sitter is None:
|
||||
print(
|
||||
(
|
||||
'tree_sitter import failed, please check whether the package is installed correctly,'
|
||||
'Please refer to the file:'
|
||||
f'{IDF_PATH}/components/bt/common/ble_log/log_compression/scripts/install.en.md'
|
||||
' for installation instructions.'
|
||||
),
|
||||
file=sys.stderr,
|
||||
)
|
||||
exit(1)
|
||||
if tree_sitter_c is None:
|
||||
print(
|
||||
(
|
||||
'tree_sitter_c import failed, '
|
||||
'please check whether the package is installed correctly,'
|
||||
'Please refer to the file:'
|
||||
f'{IDF_PATH}/components/bt/common/ble_log/log_compression/scripts/install.en.md'
|
||||
' for installation instructions.'
|
||||
),
|
||||
file=sys.stderr,
|
||||
)
|
||||
exit(1)
|
||||
|
||||
|
||||
def test_parse() -> None:
|
||||
try:
|
||||
lang, parser = TsInit()
|
||||
tree = parser.parse(TEST_C_STR)
|
||||
captures = TsQueryByTree(lang, tree, TEST_LOG_QUERY)
|
||||
|
||||
assert len(captures.keys()) == 3
|
||||
assert len(captures.values()) == 3
|
||||
assert 'log_stmt' in captures.keys()
|
||||
assert 'fname' in captures.keys()
|
||||
assert 'args' in captures.keys()
|
||||
assert captures['log_stmt'][0].type == 'call_expression'
|
||||
assert captures['log_stmt'][0].start_point == (3, 4)
|
||||
assert captures['log_stmt'][0].end_point == (4, 2)
|
||||
|
||||
captures = TsQueryByTree(lang, tree, TEST_FUNCTION_QUERY)
|
||||
print(captures, file=sys.stderr)
|
||||
assert len(captures.keys()) == 2
|
||||
assert len(captures.values()) == 2
|
||||
assert 'func_decls' in captures.keys()
|
||||
assert 'func_name' in captures.keys()
|
||||
assert len(captures['func_name']) == 2
|
||||
assert len(captures['func_decls']) == 1
|
||||
assert captures['func_name'][0].type == 'identifier'
|
||||
assert captures['func_name'][0].start_point == (1, 5)
|
||||
assert captures['func_name'][0].end_point == (1, 14)
|
||||
|
||||
except Exception:
|
||||
print(
|
||||
(
|
||||
f'Code parsing error,'
|
||||
f'please provide the following information to Espressif to help you solve the problem'
|
||||
f'tree-sitter version: {version(tree_sitter)} '
|
||||
f'tree-sitter-c version: {version(tree_sitter_c)} '
|
||||
f'python version: {platform.python_version()} ',
|
||||
f'os_system: {platform.system()} ',
|
||||
f'os_release: {platform.release()} ',
|
||||
f'os_version: {platform.version()} ',
|
||||
f'machine: {platform.machine()}',
|
||||
),
|
||||
file=sys.stderr,
|
||||
)
|
||||
exit(1)
|
||||
|
||||
|
||||
check_py_version()
|
||||
validate()
|
||||
test_parse()
|
||||
exit(0)
|
||||
@@ -0,0 +1,166 @@
|
||||
# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
"""
|
||||
用于适配标准化打印
|
||||
file_path: /usr/include/inttypes.h
|
||||
"""
|
||||
|
||||
__PRI64_PREFIX = 'll'
|
||||
__PRIPTR_PREFIX = ''
|
||||
|
||||
TYPES_MACRO_MAP = {
|
||||
'PRId8': 'd',
|
||||
'PRId16': 'd',
|
||||
'PRId32': 'd',
|
||||
'PRId64': __PRI64_PREFIX + 'd',
|
||||
'PRIdLEAST8': 'd',
|
||||
'PRIdLEAST16': 'd',
|
||||
'PRIdLEAST32': 'd',
|
||||
'PRIdLEAST64': __PRI64_PREFIX + 'd',
|
||||
'PRIdFAST8': 'd',
|
||||
'PRIdFAST16': __PRIPTR_PREFIX + 'd',
|
||||
'PRIdFAST32': __PRIPTR_PREFIX + 'd',
|
||||
'PRIdFAST64': __PRI64_PREFIX + 'd',
|
||||
'PRIi8': 'i',
|
||||
'PRIi16': 'i',
|
||||
'PRIi32': 'i',
|
||||
'PRIi64': __PRI64_PREFIX + 'i',
|
||||
'PRIiLEAST8': 'i',
|
||||
'PRIiLEAST16': 'i',
|
||||
'PRIiLEAST32': 'i',
|
||||
'PRIiLEAST64': __PRI64_PREFIX + 'i',
|
||||
'PRIiFAST8': 'i',
|
||||
'PRIiFAST16': __PRIPTR_PREFIX + 'i',
|
||||
'PRIiFAST32': __PRIPTR_PREFIX + 'i',
|
||||
'PRIiFAST64': __PRI64_PREFIX + 'i',
|
||||
'PRIo8': 'o',
|
||||
'PRIo16': 'o',
|
||||
'PRIo32': 'o',
|
||||
'PRIo64': __PRI64_PREFIX + 'o',
|
||||
'PRIoLEAST8': 'o',
|
||||
'PRIoLEAST16': 'o',
|
||||
'PRIoLEAST32': 'o',
|
||||
'PRIoLEAST64': __PRI64_PREFIX + 'o',
|
||||
'PRIoFAST8': 'o',
|
||||
'PRIoFAST16': __PRIPTR_PREFIX + 'o',
|
||||
'PRIoFAST32': __PRIPTR_PREFIX + 'o',
|
||||
'PRIoFAST64': __PRI64_PREFIX + 'o',
|
||||
'PRIu8': 'u',
|
||||
'PRIu16': 'u',
|
||||
'PRIu32': 'u',
|
||||
'PRIu64': __PRI64_PREFIX + 'u',
|
||||
'PRIuLEAST8': 'u',
|
||||
'PRIuLEAST16': 'u',
|
||||
'PRIuLEAST32': 'u',
|
||||
'PRIuLEAST64': __PRI64_PREFIX + 'u',
|
||||
'PRIuFAST8': 'u',
|
||||
'PRIuFAST16': __PRIPTR_PREFIX + 'u',
|
||||
'PRIuFAST32': __PRIPTR_PREFIX + 'u',
|
||||
'PRIuFAST64': __PRI64_PREFIX + 'u',
|
||||
'PRIx8': 'x',
|
||||
'PRIx16': 'x',
|
||||
'PRIx32': 'x',
|
||||
'PRIx64': __PRI64_PREFIX + 'x',
|
||||
'PRIxLEAST8': 'x',
|
||||
'PRIxLEAST16': 'x',
|
||||
'PRIxLEAST32': 'x',
|
||||
'PRIxLEAST64': __PRI64_PREFIX + 'x',
|
||||
'PRIxFAST8': 'x',
|
||||
'PRIxFAST16': __PRIPTR_PREFIX + 'x',
|
||||
'PRIxFAST32': __PRIPTR_PREFIX + 'x',
|
||||
'PRIxFAST64': __PRI64_PREFIX + 'x',
|
||||
'PRIX8': 'X',
|
||||
'PRIX16': 'X',
|
||||
'PRIX32': 'X',
|
||||
'PRIX64': __PRI64_PREFIX + 'X',
|
||||
'PRIXLEAST8': 'X',
|
||||
'PRIXLEAST16': 'X',
|
||||
'PRIXLEAST32': 'X',
|
||||
'PRIXLEAST64': __PRI64_PREFIX + 'X',
|
||||
'PRIXFAST8': 'X',
|
||||
'PRIXFAST16': __PRIPTR_PREFIX + 'X',
|
||||
'PRIXFAST32': __PRIPTR_PREFIX + 'X',
|
||||
'PRIXFAST64': __PRI64_PREFIX + 'X',
|
||||
'PRIdMAX': __PRI64_PREFIX + 'd',
|
||||
'PRIiMAX': __PRI64_PREFIX + 'i',
|
||||
'PRIoMAX': __PRI64_PREFIX + 'o',
|
||||
'PRIuMAX': __PRI64_PREFIX + 'u',
|
||||
'PRIxMAX': __PRI64_PREFIX + 'x',
|
||||
'PRIXMAX': __PRI64_PREFIX + 'X',
|
||||
'PRIdPTR': __PRIPTR_PREFIX + 'd',
|
||||
'PRIiPTR': __PRIPTR_PREFIX + 'i',
|
||||
'PRIoPTR': __PRIPTR_PREFIX + 'o',
|
||||
'PRIuPTR': __PRIPTR_PREFIX + 'u',
|
||||
'PRIxPTR': __PRIPTR_PREFIX + 'x',
|
||||
'PRIXPTR': __PRIPTR_PREFIX + 'X',
|
||||
'SCNd8': 'hhd',
|
||||
'SCNd16': 'hd',
|
||||
'SCNd32': 'd',
|
||||
'SCNd64': __PRI64_PREFIX + 'd',
|
||||
'SCNdLEAST8': 'hhd',
|
||||
'SCNdLEAST16': 'hd',
|
||||
'SCNdLEAST32': 'd',
|
||||
'SCNdLEAST64': __PRI64_PREFIX + 'd',
|
||||
'SCNdFAST8': 'hhd',
|
||||
'SCNdFAST16': __PRIPTR_PREFIX + 'd',
|
||||
'SCNdFAST32': __PRIPTR_PREFIX + 'd',
|
||||
'SCNdFAST64': __PRI64_PREFIX + 'd',
|
||||
'SCNi8': 'hhi',
|
||||
'SCNi16': 'hi',
|
||||
'SCNi32': 'i',
|
||||
'SCNi64': __PRI64_PREFIX + 'i',
|
||||
'SCNiLEAST8': 'hhi',
|
||||
'SCNiLEAST16': 'hi',
|
||||
'SCNiLEAST32': 'i',
|
||||
'SCNiLEAST64': __PRI64_PREFIX + 'i',
|
||||
'SCNiFAST8': 'hhi',
|
||||
'SCNiFAST16': __PRIPTR_PREFIX + 'i',
|
||||
'SCNiFAST32': __PRIPTR_PREFIX + 'i',
|
||||
'SCNiFAST64': __PRI64_PREFIX + 'i',
|
||||
'SCNu8': 'hhu',
|
||||
'SCNu16': 'hu',
|
||||
'SCNu32': 'u',
|
||||
'SCNu64': __PRI64_PREFIX + 'u',
|
||||
'SCNuLEAST8': 'hhu',
|
||||
'SCNuLEAST16': 'hu',
|
||||
'SCNuLEAST32': 'u',
|
||||
'SCNuLEAST64': __PRI64_PREFIX + 'u',
|
||||
'SCNuFAST8': 'hhu',
|
||||
'SCNuFAST16': __PRIPTR_PREFIX + 'u',
|
||||
'SCNuFAST32': __PRIPTR_PREFIX + 'u',
|
||||
'SCNuFAST64': __PRI64_PREFIX + 'u',
|
||||
'SCNo8': 'hho',
|
||||
'SCNo16': 'ho',
|
||||
'SCNo32': 'o',
|
||||
'SCNo64': __PRI64_PREFIX + 'o',
|
||||
'SCNoLEAST8': 'hho',
|
||||
'SCNoLEAST16': 'ho',
|
||||
'SCNoLEAST32': 'o',
|
||||
'SCNoLEAST64': __PRI64_PREFIX + 'o',
|
||||
'SCNoFAST8': 'hho',
|
||||
'SCNoFAST16': __PRIPTR_PREFIX + 'o',
|
||||
'SCNoFAST32': __PRIPTR_PREFIX + 'o',
|
||||
'SCNoFAST64': __PRI64_PREFIX + 'o',
|
||||
'SCNx8': 'hhx',
|
||||
'SCNx16': 'hx',
|
||||
'SCNx32': 'x',
|
||||
'SCNx64': __PRI64_PREFIX + 'x',
|
||||
'SCNxLEAST8': 'hhx',
|
||||
'SCNxLEAST16': 'hx',
|
||||
'SCNxLEAST32': 'x',
|
||||
'SCNxLEAST64': __PRI64_PREFIX + 'x',
|
||||
'SCNxFAST8': 'hhx',
|
||||
'SCNxFAST16': __PRIPTR_PREFIX + 'x',
|
||||
'SCNxFAST32': __PRIPTR_PREFIX + 'x',
|
||||
'SCNxFAST64': __PRI64_PREFIX + 'x',
|
||||
'SCNdMAX': __PRI64_PREFIX + 'd',
|
||||
'SCNiMAX': __PRI64_PREFIX + 'i',
|
||||
'SCNoMAX': __PRI64_PREFIX + 'o',
|
||||
'SCNuMAX': __PRI64_PREFIX + 'u',
|
||||
'SCNxMAX': __PRI64_PREFIX + 'x',
|
||||
'SCNdPTR': __PRIPTR_PREFIX + 'd',
|
||||
'SCNiPTR': __PRIPTR_PREFIX + 'i',
|
||||
'SCNoPTR': __PRIPTR_PREFIX + 'o',
|
||||
'SCNuPTR': __PRIPTR_PREFIX + 'u',
|
||||
'SCNxPTR': __PRIPTR_PREFIX + 'x',
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
tree_sitter~=0.21; python_version == "3.8"
|
||||
tree_sitter_c~=0.21; python_version == "3.8"
|
||||
tree_sitter>=0.23,<=0.23.2; python_version == "3.9"
|
||||
tree_sitter_c>=0.23,<0.23.5; python_version == "3.9"
|
||||
tree-sitter~=0.25; python_version >= "3.10"
|
||||
tree-sitter-c~=0.24; python_version >= "3.10"
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef __BLE_LOG_H__
|
||||
#define __BLE_LOG_H__
|
||||
|
||||
/* ------- */
|
||||
/* BLE Log */
|
||||
/* ------- */
|
||||
|
||||
/* INCLUDE */
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/* TYPEDEF */
|
||||
/* CRITICAL:
|
||||
* The number of BLE Log source code will directly determine the number of statistic manager
|
||||
* memory requirements, keep it as less as possible; it's recommended to use subcode for more
|
||||
* log data structure decoding */
|
||||
typedef enum {
|
||||
/* Internal */
|
||||
BLE_LOG_SRC_INTERNAL = 0,
|
||||
|
||||
/* Custom */
|
||||
BLE_LOG_SRC_CUSTOM,
|
||||
|
||||
/* BLE Stack */
|
||||
BLE_LOG_SRC_LL_TASK,
|
||||
BLE_LOG_SRC_LL_HCI,
|
||||
BLE_LOG_SRC_LL_ISR,
|
||||
BLE_LOG_SRC_HOST,
|
||||
BLE_LOG_SRC_HCI,
|
||||
BLE_LOG_SRC_ENCODE,
|
||||
|
||||
BLE_LOG_SRC_MAX,
|
||||
} ble_log_src_t;
|
||||
|
||||
/* INTERFACE */
|
||||
bool ble_log_init(void);
|
||||
void ble_log_deinit(void);
|
||||
bool ble_log_enable(bool enable);
|
||||
void ble_log_flush(void);
|
||||
bool ble_log_write_hex(ble_log_src_t src_code, const uint8_t *addr, size_t len);
|
||||
void ble_log_dump_to_console(void);
|
||||
#if CONFIG_BLE_LOG_LL_ENABLED
|
||||
void ble_log_write_hex_ll(uint32_t len, const uint8_t *addr,
|
||||
uint32_t len_append, const uint8_t *addr_append, uint32_t flag);
|
||||
#endif /* CONFIG_BLE_LOG_LL_ENABLED */
|
||||
#if CONFIG_BLE_LOG_TS_ENABLED
|
||||
bool ble_log_sync_enable(bool enable);
|
||||
#endif /* CONFIG_BLE_LOG_TS_ENABLED */
|
||||
|
||||
#endif /* __BLE_LOG_H__ */
|
||||
@@ -11,30 +11,38 @@
|
||||
#include "driver/spi_master.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_timer.h"
|
||||
#include "esp_log.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp_task.h"
|
||||
|
||||
// Public typedefs
|
||||
#define BLE_LOG_SPI_OUT_SOURCE_ESP 0
|
||||
#define BLE_LOG_SPI_OUT_SOURCE_ESP_LEGACY 1
|
||||
#define BLE_LOG_SPI_OUT_SOURCE_BLUEDROID 2
|
||||
#define BLE_LOG_SPI_OUT_SOURCE_NIMBLE 3
|
||||
#define BLE_LOG_SPI_OUT_SOURCE_HCI_UPSTREAM 4
|
||||
#define BLE_LOG_SPI_OUT_SOURCE_HCI_DOWNSTREAM 5
|
||||
#define BLE_LOG_SPI_OUT_SOURCE_ESP_ISR 6
|
||||
#define BLE_LOG_SPI_OUT_SOURCE_ESP_LEGACY_ISR 7
|
||||
#define BLE_LOG_SPI_OUT_SOURCE_USER 0x10
|
||||
#define BLE_LOG_SPI_OUT_SOURCE_SYNC 0xFE
|
||||
#define BLE_LOG_SPI_OUT_SOURCE_LOSS 0xFF
|
||||
// Public enums
|
||||
enum {
|
||||
BLE_LOG_SPI_OUT_SOURCE_ESP = 0,
|
||||
BLE_LOG_SPI_OUT_SOURCE_ESP_LEGACY,
|
||||
BLE_LOG_SPI_OUT_SOURCE_BLUEDROID,
|
||||
BLE_LOG_SPI_OUT_SOURCE_NIMBLE,
|
||||
BLE_LOG_SPI_OUT_SOURCE_HCI_UPSTREAM,
|
||||
BLE_LOG_SPI_OUT_SOURCE_HCI_DOWNSTREAM,
|
||||
BLE_LOG_SPI_OUT_SOURCE_ESP_ISR,
|
||||
BLE_LOG_SPI_OUT_SOURCE_ESP_LEGACY_ISR,
|
||||
BLE_LOG_SPI_OUT_SOURCE_LL_HCI,
|
||||
BLE_LOG_SPI_OUT_SOURCE_LE_AUDIO,
|
||||
BLE_LOG_SPI_OUT_SOURCE_MESH,
|
||||
BLE_LOG_SPI_OUT_SOURCE_USER = 0x10,
|
||||
BLE_LOG_SPI_OUT_SOURCE_SSC = 0xFD,
|
||||
BLE_LOG_SPI_OUT_SOURCE_SYNC,
|
||||
BLE_LOG_SPI_OUT_SOURCE_LOSS,
|
||||
};
|
||||
|
||||
// SPI Log Level Definitions
|
||||
#define BLE_LOG_SPI_OUT_LEVEL_NONE 0 /*!< No log output */
|
||||
#define BLE_LOG_SPI_OUT_LEVEL_ERROR 1 /*!< Critical errors that SPI driver cannot recover from */
|
||||
#define BLE_LOG_SPI_OUT_LEVEL_WARN 2 /*!< Recoverable error conditions in SPI communication */
|
||||
#define BLE_LOG_SPI_OUT_LEVEL_INFO 3 /*!< Informational messages about SPI transactions */
|
||||
#define BLE_LOG_SPI_OUT_LEVEL_DEBUG 4 /*!< Detailed debug information, such as SPI register values */
|
||||
#define BLE_LOG_SPI_OUT_LEVEL_VERBOSE 5 /*!< Very detailed debugging logs, potentially flooding output */
|
||||
#define BLE_LOG_SPI_OUT_LEVEL_MAX 6 /*!< Number of SPI log levels supported */
|
||||
#define BLE_LOG_SPI_OUT_LEVEL_NONE 0
|
||||
#define BLE_LOG_SPI_OUT_LEVEL_ERROR 1
|
||||
#define BLE_LOG_SPI_OUT_LEVEL_WARN 2
|
||||
#define BLE_LOG_SPI_OUT_LEVEL_INFO 3
|
||||
#define BLE_LOG_SPI_OUT_LEVEL_DEBUG 4
|
||||
#define BLE_LOG_SPI_OUT_LEVEL_VERBOSE 5
|
||||
#define BLE_LOG_SPI_OUT_STR(x) #x
|
||||
#define BLE_LOG_SPI_OUT_XSTR(x) BLE_LOG_SPI_OUT_STR(x)
|
||||
#define BLE_LOG_SPI_OUT_BUILD_PREFIX(LEVEL, TAG) "[" BLE_LOG_SPI_OUT_XSTR(LEVEL) "][" TAG "]"
|
||||
|
||||
// Public functions
|
||||
int ble_log_spi_out_init(void);
|
||||
@@ -46,9 +54,11 @@ void ble_log_spi_out_ll_write(uint32_t len, const uint8_t *addr, uint32_t len_ap
|
||||
void ble_log_spi_out_ll_log_ev_proc(void);
|
||||
void ble_log_spi_out_ts_sync_start(void);
|
||||
void ble_log_spi_out_ts_sync_stop(void);
|
||||
int ble_log_spi_out_printf(uint8_t source, const char *format, ...);
|
||||
int ble_log_spi_out_printf_enh(uint8_t source, uint8_t level, const char *tag, const char *format, ...);
|
||||
int ble_log_spi_out_write_with_ts(uint8_t source, const uint8_t *addr, uint16_t len);
|
||||
void ble_log_spi_out_dump_all(void);
|
||||
|
||||
void ble_log_spi_out_enable(bool enable);
|
||||
void ble_log_spi_out_flush(void);
|
||||
void ble_log_spi_out_le_audio_write(const uint8_t *addr, uint16_t len);
|
||||
int ble_log_spi_out_host_write(uint8_t source, const char *prefix, const char *format, ...);
|
||||
int ble_log_spi_out_hci_write(uint8_t source, const uint8_t *addr, uint16_t len);
|
||||
int ble_log_spi_out_mesh_write(const char *prefix, const char *format, ...);
|
||||
#endif // __BT_SPI_OUT_H__
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef __BT_SPI_OUT_H__
|
||||
#define __BT_SPI_OUT_H__
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include "driver/uhci.h"
|
||||
#include "driver/uart.h"
|
||||
#include "driver/uart_vfs.h"
|
||||
#include "esp_rom_uart.h"
|
||||
#include "esp_timer.h"
|
||||
#include "freertos/semphr.h"
|
||||
|
||||
// Public enums
|
||||
enum {
|
||||
BLE_LOG_UHCI_OUT_SOURCE_ESP = 0,
|
||||
BLE_LOG_UHCI_OUT_SOURCE_ESP_ISR = 6,
|
||||
BLE_LOG_UHCI_OUT_SOURCE_LL_HCI = 8,
|
||||
BLE_LOG_UHCI_OUT_SOURCE_USER = 0x10,
|
||||
BLE_LOG_UHCI_OUT_SOURCE_LOSS = 0xFF,
|
||||
};
|
||||
|
||||
// Public functions
|
||||
int ble_log_uhci_out_init(void);
|
||||
void ble_log_uhci_out_deinit(void);
|
||||
void ble_log_uhci_out_ll_write(uint32_t len, const uint8_t *addr, uint32_t len_append,
|
||||
const uint8_t *addr_append, uint32_t flag);
|
||||
void ble_log_uhci_out_ll_log_ev_proc(void);
|
||||
void ble_log_uhci_out_dump_all(void);
|
||||
|
||||
#endif // __BT_SPI_OUT_H__
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
/* ------- */
|
||||
/* BLE Log */
|
||||
/* ------- */
|
||||
|
||||
/* INCLUDE */
|
||||
#include "ble_log.h"
|
||||
#include "ble_log_rt.h"
|
||||
#include "ble_log_lbm.h"
|
||||
#include "ble_log_prph.h"
|
||||
#include "ble_log_util.h"
|
||||
#if CONFIG_BLE_LOG_TS_ENABLED
|
||||
#include "ble_log_ts.h"
|
||||
#endif /* CONFIG_BLE_LOG_TS_ENABLED */
|
||||
|
||||
/* VARIABLE */
|
||||
BLE_LOG_STATIC bool ble_log_inited = false;
|
||||
|
||||
/* INTERFACE */
|
||||
bool ble_log_init(void)
|
||||
{
|
||||
/* Avoid double init */
|
||||
if (ble_log_inited) {
|
||||
return true;
|
||||
}
|
||||
|
||||
#if CONFIG_BLE_LOG_TS_ENABLED
|
||||
/* Initialize BLE Log TS */
|
||||
if (!ble_log_ts_init()) {
|
||||
goto exit;
|
||||
}
|
||||
#endif /* CONFIG_BLE_LOG_TS_ENABLED */
|
||||
|
||||
/* Initialize BLE Log Runtime */
|
||||
if (!ble_log_rt_init()) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Initialize BLE Log LBM */
|
||||
if (!ble_log_lbm_init()) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Initialize BLE Log peripheral interface */
|
||||
if (!ble_log_prph_init(BLE_LOG_LBM_CNT)) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Initialization done */
|
||||
ble_log_inited = true;
|
||||
ble_log_enable(true);
|
||||
|
||||
/* Write initialization done log */
|
||||
ble_log_info_t ble_log_info = {
|
||||
.int_src_code = BLE_LOG_INT_SRC_INIT_DONE,
|
||||
.version = BLE_LOG_VERSION,
|
||||
};
|
||||
ble_log_write_hex(BLE_LOG_SRC_INTERNAL, (const uint8_t *)&ble_log_info, sizeof(ble_log_info_t));
|
||||
return true;
|
||||
|
||||
exit:
|
||||
ble_log_deinit();
|
||||
return false;
|
||||
}
|
||||
|
||||
void ble_log_deinit(void)
|
||||
{
|
||||
ble_log_enable(false);
|
||||
ble_log_inited = false;
|
||||
|
||||
/* CRITICAL:
|
||||
* BLE Log peripheral interface must be deinitialized at first,
|
||||
* because there's a risky scenario that may cause severe peripheral
|
||||
* driver fault - if a log buffer is sent to peripheral driver, and
|
||||
* ble_log_deinit is called; in this case, if LBM is deinitialized
|
||||
* before peripheral interface, the log buffer may be freed before
|
||||
* peripheral driver completing tx, and the result would be faulty */
|
||||
ble_log_prph_deinit();
|
||||
|
||||
/* Deinitialize BLE Log LBM */
|
||||
ble_log_lbm_deinit();
|
||||
|
||||
/* Deinitialize BLE Log Runtime */
|
||||
ble_log_rt_deinit();
|
||||
|
||||
#if CONFIG_BLE_LOG_TS_ENABLED
|
||||
/* Deinitialize BLE Log TS */
|
||||
ble_log_ts_deinit();
|
||||
#endif /* CONFIG_BLE_LOG_TS_ENABLED */
|
||||
}
|
||||
@@ -0,0 +1,557 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
/* ------------------------------- */
|
||||
/* BLE Log - Log Buffer Management */
|
||||
/* ------------------------------- */
|
||||
|
||||
/* INCLUDE */
|
||||
#include "ble_log.h"
|
||||
#include "ble_log_lbm.h"
|
||||
#include "ble_log_rt.h"
|
||||
|
||||
#if CONFIG_SOC_ESP_NIMBLE_CONTROLLER
|
||||
#include "os/os_mbuf.h"
|
||||
#endif /* CONFIG_SOC_ESP_NIMBLE_CONTROLLER */
|
||||
|
||||
/* VARIABLE */
|
||||
BLE_LOG_STATIC volatile uint32_t lbm_ref_count = 0;
|
||||
BLE_LOG_STATIC bool lbm_inited = false;
|
||||
BLE_LOG_STATIC bool lbm_enabled = false;
|
||||
BLE_LOG_STATIC ble_log_lbm_ctx_t *lbm_ctx = NULL;
|
||||
BLE_LOG_STATIC ble_log_stat_mgr_t *stat_mgr_ctx[BLE_LOG_SRC_MAX] = {0};
|
||||
|
||||
/* PRIVATE FUNCTION DECLARATION */
|
||||
BLE_LOG_STATIC ble_log_lbm_t *ble_log_lbm_acquire(void);
|
||||
BLE_LOG_STATIC void ble_log_lbm_release(ble_log_lbm_t *lbm);
|
||||
BLE_LOG_STATIC
|
||||
void ble_log_lbm_write_trans(ble_log_prph_trans_t **trans, ble_log_src_t src_code,
|
||||
const uint8_t *addr, uint16_t len,
|
||||
const uint8_t *addr_append, uint16_t len_append, bool omdata);
|
||||
#if CONFIG_BLE_LOG_ENH_STAT_ENABLED
|
||||
BLE_LOG_STATIC void ble_log_stat_mgr_update(ble_log_src_t src_code, uint32_t len, bool lost);
|
||||
#endif /* CONFIG_BLE_LOG_ENH_STAT_ENABLED */
|
||||
|
||||
/* ------------------------- */
|
||||
/* PRIVATE INTERFACE */
|
||||
/* ------------------------- */
|
||||
BLE_LOG_IRAM_ATTR BLE_LOG_STATIC
|
||||
ble_log_lbm_t *ble_log_lbm_acquire(void)
|
||||
{
|
||||
ble_log_lbm_t *lbm = NULL;
|
||||
ble_log_lbm_t *atomic_pool;
|
||||
ble_log_lbm_t *spin_lbm;
|
||||
int atomic_pool_size;
|
||||
|
||||
if (BLE_LOG_IN_ISR()) {
|
||||
atomic_pool = lbm_ctx->atomic_pool_isr;
|
||||
spin_lbm = &(lbm_ctx->spin_isr);
|
||||
atomic_pool_size = BLE_LOG_LBM_ATOMIC_ISR_CNT;
|
||||
} else {
|
||||
atomic_pool = lbm_ctx->atomic_pool_task;
|
||||
spin_lbm = &(lbm_ctx->spin_task);
|
||||
atomic_pool_size = BLE_LOG_LBM_ATOMIC_TASK_CNT;
|
||||
}
|
||||
|
||||
/* Try to acquire atomic LBM first */
|
||||
for (int i = 0; i < atomic_pool_size; i++) {
|
||||
lbm = &atomic_pool[i];
|
||||
if (ble_log_cas_acquire(&(lbm->atomic_lock))) {
|
||||
return lbm;
|
||||
}
|
||||
}
|
||||
|
||||
/* Fallback to spinlock LBM */
|
||||
lbm = spin_lbm;
|
||||
BLE_LOG_ACQUIRE_SPIN_LOCK(&(lbm->spin_lock));
|
||||
return lbm;
|
||||
}
|
||||
|
||||
BLE_LOG_IRAM_ATTR BLE_LOG_STATIC
|
||||
void ble_log_lbm_release(ble_log_lbm_t *lbm)
|
||||
{
|
||||
switch (lbm->lock_type) {
|
||||
case BLE_LOG_LBM_LOCK_ATOMIC:
|
||||
ble_log_cas_release(&(lbm->atomic_lock));
|
||||
break;
|
||||
case BLE_LOG_LBM_LOCK_SPIN:
|
||||
BLE_LOG_RELEASE_SPIN_LOCK(&lbm->spin_lock);
|
||||
break;
|
||||
case BLE_LOG_LBM_LOCK_NONE:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
BLE_LOG_IRAM_ATTR BLE_LOG_STATIC
|
||||
void ble_log_lbm_write_trans(ble_log_prph_trans_t **trans, ble_log_src_t src_code,
|
||||
const uint8_t *addr, uint16_t len,
|
||||
const uint8_t *addr_append, uint16_t len_append, bool omdata)
|
||||
{
|
||||
/* Preparation before writing */
|
||||
uint8_t *buf = (*trans)->buf + (*trans)->pos;
|
||||
uint16_t payload_len = len + len_append;
|
||||
ble_log_stat_mgr_t *stat_mgr = stat_mgr_ctx[src_code];
|
||||
uint32_t frame_sn = BLE_LOG_GET_FRAME_SN(&(stat_mgr->frame_sn));
|
||||
ble_log_frame_head_t frame_head = {
|
||||
.length = payload_len,
|
||||
.frame_meta = BLE_LOG_MAKE_FRAME_META(src_code, frame_sn),
|
||||
};
|
||||
|
||||
/* Memory operation */
|
||||
BLE_LOG_MEMCPY(buf, &frame_head, BLE_LOG_FRAME_HEAD_LEN);
|
||||
if (len) {
|
||||
BLE_LOG_MEMCPY(buf + BLE_LOG_FRAME_HEAD_LEN, addr, len);
|
||||
}
|
||||
if (len_append) {
|
||||
#if CONFIG_SOC_ESP_NIMBLE_CONTROLLER
|
||||
if (omdata) {
|
||||
os_mbuf_copydata((struct os_mbuf *)addr_append, 0,
|
||||
len_append, buf + BLE_LOG_FRAME_HEAD_LEN + len);
|
||||
}
|
||||
else
|
||||
#endif /* CONFIG_SOC_ESP_NIMBLE_CONTROLLER */
|
||||
{
|
||||
BLE_LOG_MEMCPY(buf + BLE_LOG_FRAME_HEAD_LEN + len, addr_append, len_append);
|
||||
}
|
||||
}
|
||||
|
||||
/* Data integrity check */
|
||||
#if CONFIG_BLE_LOG_PAYLOAD_CHECKSUM_ENABLED
|
||||
uint32_t checksum = ble_log_fast_checksum((const uint8_t *)buf, BLE_LOG_FRAME_HEAD_LEN + payload_len);
|
||||
#else /* !CONFIG_BLE_LOG_PAYLOAD_CHECKSUM_ENABLED */
|
||||
/* Note:
|
||||
* Minimum data integrity check is still required for log parsing reliability,
|
||||
* which can be achieved by validating the checksum of frame head only */
|
||||
uint32_t checksum = ble_log_fast_checksum((const uint8_t *)buf, BLE_LOG_FRAME_HEAD_LEN);
|
||||
#endif /* CONFIG_BLE_LOG_PAYLOAD_CHECKSUM_ENABLED */
|
||||
BLE_LOG_MEMCPY(buf + BLE_LOG_FRAME_HEAD_LEN + payload_len, &checksum, BLE_LOG_FRAME_TAIL_LEN);
|
||||
|
||||
/* Update peripheral transport */
|
||||
(*trans)->pos += payload_len + BLE_LOG_FRAME_OVERHEAD;
|
||||
|
||||
#if CONFIG_BLE_LOG_ENH_STAT_ENABLED
|
||||
ble_log_stat_mgr_update(src_code, payload_len, false);
|
||||
#endif /* CONFIG_BLE_LOG_ENH_STAT_ENABLED */
|
||||
|
||||
/* Queue trans if full */
|
||||
if (BLE_LOG_TRANS_FREE_SPACE((*trans)) <= BLE_LOG_FRAME_OVERHEAD) {
|
||||
ble_log_rt_queue_trans(trans);
|
||||
}
|
||||
}
|
||||
|
||||
#if CONFIG_BLE_LOG_ENH_STAT_ENABLED
|
||||
BLE_LOG_IRAM_ATTR BLE_LOG_STATIC
|
||||
void ble_log_stat_mgr_update(ble_log_src_t src_code, uint32_t len, bool lost)
|
||||
{
|
||||
/* Get statistic manager by source code */
|
||||
ble_log_stat_mgr_t *stat_mgr = stat_mgr_ctx[src_code];
|
||||
|
||||
/* Update statistics */
|
||||
uint32_t bytes_cnt = len + BLE_LOG_FRAME_OVERHEAD;
|
||||
if (lost) {
|
||||
stat_mgr->enh_stat.lost_frame_cnt++;
|
||||
stat_mgr->enh_stat.lost_bytes_cnt += bytes_cnt;
|
||||
} else {
|
||||
stat_mgr->enh_stat.written_frame_cnt++;
|
||||
stat_mgr->enh_stat.written_bytes_cnt += bytes_cnt;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_BLE_LOG_ENH_STAT_ENABLED */
|
||||
|
||||
/* -------------------------- */
|
||||
/* INTERNAL INTERFACE */
|
||||
/* -------------------------- */
|
||||
bool ble_log_lbm_init(void)
|
||||
{
|
||||
/* Avoid double init */
|
||||
if (lbm_inited) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Initialize LBM context */
|
||||
lbm_ctx = (ble_log_lbm_ctx_t *)BLE_LOG_MALLOC(sizeof(ble_log_lbm_ctx_t));
|
||||
if (!lbm_ctx) {
|
||||
goto exit;
|
||||
}
|
||||
BLE_LOG_MEMSET(lbm_ctx, 0, sizeof(ble_log_lbm_ctx_t));
|
||||
|
||||
/* Initialize peripheral transport for common LBMs */
|
||||
ble_log_lbm_t *lbm;
|
||||
for (int i = 0; i < BLE_LOG_LBM_COMMON_CNT; i++) {
|
||||
lbm = &(lbm_ctx->lbm_common_pool[i]);
|
||||
for (int j = 0; j < BLE_LOG_TRANS_PING_PONG_BUF_CNT; j++) {
|
||||
if (!ble_log_prph_trans_init(&(lbm->trans[j]),
|
||||
CONFIG_BLE_LOG_LBM_TRANS_SIZE)) {
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialize lock types for atomic pool */
|
||||
for (int i = 0; i < BLE_LOG_LBM_ATOMIC_CNT; i++) {
|
||||
lbm_ctx->atomic_pool[i].lock_type = BLE_LOG_LBM_LOCK_ATOMIC;
|
||||
}
|
||||
|
||||
/* Initialize lock types for spin pool */
|
||||
for (int i = 0; i < BLE_LOG_LBM_SPIN_MAX; i++) {
|
||||
lbm_ctx->spin_pool[i].lock_type = BLE_LOG_LBM_LOCK_SPIN;
|
||||
}
|
||||
|
||||
#if CONFIG_BLE_LOG_LL_ENABLED
|
||||
for (int i = 0; i < BLE_LOG_LBM_LL_MAX; i++) {
|
||||
lbm = &(lbm_ctx->lbm_ll_pool[i]);
|
||||
for (int j = 0; j < BLE_LOG_TRANS_PING_PONG_BUF_CNT; j++) {
|
||||
if (!ble_log_prph_trans_init(&(lbm->trans[j]),
|
||||
CONFIG_BLE_LOG_LBM_LL_TRANS_SIZE)) {
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialize lock types for LL pool */
|
||||
for (int i = 0; i < BLE_LOG_LBM_LL_MAX; i++) {
|
||||
lbm_ctx->lbm_ll_pool[i].lock_type = BLE_LOG_LBM_LOCK_NONE;
|
||||
}
|
||||
#endif /* CONFIG_BLE_LOG_LL_ENABLED */
|
||||
|
||||
/* Initialize statistic manager context */
|
||||
for (int i = 0; i < BLE_LOG_SRC_MAX; i++) {
|
||||
stat_mgr_ctx[i] = (ble_log_stat_mgr_t *)BLE_LOG_MALLOC(sizeof(ble_log_stat_mgr_t));
|
||||
if (!stat_mgr_ctx[i]) {
|
||||
goto exit;
|
||||
}
|
||||
BLE_LOG_MEMSET(stat_mgr_ctx[i], 0, sizeof(ble_log_stat_mgr_t));
|
||||
|
||||
#if CONFIG_BLE_LOG_ENH_STAT_ENABLED
|
||||
stat_mgr_ctx[i]->enh_stat.int_src_code = BLE_LOG_INT_SRC_ENH_STAT;
|
||||
stat_mgr_ctx[i]->enh_stat.src_code = i;
|
||||
#endif /* CONFIG_BLE_LOG_ENH_STAT_ENABLED */
|
||||
}
|
||||
|
||||
/* Initialization done */
|
||||
lbm_ref_count = 0;
|
||||
lbm_inited = true;
|
||||
lbm_enabled = false;
|
||||
return true;
|
||||
|
||||
exit:
|
||||
ble_log_lbm_deinit();
|
||||
return false;
|
||||
}
|
||||
|
||||
void ble_log_lbm_deinit(void)
|
||||
{
|
||||
/* Set inited flag to false to prevent new references */
|
||||
lbm_inited = false;
|
||||
lbm_enabled = false;
|
||||
|
||||
/* Disable module and wait for all references to be released */
|
||||
uint32_t time_waited = 0;
|
||||
while (lbm_ref_count > 0) {
|
||||
vTaskDelay(pdMS_TO_TICKS(1));
|
||||
BLE_LOG_ASSERT(time_waited++ < 1000);
|
||||
}
|
||||
|
||||
/* Release statistic manager context */
|
||||
for (int i = 0; i < BLE_LOG_SRC_MAX; i++) {
|
||||
if (stat_mgr_ctx[i]) {
|
||||
BLE_LOG_FREE(stat_mgr_ctx[i]);
|
||||
stat_mgr_ctx[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Release LBM */
|
||||
if (lbm_ctx) {
|
||||
/* Release peripheral transport for common pools */
|
||||
ble_log_lbm_t *lbm;
|
||||
for (int i = 0; i < BLE_LOG_LBM_CNT; i++) {
|
||||
lbm = &(lbm_ctx->lbm_pool[i]);
|
||||
for (int j = 0; j < BLE_LOG_TRANS_PING_PONG_BUF_CNT; j++) {
|
||||
ble_log_prph_trans_deinit(&(lbm->trans[j]));
|
||||
}
|
||||
}
|
||||
|
||||
/* Release LBM context */
|
||||
BLE_LOG_FREE(lbm_ctx);
|
||||
lbm_ctx = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Note:
|
||||
* The function below should be private, but when UART redirection is required,
|
||||
* it would be a waste to implement get transport function again, thus
|
||||
* make it available internally */
|
||||
BLE_LOG_IRAM_ATTR
|
||||
ble_log_prph_trans_t **ble_log_lbm_get_trans(ble_log_lbm_t *lbm, size_t log_len)
|
||||
{
|
||||
/* Check if available buffer can contain incoming log */
|
||||
ble_log_prph_trans_t **trans;
|
||||
for (int i = 0; i < BLE_LOG_TRANS_PING_PONG_BUF_CNT; i++) {
|
||||
trans = &(lbm->trans[lbm->trans_idx]);
|
||||
if (!(*trans)->prph_owned) {
|
||||
/* Return if there's enough free space in current transport */
|
||||
if (BLE_LOG_TRANS_FREE_SPACE((*trans)) >= (log_len + BLE_LOG_FRAME_OVERHEAD)) {
|
||||
return trans;
|
||||
}
|
||||
|
||||
/* Queue transport if there's insufficient free space */
|
||||
if ((*trans)->pos) {
|
||||
ble_log_rt_queue_trans(trans);
|
||||
}
|
||||
}
|
||||
|
||||
/* Current transport unavailable, switch to the other */
|
||||
lbm->trans_idx = !lbm->trans_idx;
|
||||
}
|
||||
|
||||
/* Both ping-pong buffers are unavailable */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if CONFIG_BLE_LOG_ENH_STAT_ENABLED
|
||||
void ble_log_write_enh_stat(void)
|
||||
{
|
||||
BLE_LOG_REF_COUNT_ACQUIRE(&lbm_ref_count);
|
||||
if (!lbm_enabled) {
|
||||
goto deref;
|
||||
}
|
||||
|
||||
for (int i = 0; i < BLE_LOG_SRC_MAX; i++) {
|
||||
ble_log_enh_stat_t *enh_stat = &(stat_mgr_ctx[i]->enh_stat);
|
||||
ble_log_write_hex(BLE_LOG_SRC_INTERNAL, (const uint8_t *)enh_stat, sizeof(ble_log_enh_stat_t));
|
||||
}
|
||||
|
||||
deref:
|
||||
BLE_LOG_REF_COUNT_RELEASE(&lbm_ref_count);
|
||||
}
|
||||
#endif /* CONFIG_BLE_LOG_ENH_STAT_ENABLED */
|
||||
|
||||
/* ------------------------ */
|
||||
/* PUBLIC INTERFACE */
|
||||
/* ------------------------ */
|
||||
bool ble_log_enable(bool enable)
|
||||
{
|
||||
if (!lbm_inited) {
|
||||
return false;
|
||||
}
|
||||
lbm_enabled = enable;
|
||||
return true;
|
||||
}
|
||||
|
||||
void ble_log_flush(void)
|
||||
{
|
||||
BLE_LOG_REF_COUNT_ACQUIRE(&lbm_ref_count);
|
||||
if (!lbm_inited) {
|
||||
goto deref;
|
||||
}
|
||||
|
||||
#if CONFIG_BLE_LOG_ENH_STAT_ENABLED
|
||||
/* Write enhanced statistics before module disable */
|
||||
ble_log_write_enh_stat();
|
||||
#endif /* CONFIG_BLE_LOG_ENH_STAT_ENABLED */
|
||||
|
||||
/* Write BLE Log flush log */
|
||||
ble_log_info_t ble_log_info = {
|
||||
.int_src_code = BLE_LOG_INT_SRC_FLUSH,
|
||||
.version = BLE_LOG_VERSION,
|
||||
};
|
||||
ble_log_write_hex(BLE_LOG_SRC_INTERNAL, (const uint8_t *)&ble_log_info, sizeof(ble_log_info_t));
|
||||
|
||||
/* Disable module and wait for all other references to release */
|
||||
bool lbm_enabled_copy = lbm_enabled;
|
||||
lbm_enabled = false;
|
||||
uint32_t time_waited = 0;
|
||||
while (lbm_ref_count > 1) {
|
||||
vTaskDelay(pdMS_TO_TICKS(1));
|
||||
BLE_LOG_ASSERT(time_waited++ < 1000);
|
||||
}
|
||||
|
||||
/* Queue transports with logs */
|
||||
ble_log_lbm_t *lbm;
|
||||
ble_log_prph_trans_t **trans;
|
||||
|
||||
/* Flush pools */
|
||||
for (int i = 0; i < BLE_LOG_LBM_CNT; i++) {
|
||||
lbm = &(lbm_ctx->lbm_pool[i]);
|
||||
int trans_idx = lbm->trans_idx;
|
||||
for (int j = 0; j < BLE_LOG_TRANS_PING_PONG_BUF_CNT; j++) {
|
||||
trans = &(lbm->trans[trans_idx]);
|
||||
if (!(*trans)->prph_owned && (*trans)->pos) {
|
||||
ble_log_rt_queue_trans(trans);
|
||||
}
|
||||
trans_idx = !trans_idx;
|
||||
}
|
||||
}
|
||||
|
||||
/* Wait for transportation to finish */
|
||||
time_waited = 0;
|
||||
bool in_progress;
|
||||
do {
|
||||
in_progress = false;
|
||||
for (int i = 0; i < BLE_LOG_LBM_CNT; i++) {
|
||||
lbm = &(lbm_ctx->lbm_pool[i]);
|
||||
for (int j = 0; j < BLE_LOG_TRANS_PING_PONG_BUF_CNT; j++) {
|
||||
trans = &(lbm->trans[j]);
|
||||
in_progress |= (*trans)->prph_owned;
|
||||
}
|
||||
}
|
||||
if (in_progress) {
|
||||
vTaskDelay(pdMS_TO_TICKS(1));
|
||||
BLE_LOG_ASSERT(time_waited++ < 1000);
|
||||
}
|
||||
} while (in_progress);
|
||||
|
||||
/* Reset statistics manager after all operations complete */
|
||||
for (int i = 0; i < BLE_LOG_SRC_MAX; i++) {
|
||||
BLE_LOG_MEMSET(stat_mgr_ctx[i], 0, sizeof(ble_log_stat_mgr_t));
|
||||
#if CONFIG_BLE_LOG_ENH_STAT_ENABLED
|
||||
/* Reinitialize enhanced statistics fields */
|
||||
stat_mgr_ctx[i]->enh_stat.int_src_code = BLE_LOG_INT_SRC_ENH_STAT;
|
||||
stat_mgr_ctx[i]->enh_stat.src_code = i;
|
||||
#endif /* CONFIG_BLE_LOG_ENH_STAT_ENABLED */
|
||||
}
|
||||
|
||||
/* Resume enable status */
|
||||
lbm_enabled = lbm_enabled_copy;
|
||||
|
||||
deref:
|
||||
BLE_LOG_REF_COUNT_RELEASE(&lbm_ref_count);
|
||||
}
|
||||
|
||||
bool ble_log_write_hex(ble_log_src_t src_code, const uint8_t *addr, size_t len)
|
||||
{
|
||||
BLE_LOG_REF_COUNT_ACQUIRE(&lbm_ref_count);
|
||||
size_t payload_len = len + sizeof(uint32_t);
|
||||
if (!lbm_enabled) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Get transport */
|
||||
ble_log_lbm_t *lbm = ble_log_lbm_acquire();
|
||||
ble_log_prph_trans_t **trans = ble_log_lbm_get_trans(lbm, payload_len);
|
||||
if (!trans) {
|
||||
ble_log_lbm_release(lbm);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Write transport */
|
||||
uint32_t os_ts = pdTICKS_TO_MS(BLE_LOG_IN_ISR()?
|
||||
xTaskGetTickCountFromISR():
|
||||
xTaskGetTickCount());
|
||||
ble_log_lbm_write_trans(trans, src_code, (const uint8_t *)&os_ts,
|
||||
sizeof(uint32_t), addr, len, false);
|
||||
|
||||
/* Release */
|
||||
ble_log_lbm_release(lbm);
|
||||
BLE_LOG_REF_COUNT_RELEASE(&lbm_ref_count);
|
||||
return true;
|
||||
|
||||
exit:
|
||||
#if CONFIG_BLE_LOG_ENH_STAT_ENABLED
|
||||
if (lbm_inited) {
|
||||
ble_log_stat_mgr_update(src_code, payload_len, true);
|
||||
}
|
||||
#endif /* CONFIG_BLE_LOG_ENH_STAT_ENABLED */
|
||||
BLE_LOG_REF_COUNT_RELEASE(&lbm_ref_count);
|
||||
return false;
|
||||
}
|
||||
|
||||
#if CONFIG_BLE_LOG_LL_ENABLED
|
||||
BLE_LOG_IRAM_ATTR
|
||||
void ble_log_write_hex_ll(uint32_t len, const uint8_t *addr,
|
||||
uint32_t len_append, const uint8_t *addr_append, uint32_t flag)
|
||||
{
|
||||
BLE_LOG_REF_COUNT_ACQUIRE(&lbm_ref_count);
|
||||
size_t payload_len = len + len_append;
|
||||
|
||||
/* Source code shall be determined before LBM enable status check */
|
||||
ble_log_src_t src_code;
|
||||
bool use_ll_task = false;
|
||||
if (flag & BIT(BLE_LOG_LL_FLAG_ISR)) {
|
||||
src_code = BLE_LOG_SRC_LL_ISR;
|
||||
} else if (flag & BIT(BLE_LOG_LL_FLAG_HCI)) {
|
||||
src_code = BLE_LOG_SRC_LL_HCI;
|
||||
} else if (flag & BIT(BLE_LOG_LL_FLAG_HCI_UPSTREAM)) {
|
||||
src_code = BLE_LOG_SRC_HCI;
|
||||
} else {
|
||||
src_code = BLE_LOG_SRC_LL_TASK;
|
||||
use_ll_task = true;
|
||||
}
|
||||
bool omdata = flag & BIT(BLE_LOG_LL_FLAG_OMDATA);
|
||||
|
||||
if (!lbm_enabled) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Determine LBM by flag */
|
||||
ble_log_lbm_t *lbm;
|
||||
if (BLE_LOG_IN_ISR()) {
|
||||
/* Reuse common LBM acquire logic */
|
||||
lbm = ble_log_lbm_acquire();
|
||||
} else {
|
||||
lbm = (use_ll_task)? &(lbm_ctx->lbm_ll_task): &(lbm_ctx->lbm_ll_hci);
|
||||
}
|
||||
|
||||
/* Get transport */
|
||||
ble_log_prph_trans_t **trans = ble_log_lbm_get_trans(lbm, payload_len);
|
||||
if (!trans) {
|
||||
ble_log_lbm_release(lbm);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Write transport */
|
||||
ble_log_lbm_write_trans(trans, src_code, addr, len, addr_append, len_append, omdata);
|
||||
|
||||
ble_log_lbm_release(lbm);
|
||||
BLE_LOG_REF_COUNT_RELEASE(&lbm_ref_count);
|
||||
return;
|
||||
|
||||
exit:
|
||||
#if CONFIG_BLE_LOG_ENH_STAT_ENABLED
|
||||
if (lbm_inited) {
|
||||
ble_log_stat_mgr_update(src_code, payload_len, true);
|
||||
}
|
||||
#endif /* CONFIG_BLE_LOG_ENH_STAT_ENABLED */
|
||||
BLE_LOG_REF_COUNT_RELEASE(&lbm_ref_count);
|
||||
return;
|
||||
}
|
||||
#endif /* CONFIG_BLE_LOG_LL_ENABLED */
|
||||
|
||||
void ble_log_dump_to_console(void)
|
||||
{
|
||||
BLE_LOG_REF_COUNT_ACQUIRE(&lbm_ref_count);
|
||||
if (!lbm_inited) {
|
||||
goto deref;
|
||||
}
|
||||
|
||||
int trans_idx;
|
||||
ble_log_lbm_t *lbm;
|
||||
ble_log_prph_trans_t *trans;
|
||||
BLE_LOG_ENTER_CRITICAL();
|
||||
BLE_LOG_CONSOLE("[BLE_LOG_DUMP_START:\n");
|
||||
for (int i = 0; i < BLE_LOG_LBM_CNT; i++) {
|
||||
lbm = &(lbm_ctx->lbm_pool[i]);
|
||||
trans_idx = lbm->trans_idx;
|
||||
for (int j = 0; j < BLE_LOG_TRANS_PING_PONG_BUF_CNT; j++) {
|
||||
trans = lbm->trans[trans_idx];
|
||||
BLE_LOG_FEED_WDT();
|
||||
|
||||
for (int k = 0; k < trans->size; k++) {
|
||||
BLE_LOG_CONSOLE("%02x ", trans->buf[k]);
|
||||
if (!(k & 0xFF)) {
|
||||
BLE_LOG_FEED_WDT();
|
||||
}
|
||||
}
|
||||
trans_idx = !trans_idx;
|
||||
}
|
||||
}
|
||||
BLE_LOG_CONSOLE("\n:BLE_LOG_DUMP_END]\n\n");
|
||||
BLE_LOG_EXIT_CRITICAL();
|
||||
|
||||
deref:
|
||||
BLE_LOG_REF_COUNT_RELEASE(&lbm_ref_count);
|
||||
return;
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/* ----------------- */
|
||||
/* BLE Log - Runtime */
|
||||
/* ----------------- */
|
||||
|
||||
/* INCLUDE */
|
||||
#include "ble_log.h"
|
||||
#include "ble_log_rt.h"
|
||||
#include "ble_log_lbm.h"
|
||||
|
||||
/* VARIABLE */
|
||||
BLE_LOG_STATIC bool rt_inited = false;
|
||||
BLE_LOG_STATIC TaskHandle_t rt_task_handle = NULL;
|
||||
BLE_LOG_STATIC QueueHandle_t rt_queue_handle = NULL;
|
||||
#if CONFIG_BLE_LOG_TS_ENABLED
|
||||
BLE_LOG_STATIC bool rt_ts_enabled = false;
|
||||
#endif /* CONFIG_BLE_LOG_TS_ENABLED */
|
||||
|
||||
/* PRIVATE FUNCTION */
|
||||
BLE_LOG_IRAM_ATTR BLE_LOG_STATIC void ble_log_rt_task(void *pvParameters)
|
||||
{
|
||||
(void)pvParameters;
|
||||
ble_log_prph_trans_t *trans = NULL;
|
||||
uint32_t curr_os_ts = 0;
|
||||
uint32_t last_hook_os_ts = 0;
|
||||
#ifndef UNIT_TEST
|
||||
while (1)
|
||||
#endif /* !UNIT_TEST */
|
||||
{
|
||||
/* CRITICAL:
|
||||
* Blocking queue receive is mandatory for light sleep support */
|
||||
if (xQueueReceive(rt_queue_handle, &trans, portMAX_DELAY) == pdTRUE) {
|
||||
ble_log_prph_send_trans(trans);
|
||||
}
|
||||
|
||||
/* Task hook */
|
||||
curr_os_ts = pdTICKS_TO_MS(xTaskGetTickCount());
|
||||
if ((curr_os_ts - last_hook_os_ts) < BLE_LOG_TASK_HOOK_TIMEOUT_MS) {
|
||||
#ifndef UNIT_TEST
|
||||
continue;
|
||||
#else /* UNIT_TEST */
|
||||
return;
|
||||
#endif /* !UNIT_TEST */
|
||||
}
|
||||
last_hook_os_ts = curr_os_ts;
|
||||
|
||||
/* Write BLE Log info log */
|
||||
ble_log_info_t ble_log_info = {
|
||||
.int_src_code = BLE_LOG_INT_SRC_INFO,
|
||||
.version = BLE_LOG_VERSION,
|
||||
};
|
||||
ble_log_write_hex(BLE_LOG_SRC_INTERNAL, (const uint8_t *)&ble_log_info, sizeof(ble_log_info_t));
|
||||
|
||||
#if CONFIG_BLE_LOG_TS_ENABLED
|
||||
if (rt_ts_enabled) {
|
||||
ble_log_ts_info_t *ts_info = NULL;
|
||||
ble_log_ts_info_update(&ts_info);
|
||||
ble_log_write_hex(BLE_LOG_SRC_INTERNAL, (const uint8_t *)ts_info, sizeof(ble_log_ts_info_t));
|
||||
}
|
||||
#endif /* CONFIG_BLE_LOG_TS_ENABLED */
|
||||
|
||||
#if CONFIG_BLE_LOG_ENH_STAT_ENABLED
|
||||
ble_log_write_enh_stat();
|
||||
#endif /* CONFIG_BLE_LOG_ENH_STAT_ENABLED */
|
||||
}
|
||||
}
|
||||
|
||||
/* INTERFACE */
|
||||
bool ble_log_rt_init(void)
|
||||
{
|
||||
if (rt_inited) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* CRITICAL:
|
||||
* Queue must be initialized before creating task */
|
||||
rt_queue_handle = xQueueCreate(BLE_LOG_LBM_CNT, sizeof(ble_log_prph_trans_t *));
|
||||
if (!rt_queue_handle) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Initialize task */
|
||||
if (xTaskCreate(ble_log_rt_task, "ble_log", BLE_LOG_TASK_STACK_SIZE, NULL,
|
||||
BLE_LOG_TASK_PRIO, &rt_task_handle) != pdTRUE) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
rt_inited = true;
|
||||
#if CONFIG_BLE_LOG_TS_ENABLED
|
||||
rt_ts_enabled = false;
|
||||
#endif /* CONFIG_BLE_LOG_TS_ENABLED */
|
||||
return true;
|
||||
|
||||
exit:
|
||||
ble_log_rt_deinit();
|
||||
return false;
|
||||
}
|
||||
|
||||
void ble_log_rt_deinit(void)
|
||||
{
|
||||
rt_inited = false;
|
||||
#if CONFIG_BLE_LOG_TS_ENABLED
|
||||
rt_ts_enabled = false;
|
||||
#endif /* CONFIG_BLE_LOG_TS_ENABLED */
|
||||
|
||||
/* CRITICAL:
|
||||
* Task must be deinitialized before deinitializing queue */
|
||||
if (rt_task_handle) {
|
||||
vTaskDelete(rt_task_handle);
|
||||
rt_task_handle = NULL;
|
||||
}
|
||||
|
||||
/* Release task queue */
|
||||
if (rt_queue_handle) {
|
||||
vQueueDelete(rt_queue_handle);
|
||||
rt_queue_handle = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
BLE_LOG_IRAM_ATTR void ble_log_rt_queue_trans(ble_log_prph_trans_t **trans)
|
||||
{
|
||||
(*trans)->prph_owned = true;
|
||||
if (BLE_LOG_IN_ISR()) {
|
||||
xQueueSendFromISR(rt_queue_handle, trans, NULL);
|
||||
} else {
|
||||
xQueueSend(rt_queue_handle, trans, portMAX_DELAY);
|
||||
}
|
||||
}
|
||||
|
||||
#if CONFIG_BLE_LOG_TS_ENABLED
|
||||
bool ble_log_sync_enable(bool enable)
|
||||
{
|
||||
if (!rt_inited) {
|
||||
return false;
|
||||
}
|
||||
rt_ts_enabled = enable;
|
||||
return true;
|
||||
}
|
||||
#endif /* CONFIG_BLE_LOG_TS_ENABLED */
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
/* ----------------------------------- */
|
||||
/* BLE Log - Timestamp Synchronization */
|
||||
/* ----------------------------------- */
|
||||
|
||||
/* INCLUDE */
|
||||
#include "ble_log_ts.h"
|
||||
|
||||
/* VARIABLE */
|
||||
BLE_LOG_STATIC bool ts_inited = false;
|
||||
BLE_LOG_STATIC ble_log_ts_info_t *ts_info = NULL;
|
||||
|
||||
/* INTERFACE */
|
||||
bool ble_log_ts_init(void)
|
||||
{
|
||||
if (ts_inited) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Initialize toggle IO */
|
||||
gpio_config_t sync_io_conf = {
|
||||
.intr_type = GPIO_INTR_DISABLE,
|
||||
.mode = GPIO_MODE_OUTPUT,
|
||||
.pin_bit_mask = BIT(CONFIG_BLE_LOG_SYNC_IO_NUM),
|
||||
};
|
||||
if (gpio_config(&sync_io_conf) != ESP_OK) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Initialize sync data */
|
||||
ts_info = (ble_log_ts_info_t *)BLE_LOG_MALLOC(sizeof(ble_log_ts_info_t));
|
||||
if (!ts_info) {
|
||||
goto exit;
|
||||
}
|
||||
BLE_LOG_MEMSET(ts_info, 0, sizeof(ble_log_ts_info_t));
|
||||
ts_info->int_src_code = BLE_LOG_INT_SRC_TS;
|
||||
|
||||
ts_inited = true;
|
||||
return true;
|
||||
|
||||
exit:
|
||||
ble_log_ts_deinit();
|
||||
return false;
|
||||
}
|
||||
|
||||
void ble_log_ts_deinit(void)
|
||||
{
|
||||
ts_inited = false;
|
||||
|
||||
/* Release sync data */
|
||||
if (ts_info) {
|
||||
BLE_LOG_FREE(ts_info);
|
||||
ts_info = NULL;
|
||||
}
|
||||
|
||||
/* Release toggle IO */
|
||||
gpio_reset_pin(CONFIG_BLE_LOG_SYNC_IO_NUM);
|
||||
}
|
||||
|
||||
void ble_log_ts_info_update(ble_log_ts_info_t **info)
|
||||
{
|
||||
BLE_LOG_ENTER_CRITICAL();
|
||||
ts_info->io_level = !ts_info->io_level;
|
||||
gpio_set_level(CONFIG_BLE_LOG_SYNC_IO_NUM, ts_info->io_level);
|
||||
ts_info->lc_ts = BLE_LOG_GET_LC_TS;
|
||||
ts_info->esp_ts = esp_timer_get_time();
|
||||
ts_info->os_ts = pdTICKS_TO_MS(xTaskGetTickCountFromISR());
|
||||
BLE_LOG_EXIT_CRITICAL();
|
||||
|
||||
*info = ts_info;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user