{"id":325949,"date":"2021-07-04T21:00:33","date_gmt":"2021-07-04T21:00:33","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=325949"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=325949","title":{"rendered":"\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 coroutines \u0438\u0437 \u0421++20 \u0432 \u0441\u0432\u044f\u0437\u043a\u0435 \u0441 NRF52832 \u0438 GTest"},"content":{"rendered":"\n<div class=\"post__text post__text_v2\" id=\"post-content-body\">\n<h4><\/h4>\n<p>\u041f\u043e\u044f\u0432\u0438\u043b\u0430\u0441\u044c \u0438\u0434\u0435\u044f \u0432 \u0434\u043e\u043c\u0430\u0448\u043d\u0435\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u043f\u043e\u043f\u0440\u043e\u0431\u043e\u0432\u0430\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u043e\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b \u0438\u0437 \u0421++20 \u043d\u0430 \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u043e\u0439 \u0436\u0435\u043b\u0435\u0437\u043a\u0435. \u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043c\u043e\u0434\u0443\u043b\u044f \u0434\u043b\u044f \u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u043e\u0432 \u0431\u044b\u043b \u0432\u044b\u0431\u0440\u0430\u043d E73 NRF52832. \u0418\u0437 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0441\u044f \u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438- arm-gcc-gnu-none-eabi 10.2, MSVC \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0438\u0434\u0435\u0439 \u0438 \u043f\u0440\u043e\u0433\u043e\u043d\u0430 \u0442\u0435\u0441\u0442\u043e\u0432 \u043d\u0430 Windows-\u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0435. \u0418\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e \u0431\u044b\u043b\u043e \u0432 \u043f\u043b\u0430\u043d\u0430\u0445 \u043f\u0440\u043e\u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0430 \u0447\u0435\u043c-\u0442\u043e \u043a\u043e\u043d\u0446\u0435\u043f\u0446\u0438\u044e \u0438 \u043a\u0430\u043a \u0438\u043c\u0435\u043d\u043d\u043e \u0438\u0445 \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0442\u044c. \u0411\u044b\u043b\u0430 \u0438\u0434\u0435\u044f \u0430\u0434\u0430\u043f\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u0432 \u0432\u0438\u0434\u0435 \u043c\u0438\u0433\u0430\u043d\u0438\u044f \u0441\u0432\u0435\u0442\u043e\u0434\u0438\u043e\u0434\u0438\u043a\u043e\u043c. \u041d\u043e \u043e\u043d \u0431\u044b\u043b \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u043f\u0440\u043e\u0441\u0442\u043e\u0439. \u041d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0431\u044b\u043b\u043e \u043f\u0440\u0438\u0434\u0443\u043c\u0430\u0442\u044c \u0447\u0442\u043e-\u0442\u043e \u0431\u043e\u043b\u0435\u0435 \u0441\u043b\u043e\u0436\u043d\u043e\u0435 \u0438 \u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u043b\u0435\u0437\u043d\u043e\u0435, \u0447\u0442\u043e \u043b\u0438. \u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u0438 \u043f\u043e\u044f\u0432\u0438\u043b\u0430\u0441\u044c \u0438\u0434\u0435\u044f \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u0430\u0442\u044c \u0434\u0440\u0430\u0439\u0432\u0435\u0440 \u0434\u0438\u0441\u043f\u043b\u0435\u044f \u0438 \u043f\u0430\u0440\u044b \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u043e\u0432 SPI-FLASH \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0435-\u0434\u043e\u043b\u0433\u043e\u0441\u0442\u0440\u043e\u0435.<\/p>\n<p>\u041d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u043f\u043b\u0430\u043d, \u0447\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0432 \u0437\u0430\u043c\u0435\u0442\u043a\u0435:<\/p>\n<ol start=\"0\">\n<li>\n<p>\u041f\u0440\u0435\u0434\u044b\u0441\u0442\u043e\u0440\u0438\u044f \u0441 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u044f\u043c\u0438<\/p>\n<\/li>\n<li>\n<p>\u041a\u0430\u043a \u044d\u0442\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0432 \u043e\u0431\u0449\u0438\u0445 \u0447\u0435\u0440\u0442\u0430\u0445<\/p>\n<\/li>\n<li>\n<p>\u0420\u0430\u0431\u043e\u0442\u0430\u0435\u043c \u0441 SPI \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u043e\u043c<\/p>\n<\/li>\n<li>\n<p>\u041c\u0430\u0441\u0441\u0438\u0432 \u043a\u043e\u043c\u0430\u043d\u0434 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438<\/p>\n<\/li>\n<li>\n<p>\u0418\u0434\u0435\u0438 \u0441 std::tuple \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0439<\/p>\n<\/li>\n<li>\n<p>\u0420\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c when_all_sequence<\/p>\n<\/li>\n<li>\n<p>\u041a\u0430\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 Task \u0438\u0437 cppcoro<\/p>\n<\/li>\n<li>\n<p>\u041a\u0430\u043a \u044d\u0442\u043e \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c?<\/p>\n<\/li>\n<li>\n<p>\u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0442\u0435\u0441\u0442\u044b \u0432 GTest<\/p>\n<\/li>\n<li>\n<p>\u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0447\u0435\u0440\u043d\u043e\u0432\u043e\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u0434\u0440\u0430\u0439\u0432\u0435\u0440\u0430 \u0434\u043b\u044f SPI-FLASH<\/p>\n<\/li>\n<li>\n<p>\u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0447\u0442\u0435\u043d\u0438\u0435 JEDEC ID<\/p>\n<\/li>\n<li>\n<p>\u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0447\u0442\u0435\u043d\u0438\u0435 device id<\/p>\n<\/li>\n<li>\n<p>\u041e\u0436\u0438\u0434\u0430\u043d\u0438\u0435 \u043e\u043a\u043e\u043d\u0447\u0430\u043d\u0438\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0441\u043e\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b<\/p>\n<\/li>\n<\/ol>\n<h4>0. \u041f\u0435\u0440\u0435\u0434 \u043f\u0440\u043e\u0447\u0442\u0435\u043d\u0438\u0435\u043c<\/h4>\n<p>\u0417\u0430\u043c\u0435\u0442\u043a\u0430 \u043f\u0440\u0435\u0434\u043f\u043e\u043b\u0430\u0433\u0430\u0435\u0442 \u0431\u0430\u0437\u043e\u0432\u043e\u0435 \u0437\u043d\u0430\u043a\u043e\u043c\u0441\u0442\u0432\u043e \u0447\u0438\u0442\u0430\u0442\u0435\u043b\u044f \u0441 \u0441\u043e\u043f\u0440\u043e\u0433\u0440\u043c\u0430\u043c\u043c\u0430\u043c\u0438 \/ \u0438\u0445 \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441\u043e\u043c. \u0412 \u0441\u0438\u043b\u0443 \u043d\u0430\u043b\u0438\u0447\u0438\u044f \u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u044b\u0445 \u0441\u0442\u0430\u0442\u0435\u0439 \u043d\u0430 \u0442\u0435\u043c\u0443 \u0434\u0435\u0442\u0430\u043b\u0435\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0441\u043e\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c \u0438 \u0438\u0445 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u044e\u0442\u0441\u044f \u043a \u043f\u0440\u043e\u0447\u0442\u0435\u043d\u0438\u044e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u044b:<\/p>\n<ul>\n<li>\n<p><a href=\"https:\/\/blog.panicsoftware.com\/your-first-coroutine\/\" rel=\"noopener noreferrer nofollow\">YOUR FIRST COROUTINE,panicsoftware<\/a><\/p>\n<\/li>\n<\/ul>\n<p>\u0421\u0435\u0440\u0438\u044f \u0441\u0442\u0430\u0442\u0435\u0439 \u043e\u0442 \u0430\u0432\u0442\u043e\u0440\u0430 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 <a href=\"https:\/\/github.com\/lewissbaker\/cppcoro\" rel=\"noopener noreferrer nofollow\">cppcoro<\/a><\/p>\n<ul>\n<li>\n<p><a href=\"https:\/\/lewissbaker.github.io\/2017\/09\/25\/coroutine-theory\" rel=\"noopener noreferrer nofollow\">https:\/\/lewissbaker.github.io\/2017\/09\/25\/coroutine-theory<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/lewissbaker.github.io\/2017\/11\/17\/understanding-operator-co-await\" rel=\"noopener noreferrer nofollow\">https:\/\/lewissbaker.github.io\/2017\/11\/17\/understanding-operator-co-await<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/lewissbaker.github.io\/2018\/09\/05\/understanding-the-promise-type\" rel=\"noopener noreferrer nofollow\">https:\/\/lewissbaker.github.io\/2018\/09\/05\/understanding-the-promise-type<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/lewissbaker.github.io\/2020\/05\/11\/understanding_symmetric_transfer\" rel=\"noopener noreferrer nofollow\">https:\/\/lewissbaker.github.io\/2020\/05\/11\/understanding_symmetric_transfer<\/a><\/p>\n<\/li>\n<\/ul>\n<p>\u0412 \u0437\u0430\u043c\u0435\u0442\u043a\u0435 \u0438\u0437\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u0430 \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c\u0441\u044f \u043d\u0435\u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u043c. \u041f\u0440\u0435\u0434\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0431\u0443\u0434\u0443 \u0440\u0430\u0434 \u0443\u0432\u0438\u0434\u0435\u0442\u044c \u0432 \u0432\u0438\u0434\u0435 issues \u0438\u043b\u0438 \u0436\u0435 \u0432 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f\u0445\/\u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f\u0445 \u0432 Telegram.<\/p>\n<p>\u0427\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u043e:<\/p>\n<ul>\n<li>\n<p>\u0434\u0440\u0430\u0439\u0432\u0435\u0440 \u0434\u0438\u0441\u043f\u043b\u0435\u044f \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0441\u043e\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c, \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043d\u0430 \u0431\u0430\u0437\u0435 std::tuple \u0438 \u043a\u043b\u0430\u0441\u0441\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430 \u043d\u0430 \u0431\u0430\u0437\u0435 \u043c\u0430\u0441\u0441\u0438\u0432\u0430 \u043a\u043e\u043c\u0430\u043d\u0434.<\/p>\n<\/li>\n<li>\n<p>\u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442 \u0434\u0440\u0430\u0439\u0432\u0435\u0440\u0430 \u0434\u043b\u044f SPI-FLASH \u043f\u0430\u043c\u044f\u0442\u0438<\/p>\n<\/li>\n<li>\n<p>\u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0442\u0435\u0441\u0442\u043e\u0432 \u043d\u0430 \u0434\u0440\u0430\u0439\u0432\u0435\u0440 SPI \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0442\u0435\u0441\u0442\u043e\u0432 \u0432 GTest<\/p>\n<\/li>\n<li>\n<p>\u0420\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u0438\u0435 \u0440\u0430\u0431\u043e\u0442\u044b \u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u043f\u0440\u0438\u043c\u0438\u0442\u0438\u0432\u043e\u0432 \u0438\u0437 cppcoro \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438.<\/p>\n<\/li>\n<\/ul>\n<h4>1. \u041f\u0440\u0435\u0434\u044b\u0441\u0442\u043e\u0440\u0438\u044f \u0441 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u044f\u043c\u0438<\/h4>\n<p>\u0418\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e, \u0438\u0434\u0435\u044f \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u044b\u0432\u0430\u043d\u0438\u044f \u0441 \u043f\u043e\u0434\u0445\u043e\u0434\u0430 \u0432 \u0432\u0438\u0434\u0435 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0439 \u043f\u043e\u044f\u0432\u0438\u043b\u0430\u0441\u044c \u043a\u0430\u043a \u0442\u043e\u043b\u044c\u043a\u043e \u0432\u043e\u0437\u043d\u0438\u043a\u043b\u0430 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u044c \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u043e\u043d\u043d\u043e\u0441\u0442\u0438 read-\u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u044f\u043c\u0438. \u0414\u043b\u044f \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043e\u0447\u0435\u0440\u0435\u0434\u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u044d\u0442\u043e\u0442 \u043f\u043e\u0434\u0445\u043e\u0434 \u0431\u044b\u043b \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0443\u0434\u043e\u0431\u043d\u044b\u043c, \u043d\u043e \u0434\u043b\u044f \u043e\u0447\u0435\u0440\u0435\u0434\u0438 \u043f\u0440\u0438\u0435\u043c\u0430 \u043f\u043e\u043b\u0443\u0447\u0430\u043b\u043e\u0441\u044c \u0447\u0442\u043e-\u0442\u043e \u0432\u0440\u043e\u0434\u0435 callback-hell \u043f\u043e\u0434\u0445\u043e\u0434\u0430.<\/p>\n<p>\u0412 \u043e\u0431\u0449\u0438\u0445 \u0447\u0435\u0440\u0442\u0430\u0445, \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u043e\u043d\u043d\u044b\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u043b \u0441\u043e\u0431\u043e\u0439 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u0438\u0434\u0435\u044e:<\/p>\n<pre><code class=\"cpp\">template &lt;typename... Args&gt; void sendCommand(std::uint8_t command, Args... commandArgs) noexcept {     sendCommand(command);     sendChunk(static_cast&lt;std::uint8_t&gt;(commandArgs)...); }  template &lt;typename... Args&gt; void sendChunk(Args... _chunkArgs) noexcept {     std::array chunk = {static_cast&lt;std::uint8_t&gt;(_chunkArgs)...};     Interface::Spi::Transaction chunkTransaction{};      chunkTransaction.beforeTransaction = [this] { setDcPin(); };      chunkTransaction.transactionAction = [this, chunkToSend = std::move(chunk)] {         m_pBusPtr-&gt;sendChunk(             reinterpret_cast&lt;const std::uint8_t*&gt;(chunkToSend.data()), chunkToSend.size());     };      chunkTransaction.afterTransaction = [this] { resetDcPin(); };      m_pBusPtr-&gt;addTransaction(std::move(chunkTransaction)); }<\/code><\/pre>\n<p>\u0422.\u0435. \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0434\u043e \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0438, \u0441\u0430\u043c\u0430 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u044f \u0438 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u043e \u043f\u043e\u0441\u043b\u0435 \u043d\u0435\u0435. \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0442\u0430\u043a-\u0436\u0435 \u0431\u044b\u043b\u043e \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0443\u0434\u043e\u0431\u043d\u044b\u043c:<\/p>\n<pre><code class=\"cpp\">sendCommand(DisplayReg::SLPOUT); sendCommand(DisplayReg::COLMOD, 0x55); sendCommand(DisplayReg::MADCTL, 0x08); sendCommand(DisplayReg::CASET, 0x00, 0, 0, 240);<\/code><\/pre>\n<p>\u042d\u0442\u043e\u0442 \u043f\u043e\u0434\u0445\u043e\u0434 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0445\u043e\u0440\u043e\u0448\u043e \u0441\u0435\u0431\u044f \u043f\u043e\u043a\u0430\u0437\u0430\u043b \u0432 \u0440\u0430\u0431\u043e\u0442\u0435. \u0422\u0438\u043f\u043e\u0432\u0430\u044f \u0437\u0430\u0434\u0430\u0447\u0430 \u0434\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0438\u043c\u0435\u043b\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0432\u0438\u0434:<\/p>\n<ol start=\"0\">\n<li>\n<p>\u0412\u044b\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043f\u043e\u0440\u0442\u0430 D\/C \u0434\u043b\u044f \u0434\u0438\u0441\u043f\u043b\u0435\u044f \u0434\u043b\u044f \u0432\u044b\u0431\u043e\u0440\u0430 \u0442\u0438\u043f\u0430 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u043c\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 (\u043a\u043e\u043c\u0430\u043d\u0434\u0430 \u0438\u043b\u0438 \u0434\u0430\u043d\u043d\u044b\u0435) <\/p>\n<\/li>\n<li>\n<p>\u0421\u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u0442\u044c DMA- \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u044e<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e \u0435\u0435 \u043e\u043a\u043e\u043d\u0447\u0430\u043d\u0438\u044e \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0443, \u0435\u0441\u043b\u0438 \u0431\u043b\u043e\u043a \u0434\u0430\u043d\u043d\u044b\u0445 \u0431\u044b\u043b \u043d\u0435 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d<\/p>\n<\/li>\n<li>\n<p>\u0418\u043b\u0438 \u0432\u0435\u0440\u043d\u0443\u0442\u044c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043f\u043e\u0440\u0442\u0430 D\/C \u0432 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0438 \u043f\u0435\u0440\u0435\u0439\u0442\u0438 \u043a \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0438<\/p>\n<\/li>\n<\/ol>\n<p>\u041d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043a\u0438 \u0441\u0442\u0430\u043b\u0438 \u043f\u0440\u043e\u044f\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u043f\u0440\u0438 \u043f\u043e\u043f\u044b\u0442\u043a\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0434\u0440\u0430\u0439\u0432\u0435\u0440\u0430 \u0434\u043b\u044f SPI-FLASH \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0434\u043e\u043b\u0436\u043d\u0430 \u0431\u044b\u043b\u0430 \u0431\u044b\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0430 \u0432 \u0441\u0432\u044f\u0437\u043a\u0435 \u0441 Little FS. \u0413\u0434\u0435-\u0442\u043e \u0432 \u0442\u043e\u0442-\u0436\u0435 \u043f\u0435\u0440\u0438\u043e\u0434 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0431\u044b\u043b\u043e \u043d\u0430\u0439\u0434\u0435\u043d\u043e \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0432 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442 \u0421++20 \u043f\u043e \u0441\u043e\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0430\u043c, \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u0430 \u0441\u0435\u0440\u0438\u044f \u043c\u043e\u0442\u0438\u0432\u0438\u0440\u0443\u044e\u0449\u0438\u0445 \u0441\u0442\u0430\u0442\u0435\u0439:<\/p>\n<ul>\n<li>\n<p><a href=\"https:\/\/habr.com\/ru\/company\/yandex\/blog\/420861\/\" rel=\"noopener noreferrer nofollow\">\u0413\u043e\u0442\u043e\u0432\u0438\u043c\u0441\u044f \u043a \u0421++20. Coroutines TS \u043d\u0430 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u0435<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/habr.com\/ru\/post\/201826\/\" rel=\"noopener noreferrer nofollow\">\u0410\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0441\u0442\u044c: \u043d\u0430\u0437\u0430\u0434 \u0432 \u0431\u0443\u0434\u0443\u0449\u0435\u0435<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/habr.com\/ru\/company\/yandex\/blog\/240525\/\" rel=\"noopener noreferrer nofollow\">\u0410\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0441\u0442\u044c 2: \u0442\u0435\u043b\u0435\u043f\u043e\u0440\u0442\u0430\u0446\u0438\u044f \u0441\u043a\u0432\u043e\u0437\u044c \u043f\u043e\u0440\u0442\u0430\u043b\u044b<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/habr.com\/ru\/post\/340732\/\" rel=\"noopener noreferrer nofollow\">\u0410\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0441\u0442\u044c 3: \u0421\u0443\u0431\u044a\u0435\u043a\u0442\u043e\u0440\u043d\u0430\u044f \u043c\u043e\u0434\u0435\u043b\u044c<\/a><\/p>\n<\/li>\n<\/ul>\n<p>\u0418 \u0431\u044b\u043b\u043e \u043f\u0440\u0438\u043d\u044f\u0442\u043e \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043e \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u044b\u0432\u0430\u043d\u0438\u0438 \u043d\u0430 \u0441\u043e\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b \u0447\u0430\u0441\u0442\u0438 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u0434\u0440\u0430\u0439\u0432\u0435\u0440\u043e\u0432.<\/p>\n<h4>2. \u041a\u0430\u043a \u044d\u0442\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0432 \u043e\u0431\u0449\u0438\u0445 \u0447\u0435\u0440\u0442\u0430\u0445<\/h4>\n<p>\u0414\u043b\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u043c\u0435\u043b\u0438 \u0434\u0435\u043b\u043e \u0441 C#\/Python\/JS \u043d\u0435 \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0447\u0435\u043c-\u0442\u043e \u043d\u043e\u0432\u044b\u043c \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u0441\u043b\u043e\u0432\u0430 <code>yeild<\/code>, <code>await<\/code>,<code>async<\/code>.(\u0414\u0430, \u043e\u043d\u0438 \u0442\u0443\u0442 \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u043d\u044b \u0432 \u043e\u0431\u0449\u0435\u043c \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0435, \u0431\u0435\u0437 \u043f\u0440\u0438\u043d\u0430\u0434\u043b\u0435\u0436\u043d\u043e\u0441\u0442\u0438 \u043a \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u043c\u0443 \u044f\u0437\u044b\u043a\u0443). \u0412 \u043a\u0440\u0430\u0442\u0446\u0435, \u0438\u0434\u0435\u044f \u0441\u043e\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0432 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u043f\u0440\u0438\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0432 \u043b\u044e\u0431\u043e\u043c \u043c\u0435\u0441\u0442\u0435 \u0438\u0441\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0441 \u043f\u043e\u0441\u043b\u0435\u0434\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u043c \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435\u043c \u0435\u0435 \u0440\u0430\u0431\u043e\u0442\u044b \u0438\u0437 \u043f\u0440\u0435\u0440\u0432\u0430\u043d\u043d\u043e\u0439 \u0442\u043e\u0447\u043a\u0438. \u0424\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438, \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043b\u0435\u0433\u043a\u043e\u0432\u0435\u0441\u043d\u044b\u0435 \u043f\u043e\u0442\u043e\u043a\u0438 \u0443\u0440\u043e\u0432\u043d\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f, \u0442.\u0435. \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u0441\u043e\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c \u043d\u0430\u043c \u043d\u0435\u0442 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0431\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u043a \u044f\u0434\u0440\u0443 \u041e\u0421\/etc.<\/p>\n<p>\u0412 \u0421++20 \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u0439 \u043f\u0440\u0438\u043c\u0435\u0440 \u0441\u043e\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d \u0432 \u0432\u0438\u0434\u0435 \u0441\u043b\u0435\u0434\u0443\u0449\u0435\u0439 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u0438:<\/p>\n<pre><code class=\"cpp\">#include &lt;coroutine&gt; #include &lt;iostream&gt;  struct Awaitable {     struct Promise;     using promise_type = Promise;      Awaitable(std::coroutine_handle&lt;promise_type&gt; coroHandle) : thisCoroutine{coroHandle}     {         std::cout &lt;&lt; \"Awaitable created\\n\";     }     ~Awaitable()     {         std::cout &lt;&lt; \"Awaitable destroyed\\n\";         if (thisCoroutine)             thisCoroutine.destroy();     }     struct Promise     {         auto initial_suspend() noexcept         {             return std::suspend_always();         }         auto final_suspend() noexcept         {             return std::suspend_always();         }         void unhandled_exception()         {             std::terminate();         }          Awaitable get_return_object()         {             return Awaitable(std::coroutine_handle&lt;promise_type&gt;::from_promise(*this));         }         void return_void() noexcept         {         }     };     bool isFinished()     {         if (thisCoroutine)             return thisCoroutine.done();         return false;     }     void restore()     {         if (thisCoroutine &amp;&amp; !thisCoroutine.done())             thisCoroutine.resume();     }     std::coroutine_handle&lt;promise_type&gt; thisCoroutine; };  Awaitable callMe() {     std::cout &lt;&lt; \"Hello \";     co_await std::suspend_always{};     std::cout &lt;&lt; \"World\\n\"; } int main() {     auto lazyHello = callMe();     while (!lazyHello.isFinished())         lazyHello.restore();      return 0; }<\/code><\/pre>\n<p>\u0413\u0434\u0435 \u043f\u043e\u043b\u0435\u0437\u043d\u0430\u044f \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0430- \u043b\u0435\u043d\u0438\u0432\u044b\u0439 \u0432\u044b\u0432\u043e\u0434 \u0444\u0440\u0430\u0437\u044b &#171;Hello world&#187;. \u041f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0438\u0434\u0435\u044e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f, \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0447\u0435\u0433\u043e-\u0442\u043e \u0440\u0435\u0430\u043b\u044c\u043d\u0435\u0435. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0438 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0434\u0438\u0441\u043f\u043b\u0435\u0435\u043c. \u0414\u043b\u044f \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0430, \u0432\u0435\u0441\u044c \u043e\u0431\u043c\u0435\u043d \u0434\u043e\u043b\u0436\u0435\u043d \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442\u044c \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c DMA \u043c\u0438\u043a\u0440\u043e\u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430.<\/p>\n<h4>3. \u0420\u0430\u0431\u043e\u0442\u0430 \u0441 SPI \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u043e\u043c<\/h4>\n<p> \u0414\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 SPI \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u043e\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u043d\u0430\u0431\u043e\u0440 Awaitable-\u0442\u0438\u043f\u043e\u0432, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0432\u044b\u0437\u0432\u0430\u043d \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440 <code>co_await<\/code>. \u0421\u0430\u043c\u044b\u0439 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u0438\u043c\u0435\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0432\u0438\u0434:<\/p>\n<pre><code class=\"cpp\">struct Awaiter {     bool resetDcPin = false;     bool restoreInSpiCtx = false;     const std::uint8_t* pTransmitBuffer;     This_t* pBaseDisplay;     std::uint16_t bufferSize;      bool await_ready() const noexcept     {         \/\/ \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c, \u0435\u0441\u0442\u044c \u043b\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u044c \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u043f\u0440\u0438\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0443 \u0441\u043e\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b         const bool isAwaitReady = pTransmitBuffer == nullptr || bufferSize == 0;         return isAwaitReady;     }     void await_resume() const noexcept     {         \/\/\u0432\u044b\u0437\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0432\u0435\u0440\u0448\u0435\u043d \u043f\u0440\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0438 .resume() \u0443 \u0441\u043e\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b         if (resetDcPin)             pBaseDisplay-&gt;setDcPin();     }     void await_suspend(std::coroutine_handle&lt;&gt; thisCoroutine) const     {         \/\/\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u043d\u0430 \u0432\u0440\u0435\u043c\u044f \u043f\u0440\u0438\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0441\u043e\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b. \u0412 SPI \u0434\u0440\u0430\u0439\u0432\u0435\u0440 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442\u0441\u044f handle \u0441\u043e\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b,         \/\/ \u043f\u043e\u0441\u043b\u0435 \u0447\u0435\u0433\u043e \u043e\u043d\u0430 \u043f\u0440\u0438\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0430.         if (resetDcPin)             pBaseDisplay-&gt;resetDcPin();          pBaseDisplay-&gt;getSpiBus()-&gt;transmitBuffer(             pTransmitBuffer, bufferSize, thisCoroutine.address(), restoreInSpiCtx);     } };<\/code><\/pre>\n<p>\u0412 \u0441\u0432\u043e\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c, \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 SPI-\u0434\u0440\u0430\u0439\u0432\u0435\u0440\u0430 \u043f\u043e \u043e\u043a\u043e\u043d\u0447\u0430\u043d\u0438\u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u043a\u043e\u0434:<\/p>\n<pre><code class=\"cpp\">void transmitCompleted() noexcept {     const bool isAllDmaTransactionsProceeded = m_transmitContext.fullDmaTransactionsCount == 0;     const bool isAllChunckedTransactionsCompleted =         m_transmitContext.chunkedTransactionBufSize == 0;      if (!isAllDmaTransactionsProceeded)     {         \/\/\u0415\u0441\u043b\u0438 \u0435\u0449\u0435 \u043c\u043e\u0436\u0435\u043c \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0438 \u0440\u0430\u0437\u043c\u0435\u0440\u043e\u043c \u0441 DMA \u0431\u0443\u0444\u0435\u0440     }     else if (!isAllChunckedTransactionsCompleted)     {         \/\/ \u0415\u0441\u043b\u0438 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0438 \u043c\u0435\u043d\u044c\u0448\u0435 \u0440\u0430\u0437\u043c\u0435\u0440\u0430 DMA \u0431\u0443\u0444\u0435\u0440\u0430 \u043d\u0435 \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u044b     }     else     {         \/\/ \u0412 \u0441\u043b\u0443\u0447\u0430\u0435, \u0435\u0441\u043b\u0438 \u0432\u0441\u0435 DMA \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u044b- \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c, \u0432 \u043a\u0430\u043a\u043e\u043c \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f         \/\/ \u0434\u043e\u043b\u0436\u043d\u0430 \u0431\u044b\u0442\u044c \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0430 \u0441\u043e\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0430.\u041d\u0435 \u0437\u0430\u0431\u044b\u0432\u0430\u0435\u043c, \u0447\u0442\u043e \u044d\u0442\u043e\u0442 \u043c\u0435\u0442\u043e\u0434 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0438\u0437 \u043a\u043e\u043d\u0442\u0435\u043a\u0442\u0430         \/\/ \u043f\u0440\u0435\u0440\u044b\u0432\u0430\u043d\u0438\u044f \u0438 \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0442\u044f\u0436\u0435\u043b\u043e\u0439 \u0441\u043e\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u0438\u0432\u0435\u0441\u0442\u0438 \u043a \u0442\u0440\u0443\u0434\u043d\u043e\u0443\u043b\u0430\u0432\u043b\u0438\u0432\u0430\u0430\u0435\u043c\u044b\u043c         \/\/ \u043e\u0448\u0438\u0431\u043a\u0430\u043c. \u0422\u0443\u0442 \u0435\u0441\u0442\u044c \u0434\u0432\u0430 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430 - \u043b\u0438\u0431\u043e \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c\u0441\u044f \u0432 \u043a\u043e\u043d\u0442\u0435\u043a\u0442\u0435 \u043f\u0440\u0435\u0440\u044b\u0432\u0430\u043d\u0438\u044f, \u043b\u0438\u0431\u043e         \/\/ \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u043c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0441\u043e\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b \u0432 \u043e\u0447\u0435\u0440\u0435\u0434\u044c,\u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0432 \u0433\u043b\u0430\u0432\u043d\u043e\u043c \u043f\u043e\u0442\u043e\u043a\u0435. \u0422\u0430\u043a\u0438\u043c         \/\/ \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u0441\u043e\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0430 \u0431\u0443\u0434\u0435\u0442 \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0430 \u0438\u0437 main-\u043f\u043e\u0442\u043e\u043a\u0430.         if (m_transmitContext.restoreInSpiCtx)         {             m_coroHandle.resume();         }         else         {             CoroUtils::CoroQueueMainLoop::GetInstance().pushToLater(m_coroHandle);         }     } }<\/code><\/pre>\n<p>\u0412 \u0446\u0435\u043b\u044f\u0445 \u0443\u043c\u0435\u043d\u044c\u0448\u0435\u043d\u0438\u044f \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u043d\u0430 \u0447\u0442\u0435\u043d\u0438\u0435 \u043a\u043e\u0434\u0430- \u043f\u0440\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0438 <code>transmitBuffer<\/code> \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430 \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u0434\u0440\u0430\u0439\u0432\u0435\u0440\u0435, \u043f\u043e\u0441\u043b\u0435 \u0447\u0435\u0433\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u0440\u0430\u0441\u0441\u0447\u0435\u0442 \u0446\u0435\u043b\u043e\u0433\u043e \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 DMA \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0439 + \u0440\u0430\u0437\u043c\u0435\u0440 \u043e\u0441\u0442\u0430\u0432\u0448\u0435\u0433\u043e\u0441\u044f \u0431\u0443\u0444\u0435\u0440\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0442\u0430\u043a-\u0436\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u0435\u0440\u0435\u0434\u0430\u043d. \u0414\u0430\u043b\u0435\u0435, \u043f\u043e \u043e\u043a\u043e\u043d\u0447\u0430\u043d\u0438\u044e \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438 DMA \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0438 \u0432\u044b\u043f\u043e\u043b\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u0432\u044b\u0437\u043e\u0432 <code>transmitCompleted<\/code> \u0433\u0434\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043d\u043e\u0432\u043e\u0439 \u043f\u043e\u0441\u044b\u043b\u043a\u0438 \u0438\u043b\u0438 \u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u043f\u0440\u0438\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043d\u043e\u0439 \u0441\u043e\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b \u0432 \u0437\u0430\u0434\u0430\u043d\u043d\u043e\u043c \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f( \u0432 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0435 \u043f\u0440\u0435\u0440\u044b\u0432\u0430\u043d\u0438\u044f \u0438\u043b\u0438 \u0436\u0435 \u0432 \u0433\u043b\u0430\u0432\u043d\u043e\u043c \u043f\u043e\u0442\u043e\u043a\u0435 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b).<\/p>\n<h4>4. \u0418\u0442\u0435\u0440\u0430\u0446\u0438\u044f \u043d\u0430 \u043c\u0430\u0441\u0441\u0438\u0432\u0435 \u043a\u043e\u043c\u0430\u043d\u0434 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438<\/h4>\n<p>\u041d\u0430\u043c \u0431\u0443\u0434\u0443\u0442 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0432\u0441\u043e\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0439. \u0418\u0445 \u0431\u043e\u043b\u044c\u0448\u0435, \u0447\u0435\u043c \u0434\u0432\u0435. \u043d\u043e \u0432 \u043e\u0431\u0449\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u0438\u043c \u0438\u0445 \u0442\u0430\u043a:<\/p>\n<pre><code class=\"cpp\">auto sendCommand(const std::uint8_t* pBuffer, std::size_t bufferSize) noexcept {     const std::uint8_t* commandBuf = pBuffer;     const std::uint8_t* ArgBuf = pBuffer + 1;     const std::uint16_t ArgsBufferSize = static_cast&lt;std::uint16_t&gt;(bufferSize - 1);      return CoroUtils::when_all_sequence(         sendCommandImpl(commandBuf),         ArgsBufferSize &gt; 0 ? sendChunk(ArgBuf, ArgsBufferSize) : sendChunk(nullptr, 0)); }  auto sendChunk(const std::uint8_t* pBuffer, std::size_t bufferSize) noexcept {     return Awaiter{.pTransmitBuffer = pBuffer,                    .pBaseDisplay = this,                    .bufferSize = static_cast&lt;std::uint16_t&gt;(bufferSize)}; }<\/code><\/pre>\n<p>\u041c\u0430\u0441\u0441\u0438\u0432 \u0434\u043b\u044f \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0434\u0438\u0441\u043f\u043b\u0435\u044f \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<pre><code class=\"cpp\">namespace DisplayDriver::InitializationCommands { \/\/ clang-format off constexpr std::size_t CommandsSize = 328; constexpr std::size_t CommandsTransactionsCount = 59; static auto Commands = std::array&lt;std::uint8_t, CommandsSize&gt; {     \/***Cmd****Argc****delay****argv*****************************\/         0xFE,   0,      0     ,   0xEF,   0,      0     ,   0xEB,   1,      0,      0x14      ,   0xFE,   0,      0     ,   0xEF,   0,      0     ,   0xEB,   1,      0,      0x14     ,   0xFE,   0,      0     ,   0xEF,   0,      0     ,   0xEB,   1,      0,      0x14     ..... } \/\/ clang-format on } \/\/ namespace DisplayDriver::InitializationCommands<\/code><\/pre>\n<p>\u0421\u043e\u0431\u0438\u0440\u0430\u0435\u043c \u0432 \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u0443\u044e \u043a\u0430\u0440\u0442\u0438\u043d\u0443 \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0434\u0438\u0441\u043f\u043b\u0435\u044f. \u0414\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0443 \u043a\u043e\u043c\u0430\u043d\u0434\u044b + \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0443 \u0435\u0435 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u0432, \u0435\u0441\u043b\u0438 \u043e\u043d\u0438 \u0435\u0441\u0442\u044c + \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u043e\u0436\u0438\u0434\u0430\u043d\u0438\u0435 N \u043c\u0438\u043b\u043b\u0438\u0441\u0435\u043a\u0443\u043d\u0434(\u043f\u043e\u0441\u043b\u0435 \u043a\u043e\u043c\u0430\u043d\u0434\u044b DISP_ON, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440). \u0422.\u043a. \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0440\u0430\u043d\u0435\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0439 &#8212; \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0432\u0438\u0434 \u0442\u0435\u043b\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u0438:<\/p>\n<pre><code class=\"cpp\">void initDisplay() noexcept {     TBaseSpiDisplay::resetResetPin();     Delay::waitFor(100);     TBaseSpiDisplay::setResetPin();     size_t CommandCount = InitializationCommands::CommandsTransactionsCount;     const std::uint8_t* pBuffer = InitializationCommands::Commands.data();     while (CommandCount--)     {         const std::uint8_t* Command = pBuffer++;         const std::uint8_t NumArgs = *pBuffer++;         const std::uint8_t Delay = *pBuffer++;          co_await TBaseSpiDisplay::sendCommandImpl(Command);         if (NumArgs)         {             co_await TBaseSpiDisplay::sendChunk(pBuffer++, NumArgs);             pBuffer += (NumArgs - 1);         }         if (Delay)             Delay::waitFor(Delay);     }     TBaseSpiDisplay::m_displayInitialized.set(); }<\/code><\/pre>\n<p>\u0427\u0442\u043e \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438? \u041a\u0430\u0436\u0434\u044b\u0439 \u0432\u044b\u0437\u043e\u0432 <code>sendCommandImpl<\/code> &#8212; \u0430\u0441\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439 &#171;\u043f\u043e\u0434 \u043a\u0430\u043f\u043e\u0442\u043e\u043c&#187;. \u041f\u0440\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0438 <code>co_await TBaseSpiDisplay::sendCommandImpl<\/code> \u0438\u043b\u0438 <code>co_await TBaseSpiDisplay::sendChunk<\/code> &#8212; \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u043f\u0440\u0438\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 initDisplay, \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u0432\u044b\u0437\u044b\u0432\u0430\u044e\u0449\u0435\u0439 \u0441\u0442\u043e\u0440\u043e\u043d\u0435. \u041f\u043e \u043e\u043a\u043e\u043d\u0447\u0430\u043d\u0438\u0438 \u043f\u0440\u043e\u0446\u0435\u0434\u0443\u0440\u044b \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0444\u043b\u0430\u0433\u0430 \u043e\u043a\u043e\u043d\u0447\u0430\u043d\u0438\u044f \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0434\u0438\u0441\u043f\u043b\u0435\u044f.<\/p>\n<p>\u041a\u0430\u043a \u043c\u043e\u0436\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u043f\u0440\u043e\u0446\u0435\u0434\u0443\u0440\u0430 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0434\u0438\u0441\u043f\u043b\u0435\u0439\u043d\u043e\u0433\u043e \u0431\u0443\u0444\u0435\u0440\u0430? \u0422.\u043a. \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 LVGL &#8212; \u0444\u0440\u0435\u0439\u043c\u0431\u0443\u0444\u0435\u0440 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c non-screen-sized, \u0442.\u0435. \u043d\u0435 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0440\u0430\u0437\u043c\u0435\u0440\u0443 \u0431\u0443\u0444\u0435\u0440\u0430 \u044d\u043a\u0440\u0430\u043d\u0430, \u0447\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0443 \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u0430\u043c\u0438.(\u0418\u043d\u043e\u0433\u0434\u0430 \u043c\u043e\u0436\u0435\u0442 \u043d\u0435 \u0431\u044b\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u043f\u043e\u043c\u0435\u0441\u0442\u0438\u0442\u044c \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0432 \u043f\u0430\u043c\u044f\u0442\u044c \u0431\u0443\u0444\u0435\u0440 \u0434\u0438\u0441\u043f\u043b\u0435\u044f)<\/p>\n<p>\u0414\u043b\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u043d\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0443 \u043a\u043e\u043c\u0430\u043d\u0434 \u043d\u0430 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0443 \u043e\u0431\u043b\u0430\u0441\u0442\u0438 \u044d\u043a\u0440\u0430\u043d\u0430, \u0432 \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0431\u0443\u0434\u0435\u0442 \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u0435\u043d\u0430 \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0430, \u043f\u043e\u0441\u043b\u0435 \u0447\u0435\u0433\u043e \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u043a\u043e\u043c\u0430\u043d\u0434\u0443 \u043d\u0430 \u0437\u0430\u043f\u0438\u0441\u044c \u0432 \u043f\u0430\u043c\u044f\u0442\u044c \u0434\u0438\u0441\u043f\u043b\u0435\u044f \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0443 \u0434\u0438\u0441\u043f\u043b\u0435\u0439\u043d\u043e\u0433\u043e \u0431\u0443\u0444\u0435\u0440\u0430. \u0427\u0442\u043e-\u0436\u0435. \u0412 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u043c \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0435, \u0434\u0430\u043d\u043d\u044b\u0439 \u043a\u043e\u0434 \u043c\u043e\u0433 \u0431\u044b \u0438\u043c\u0435\u0442\u044c \u0432\u0438\u0434:<\/p>\n<pre><code class=\"cpp\">void fillRectangle(     std::uint16_t x,     std::uint16_t y,     std::uint16_t width,     std::uint16_t height,     TBaseSpiDisplay::TColor* colorToFill) noexcept {      const std::uint16_t DisplayHeight = TBaseSpiDisplay::getHeight();     const std::uint16_t DisplayWidth = TBaseSpiDisplay::getWidth();      const bool isCoordsValid{!((x &gt;= DisplayWidth) || (y &gt;= DisplayHeight))};     if (isCoordsValid)     {         \/\/\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u0440\u0430\u0437\u043c\u0435\u0440\u044b \u0431\u0443\u0444\u0435\u0440\u0430 \u0434\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438         const size_t BytesSizeX = (width - x + 1);         const size_t BytesSizeY = (height - y + 1);         const size_t BytesSquare = BytesSizeX * BytesSizeY;         const size_t TransferBufferSize = (BytesSquare * sizeof(typename TBaseSpiDisplay::TColor));          \/\/\u0424\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c \u043e\u0431\u043b\u0430\u0441\u0442\u044c \u044d\u043a\u0440\u0430\u043d\u0430 \u0434\u043b\u044f \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f         setAddrWindow(x, y, width, height);          static std::uint8_t RamWriteCmd{0x2C};         \/\/ \u041a\u043e\u043c\u0430\u043d\u0434\u0430 \u043d\u0430 \u0437\u0430\u043f\u0438\u0441\u044c \u0432 \u044d\u043a\u0440\u0430\u043d\u043d\u044b\u0439 \u0431\u0443\u0444\u0435\u0440         TBaseSpiDisplay::sendCommandImplFast(&amp;RamWriteCmd);          \/\/\u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u043a\u0430\u0435\u043c \u043f\u043e\u0440\u0442 Data\/Command \u0432 \u0440\u0435\u0436\u0438\u043c \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438(\u0432\u0441\u0435 \u0447\u0442\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u043e \u0432 \u0434\u0438\u0441\u043f\u043b\u0435\u0439         \/\/\u0432\u043e\u0441\u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442\u0441\u044f, \u043a\u0430\u043a \u0434\u0430\u043d\u043d\u044b\u0435, \u0430 \u043d\u0435 \u043a\u0430\u043a \u043a\u043e\u043c\u0430\u043d\u0434\u044b)         TBaseSpiDisplay::setDcPin();         \/\/ \u041e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u0434\u0438\u0441\u043f\u043b\u0435\u0439\u043d\u044b\u0439 \u0431\u0443\u0444\u0435\u0440         TBaseSpiDisplay::sendChunk(             reinterpret_cast&lt;const std::uint8_t*&gt;(colorToFill), TransferBufferSize);         \/\/ \u0412\u043e\u0441\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043f\u043e\u0440\u0442\u0430 Data\/Command         TBaseSpiDisplay::resetDcPin();         \/\/ \u0421\u0438\u0433\u043d\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u043c \u043e\u0431 \u043e\u043a\u043e\u043d\u0447\u0430\u043d\u0438\u0438 \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0438 \u043e\u0431\u043b\u0430\u0441\u0442\u0438 \u0434\u0438\u0441\u043f\u043b\u0435\u044f         TBaseSpiDisplay::onRectArreaFilled.emitLater();     } }<\/code><\/pre>\n<p>\u0410 \u0447\u0442\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c, \u0447\u0442\u043e\u0431\u044b \u043a\u043e\u0434 \u0441\u0442\u0430\u043b \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c\u0441\u044f \u0430\u0441\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e? \u0422.\u0435. \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u043b\u0438 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u044e \u043f\u043e DMA- \u0432\u0435\u0440\u043d\u0443\u043b\u0438\u0441\u044c \u0432 \u0442\u043e\u0447\u043a\u0443 \u043f\u0440\u0438\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438, \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u043b\u0438 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u043a\u043e\u043c\u0430\u043d\u0434\u0443 \u0438\/\u0438\u043b\u0438 \u0434\u0438\u0441\u043f\u043b\u0435\u0439\u043d\u044b\u0439 \u0431\u0443\u0444\u0435\u0440 \u0438 \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u043b\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435? \u041d\u0430 \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u0435 \u043d\u0438\u0436\u0435 \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u043d\u044b \u0432\u0441\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c(\u043f\u0440\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0432\u0441\u0435).<\/p>\n<pre><code class=\"cpp\">\/\/\u0424\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c \u043e\u0431\u043b\u0430\u0441\u0442\u044c \u044d\u043a\u0440\u0430\u043d\u0430 \u0434\u043b\u044f \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f co_await setAddrWindow(x, y, width, height); \/\/ &lt;=============== co_await here  static std::uint8_t RamWriteCmd{0x2C}; \/\/ \u041a\u043e\u043c\u0430\u043d\u0434\u0430 \u043d\u0430 \u0437\u0430\u043f\u0438\u0441\u044c \u0432 \u044d\u043a\u0440\u0430\u043d\u043d\u044b\u0439 \u0431\u0443\u0444\u0435\u0440 co_await TBaseSpiDisplay::sendCommandImplFast(&amp;RamWriteCmd); \/\/ &lt;=============== co_await here  TBaseSpiDisplay::setDcPin(); \/\/ \u041e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u0434\u0438\u0441\u043f\u043b\u0435\u0439\u043d\u044b\u0439 \u0431\u0443\u0444\u0435\u0440 co_await TBaseSpiDisplay::sendChunk(     reinterpret_cast&lt;const std::uint8_t*&gt;(colorToFill),     TransferBufferSize); \/\/ &lt;=============== co_await here  TBaseSpiDisplay::resetDcPin();  TBaseSpiDisplay::onRectArreaFilled.emitLater();<\/code><\/pre>\n<p>\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435\u043c \u0432 \u0442\u0440\u0435\u0445 \u0441\u0442\u0440\u043e\u043a\u0430\u0445 <code>co_await<\/code> \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438 \u0430\u0441\u0441\u0438\u043d\u0445\u0445\u0440\u043e\u043d\u043d\u044b\u0439 \u043a\u043e\u0434. \u041e\u0441\u0442\u0430\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043e\u043f\u0438\u0441\u0430\u0442\u044c \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u043f\u0440\u0438\u043c\u0438\u0442\u0438\u0432\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u043d\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b, \u0447\u0442\u043e\u0431\u044b \u044d\u0442\u043e \u0432\u0441\u0435 \u0437\u0430\u0440\u0430\u0431\u043e\u0442\u0430\u043b\u043e. \u0410 \u0438\u043c\u0435\u043d\u043d\u043e, \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u0438\u0442\u0438\u0432\u044b <code>when_all_sequence<\/code> \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u0438 <code>Task<\/code> \u0434\u043b\u044f \u0432\u044b\u0437\u043e\u0432\u0430 <code>co_await<\/code> \u043d\u0430 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u043e\u043c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <code>setAddrWindow<\/code>.<\/p>\n<h4>5. \u0414\u043b\u044f \u043b\u044e\u0431\u0438\u0442\u0435\u043b\u0435\u0439 \u043f\u043e\u0441\u043b\u043e\u0436\u043d\u0435\u0435 &#8212; \u0438\u0442\u0435\u0440\u0430\u0446\u0438\u044f \u043d\u0430 std::tuple<\/h4>\n<p>\u0414\u0430\u043d\u043d\u0430\u044f \u0438\u0434\u0435\u044f \u0431\u044b\u043b\u0430 \u043f\u0435\u0440\u0432\u043e\u0439. \u041f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c \u0442\u0430\u0431\u043b\u0438\u0446\u0443 \u043a\u043e\u043c\u0430\u043d\u0434 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0434\u0438\u0441\u043f\u043b\u043b\u0435\u044f \u0432 \u0432\u0438\u0434\u0435 std::tuple \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432 \u0441\u0432\u043e\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u0441\u043e\u0441\u0442\u043e\u044f\u043b \u0431\u044b \u0438\u0437 \u0414\u0435\u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0440\u043e\u0432 \u043a\u043e\u043c\u0430\u043d\u0434. \u041f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u043e- \u043d\u0435\u0442 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u0443 \u043a\u043e\u043c\u0430\u043d\u0434\u044b. \u0412\u0441\u0435, \u0447\u0442\u043e \u0437\u0430\u0434\u0430\u043d\u043e \u043f\u043e\u0441\u043b\u0435 <code>DefaultDelay<\/code>&#8212; \u0431\u0443\u0434\u0435\u0442 \u0441\u0447\u0438\u0442\u0430\u0442\u044c\u0441\u044f \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u043c \u043a\u043e\u043c\u0430\u043d\u0434\u044b.<\/p>\n<p>\u0414\u0435\u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0440 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0431\u044b\u043b \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d \u043a\u0430\u043a:<\/p>\n<pre><code class=\"cpp\">template &lt;std::uint8_t... Command&gt; struct CommandDescriptor { };  template &lt;std::uint8_t Command, std::uint8_t CommandDelay, std::uint8_t... CommandArgs&gt; struct CommandDescriptor&lt;Command, CommandDelay, CommandArgs...&gt; {     std::uint8_t commandDelay = CommandDelay;     std::array&lt;std::uint8_t, sizeof...(CommandArgs) + 1&gt; command{Command, CommandArgs...}; };  template &lt;std::uint8_t Command, std::uint8_t CommandDelay&gt; struct CommandDescriptor&lt;Command, CommandDelay&gt; {     std::uint8_t commandDelay = CommandDelay;     std::array&lt;std::uint8_t, 1&gt; command{Command}; };  template &lt;std::uint8_t Command&gt; struct CommandDescriptor&lt;Command&gt; {     std::uint8_t commandDelay = 0;     std::array&lt;std::uint8_t, 1&gt; command{Command}; };<\/code><\/pre>\n<p>\u0412 \u0441\u0432\u043e\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c, \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u043a\u043e\u043c\u0430\u043d\u0434 \u0434\u043b\u044f \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0431\u044b\u043b\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0438\u0445 \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432 tuple. \u0412 \u043f\u0435\u0440\u0432\u043e\u0439 \u0438\u0442\u0435\u0440\u0430\u0446\u0438\u0438, \u044d\u0442\u043e \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u043b\u043e \u0432\u043e\u0442 \u0442\u0430\u043a:<\/p>\n<pre><code class=\"cpp\">static std::tuple CommandsArray = {     CommandDescriptor&lt;0xFE&gt;{},     CommandDescriptor&lt;0xEF&gt;{},     CommandDescriptor&lt;0xEB, DefaultDelay, 0x14&gt;{},     CommandDescriptor&lt;0xFF, DefaultDelay, 0x60, 0x01, 0x04&gt;{},     CommandDescriptor&lt;0x74, DefaultDelay, 0x10, 0x75, 0x80, 0x00, 0x00, 0x4E, 0x00&gt;{},     CommandDescriptor&lt;0xC3, DefaultDelay, 0x14, 0xC4, 0x14, 0xC9, 0x25&gt;{},     CommandDescriptor&lt;0x74, DefaultDelay, 0x10, 0x85, 0x80, 0x00, 0x00, 0x4e, 0x00&gt;{},     CommandDescriptor&lt;0x29&gt;{}};<\/code><\/pre>\n<p>\u041a\u0430\u043a \u0440\u0430\u0441\u043f\u0430\u043a\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0434\u043e\u0431\u043d\u044b\u0439 <code>std::tuple<\/code> \u0434\u0435\u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0440\u043e\u0432? \u041c\u043e\u0436\u043d\u043e \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u0442\u044c <code>std::apply<\/code>\u0438 \u0432 \u043d\u0435\u043c \u0443\u0436\u0435 \u0437\u0430\u043d\u0438\u043c\u0430\u0442\u044c\u0441\u044f \u0440\u0430\u0441\u043f\u0430\u043a\u043e\u0432\u043a\u043e\u0439 \u043a\u043e\u043c\u0430\u043d\u0434 \u0434\u043b\u044f \u0438\u0445 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438. \u0412 \u0442\u0430\u043a\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435, \u043f\u0440\u043e\u0438\u0437\u043e\u0439\u0434\u0435\u0442 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0435 \u0432\u0438\u0434\u043e\u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0434\u043b\u044f \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0434\u0438\u0441\u043f\u043b\u0435\u044f.<\/p>\n<pre><code class=\"cpp\">template &lt;typename Tuple, std::size_t... Indexes&gt; CoroUtils::VoidTask launchInit(     Tuple&amp;&amp; commandSequence,     std::integer_sequence&lt;std::size_t, Indexes...&gt;) noexcept {     (co_await CoroUtils::when_all_sequence(sendCommand(          std::get&lt;Indexes&gt;(commandSequence).command.data(),          std::get&lt;Indexes&gt;(commandSequence).command.size())),      ...); }<\/code><\/pre>\n<p>\u041f\u0435\u0440\u0435\u0439\u0434\u0435\u043c \u043a \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u0438\u044e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0445 \u043f\u0440\u0438\u043c\u0438\u0442\u0438\u0432\u043e\u0432, \u0430 \u0438\u043c\u0435\u043d\u043d\u043e <code>CoroUtils::when_all_sequence<\/code> \u0438 <code>CoroUtils::VoidTask<\/code>.<\/p>\n<h4>6. \u0420\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c when_all_sequence<\/h4>\n<p>\u041f\u0440\u0435\u0436\u0434\u0435 \u0432\u0441\u0435\u0433\u043e- \u0437\u0430\u0447\u0435\u043c \u043e\u043d \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c? \u0412 \u043e\u0431\u0449\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435- \u043a\u043e\u0433\u0434\u0430 \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u0432\u044b\u0437\u0432\u0430\u0442\u044c <code>co_await<\/code> \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u043d\u044b\u0445 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u0432.<\/p>\n<p>\u041a\u0430\u043a \u0431\u044b\u043b\u043e \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u043e \u0432 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0432\u044b\u0448\u0435, \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u044c \u0440\u0430\u0441\u043f\u0430\u043a\u043e\u0432\u0430\u0442\u044c <code>std::tuple<\/code> \u043a\u043e\u043c\u0430\u043d\u0434. \u0418\u043b\u0438 \u0436\u0435, \u043c\u044b \u043d\u0435 \u0445\u043e\u0442\u0438\u043c \u043f\u0438\u0441\u0430\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0430\u0437 <code>co_await<\/code> \u0434\u0440\u0443\u0433-\u0437\u0430 \u0434\u0440\u0443\u0433\u043e\u043c. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u044d\u043a\u0440\u0430\u043d\u043d\u043e\u0439 \u043e\u0431\u043b\u0430\u0441\u0442\u0438, \u043d\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b \u043f\u043e X\/Y.\u0424\u0440\u0430\u0433\u043c\u0435\u043d\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0438\u043c\u0435\u0435\u0442 \u0432\u0438\u0434:<\/p>\n<pre><code class=\"cpp\">static std::array xAxisCommand = std::array{static_cast&lt;std::uint8_t&gt;(0x2a),                                             static_cast&lt;std::uint8_t&gt;(xa &gt;&gt; 24),                                             static_cast&lt;std::uint8_t&gt;(xa &gt;&gt; 16),                                             static_cast&lt;std::uint8_t&gt;(xa &gt;&gt; 8),                                             static_cast&lt;std::uint8_t&gt;(xa)}; static std::array yAxisCommand = std::array{static_cast&lt;std::uint8_t&gt;(0x2b),                                             static_cast&lt;std::uint8_t&gt;(ya &gt;&gt; 24),                                             static_cast&lt;std::uint8_t&gt;(ya &gt;&gt; 16),                                             static_cast&lt;std::uint8_t&gt;(ya &gt;&gt; 8),                                             static_cast&lt;std::uint8_t&gt;(ya)}; co_await sendCommand(xAxisCommand.data(), xAxisCommand.size()); co_await sendCommand(yAxisCommand.data(), yAxisCommand.size());<\/code><\/pre>\n<p>\u041f\u0440\u0435\u0434\u043f\u043e\u043b\u043e\u0436\u0438\u043c, \u0447\u0442\u043e \u0434\u0432\u0430 \u043f\u043e\u0434\u0440\u044f\u0434 <code>co_await<\/code> \u044d\u0442\u043e \u043d\u0435 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430. \u041d\u043e \u0447\u0442\u043e \u0434\u0435\u043b\u0430\u0442\u044c, \u0435\u0441\u043b\u0438 \u0438\u0445 \u0441\u0442\u0430\u043d\u0435\u0442 \u0431\u043e\u043b\u044c\u0448\u0435? \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u0440\u0430\u0441\u043f\u0430\u043a\u043e\u0432\u043a\u0438 <code>std::tuple<\/code> \u0441 \u0434\u0435\u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0440\u0430\u043c\u0438 \u043a\u043e\u043c\u0430\u043d\u0434 \u043d\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0432\u044b\u0437\u0432\u0430\u0442\u044c co_await \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0434\u0435\u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0440\u0430. \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u0441\u044f, \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430 \u043f\u0440\u0438\u0439\u0434\u0435\u0442\u0441\u044f \u043f\u0438\u0441\u0430\u0442\u044c <code>co_await std::get&lt;N&gt;<\/code>? \u041d\u0435 \u043f\u043e\u0440\u044f\u0434\u043e\u043a. \u0414\u043b\u044f \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430 \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u0442\u044c fold-expression \u0438\u0437 \u0421++17, \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0432\u044b\u0437\u0432\u0430\u0442\u044c <code>co_await<\/code> \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0430. \u041f\u0440\u0438 \u044d\u0442\u043e\u043c, \u0432\u0441\u0435 \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u043d\u044b\u0435 \u0437\u0430\u0434\u0430\u0447\u0438 \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432 <code>std::tuple<\/code>. \u041f\u0440\u0438\u0432\u0435\u0434\u0435\u043c \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e <code>WhenAllSequence<\/code> \u0441 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f\u043c\u0438:<\/p>\n<pre><code class=\"cpp\">template &lt;typename... Tasks&gt; struct WhenAllSequence {   \/\/  \u0425\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u043d\u044b\u0445 \u0437\u0430\u0434\u0430\u0447   std::tuple&lt;Tasks...&gt; m_taskList;    explicit WhenAllSequence(Tasks &amp;&amp;... tasks) noexcept       : m_taskList(std::move(tasks)...) {}    explicit WhenAllSequence(std::tuple&lt;Tasks...&gt; &amp;&amp;tasks) noexcept       : m_taskList(std::move(tasks)) {}    bool await_ready() const noexcept {     \/\/\u0412\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c false, \u0442.\u043a. \u0432\u044b\u0437\u043e\u0432 await_suspend \u0434\u043e\u043b\u0435\u0436\u043d \u0431\u044b\u0442\u044c \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d. \u0415\u0441\u043b\u0438     \/\/\u0432\u0435\u0440\u043d\u0443\u0442\u044c true- \u043f\u0440\u0438\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0441\u043e\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430 \u043d\u0435 \u0431\u0443\u0434\u0435\u0442, \u0442\u0435\u043b\u043e     \/\/await_suspend \u0432\u044b\u0437\u0432\u0430\u043d\u043e \u043d\u0435 \u0431\u0443\u0434\u0435\u0442.     return false;   }    void await_suspend(stdcoro::coroutine_handle&lt;&gt; handle) noexcept {     \/\/ \u043f\u0440\u0438 \u0432\u044b\u0437\u043e\u0432\u0435 co_await \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d \u0432\u044b\u0437\u043e\u0432 launchAll, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440\u043c     \/\/ \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430 std::tuple \u0431\u044b\u043b \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0440\u043e\u0432\u0430\u043d \u0432\u044b\u0437\u043e\u0432 co_await     co_await launchAll(         std::make_integer_sequence&lt;std::size_t, sizeof...(Tasks)&gt;{});     handle.resume();   }    template &lt;std::size_t... Indexes&gt;   VoidTask launchAll(std::integer_sequence&lt;std::size_t, Indexes...&gt;) {     \/\/ \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f fold-expression \u0438\u0437 C++17 - \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c co_await \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e     \/\/ \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430 tuple     (co_await std::get&lt;Indexes&gt;(m_taskList), ...);   }    void await_resume() noexcept {} };  template &lt;typename... Args&gt; auto when_all_sequence(Args &amp;&amp;... args) noexcept {   \/\/ \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u0438\u0440\u0443\u0435\u043c WhenAllSequence \u043e\u0442 \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u043d\u044b\u0445 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u0432, \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u0438\u0437   \/\/ \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c tuple.   return WhenAllSequence{std::make_tuple(std::move(args)...)}; }  } \/\/ namespace CoroUtils<\/code><\/pre>\n<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043d\u0435 \u0434\u0443\u0431\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0435 <code>co_await<\/code> \u0434\u043b\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u043c\u044b\u0445 \u0441\u043e\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c. <\/p>\n<p>\u0412 \u0434\u0430\u043d\u043d\u043e\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0443 \u043d\u0430\u0441 \u043f\u043e\u044f\u0432\u0438\u043b\u0441\u044f \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u044b\u0439 \u0442\u0438\u043f <code>VoidTask<\/code>. \u041e\u043d \u043d\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c \u0434\u043b\u044f \u043f\u0440\u0438\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f <code>await_suspend<\/code> \u0442.\u043a. \u0432 \u0438\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043f\u0440\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0438 <code>co_await<\/code> \u0434\u043b\u044f \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u0438\u0437 \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u043d\u044b\u0445 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u0432 <code>launchAll<\/code> \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u043e \u0432\u043e\u0437\u0432\u0430\u0449\u0435\u043d\u0438\u0435 \u043d\u0430 \u0432\u044b\u0437\u044b\u0432\u0430\u044e\u0449\u0443\u044e \u0441\u0442\u043e\u0440\u043e\u043d\u0443, \u043f\u043e\u0441\u043b\u0435 \u0447\u0435\u0433\u043e \u0432\u044b\u0437\u043e\u0432 <code>handle.resume()<\/code> \u0447\u0442\u043e \u043d\u0435 \u0441\u043e\u0432\u0441\u0435\u043c \u0441\u043e\u043e\u0442\u0432\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u043e\u0436\u0438\u0434\u0430\u0435\u043c\u043e\u043c\u0443 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0443. \u0412\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u043e\u0436\u0438\u0434\u0430\u044e\u0449\u0435\u0439 \u0441\u043e\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u0441\u043b\u0435 \u043e\u043a\u043e\u043d\u0447\u0430\u043d\u0438\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0432\u0441\u0435\u0445 \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u043d\u044b\u0445 \u0437\u0430\u0434\u0430\u0447.<\/p>\n<p>\u0420\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0442\u0438\u043f\u0430 <code>VoidTask<\/code>. \u0414\u0430\u043d\u043d\u044b\u0439 \u0442\u0438\u043f \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u0431\u043e\u0439 &#171;\u043b\u0435\u043d\u0438\u0432\u0443\u044e&#187; \u0437\u0430\u0434\u0430\u0447\u0443 \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043d\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u0434\u043e \u043c\u043e\u043c\u0435\u043d\u0442\u0430 \u0432\u044b\u0437\u043e\u0432\u0430 \u043d\u0430 \u043d\u0435\u0439 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u0430 <code>co_await<\/code>. \u0418\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e \u0437\u0430\u0434\u0430\u0447\u0430 \u043f\u0440\u0438\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0430. \u0420\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u043f\u0440\u0438\u043c\u0435\u0440 \u0435\u0435 \u0440\u0430\u0431\u043e\u0442\u044b, \u043f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u0434\u0435\u0442\u0430\u043b\u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438.<\/p>\n<pre><code class=\"cpp\">VoidTask lazyTask() {     std::cout&lt;&lt;\"I was called\\n\";     co_return; } int main() {     auto lazy = lazyTask();      return 0; }<\/code><\/pre>\n<p>\u0415\u0441\u043b\u0438 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u043d\u0430 wandbox &#8212; \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0432\u044b\u0432\u043e\u0434:<\/p>\n<pre><code>Start 0 Finish<\/code><\/pre>\n<p>\u0422.\u0435. \u0442\u0435\u043b\u043e \u0441\u043e\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b \u043d\u0435 \u0431\u044b\u043b\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u043e. \u0414\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0442\u0435\u043b\u043e \u0441\u043e\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b &#8212; \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432\u044b\u0437\u043e\u0432 <code>co_await<\/code> \u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e <code>promise_type<\/code> \u0434\u043b\u044f \u0441\u043e\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d <code>co_await<\/code>:<\/p>\n<pre><code class=\"cpp\">struct Promise {     auto initial_suspend() noexcept     {         return std::suspend_never{};     }     auto final_suspend() noexcept     {         return std::suspend_never{};     }  void get_return_object() { } void return_void() { }  void unhandled_exception() {     while (1)     {     } }  }; template &lt;typename... Args&gt; struct std::coroutine_traits&lt;void, Args...&gt; {     using promise_type = Promise; }; void taskEval() {     auto lazy = lazyTask();     co_await lazy; } int main() {    taskEval();     return 0; }<\/code><\/pre>\n<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438 &#171;\u043b\u0435\u043d\u0438\u0432\u0443\u044e&#187; \u0437\u0430\u0434\u0430\u0447\u0443.<\/p>\n<h4>7. \u041a\u0430\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 Task \u0438\u0437 cppcoro<\/h4>\n<p><code>VoidTask<\/code> \u0431\u0443\u0434\u0435\u0442 \u0447\u0430\u0441\u0442\u0438\u0447\u043d\u044b\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u043e\u043c \u0438\u0437 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 cppcoro, \u0442.\u043a. \u0432 \u0435\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 <code>VoidTask<\/code> \u044d\u0442\u043e \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0448\u0430\u0431\u043b\u043e\u043d\u043d\u043e\u0433\u043e \u043a\u043b\u0430\u0441\u0441\u0430 <code>Task<\/code> \u0432\u0438\u0434\u0430 <code>Task&lt;void&gt;<\/code>. \u0420\u0430\u0437\u0431\u0435\u0440\u0435\u043c\u0441\u044f, \u043a\u0430\u043a \u043e\u043d \u0443\u0441\u0442\u0440\u043e\u0435\u043d \u0438 \u043a\u0430\u043a \u043e\u043d \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442.<\/p>\n<p>\u041f\u0440\u0435\u0436\u0434\u0435 \u0432\u0441\u0435\u0433\u043e, \u0434\u043b\u044f \u0441\u043e\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c <code>promise_type<\/code>.  \u0412 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435, \u0442.\u043a. \u0441\u043e\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0430 \u043f\u0440\u0438\u043e\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442 \u0441\u0432\u043e\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u043f\u043e\u0441\u043b\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f- \u0443 <code>promise_type<\/code> \u0432\u044b\u0437\u043e\u0432 <code>initial_suspend<\/code> \u0434\u043e\u043b\u0436\u0435\u043d \u0432\u0435\u0440\u043d\u0443\u0442\u044c <code>std::suspend_always<\/code>. \u041e\u0442\u043c\u0435\u0442\u0438\u043c, \u0447\u0442\u043e \u0442\u0430\u043a-\u0436\u0435 <code>promise_type<\/code> \u0434\u043e\u043b\u0436\u0435\u043d \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u044f \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u0432\u044b\u0431\u0440\u043e\u0441\u0430 \u043d\u0435\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u043d\u043d\u043e\u0433\u043e \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f(\u0432 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043c\u043e\u0436\u0435\u043c \u0443\u0439\u0442\u0438 \u0432 <code>std::terminate<\/code>), \u0438 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u0442\u0438\u043f \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u043e\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u043d\u0430\u0440\u0443\u0436\u0443, \u0442.\u0435. \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043c\u0435\u0442\u043e\u0434 <code>get_return_object<\/code>.<\/p>\n<pre><code class=\"cpp\">struct task_promise     {         task_promise() noexcept = default;         void return_void() noexcept         {         }         void unhandled_exception() noexcept         {             std::terminate();         }         VoidTask get_return_object() noexcept         {             return VoidTask{std::coroutine_handle&lt;task_promise&gt;::from_promise(*this)};         }          auto initial_suspend() noexcept         {             return std::suspend_always{};         }     };<\/code><\/pre>\n<p>\u0412 \u0441\u0432\u043e\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c, VoidTask \u0434\u043e\u043b\u0436\u0435\u043d \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u0443 \u0441\u0435\u0431\u044f \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440 <code>co_await<\/code> \u0434\u043b\u044f \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0435\u0433\u043e \u0432\u044b\u0437\u043e\u0432\u0430.<\/p>\n<p><code>operator co_await<\/code> \u0434\u043e\u043b\u0436\u0435\u043d \u0432\u0435\u0440\u043d\u0443\u0442\u044c \u043d\u0430 \u0432\u044b\u0437\u0432\u0430\u044e\u0449\u0443\u044e \u0441\u0442\u043e\u0440\u043e\u043d\u0443 <code>task_awaitable<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0438\u043c\u0435\u0435\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u043f\u0440\u0438\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043d\u043e\u0439 \u0441\u043e\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b \u0438 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c <code>continuation<\/code>, \u0442.\u0435. \u0441\u043e\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0443, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u0443\u0434\u0435\u0442 \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0430 \u043f\u043e\u0441\u043b\u0435 \u043e\u043a\u043e\u043d\u0447\u0430\u043d\u0438\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u0441\u043e\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b.<\/p>\n<pre><code class=\"cpp\"> struct task_awaitable     {         task_awaitable(std::coroutine_handle&lt;promise_type&gt; coroutine) : m_coroutine{coroutine}         {         }         bool await_ready() const noexcept         {             return !m_coroutine || m_coroutine.done();         }         auto await_suspend(std::coroutine_handle&lt;&gt; awaitingRoutine)         {             \/\/ \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c symmetric-transfer             \/\/ \u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043c\u043e\u0436\u043d\u043e \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f:             \/\/ https:\/\/lewissbaker.github.io\/2020\/05\/11\/understanding_symmetric_transfer              m_coroutine.promise().set_continuation(awaitingRoutine);             return m_coroutine;         }          void await_resume()         {         }          std::coroutine_handle&lt;promise_type&gt; m_coroutine;     };<\/code><\/pre>\n<p>\u041d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0443 <code>promise<\/code> \u043c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 <code>continuation<\/code> \u0438 \u0442\u0430\u043a-\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0432\u044b\u0437\u043e\u0432\u0430 <code>continuation<\/code>.<\/p>\n<p>\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 <code>continuation<\/code> \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u0431\u043e\u0439 \u043c\u0435\u0442\u043e\u0434:<\/p>\n<pre><code class=\"cpp\">void set_continuation(std::coroutine_handle&lt;&gt; continuation) {     m_continuation = continuation; }<\/code><\/pre>\n<p>\u0414\u043b\u044f \u0432\u044b\u0437\u043e\u0432\u0430 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043d\u043e\u0433\u043e <code>continuation<\/code> \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0443 promise \u043c\u0435\u0442\u043e\u0434 <code>final_suspend<\/code>. \u0412 \u043c\u0435\u0442\u043e\u0434\u0435 <code>final_suspend<\/code> \u0432\u043c\u0435\u0441\u0442\u043e <code>std::suspend_always\/std::suspend_never<\/code> \u043c\u043e\u0436\u043d\u043e \u0432\u0435\u0440\u043d\u0443\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0439 Awaitable-\u0442\u0438\u043f, \u0434\u043b\u044f \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0431\u0443\u0434\u0435\u0442 \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d \u0432\u044b\u0437\u043e\u0432 <code>co_await<\/code>.<\/p>\n<pre><code class=\"cpp\">struct final_awaitable {     bool await_ready() noexcept     {         return false;     }     template &lt;typename TPromise&gt;     auto await_suspend(std::coroutine_handle&lt;TPromise&gt; coroutine) noexcept     {         task_promise&amp; promise = coroutine.promise();         return promise.m_continuation;     } void await_resume() noexcept { }  };<\/code><\/pre>\n<p>\u0420\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043f\u043e\u043b\u043d\u0443\u044e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0441 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f\u043c\u0438 \u0434\u043b\u044f \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0445 \u043c\u043e\u043c\u0435\u043d\u0442\u043e\u0432:<\/p>\n<pre><code class=\"cpp\">#include &lt;coroutine&gt; #include &lt;iostream&gt; struct VoidTask {     struct task_promise;     using promise_type = task_promise; struct task_promise {     task_promise() noexcept = default;     \/\/\u0421\u043e\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0430 \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442. return_void     void return_void() noexcept     {     }     \/\/ \u041f\u0440\u0438 \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u0435 \u043d\u0435\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u043d\u043d\u043e\u0433\u043e \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f - std::terminate     void unhandled_exception() noexcept     {         std::terminate();     }     \/\/\u0412\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u044b\u0439 \u043d\u0430 \u0432\u044b\u0437\u044b\u0432\u0430\u044e\u0449\u0443\u044e \u0441\u0442\u043e\u0440\u043e\u043d\u0443 \u043e\u0431\u044a\u0435\u043a\u0442 - VoidTask \u0441 \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u043d\u044b\u043c \u0432 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440     \/\/coroutine_handle     VoidTask get_return_object() noexcept     {         return VoidTask{std::coroutine_handle&amp;lt;task_promise&amp;gt;::from_promise(*this)};     }      \/\/ \u0418\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e \u0441\u043e\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0430 \u043f\u0440\u0438\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0430     auto initial_suspend() noexcept     {         return std::suspend_always{};     }      struct final_awaitable     {         bool await_ready() noexcept         {             \/\/ await_ready - false, \u0432\u044b\u0437\u043e\u0432 \u0442\u0435\u043b\u0430 await_suspend \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u043c             return false;         }         template &amp;lt;typename TPromise&amp;gt;         auto await_suspend(std::coroutine_handle&amp;lt;TPromise&amp;gt; coroutine) noexcept         {             \/\/ https:\/\/lewissbaker.github.io\/2020\/05\/11\/understanding_symmetric_transfer             task_promise&amp;amp; promise = coroutine.promise();             return promise.m_continuation;         }          void await_resume() noexcept         {         }     };      void set_continuation(std::coroutine_handle&amp;lt;&amp;gt; continuation)     {         m_continuation = continuation;     }      auto final_suspend() noexcept     {         return final_awaitable{};     }      std::coroutine_handle&amp;lt;&amp;gt; m_continuation; };  struct task_awaitable {     task_awaitable(std::coroutine_handle&amp;lt;promise_type&amp;gt; coroutine) : m_coroutine{coroutine}     {     }     bool await_ready() const noexcept     {         return !m_coroutine || m_coroutine.done();     }     auto await_suspend(std::coroutine_handle&amp;lt;&amp;gt; awaitingRoutine)     {         m_coroutine.promise().set_continuation(awaitingRoutine);         return m_coroutine;     }      void await_resume()     {     }      std::coroutine_handle&amp;lt;promise_type&amp;gt; m_coroutine; };  VoidTask(std::coroutine_handle&amp;lt;task_promise&amp;gt; suspendedCoroutine)     : m_coroutine{suspendedCoroutine} { }  ~VoidTask() {     \/\/ \u0442.\u043a. \u043c\u044b \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u043b\u0438 \u0434\u043b\u044f initial_suspend \u0443 promise_type std::suspend_always -     \/\/ \u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0441\u0442\u044c \u0437\u0430 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0435 coroutine handle \u043e\u0441\u0442\u0430\u0435\u0442\u0441\u044f \u043d\u0430 \u043d\u0430\u0441.     if (m_coroutine)         m_coroutine.destroy(); }  bool await_ready() const noexcept {     return !m_coroutine || m_coroutine.done(); }  auto operator co_await() noexcept {     return task_awaitable{m_coroutine}; }  void await_resume() { }  std::coroutine_handle&amp;lt;promise_type&amp;gt; m_coroutine;  };<\/code><\/pre>\n<h4>8. \u041a\u0430\u043a \u044d\u0442\u043e \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c?<\/h4>\n<p>\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f SPI-\u0434\u0440\u0430\u0439\u0432\u0435\u0440\u0430 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u0431\u043e\u0439 \u0448\u0430\u0431\u043b\u043e\u043d\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441, \u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u043e\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c backend, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438. \u0420\u0435\u0448\u0435\u043d\u0438\u0435 \u0431\u044b\u043b\u043e \u043f\u0440\u0438\u043d\u044f\u0442\u043e \u0441 \u0446\u0435\u043b\u044c\u044e \u043f\u043e\u0432\u044b\u0448\u0435\u043d\u0438\u044f \u0442\u0435\u0441\u0442\u043e\u043f\u0440\u0438\u0433\u043e\u0434\u043d\u043e\u0441\u0442\u0438 \u043c\u043e\u0434\u0443\u043b\u044f. \u0412 \u0446\u0435\u043b\u043e\u043c, \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0432 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u043c \u0441 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u043c\u0438 \u043c\u0435\u0442\u043e\u0434\u0430\u043c\u0438:<\/p>\n<pre><code class=\"cpp\">void transmitBuffer(     const std::uint8_t* pBuffer,     std::uint16_t pBufferSize,     void* pUserData,     bool restoreInSpiCtx) noexcept {     \/\/ \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043b\u0438 coroutine_handle     m_coroHandle = std::coroutine_handle&lt;&gt;::from_address(pUserData);     \/\/\u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043b\u0438 \u0432\u044b\u0437\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0437\u0432\u0430\u043d \u043f\u043e \u043e\u043a\u043e\u043d\u0447\u0430\u043d\u0438\u044e \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438 \u0432 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 SPI     m_backendImpl.setTransactionCompletedHandler([this] { transmitCompleted(); });      const size_t TransferBufferSize = pBufferSize;     const size_t FullDmaTransactionsCount = TransferBufferSize \/ DmaBufferSize;     const size_t ChunkedTransactionsBufSize = TransferBufferSize % DmaBufferSize;     const bool ComputeChunkOffsetWithDma = FullDmaTransactionsCount &gt;= 1;      \/\/ \u0441\u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043b\u0438 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0438     TransactionContext newContext{.restoreInSpiCtx = restoreInSpiCtx,                                   .computeChunkOffsetWithDma = ComputeChunkOffsetWithDma,                                   .pDataToTransmit = pBuffer,                                   .fullDmaTransactionsCount = FullDmaTransactionsCount,                                   .chunkedTransactionBufSize = ChunkedTransactionsBufSize,                                   .completedTransactionsCount = 0};      m_transmitContext = std::move(newContext);      \/\/ \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u043b\u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0443 \u0434\u0430\u043d\u043d\u044b\u0445     if (FullDmaTransactionsCount)     {         --m_transmitContext.fullDmaTransactionsCount;         m_backendImpl.sendChunk(pBuffer, DmaBufferSize);     }     else     {         m_transmitContext.chunkedTransactionBufSize = 0;         m_backendImpl.sendChunk(pBuffer, pBufferSize);     } }<\/code><\/pre>\n<p>\u041f\u043e \u043e\u043a\u043e\u043d\u0447\u0430\u043d\u0438\u044e \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438 \u0434\u0430\u043d\u043d\u044b\u0445, \u0432 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 backend \u0432\u044b\u0437\u0432\u0430\u0435\u0442\u0441\u044f <code>TransactionCompletedHandler<\/code>. \u0420\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0434\u043b\u044f Nordic:<\/p>\n<pre><code class=\"cpp\">template &lt;typename PeripheralInstance&gt; class NordicSpi {  public:     using This_t = NordicSpi&lt;PeripheralInstance&gt;;     NordicSpi() noexcept     {          nrfx_spim_config_t spiConfig{};          \/\/ \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f SPI \u043f\u0440\u043e\u043f\u0443\u0449\u0435\u043d\u0430 .... \/\/         \/\/\u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043c\u043e\u0434\u0443\u043b\u044f SPIM. \u0435\u0441\u043b\u0438 \u0432\u043c\u0435\u0441\u0442\u043e spimEventHandlerThisOne \u0438 this \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c nullptr \u0438         \/\/nullptr - \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0430 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430 \u0431\u0435\u0437 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f EasyDMA, \u0442.\u0435. \u0432 \u0431\u043b\u043e\u043a\u0438\u0440\u0443\u044e\u0449\u0435\u043c \u0440\u0435\u0436\u0438\u043c\u0435         APP_ERROR_CHECK(nrfx_spim_init(             &amp;SpiInstance::HandleStorage[PeripheralInstance::HandleIdx],             &amp;spiConfig,             spimEventHandlerThisOne,             this));     }      void sendChunk(const std::uint8_t* pBuffer, const size_t bufferSize) noexcept     {         \/\/ \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0434\u0435\u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0440\u0430 \u043d\u0430 \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0443 \u0434\u0430\u043d\u043d\u044b\u0445         nrfx_spimxfer_desc_t xferDesc = NRFX_SPIMXFER_TX(pBuffer, bufferSize);          \/\/ \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0438         nrfx_err_t transmissionError = nrfx_spimxfer(             &amp;SpiInstance::HandleStorage[PeripheralInstance::HandleIdx], &amp;xferDesc, 0);         APP_ERROR_CHECK(transmissionError);     }      void xferChunk(         std::span&lt;const std::uint8_t&gt; _transmitArray,         std::span&lt;std::uint8_t&gt; _receiveArray)     {         \/\/ \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 transmit-receive \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0438         nrfx_spimxfer_desc_t xferDesc = NRFX_SPIMXFER_TRX(             _transmitArray.data(),             _transmitArray.size(),             _receiveArray.data(),             _receiveArray.size());          nrfx_err_t transmissionError = nrfx_spimxfer(             &amp;SpiInstance::HandleStorage[PeripheralInstance::HandleIdx], &amp;xferDesc, 0);         APP_ERROR_CHECK(transmissionError);     }      using TTransactionCompletedHandler = std::function&lt;void()&gt;;     void setTransactionCompletedHandler(const TTransactionCompletedHandler&amp; _handler) noexcept     {         m_transactionCompleted = _handler;     }  private:     static void spimEventHandlerThisOne(nrfx_spim_evt_t const* _pEvent, void* _pContext) noexcept     {         \/\/ \u0434\u0430\u043d\u043d\u044b\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043f\u043e \u043e\u043a\u043e\u043d\u0447\u0430\u043d\u0438\u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 EasyDMA         if (_pEvent-&gt;type == NRFX_SPIM_EVENT_DONE)         {             \/\/ \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c \u0440\u0430\u043d\u0435\u0435 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043d\u044b\u0439 callback \u043d\u0430 \u0434\u0440\u0430\u0439\u0432\u0435\u0440\u0435 \u0432\u0435\u0440\u0445\u043d\u0435\u0433\u043e \u0443\u0440\u043e\u0432\u043d\u044f.             auto pThis = reinterpret_cast&lt;This_t*&gt;(_pContext);             pThis-&gt;m_transactionCompleted();         }     }  public:     TTransactionCompletedHandler m_transactionCompleted; }; <\/code><\/pre>\n<p>\u0412 \u0441\u0432\u043e\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c, \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0434\u0440\u0430\u0439\u0432\u0435\u0440\u0430 \u0432\u0435\u0440\u0445\u043d\u0435\u0433\u043e \u0443\u0440\u043e\u0432\u043d\u044f \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0440\u0435\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 <code>stub-backend<\/code> + \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0442\u0435\u0441\u0442\u044b. \u0420\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0435\u043c\u044b\u0435 \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0435 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0438:<\/p>\n<ul>\n<li>\n<p>\u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0430 \u0431\u043b\u043e\u043a\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u043c\u0435\u043d\u044c\u0448\u0435 \u0440\u0430\u0437\u043c\u0435\u0440\u0430 DMA \u0431\u0443\u0444\u0435\u0440\u0430<\/p>\n<\/li>\n<li>\n<p>\u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0430 \u0431\u043b\u043e\u043a\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u0440\u0430\u0437\u043c\u0435\u0440\u043e\u043c \u0441 DMA \u0431\u0443\u0444\u0435\u0440<\/p>\n<\/li>\n<li>\n<p>\u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0430 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u0431\u043b\u043e\u043a\u043e\u0432 \u0434\u0430\u043d\u043d\u044b\u0445 \u0440\u0430\u0437\u043c\u0435\u0440\u043e\u043c \u0441 DMA \u0431\u0443\u0444\u0435\u0440<\/p>\n<\/li>\n<li>\n<p>\u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0430 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u0431\u043b\u043e\u043a\u043e\u0432 \u0440\u0430\u0437\u043c\u0435\u0440\u043e\u043c \u0441 DMA \u0431\u0443\u0444\u0435\u0440 \u0438 \u043d\u0435\u043f\u043e\u043b\u043d\u043e\u0433\u043e \u0431\u043b\u043e\u043a\u0430<\/p>\n<\/li>\n<\/ul>\n<h4>9. \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0442\u0435\u0441\u0442\u044b \u0432 GTest<\/h4>\n<p>\u0422\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0431\u0443\u0434\u0435\u043c \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u044c \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c GTest \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430. \u0421 \u0446\u0435\u043b\u044c\u044e \u0438\u0437\u0431\u0435\u0433\u0430\u043d\u0438\u044f copy-paste \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u043e\u0432 \u0441 \u0432\u044b\u0448\u0435\u0443\u043f\u043e\u043c\u044f\u043d\u0443\u0442\u044b\u043c\u0438 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u044f\u043c\u0438- \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0441\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u043e\u043c, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0449\u0438\u043c \u0438\u043d\u0441\u0442\u0430\u043d\u0446\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0442\u0435\u0441\u0442\u044b.<\/p>\n<p>\u0414\u043b\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0442\u0435\u0441\u0442\u043e\u0432 \u0432 \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0435\u0449\u0435 \u043e\u0434\u043d\u0438\u043d \u043a\u043b\u0430\u0441\u0441, \u043e\u0442 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0438\u0434\u0435\u0442 \u043d\u0430\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u043e\u043c\u0438\u043c\u043e \u0431\u0430\u0437\u043e\u0432\u043e\u0433\u043e <code>::testing::Test<\/code>. \u0414\u043b\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0442\u0435\u0441\u0442\u043e\u0432 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043d\u0430\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u0435 \u043e\u0442 <code>::testing::WithParamInterface<\/code>.<\/p>\n<p>\u0412 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u044d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 <code>std::tuple<\/code> \u0432\u0438\u0434\u0430:<\/p>\n<pre><code class=\"cpp\">public ::testing::WithParamInterface&lt;std::tuple&lt;std::uint16_t, std::string_view&gt;&gt;<\/code><\/pre>\n<p>\u0413\u0434\u0435 <code>std::string_view<\/code> \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044e \u0442\u0435\u0441\u0442\u0430, \u0430 <code>std::uint16_t<\/code> &#8212; \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u043b\u044f \u0437\u0430\u0434\u0430\u0432\u0430\u043d\u0438\u044f \u0440\u0430\u0437\u043c\u0435\u0440\u0430 \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u0433\u043e \u0431\u0443\u0444\u0435\u0440\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438.<\/p>\n<p>\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f stub-backend \u0434\u043b\u044f SPI \u0434\u0440\u0430\u0439\u0432\u0435\u0440\u0430 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u0431\u043e\u0439 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 spi-\u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043f\u0440\u0438 \u043a\u0430\u0436\u0434\u043e\u043c \u0432\u044b\u0437\u043e\u0432\u0435 <code>sendChunk<\/code>. \u041f\u043e\u0441\u043b\u0435 \u0447\u0435\u0433\u043e, \u043f\u043e \u043e\u043a\u043e\u043d\u0447\u0430\u043d\u0438\u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u043e \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0438\u0437 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0445 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0439 \u0432 \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u044b\u0439 \u0431\u0443\u0444\u0435\u0440 \u0441 \u0446\u0435\u043b\u044c\u044e \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u044b\u043b\u0438 \u043f\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u044b \u043d\u0430 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0443 \u0438 \u0434\u0430\u043d\u043d\u044b\u0445, \u043a\u043e\u0442\u043e\u0440\u044b \u0431\u044b\u043b\u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u044b \u0432 \u0434\u0440\u0430\u0439\u0432\u0435\u0440 \u043d\u0438\u0437\u043a\u043e\u0433\u043e \u0443\u0440\u043e\u0432\u043d\u044f.<\/p>\n<p>\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0439 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0430 \u043d\u0438\u0436\u0435:<\/p>\n<pre><code class=\"cpp\">void sendChunk(const std::uint8_t* pBuffer, const size_t bufferSize) noexcept {     BusTransactionsTransmit.emplace_back(pBuffer, bufferSize);     m_completedTransaction(); } using TDataStream = std::vector&lt;std::byte&gt;; TDataStream getTransmittedData() const {     TDataStream stream;     std::ranges::for_each(BusTransactionsTransmit, [&amp;stream](const auto&amp; _transaction) {         const auto&amp; [pArray, blockSize] = _transaction;         auto arraySpan = std::span{pArray, blockSize};         std::ranges::transform(arraySpan, std::back_inserter(stream), [](std::uint8_t _dataByte) {             return std::byte{_dataByte};         });     });     return stream; }<\/code><\/pre>\n<p> \u0414\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0438\u0447\u0435\u0441\u043a\u0438\u043c\u0438 \u0442\u0435\u0441\u0442\u0430\u043c\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0435\u0433\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 + \u0438\u043d\u0441\u0442\u0430\u043d\u0446\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435.  \u041d\u0430 \u0434\u0430\u043d\u043d\u043e\u043c \u044d\u0442\u0430\u043f\u0435 \u0431\u0443\u0434\u0435\u0442 \u043e\u043f\u0443\u0449\u0435\u043d\u0430 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043f\u0440\u0438\u043c\u0438\u0442\u0438\u0432\u0430 SyncWait, \u043e\u043d\u0430 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u043d\u0430 \u0434\u0430\u043b\u0435\u0435. \u041d\u0430\u043c \u043e\u043d\u0430 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u0430 \u0434\u043b\u044f \u043e\u0436\u0438\u0434\u0430\u043d\u0438\u044f \u043e\u043a\u043e\u043d\u0447\u0430\u043d\u0438\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441\u043e\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b.<\/p>\n<p>\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u0442\u0435\u0441\u0442\u0430 \u0431\u0443\u0434\u0435\u0442 \u0438\u043c\u0435\u0442\u044c \u0432\u0438\u0434:<\/p>\n<pre><code class=\"cpp\">TEST_P(SpiDriverTest, CheckRandomSequenceWithLengthTransmissionCorrect) {     \/\/ \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0440\u0430\u0437\u043c\u0435\u0440 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438     const std::uint16_t TransactionLength{std::get&lt;0&gt;(GetParam())};     TDataStream ExpectedStream{TransactionLength};      std::random_device randomDevice;     std::mt19937 generator(randomDevice());     std::uniform_int_distribution&lt;&gt; distribution(0x00, 0xFF);     \/\/ \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u0443\u044e \u043f\u043e\u0441\u044b\u043b\u043a\u0443     std::ranges::generate(ExpectedStream, [&amp;distribution, generator]() mutable {         return std::byte(distribution(generator));     });      CoroUtils::syncWait(sendChunk(         reinterpret_cast&lt;const std::uint8_t*&gt;(ExpectedStream.data()), ExpectedStream.size()));     \/\/ \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0434\u043e\u043b\u0436\u043d\u044b \u0431\u044b\u043b\u0438 \u0431\u044b\u0442\u044c \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u044b \u0434\u0430\u043d\u043d\u044b\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u044b\u043b\u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u044b \u0432 spi-backend     EXPECT_EQ(TransactionsToDataStream(), ExpectedStream); } <\/code><\/pre>\n<p>\u0418\u043d\u0441\u0442\u0430\u043d\u0446\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u0442\u0435\u0441\u0442\u0430 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043e \u043d\u0430 \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u0435 \u043d\u0438\u0436\u0435:<\/p>\n<pre><code class=\"cpp\">INSTANTIATE_TEST_SUITE_P(     SpiDriverTesting,     SpiDriverTest,     ::testing::Values(         std::make_tuple(Null, \"Null\"),         std::make_tuple(SmallerThanSingleDmaTransaction, \"SmallerThanSingleDmaTransaction\"),         std::make_tuple(EqualsToSingleDmaTransaction, \"EqualsToSingleDmaTransaction\"),         std::make_tuple(ThreeDmaTransactions, \"ThreeDmaTransactions\"),         std::make_tuple(SingleDmaAndChunk, \"SingleDmaAndChunk\"),         std::make_tuple(ThreeDmaAndChunk, \"ThreeDmaAndChunk\"),         std::make_tuple(StressChunked, \"StressChunked\")),     [](const auto&amp; testParam) {         const auto&amp; suiteName = std::get&lt;1&gt;(testParam.param);         return std::string(suiteName.data());     });<\/code><\/pre>\n<p>\u041f\u0435\u0440\u0435\u0434\u0430\u043d\u043d\u0430\u044f \u043b\u044f\u043c\u0431\u0434\u0430 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043e\u0442\u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0442\u0435\u0441\u0442\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f.<\/p>\n<h4>10. \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0447\u0435\u0440\u043d\u043e\u0432\u043e\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u0434\u0440\u0430\u0439\u0432\u0435\u0440\u0430 \u0434\u043b\u044f SPI-FLASH<\/h4>\n<p>\u0420\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0434\u0440\u0430\u0439\u0432\u0435\u0440\u0430 \u0434\u043b\u044f SPI-FLASH \u043f\u0430\u043c\u044f\u0442\u0438. \u041d\u0430 \u043f\u0435\u0440\u0432\u043e\u043c \u044d\u0442\u0430\u043f\u0435, \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u043c \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 JEDEC ID \u0438 device ID. \u0423\u0441\u043b\u043e\u0432\u0438\u044f \u0442\u0435-\u0436\u0435 \u0441\u0430\u043c\u044b\u0435, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c DMA, \u0430\u0441\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e, \u043d\u0435 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0430 \u043e\u0436\u0438\u0434\u0430\u043d\u0438\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u0439.<\/p>\n<p>\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c, \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<pre><code>void Board::initBoardSpiFlash() noexcept {     m_pFlashDriver = std::make_unique&lt;Hal::TFlashDriver&gt;();     if (m_pFlashDriver)     {         const std::uint32_t JedecId = co_await m_pFlashDriver-&gt;requestJEDEDCId();         LOG_DEBUG(\"Jedec Id is:\");         LOG_DEBUG_ENDL(fmt::format(\"{:#04x}\", JedecId));          const std::span&lt;std::uint8_t&gt; DeviceId = co_await m_pFlashDriver-&gt;requestDeviceId();         LOG_DEBUG_ENDL(fmt::format(\"{:02X}\", fmt::join(DeviceId, \"\")));     } }<\/code><\/pre>\n<p>\u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u0438\u043c\u0438\u0442\u0438\u0432, \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043c\u044b \u0441\u043c\u043e\u0436\u0435\u043c \u0432\u0435\u0440\u043d\u0443\u0442\u044c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043d\u0430 \u0432\u044b\u0437\u0432\u0430\u044e\u0449\u0443\u044e \u0441\u0442\u043e\u0440\u043e\u043d\u0443. \u0420\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u043d\u044b\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 <code>Task<\/code>, \u0430 \u0438\u043c\u0435\u043d\u043d\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0438\u0437\u043c\u043d\u0435\u043d\u0435\u043d\u0438\u044f \u0434\u043b\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0442\u0430 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f.<\/p>\n<ol start=\"0\">\n<li>\n<p>\u041d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u0442\u0438\u043f <code>await_resume<\/code> \u0443 <code>task_awaitable<\/code>:<\/p>\n<\/li>\n<\/ol>\n<pre><code class=\"cpp\">decltype(auto) await_resume() {     return m_coroutine.promise().result(); }<\/code><\/pre>\n<ol start=\"2\">\n<li>\n<p>\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043c\u0435\u0442\u043e\u0434 <code>.result()<\/code> \u0443 <code>promise<\/code>:<\/p>\n<\/li>\n<\/ol>\n<pre><code class=\"cpp\">TResult&amp; result() {     return m_coroutineResult; }<\/code><\/pre>\n<ol start=\"3\">\n<li>\n<p>\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0443 <code>promise<\/code> \u043c\u0435\u0442\u043e\u0434 <code>return_value<\/code>:<\/p>\n<\/li>\n<\/ol>\n<pre><code class=\"cpp\">void return_value(const TResult&amp; _value)noexcept {     m_coroutineResult = _value; }<\/code><\/pre>\n<ol start=\"4\">\n<li>\n<p>\u0421\u0434\u0435\u043b\u0430\u0442\u044c <code>Task<\/code> \u0448\u0430\u0431\u043b\u043e\u043d\u043d\u044b\u043c:<\/p>\n<\/li>\n<\/ol>\n<pre><code class=\"cpp\">template &lt;typename TResult&gt; struct Task<\/code><\/pre>\n<ol start=\"5\">\n<li>\n<p>\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c member \u0432 <code>promise<\/code> \u0434\u043b\u044f \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430.<\/p>\n<\/li>\n<\/ol>\n<p>\u041f\u043e\u043b\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u043d\u043e\u0433\u043e <code>Promise<\/code>:<\/p>\n<pre><code class=\"cpp\">struct ResultTaskPromise {     ResultTaskPromise() noexcept = default;      void unhandled_exception() noexcept     {         std::terminate();     }     Task&lt;TResult&gt; get_return_object() noexcept     {         \/\/ \u0418\u0437\u043c\u0435\u043d\u0438\u043b\u0438 \u0442\u0438\u043f \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u043e\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430, \u0442\u0435\u043f\u0435\u0440\u044c \u044d\u0442\u043e \u0448\u0430\u0431\u043b\u043e\u043d\u043d\u044b\u0439 Task&lt;Result&gt;         return Task&lt;TResult&gt;{std::coroutine_handle&lt;ResultTaskPromise&gt;::from_promise(*this)};     }     auto initial_suspend() noexcept     {         return std::suspend_always{};     }      void return_value(const TResult&amp; _value) noexcept     {         \/\/ \u0434\u043e\u0431\u0430\u0432\u0438\u043b\u0438 \u043c\u0435\u0442\u043e\u0434 return value         m_coroutineResult = _value;     }      void set_continuation(std::coroutine_handle&lt;&gt; continuation)     {         m_continuation = continuation;     }      TResult&amp; result()     {         \/\/ \u0434\u043e\u0431\u0430\u0432\u0438\u043b\u0438 \u043c\u0435\u0442\u043e\u0434 result \u0434\u043b\u044f \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430         return m_coroutineResult;     }      struct final_awaitable     {         bool await_ready() noexcept         {             return false;         }         template &lt;typename TPromise&gt;         void await_suspend(std::coroutine_handle&lt;TPromise&gt; coroutine) noexcept         {             ResultTaskPromise&amp; promise = coroutine.promise();             if (promise.m_continuation)             {                 promise.m_continuation.resume();             }         }          void await_resume() noexcept         {         }     };      auto final_suspend() noexcept     {         return final_awaitable{};     }      \/\/ \u0434\u043e\u0431\u0430\u0432\u0438\u043b\u0438 \u043f\u043e\u043b\u0435 \u043a\u043b\u0430\u0441\u0441\u0430 \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430     TResult m_coroutineResult;     std::coroutine_handle&lt;&gt; m_continuation; };<\/code><\/pre>\n<h4>11. \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0447\u0442\u0435\u043d\u0438\u0435 JEDEC ID<\/h4>\n<p>\u0414\u043b\u044f \u0447\u0442\u0435\u043d\u0438\u044f JEDEC ID, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u0431\u043e\u0439 std::uint32 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432 API spi-flash \u0434\u0440\u0430\u0439\u0432\u0435\u0440\u0430 \u043c\u0435\u0442\u043e\u0434 <code>requestJedecId<\/code>:<\/p>\n<pre><code class=\"cpp\">CoroUtils::Task&lt;std::uint32_t&gt; requestJEDEDCId() noexcept {     auto receivedData = co_await prepareXferTransaction(         std::forward_as_tuple(WindbondCommandSet::ReadJedecId),         WindbondCommandSet::DummyByte,         WindbondCommandSet::DummyByte,         WindbondCommandSet::DummyByte);      std::uint32_t JedecDeviceId{};     for (std::size_t i{}; i &lt; WindbondCommandSet::JedecIdLength; ++i)     {         JedecDeviceId |= (receivedData[i] &lt;&lt; (16 - i * 8));     }      co_return JedecDeviceId; }<\/code><\/pre>\n<p>\u0418\u0434\u0435\u044f \u0441 <code>std::forward_as_tuple<\/code> \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0430\u044f &#8212; \u0432\u0441\u0435 \u0447\u0442\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u043e \u0432 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0430\u0445 &#8212;  \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <code>prepareXferTransaction<\/code> \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u043e \u043a\u0430\u043a \u043a\u043e\u043c\u0430\u043d\u0434\u0430 + \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e dummy-bytes \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0443\u0436\u043d\u044b \u0434\u043b\u044f \u043f\u0440\u0438\u043d\u044f\u0442\u0438\u044f \u043a\u043e\u043c\u0430\u043d\u0434\u044b. \u0412\u0441\u0435 \u0447\u0442\u043e \u043f\u043e\u0441\u043b\u0435 <code>forward_as_tuple<\/code> &#8212; \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e dummy-bytes \u0434\u043b\u044f \u0432\u044b\u0447\u0438\u0442\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<p>\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <code>prepareXferTransaction<\/code> \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0430\u044f: \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043d\u0430 \u0432\u0445\u043e\u0434 \u043a\u043e\u043c\u0430\u043d\u0434\u0443 \u0432 \u0432\u0438\u0434\u0435 tuple + \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043f\u0443\u0441\u0442\u044b\u0445 \u043f\u043e\u0441\u044b\u043b\u043e\u043a. \u0414\u0430\u043b\u0435\u0435, \u0437\u0430\u043f\u043e\u043b\u043d\u044f\u0435\u043c \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0435\u043c\u044b\u0439 \u0431\u0443\u0444\u0435\u0440 \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u043a\u043e\u043c\u0430\u043d\u0434\u043e\u0439 \u0438 \u0435\u0435 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0430\u043c\u0438, \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u043c, \u043f\u043e\u0441\u043b\u0435- \u043f\u0443\u0441\u0442\u044b\u043c\u0438 \u043f\u043e\u0441\u044b\u043b\u043a\u0430\u043c\u0438. \u0414\u043b\u044f \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u043e\u0433\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c slice \u043d\u0430 \u0431\u0443\u0444\u0435\u0440 \u0441 \u043f\u0440\u0438\u043d\u044f\u0442\u044b\u043c\u0438 \u0434\u0430\u043d\u043d\u044b\u043c\u0438<\/p>\n<p>\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0438\u043c\u0435\u0435\u0442 \u0432\u0438\u0434:<\/p>\n<pre><code class=\"cpp\">    template &lt;typename TCommand, typename... Args&gt;     CoroUtils::Task&lt;std::span&lt;std::uint8_t&gt;&gt; prepareXferTransaction(         TCommand&amp;&amp; command,         Args&amp;&amp;... argList)     {         auto&amp; transmitBuffer = getSpiBus()-&gt;getDmaBufferTransmit();         auto&amp; receiveBuffer = getSpiBus()-&gt;getDmaBufferReceive();          getSpiBus()-&gt;setCsPinLow();          processTransmitBuffer(transmitBuffer, std::forward&lt;TCommand&amp;&amp;&gt;(command));          constexpr std::size_t CommandSize = std::tuple_size_v&lt;TCommand&gt;;          co_await transmitChunk(std::span(transmitBuffer.data(), CommandSize));          constexpr std::size_t DummyListSize = sizeof...(argList);          processTransmitBuffer(transmitBuffer, std::forward_as_tuple(argList...));          auto receivedBlockSpan = co_await xferTransaction(             std::span(transmitBuffer.data(), DummyListSize),             std::span(receiveBuffer.data(), DummyListSize));          getSpiBus()-&gt;setCsPinHigh();         co_return std::span(receiveBuffer.data(), DummyListSize);     }<\/code><\/pre>\n<p>\u041d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0443 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f, \u0432 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0432\u0435\u0440\u043d\u0435\u0442\u0441\u044f slice \u043d\u0430 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u044e\u0449\u0438\u0439 DMA-\u0431\u0443\u0444\u0435\u0440 SPI. \u0410 \u0434\u0430\u043b\u0435\u0435 \u0435\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u043e\u0442\u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c <code>fmtlib<\/code> \u0438\u043b\u0438 \u0436\u0435 <code>std::format<\/code>, \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u043c\u043e\u0433\u043e \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440\u0430. <\/p>\n<h4>13. \u041e\u0436\u0438\u0434\u0430\u043d\u0438\u0435 \u043e\u043a\u043e\u043d\u0447\u0430\u043d\u0438\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0441\u043e\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b<\/h4>\n<p>\u0418\u043d\u043e\u0433\u0434\u0430 \u043c\u043e\u0436\u0435\u0442 \u0432\u043e\u0437\u043d\u0438\u043a\u043d\u0443\u0442\u044c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u044c \u043f\u043e\u0434\u043e\u0436\u0434\u0430\u0442\u044c \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0441\u043e\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b, \u0442.\u0435. \u0437\u0430\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u043f\u043e\u0442\u043e\u043a\u0430 \u0434\u043e \u043c\u043e\u043c\u0435\u043d\u0442\u0430, \u043f\u043e\u043a\u0430 \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0430 \u0441\u043e\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0430. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u0438\u043c\u0438\u0442\u0438\u0432 SyncWait.<\/p>\n<p>\u0420\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u0435 \u044d\u0442\u043e\u0433\u043e \u043f\u0440\u0438\u043c\u0438\u0442\u0438\u0432\u0430( \u0432 cppcoro \u043e\u043d \u0442\u0430\u043a-\u0436\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d, \u0434\u0430\u043d\u043d\u044b\u0439 \u043f\u0430\u0440\u0430\u0433\u0440\u0430\u0444 \u0441\u043a\u043e\u0440\u0435\u0435 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u0438\u0435 \u0442\u043e\u0433\u043e, \u043a\u0430\u043a \u043e\u043d \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442)<\/p>\n<p>\u041c\u044b \u0445\u043e\u0442\u0438\u043c \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0432\u0438\u0434\u0430:<\/p>\n<pre><code class=\"cpp\">TEST_F(FlashDriverTest, RequestJedecId) {     auto jedecId = CoroUtils::syncWait(flashDriver.requestJEDEDCId());     constexpr std::uint32_t MagicTrashFromRawMemory = 13487565; \/\/  For fun;     EXPECT_EQ(jedecId, MagicTrashFromRawMemory); }<\/code><\/pre>\n<p>\u0422.\u0435. \u043f\u043e \u0432\u044b\u0437\u043e\u0432\u0443 <code>CoroUtils::syncWait<\/code> \u0437\u0430\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u043e \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430.<\/p>\n<ol start=\"0\">\n<li>\n<p>\u0420\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c <code>syncWait<\/code> \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0442\u0438\u043f \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u043e\u0433\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0438\u0437 \u0441\u043e\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0443\u044e \u043e\u0431\u0435\u0440\u0442\u043a\u0443, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u044d\u0442\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c. \u0412 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435, \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u044b\u0435 \u0442\u0438\u043f\u044b \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0442 \u0441\u043e\u0431\u043e\u0439 Awaitable-\u043f\u0440\u0438\u043c\u0442\u0438\u0432\u044b \u0441 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u043c <code>operator co_await<\/code>.<\/p>\n<\/li>\n<\/ol>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440\u043d\u044b\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 <code>syncWait<\/code>:<\/p>\n<pre><code class=\"cpp\">template &lt;typename TCoroutine&gt; auto syncWait(TCoroutine&amp;&amp; _coroutineTask)-&gt;\/\/\u041d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u044b\u0439 \u0442\u0438\u043f<\/code><\/pre>\n<p>\u0414\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u043e\u0433\u043e \u0442\u0438\u043f\u0430 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 <code>AwaitResultGetter<\/code>:<\/p>\n<pre><code class=\"cpp\">template &lt;typename TAwaiter&gt; auto awaiterGetter(TAwaiter&amp;&amp; _awaiter) {     return static_cast&lt;TAwaiter&amp;&amp;&gt;(_awaiter).operator co_await(); } template &lt;typename TAwaitable&gt; struct AwaitResultGetter {     using Type = decltype(awaiterGetter(std::declval&lt;TAwaitable&gt;()));     using Result = decltype(std::declval&lt;Type&gt;().await_resume()); };<\/code><\/pre>\n<p>\u0413\u0434\u0435 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u044b\u0439 \u0442\u0438\u043f \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043f\u043e\u043b\u0443\u0447\u0435\u043d \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0432\u044b\u0437\u043e\u0432\u0430 <code>.await_resume<\/code> \u043d\u0430 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 <code>declval<\/code> \u043e\u0442 awaitable-\u0442\u0438\u043f\u0430<\/p>\n<p>\u0412\u044b\u0437\u043e\u0432 <code>makeSyncWaitTask<\/code> \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u0431\u043e\u0439 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0432\u044b\u0437\u043e\u0432\u043e\u0432 <code>co_yield co_await<\/code>:<\/p>\n<pre><code class=\"cpp\">template &lt;typename TAwaitable, typename TTaskResult = AwaitResultGetter&lt;TAwaitable&gt;::Result&gt; SyncWaitTask&lt;TTaskResult&gt; makeSyncWaitTask(TAwaitable&amp;&amp; awaitable) {     co_yield co_await awaitable; }<\/code><\/pre>\n<p>\u0413\u0434\u0435 <code>co_await<\/code> \u043f\u0440\u0438\u043e\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442 \u0442\u0435\u043a\u0443\u0449\u0438\u0439 \u0432\u044b\u0437\u043e\u0432, \u0430 <code>co_yield<\/code> \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u043d\u043e\u0439 \u0441\u043e\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b.<\/p>\n<p>\u041f\u0440\u0438 \u044d\u0442\u043e\u043c, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0443\u0447\u0435\u0441\u0442\u044c, \u0447\u0442\u043e \u043f\u0440\u0438 \u0432\u044b\u0437\u043e\u0432\u0435 <code>SyncWait<\/code> \u043d\u0430 VoidTask \u0443 \u043d\u0430\u0441 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u043e\u0433\u043e \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430 \u043d\u0435 \u0431\u0443\u0434\u0435\u0442. \u041f\u0440\u043e\u0449\u0435 \u0432\u0441\u0435\u0433\u043e \u044d\u0442\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0447\u0435\u0440\u0435\u0437 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0448\u0430\u0431\u043b\u043e\u043d\u0430 \u0434\u043b\u044f <code>Promise<\/code>.<\/p>\n<p>\u0411\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u043f\u043e\u0442\u043e\u043a\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u043e \u0437\u0430 \u0441\u0447\u0435\u0442 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 <code>BlockingEvent<\/code> \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043f\u0440\u0438 \u0432\u044b\u0437\u043e\u0432\u0435 <code>.wait<\/code> \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 lock \u043d\u0430 <code>condition_wariable<\/code> \u0434\u043e \u043c\u043e\u043c\u0435\u043d\u0442\u0430, \u043f\u043e\u043a\u0430 \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d <code>atomic_bool<\/code> \u0444\u043b\u0430\u0433:<\/p>\n<pre><code class=\"cpp\">class BlockingEvent { public:     void wait()     {         std::unique_lock&lt;std::mutex&gt; lock(mutex);         condEvent.wait(lock, [this] { return m_isSet.load(std::memory_order_acquire); });     } void set() {     m_isSet.store(true, std::memory_order_release);     condEvent.notify_all(); }  private:     std::atomic_bool m_isSet = false;     std::mutex mutex;     std::condition_variable condEvent; };<\/code><\/pre>\n<p>\u0424\u0440\u0430\u0433\u043c\u0435\u043d\u0442 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 <code>SyncWait<\/code> \u0434\u043b\u044f \u0442\u0438\u043f\u043e\u0432 \u0441 \u0432\u043e\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u044b\u043c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0435\u0442\u043e\u043c \u043d\u0435-void:<\/p>\n<pre><code class=\"cpp\">template&lt;typename TResultType&gt; struct SyncTaskPromise;  template &lt;typename TResultType&gt; struct SyncWaitTask {     using promise_type = SyncTaskPromise&lt;TResultType&gt;;     using TResultRef = ResultTypeRefHolder&lt;TResultType&gt;::Type;      SyncWaitTask(stdcoro::coroutine_handle&lt;SyncTaskPromise&lt;TResultType&gt;&gt; suspendedRoutine)         : m_suspendedRoutine{suspendedRoutine}     {     }     ~SyncWaitTask()     {         if (m_suspendedRoutine)             m_suspendedRoutine.destroy();     }      decltype(auto) result() noexcept     {         return m_suspendedRoutine.promise().value();     }      void await_resume()     {     }      void start(BlockingEvent&amp; _event)     {         m_suspendedRoutine.promise().start(&amp;_event);     }     stdcoro::coroutine_handle&lt;SyncTaskPromise&lt;TResultType&gt;&gt; m_suspendedRoutine; };   template&lt;typename TResultType&gt; struct SyncTaskPromise {     using TResultRef = TResultType&amp;&amp;;      struct FinalAwaitable     {         bool await_ready() noexcept         {             return false;         }         template &lt;typename TPromise&gt;         void await_suspend(stdcoro::coroutine_handle&lt;TPromise&gt; coroutine) noexcept         {             SyncTaskPromise&amp; promise = coroutine.promise();             promise.m_event-&gt;set();         }         void await_resume() noexcept         {         }     };      auto get_return_object() noexcept     {         return SyncWaitTask&lt;TResultType&gt;{ stdcoro::coroutine_handle&lt;SyncTaskPromise&lt;TResultType&gt;&gt;::from_promise(*this) };     }     void start(BlockingEvent* _pEvent) noexcept     {         m_event = _pEvent;         stdcoro::coroutine_handle&lt;SyncTaskPromise&lt;TResultType&gt;&gt;::from_promise(*this).resume();     }     auto initial_suspend() noexcept     {         return std::suspend_always{};     }      auto final_suspend() noexcept     {         return FinalAwaitable{};     }      auto yield_value(TResultRef result) noexcept     {         m_value = std::addressof(result);         return final_suspend();     }      decltype(auto) value() noexcept     {         return static_cast&lt;TResultRef&gt;(*m_value);     }      void return_void() noexcept     {     }      void unhandled_exception()     {         std::terminate();     }      BlockingEvent* m_event;     std::remove_reference_t&lt;TResultType&gt;* m_value; };  template &lt;typename TAwaitable, typename TTaskResult = AwaitResultGetter&lt;TAwaitable&gt;::Result&gt; SyncWaitTask&lt;TTaskResult&gt; makeSyncWaitTask(TAwaitable&amp;&amp; awaitable) {     if constexpr (!std::is_same_v&lt;TTaskResult, void&gt;)         co_yield co_await awaitable;     else         co_await awaitable; } <\/code><\/pre>\n<h3>\u041d\u0435\u0431\u043e\u043b\u044c\u0448\u0438\u0435 \u043f\u0440\u0438\u043c\u0435\u0440\u044b \u0434\u043b\u044f \u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u043e\u0432<\/h3>\n<p>\u041f\u043e\u043b\u043d\u044b\u0439 \u043f\u0440\u0438\u043c\u0435\u0440 \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043c\u043e\u0436\u043d\u043e \u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c: <a href=\"https:\/\/godbolt.org\/z\/8YoxPPYsW\" rel=\"noopener noreferrer nofollow\">https:\/\/godbolt.org\/z\/8YoxPPYsW<\/a><\/p>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c SPI-\u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 \u0434\u043b\u044f \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0434\u0438\u0441\u043f\u043b\u0435\u044f. \u041c\u043e\u0436\u043d\u043e \u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c. <a href=\"https:\/\/wandbox.org\/permlink\/y6s7UVqLQUBy67xK\" rel=\"noopener noreferrer nofollow\">https:\/\/wandbox.org\/permlink\/y6s7UVqLQUBy67xK<\/a><\/p>\n<h3>\u041f\u043e\u043b\u0435\u0437\u043d\u044b\u0435 \u0441\u0441\u044b\u043b\u043a\u0438 \u0438 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u044b<\/h3>\n<ul>\n<li>\n<p><a href=\"https:\/\/blog.panicsoftware.com\/your-first-coroutine\/\" rel=\"noopener noreferrer nofollow\">https:\/\/blog.panicsoftware.com\/your-first-coroutine\/<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/lewissbaker.github.io\/2017\/09\/25\/coroutine-theory\" rel=\"noopener noreferrer nofollow\">https:\/\/lewissbaker.github.io\/2017\/09\/25\/coroutine-theory<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/lewissbaker.github.io\/2017\/11\/17\/understanding-operator-co-await\" rel=\"noopener noreferrer nofollow\">https:\/\/lewissbaker.github.io\/2017\/11\/17\/understanding-operator-co-await<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/lewissbaker.github.io\/2018\/09\/05\/understanding-the-promise-type\" rel=\"noopener noreferrer nofollow\">https:\/\/lewissbaker.github.io\/2018\/09\/05\/understanding-the-promise-type<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/lewissbaker.github.io\/2020\/05\/11\/understanding_symmetric_transfer\" rel=\"noopener noreferrer nofollow\">https:\/\/lewissbaker.github.io\/2020\/05\/11\/understanding_symmetric_transfer<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/gist.github.com\/MattPD\/9b55db49537a90545a90447392ad3aeb\" rel=\"noopener noreferrer nofollow\">https:\/\/gist.github.com\/MattPD\/9b55db49537a90545a90447392ad3aeb<\/a> &#8212; \u0441\u043e\u0431\u0440\u0430\u043d\u0438\u0435 \u0441\u0441\u044b\u043b\u043e\u043a \u0438 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u043e\u0432 \u043f\u043e \u0441\u043e\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0430\u043c(\u0434\u043e\u043a\u043b\u0430\u0434\u044b, \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438, \u043f\u0440\u0438\u043c\u0435\u0440\u044b)<\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/github.com\/lewissbaker\/cppcoro\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/lewissbaker\/cppcoro<\/a> &#8212; \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430, \u0441 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u043b\u0441\u044f \u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0437\u0430\u043c\u0435\u0442\u043a\u0438<\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/github.com\/bbelson2\/coro-mc-wwl-code\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/bbelson2\/coro-mc-wwl-code<\/a> &#8212; \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u0438\u0437 \u0438\u0441\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u044f <a href=\"https:\/\/ieeexplore.ieee.org\/abstract\/document\/8995550\" rel=\"noopener noreferrer nofollow\">C++20 Coroutines on Microcontrollers\u2014What We Learned<\/a><\/p>\n<\/li>\n<li>\n<p>\u0421\u0421\u044b\u043b\u043a\u0430 \u043d\u0430 \u043f\u0440\u043e\u0435\u043a\u0442-\u0434\u043e\u043b\u0433\u043e\u0441\u0442\u0440\u043e\u0439:<a href=\"https:\/\/github.com\/ValentiWorkLearning\/GradWork\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/ValentiWorkLearning\/GradWork<\/a><\/p>\n<\/li>\n<\/ul>\n<p>P.S. \u0412 \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u043c \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0431\u044b \u0440\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043f\u0440\u043e \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0438 \u0440\u0430\u0431\u043e\u0442\u044b \u0441\u043e\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0445 \u0430\u043b\u043b\u043e\u043a\u0430\u0442\u043e\u0440\u043e\u0432 \u0434\u043b\u044f \u043d\u0438\u0445, \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0432 \u0441\u0432\u044f\u0437\u043a\u0435 \u0441 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430\u043c\u0438.<\/p>\n<p>\u0412\u044b\u0440\u0430\u0436\u0430\u044e&nbsp;\u0431\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u043d\u043e\u0441\u0442\u044c&nbsp;@magras,&nbsp;@shiz01,&nbsp;@Dr_Zlo13&nbsp;\u0437\u0430&nbsp;\u0432\u044b\u0447\u0438\u0442\u043a\u0443&nbsp;\u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u0430&nbsp;\u0438&nbsp;\u043f\u043e\u043c\u043e\u0449\u044c&nbsp;\u0432&nbsp;\u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0435.<\/p>\n<p>P.S.S. \u0414\u0430\u043d\u043d\u0430\u044f \u0437\u0430\u043c\u0435\u0442\u043a\u0430 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u0440\u043e\u0431\u043e\u0439 \u043f\u0435\u0440\u0430. \u0411\u0443\u0434\u0443 \u0440\u0430\u0434 \u0443\u0432\u0438\u0434\u0435\u0442\u044c \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0438\/\u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0435\u043d\u0438\u044f\/\u0437\u0430\u043c\u0435\u0447\u0430\u043d\u0438\u044f.<\/p>\n<\/div>\n<p> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/post\/566070\/\"> https:\/\/habr.com\/ru\/post\/566070\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"\n<div class=\"post__text post__text_v2\" id=\"post-content-body\">\n<h4><\/h4>\n<p>\u041f\u043e\u044f\u0432\u0438\u043b\u0430\u0441\u044c \u0438\u0434\u0435\u044f \u0432 \u0434\u043e\u043c\u0430\u0448\u043d\u0435\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u043f\u043e\u043f\u0440\u043e\u0431\u043e\u0432\u0430\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u043e\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b \u0438\u0437 \u0421++20 \u043d\u0430 \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u043e\u0439 \u0436\u0435\u043b\u0435\u0437\u043a\u0435. \u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043c\u043e\u0434\u0443\u043b\u044f \u0434\u043b\u044f \u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u043e\u0432 \u0431\u044b\u043b \u0432\u044b\u0431\u0440\u0430\u043d E73 NRF52832. \u0418\u0437 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0441\u044f \u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438- arm-gcc-gnu-none-eabi 10.2, MSVC \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0438\u0434\u0435\u0439 \u0438 \u043f\u0440\u043e\u0433\u043e\u043d\u0430 \u0442\u0435\u0441\u0442\u043e\u0432 \u043d\u0430 Windows-\u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0435. \u0418\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e \u0431\u044b\u043b\u043e \u0432 \u043f\u043b\u0430\u043d\u0430\u0445 \u043f\u0440\u043e\u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0430 \u0447\u0435\u043c-\u0442\u043e \u043a\u043e\u043d\u0446\u0435\u043f\u0446\u0438\u044e \u0438 \u043a\u0430\u043a \u0438\u043c\u0435\u043d\u043d\u043e \u0438\u0445 \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0442\u044c. \u0411\u044b\u043b\u0430 \u0438\u0434\u0435\u044f \u0430\u0434\u0430\u043f\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u0432 \u0432\u0438\u0434\u0435 \u043c\u0438\u0433\u0430\u043d\u0438\u044f \u0441\u0432\u0435\u0442\u043e\u0434\u0438\u043e\u0434\u0438\u043a\u043e\u043c. \u041d\u043e \u043e\u043d \u0431\u044b\u043b \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u043f\u0440\u043e\u0441\u0442\u043e\u0439. \u041d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0431\u044b\u043b\u043e \u043f\u0440\u0438\u0434\u0443\u043c\u0430\u0442\u044c \u0447\u0442\u043e-\u0442\u043e \u0431\u043e\u043b\u0435\u0435 \u0441\u043b\u043e\u0436\u043d\u043e\u0435 \u0438 \u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u043b\u0435\u0437\u043d\u043e\u0435, \u0447\u0442\u043e \u043b\u0438. \u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u0438 \u043f\u043e\u044f\u0432\u0438\u043b\u0430\u0441\u044c \u0438\u0434\u0435\u044f \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u0430\u0442\u044c \u0434\u0440\u0430\u0439\u0432\u0435\u0440 \u0434\u0438\u0441\u043f\u043b\u0435\u044f \u0438 \u043f\u0430\u0440\u044b \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u043e\u0432 SPI-FLASH \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0435-\u0434\u043e\u043b\u0433\u043e\u0441\u0442\u0440\u043e\u0435.<\/p>\n<p>\u041d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u043f\u043b\u0430\u043d, \u0447\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0432 \u0437\u0430\u043c\u0435\u0442\u043a\u0435:<\/p>\n<ol start=\"0\">\n<li>\n<p>\u041f\u0440\u0435\u0434\u044b\u0441\u0442\u043e\u0440\u0438\u044f \u0441 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u044f\u043c\u0438<\/p>\n<\/li>\n<li>\n<p>\u041a\u0430\u043a \u044d\u0442\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0432 \u043e\u0431\u0449\u0438\u0445 \u0447\u0435\u0440\u0442\u0430\u0445<\/p>\n<\/li>\n<li>\n<p>\u0420\u0430\u0431\u043e\u0442\u0430\u0435\u043c \u0441 SPI \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u043e\u043c<\/p>\n<\/li>\n<li>\n<p>\u041c\u0430\u0441\u0441\u0438\u0432 \u043a\u043e\u043c\u0430\u043d\u0434 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438<\/p>\n<\/li>\n<li>\n<p>\u0418\u0434\u0435\u0438 \u0441 std::tuple \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0439<\/p>\n<\/li>\n<li>\n<p>\u0420\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c when_all_sequence<\/p>\n<\/li>\n<li>\n<p>\u041a\u0430\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 Task \u0438\u0437 cppcoro<\/p>\n<\/li>\n<li>\n<p>\u041a\u0430\u043a \u044d\u0442\u043e \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c?<\/p>\n<\/li>\n<li>\n<p>\u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0442\u0435\u0441\u0442\u044b \u0432 GTest<\/p>\n<\/li>\n<li>\n<p>\u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0447\u0435\u0440\u043d\u043e\u0432\u043e\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u0434\u0440\u0430\u0439\u0432\u0435\u0440\u0430 \u0434\u043b\u044f SPI-FLASH<\/p>\n<\/li>\n<li>\n<p>\u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0447\u0442\u0435\u043d\u0438\u0435 JEDEC ID<\/p>\n<\/li>\n<li>\n<p>\u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0447\u0442\u0435\u043d\u0438\u0435 device id<\/p>\n<\/li>\n<li>\n<p>\u041e\u0436\u0438\u0434\u0430\u043d\u0438\u0435 \u043e\u043a\u043e\u043d\u0447\u0430\u043d\u0438\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0441\u043e\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b<\/p>\n<\/li>\n<\/ol>\n<h4>0. \u041f\u0435\u0440\u0435\u0434 \u043f\u0440\u043e\u0447\u0442\u0435\u043d\u0438\u0435\u043c<\/h4>\n<p>\u0417\u0430\u043c\u0435\u0442\u043a\u0430 \u043f\u0440\u0435\u0434\u043f\u043e\u043b\u0430\u0433\u0430\u0435\u0442 \u0431\u0430\u0437\u043e\u0432\u043e\u0435 \u0437\u043d\u0430\u043a\u043e\u043c\u0441\u0442\u0432\u043e \u0447\u0438\u0442\u0430\u0442\u0435\u043b\u044f \u0441 \u0441\u043e\u043f\u0440\u043e\u0433\u0440\u043c\u0430\u043c\u043c\u0430\u043c\u0438 \/ \u0438\u0445 \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441\u043e\u043c. \u0412 \u0441\u0438\u043b\u0443 \u043d\u0430\u043b\u0438\u0447\u0438\u044f \u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u044b\u0445 \u0441\u0442\u0430\u0442\u0435\u0439 \u043d\u0430 \u0442\u0435\u043c\u0443 \u0434\u0435\u0442\u0430\u043b\u0435\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0441\u043e\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c \u0438 \u0438\u0445 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u044e\u0442\u0441\u044f \u043a \u043f\u0440\u043e\u0447\u0442\u0435\u043d\u0438\u044e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u044b:<\/p>\n<ul>\n<li>\n<p><a href=\"https:\/\/blog.panicsoftware.com\/your-first-coroutine\/\" rel=\"noopener noreferrer nofollow\">YOUR FIRST COROUTINE,panicsoftware<\/a><\/p>\n<\/li>\n<\/ul>\n<p>\u0421\u0435\u0440\u0438\u044f \u0441\u0442\u0430\u0442\u0435\u0439 \u043e\u0442 \u0430\u0432\u0442\u043e\u0440\u0430 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 <a href=\"https:\/\/github.com\/lewissbaker\/cppcoro\" rel=\"noopener noreferrer nofollow\">cppcoro<\/a><\/p>\n<ul>\n<li>\n<p><a href=\"https:\/\/lewissbaker.github.io\/2017\/09\/25\/coroutine-theory\" rel=\"noopener noreferrer nofollow\">https:\/\/lewissbaker.github.io\/2017\/09\/25\/coroutine-theory<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/lewissbaker.github.io\/2017\/11\/17\/understanding-operator-co-await\" rel=\"noopener noreferrer nofollow\">https:\/\/lewissbaker.github.io\/2017\/11\/17\/understanding-operator-co-await<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/lewissbaker.github.io\/2018\/09\/05\/understanding-the-promise-type\" rel=\"noopener noreferrer nofollow\">https:\/\/lewissbaker.github.io\/2018\/09\/05\/understanding-the-promise-type<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/lewissbaker.github.io\/2020\/05\/11\/understanding_symmetric_transfer\" rel=\"noopener noreferrer nofollow\">https:\/\/lewissbaker.github.io\/2020\/05\/11\/understanding_symmetric_transfer<\/a><\/p>\n<\/li>\n<\/ul>\n<p>\u0412 \u0437\u0430\u043c\u0435\u0442\u043a\u0435 \u0438\u0437\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u0430 \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c\u0441\u044f \u043d\u0435\u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u043c. \u041f\u0440\u0435\u0434\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0431\u0443\u0434\u0443 \u0440\u0430\u0434 \u0443\u0432\u0438\u0434\u0435\u0442\u044c \u0432 \u0432\u0438\u0434\u0435 issues \u0438\u043b\u0438 \u0436\u0435 \u0432 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f\u0445\/\u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f\u0445 \u0432 Telegram.<\/p>\n<p>\u0427\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u043e:<\/p>\n<ul>\n<li>\n<p>\u0434\u0440\u0430\u0439\u0432\u0435\u0440 \u0434\u0438\u0441\u043f\u043b\u0435\u044f \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0441\u043e\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c, \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043d\u0430 \u0431\u0430\u0437\u0435 std::tuple \u0438 \u043a\u043b\u0430\u0441\u0441\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430 \u043d\u0430 \u0431\u0430\u0437\u0435 \u043c\u0430\u0441\u0441\u0438\u0432\u0430 \u043a\u043e\u043c\u0430\u043d\u0434.<\/p>\n<\/li>\n<li>\n<p>\u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442 \u0434\u0440\u0430\u0439\u0432\u0435\u0440\u0430 \u0434\u043b\u044f SPI-FLASH \u043f\u0430\u043c\u044f\u0442\u0438<\/p>\n<\/li>\n<li>\n<p>\u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0442\u0435\u0441\u0442\u043e\u0432 \u043d\u0430 \u0434\u0440\u0430\u0439\u0432\u0435\u0440 SPI \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0442\u0435\u0441\u0442\u043e\u0432 \u0432 GTest<\/p>\n<\/li>\n<li>\n<p>\u0420\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u0438\u0435 \u0440\u0430\u0431\u043e\u0442\u044b \u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u043f\u0440\u0438\u043c\u0438\u0442\u0438\u0432\u043e\u0432 \u0438\u0437 cppcoro \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438.<\/p>\n<\/li>\n<\/ul>\n<h4>1. \u041f\u0440\u0435\u0434\u044b\u0441\u0442\u043e\u0440\u0438\u044f \u0441 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u044f\u043c\u0438<\/h4>\n<p>\u0418\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e, \u0438\u0434\u0435\u044f \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u044b\u0432\u0430\u043d\u0438\u044f \u0441 \u043f\u043e\u0434\u0445\u043e\u0434\u0430 \u0432 \u0432\u0438\u0434\u0435 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0439 \u043f\u043e\u044f\u0432\u0438\u043b\u0430\u0441\u044c \u043a\u0430\u043a \u0442\u043e\u043b\u044c\u043a\u043e \u0432\u043e\u0437\u043d\u0438\u043a\u043b\u0430 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u044c \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u043e\u043d\u043d\u043e\u0441\u0442\u0438 read-\u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u044f\u043c\u0438. \u0414\u043b\u044f \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043e\u0447\u0435\u0440\u0435\u0434\u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u044d\u0442\u043e\u0442 \u043f\u043e\u0434\u0445\u043e\u0434 \u0431\u044b\u043b \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0443\u0434\u043e\u0431\u043d\u044b\u043c, \u043d\u043e \u0434\u043b\u044f \u043e\u0447\u0435\u0440\u0435\u0434\u0438 \u043f\u0440\u0438\u0435\u043c\u0430 \u043f\u043e\u043b\u0443\u0447\u0430\u043b\u043e\u0441\u044c \u0447\u0442\u043e-\u0442\u043e \u0432\u0440\u043e\u0434\u0435 callback-hell \u043f\u043e\u0434\u0445\u043e\u0434\u0430.<\/p>\n<p>\u0412 \u043e\u0431\u0449\u0438\u0445 \u0447\u0435\u0440\u0442\u0430\u0445, \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u043e\u043d\u043d\u044b\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u043b \u0441\u043e\u0431\u043e\u0439 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u0438\u0434\u0435\u044e:<\/p>\n<pre><code class=\"cpp\">template &lt;typename... Args&gt; void sendCommand(std::uint8_t command, Args... commandArgs) noexcept {     sendCommand(command);     sendChunk(static_cast&lt;std::uint8_t&gt;(commandArgs)...); }  template &lt;typename... Args&gt; void sendChunk(Args... _chunkArgs) noexcept {     std::array chunk = {static_cast&lt;std::uint8_t&gt;(_chunkArgs)...};     Interface::Spi::Transaction chunkTransaction{};      chunkTransaction.beforeTransaction = [this] { setDcPin(); };      chunkTransaction.transactionAction = [this, chunkToSend = std::move(chunk)] {         m_pBusPtr-&gt;sendChunk(             reinterpret_cast&lt;const std::uint8_t*&gt;(chunkToSend.data()), chunkToSend.size());     };      chunkTransaction.afterTransaction = [this] { resetDcPin(); };      m_pBusPtr-&gt;addTransaction(std::move(chunkTransaction)); }<\/code><\/pre>\n<p>\u0422.\u0435. \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0434\u043e \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0438, \u0441\u0430\u043c\u0430 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u044f \u0438 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u043e \u043f\u043e\u0441\u043b\u0435 \u043d\u0435\u0435. \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0442\u0430\u043a-\u0436\u0435 \u0431\u044b\u043b\u043e \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0443\u0434\u043e\u0431\u043d\u044b\u043c:<\/p>\n<pre><code class=\"cpp\">sendCommand(DisplayReg::SLPOUT); sendCommand(DisplayReg::COLMOD, 0x55); sendCommand(DisplayReg::MADCTL, 0x08); sendCommand(DisplayReg::CASET, 0x00, 0, 0, 240);<\/code><\/pre>\n<p>\u042d\u0442\u043e\u0442 \u043f\u043e\u0434\u0445\u043e\u0434 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0445\u043e\u0440\u043e\u0448\u043e \u0441\u0435\u0431\u044f \u043f\u043e\u043a\u0430\u0437\u0430\u043b \u0432 \u0440\u0430\u0431\u043e\u0442\u0435. \u0422\u0438\u043f\u043e\u0432\u0430\u044f \u0437\u0430\u0434\u0430\u0447\u0430 \u0434\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0438\u043c\u0435\u043b\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0432\u0438\u0434:<\/p>\n<ol start=\"0\">\n<li>\n<p>\u0412\u044b\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043f\u043e\u0440\u0442\u0430 D\/C \u0434\u043b\u044f \u0434\u0438\u0441\u043f\u043b\u0435\u044f \u0434\u043b\u044f \u0432\u044b\u0431\u043e\u0440\u0430 \u0442\u0438\u043f\u0430 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u043c\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 (\u043a\u043e\u043c\u0430\u043d\u0434\u0430 \u0438\u043b\u0438 \u0434\u0430\u043d\u043d\u044b\u0435) <\/p>\n<\/li>\n<li>\n<p>\u0421\u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u0442\u044c DMA- \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u044e<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e \u0435\u0435 \u043e\u043a\u043e\u043d\u0447\u0430\u043d\u0438\u044e \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0443, \u0435\u0441\u043b\u0438 \u0431\u043b\u043e\u043a \u0434\u0430\u043d\u043d\u044b\u0445 \u0431\u044b\u043b \u043d\u0435 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d<\/p>\n<\/li>\n<li>\n<p>\u0418\u043b\u0438 \u0432\u0435\u0440\u043d\u0443\u0442\u044c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043f\u043e\u0440\u0442\u0430 D\/C \u0432 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0438 \u043f\u0435\u0440\u0435\u0439\u0442\u0438 \u043a \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0438<\/p>\n<\/li>\n<\/ol>\n<p>\u041d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043a\u0438 \u0441\u0442\u0430\u043b\u0438 \u043f\u0440\u043e\u044f\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u043f\u0440\u0438 \u043f\u043e\u043f\u044b\u0442\u043a\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0434\u0440\u0430\u0439\u0432\u0435\u0440\u0430 \u0434\u043b\u044f SPI-FLASH \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0434\u043e\u043b\u0436\u043d\u0430 \u0431\u044b\u043b\u0430 \u0431\u044b\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0430 \u0432 \u0441\u0432\u044f\u0437\u043a\u0435 \u0441 Little FS. \u0413\u0434\u0435-\u0442\u043e \u0432 \u0442\u043e\u0442-\u0436\u0435 \u043f\u0435\u0440\u0438\u043e\u0434 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0431\u044b\u043b\u043e \u043d\u0430\u0439\u0434\u0435\u043d\u043e \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0432 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442 \u0421++20 \u043f\u043e \u0441\u043e\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0430\u043c, \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u0430 \u0441\u0435\u0440\u0438\u044f \u043c\u043e\u0442\u0438\u0432\u0438\u0440\u0443\u044e\u0449\u0438\u0445 \u0441\u0442\u0430\u0442\u0435\u0439:<\/p>\n<ul>\n<li>\n<p><a href=\"https:\/\/habr.com\/ru\/company\/yandex\/blog\/420861\/\" rel=\"noopener noreferrer nofollow\">\u0413\u043e\u0442\u043e\u0432\u0438\u043c\u0441\u044f \u043a \u0421++20. Coroutines TS \u043d\u0430 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u0435<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/habr.com\/ru\/post\/201826\/\" rel=\"noopener noreferrer nofollow\">\u0410\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0441\u0442\u044c: \u043d\u0430\u0437\u0430\u0434 \u0432 \u0431\u0443\u0434\u0443\u0449\u0435\u0435<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/habr.com\/ru\/company\/yandex\/blog\/240525\/\" rel=\"noopener noreferrer nofollow\">\u0410\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0441\u0442\u044c 2: \u0442\u0435\u043b\u0435\u043f\u043e\u0440\u0442\u0430\u0446\u0438\u044f \u0441\u043a\u0432\u043e\u0437\u044c \u043f\u043e\u0440\u0442\u0430\u043b\u044b<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/habr.com\/ru\/post\/340732\/\" rel=\"noopener noreferrer nofollow\">\u0410\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0441\u0442\u044c 3: \u0421\u0443\u0431\u044a\u0435\u043a\u0442\u043e\u0440\u043d\u0430\u044f \u043c\u043e\u0434\u0435\u043b\u044c<\/a><\/p>\n<\/li>\n<\/ul>\n<p>\u0418 \u0431\u044b\u043b\u043e \u043f\u0440\u0438\u043d\u044f\u0442\u043e \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043e \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u044b\u0432\u0430\u043d\u0438\u0438 \u043d\u0430 \u0441\u043e\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b \u0447\u0430\u0441\u0442\u0438 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u0434\u0440\u0430\u0439\u0432\u0435\u0440\u043e\u0432.<\/p>\n<h4>2. \u041a\u0430\u043a \u044d\u0442\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0432 \u043e\u0431\u0449\u0438\u0445 \u0447\u0435\u0440\u0442\u0430\u0445<\/h4>\n<p>\u0414\u043b\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u043c\u0435\u043b\u0438 \u0434\u0435\u043b\u043e \u0441 C#\/Python\/JS \u043d\u0435 \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0447\u0435\u043c-\u0442\u043e \u043d\u043e\u0432\u044b\u043c \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u0441\u043b\u043e\u0432\u0430 <code>yeild<\/code>, <code>await<\/code>,<code>async<\/code>.(\u0414\u0430, \u043e\u043d\u0438 \u0442\u0443\u0442 \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u043d\u044b \u0432 \u043e\u0431\u0449\u0435\u043c \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0435, \u0431\u0435\u0437 \u043f\u0440\u0438\u043d\u0430\u0434\u043b\u0435\u0436\u043d\u043e\u0441\u0442\u0438 \u043a \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u043c\u0443 \u044f\u0437\u044b\u043a\u0443). \u0412 \u043a\u0440\u0430\u0442\u0446\u0435, \u0438\u0434\u0435\u044f \u0441\u043e\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0432 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u043f\u0440\u0438\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0432 \u043b\u044e\u0431\u043e\u043c \u043c\u0435\u0441\u0442\u0435 \u0438\u0441\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0441 \u043f\u043e\u0441\u043b\u0435\u0434\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u043c \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435\u043c \u0435\u0435 \u0440\u0430\u0431\u043e\u0442\u044b \u0438\u0437 \u043f\u0440\u0435\u0440\u0432\u0430\u043d\u043d\u043e\u0439 \u0442\u043e\u0447\u043a\u0438. \u0424\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438, \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043b\u0435\u0433\u043a\u043e\u0432\u0435\u0441\u043d\u044b\u0435 \u043f\u043e\u0442\u043e\u043a\u0438 \u0443\u0440\u043e\u0432\u043d\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f, \u0442.\u0435. \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u0441\u043e\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c \u043d\u0430\u043c \u043d\u0435\u0442 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0431\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u043a \u044f\u0434\u0440\u0443 \u041e\u0421\/etc.<\/p>\n<p>\u0412 \u0421++20 \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u0439 \u043f\u0440\u0438\u043c\u0435\u0440 \u0441\u043e\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d \u0432 \u0432\u0438\u0434\u0435 \u0441\u043b\u0435\u0434\u0443\u0449\u0435\u0439 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u0438:<\/p>\n<pre><code class=\"cpp\">#include &lt;coroutine&gt; #include &lt;iostream&gt;  struct Awaitable {     struct Promise;     using promise_type = Promise;      Awaitable(std::coroutine_handle&lt;promise_type&gt; coroHandle) : thisCoroutine{coroHandle}     {         std::cout &lt;&lt; \"Awaitable created\\n\";     }     ~Awaitable()     {         std::cout &lt;&lt; \"Awaitable destroyed\\n\";         if (thisCoroutine)             thisCoroutine.destroy();     }     struct Promise     {         auto initial_suspend() noexcept         {             return std::suspend_always();         }         auto final_suspend() noexcept         {             return std::suspend_always();         }         void unhandled_exception()         {             std::terminate();         }          Awaitable get_return_object()         {             return Awaitable(std::coroutine_handle&lt;promise_type&gt;::from_promise(*this));         }         void return_void() noexcept         {         }     };     bool isFinished()     {         if (thisCoroutine)             return thisCoroutine.done();         return false;     }     void restore()     {         if (thisCoroutine &amp;&amp; !thisCoroutine.done())             thisCoroutine.resume();     }     std::coroutine_handle&lt;promise_type&gt; thisCoroutine; };  Awaitable callMe() {     std::cout &lt;&lt; \"Hello \";     co_await std::suspend_always{};     std::cout &lt;&lt; \"World\\n\"; } int main() {     auto lazyHello = callMe();     while (!lazyHello.isFinished())         lazyHello.restore();      return 0; }<\/code><\/pre>\n<p>\u0413\u0434\u0435 \u043f\u043e\u043b\u0435\u0437\u043d\u0430\u044f \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0430- \u043b\u0435\u043d\u0438\u0432\u044b\u0439 \u0432\u044b\u0432\u043e\u0434 \u0444\u0440\u0430\u0437\u044b &#171;Hello world&#187;. \u041f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0438\u0434\u0435\u044e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f, \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0447\u0435\u0433\u043e-\u0442\u043e \u0440\u0435\u0430\u043b\u044c\u043d\u0435\u0435. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0438 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0434\u0438\u0441\u043f\u043b\u0435\u0435\u043c. \u0414\u043b\u044f \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0430, \u0432\u0435\u0441\u044c \u043e\u0431\u043c\u0435\u043d \u0434\u043e\u043b\u0436\u0435\u043d \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442\u044c \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c DMA \u043c\u0438\u043a\u0440\u043e\u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430.<\/p>\n<h4>3. \u0420\u0430\u0431\u043e\u0442\u0430 \u0441 SPI \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u043e\u043c<\/h4>\n<p> \u0414\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 SPI \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u043e\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u043d\u0430\u0431\u043e\u0440 Awaitable-\u0442\u0438\u043f\u043e\u0432, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0432\u044b\u0437\u0432\u0430\u043d \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440 <code>co_await<\/code>. \u0421\u0430\u043c\u044b\u0439 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u0438\u043c\u0435\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0432\u0438\u0434:<\/p>\n<pre><code class=\"cpp\">struct Awaiter {     bool resetDcPin = false;     bool restoreInSpiCtx = false;     const std::uint8_t* pTransmitBuffer;     This_t* pBaseDisplay;     std::uint16_t bufferSize;      bool await_ready() const noexcept     {         \/\/ \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c, \u0435\u0441\u0442\u044c \u043b\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u044c \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u043f\u0440\u0438\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0443 \u0441\u043e\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b         const bool isAwaitReady = pTransmitBuffer == nullptr || bufferSize == 0;         return isAwaitReady;     }     void await_resume() const noexcept     {         \/\/\u0432\u044b\u0437\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0432\u0435\u0440\u0448\u0435\u043d \u043f\u0440\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0438 .resume() \u0443 \u0441\u043e\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b         if (resetDcPin)             pBaseDisplay-&gt;setDcPin();     }     void await_suspend(std::coroutine_handle&lt;&gt; thisCoroutine) const     {         \/\/\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u043d\u0430 \u0432\u0440\u0435\u043c\u044f \u043f\u0440\u0438\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0441\u043e\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b. \u0412 SPI \u0434\u0440\u0430\u0439\u0432\u0435\u0440 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442\u0441\u044f handle \u0441\u043e\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b,         \/\/ \u043f\u043e\u0441\u043b\u0435 \u0447\u0435\u0433\u043e \u043e\u043d\u0430 \u043f\u0440\u0438\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0430.         if (resetDcPin)             pBaseDisplay-&gt;resetDcPin();          pBaseDisplay-&gt;getSpiBus()-&gt;transmitBuffer(             pTransmitBuffer, bufferSize, thisCoroutine.address(), restoreInSpiCtx);     } };<\/code><\/pre>\n<p>\u0412 \u0441\u0432\u043e\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c, \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 SPI-\u0434\u0440\u0430\u0439\u0432\u0435\u0440\u0430 \u043f\u043e \u043e\u043a\u043e\u043d\u0447\u0430\u043d\u0438\u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u043a\u043e\u0434:<\/p>\n<pre><code class=\"cpp\">void transmitCompleted() noexcept {     const bool isAllDmaTransactionsProceeded = m_transmitContext.fullDmaTransactionsCount == 0;     const bool isAllChunckedTransactionsCompleted =         m_transmitContext.chunkedTransactionBufSize == 0;      if (!isAllDmaTransactionsProceeded)     {         \/\/\u0415\u0441\u043b\u0438 \u0435\u0449\u0435 \u043c\u043e\u0436\u0435\u043c \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0438 \u0440\u0430\u0437\u043c\u0435\u0440\u043e\u043c \u0441 DMA \u0431\u0443\u0444\u0435\u0440     }     else if (!isAllChunckedTransactionsCompleted)     {         \/\/ \u0415\u0441\u043b\u0438 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0438 \u043c\u0435\u043d\u044c\u0448\u0435 \u0440\u0430\u0437\u043c\u0435\u0440\u0430 DMA \u0431\u0443\u0444\u0435\u0440\u0430 \u043d\u0435 \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u044b     }     else     {         \/\/ \u0412 \u0441\u043b\u0443\u0447\u0430\u0435, \u0435\u0441\u043b\u0438 \u0432\u0441\u0435 DMA \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u044b- \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c, \u0432 \u043a\u0430\u043a\u043e\u043c \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f         \/\/ \u0434\u043e\u043b\u0436\u043d\u0430 \u0431\u044b\u0442\u044c \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0430 \u0441\u043e\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0430.\u041d\u0435 \u0437\u0430\u0431\u044b\u0432\u0430\u0435\u043c, \u0447\u0442\u043e \u044d\u0442\u043e\u0442 \u043c\u0435\u0442\u043e\u0434 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0438\u0437 \u043a\u043e\u043d\u0442\u0435\u043a\u0442\u0430         \/\/ \u043f\u0440\u0435\u0440\u044b\u0432\u0430\u043d\u0438\u044f \u0438 \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0442\u044f\u0436\u0435\u043b\u043e\u0439 \u0441\u043e\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u0438\u0432\u0435\u0441\u0442\u0438 \u043a \u0442\u0440\u0443\u0434\u043d\u043e\u0443\u043b\u0430\u0432\u043b\u0438\u0432\u0430\u0430\u0435\u043c\u044b\u043c         \/\/ \u043e\u0448\u0438\u0431\u043a\u0430\u043c. \u0422\u0443\u0442 \u0435\u0441\u0442\u044c \u0434\u0432\u0430 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430 - \u043b\u0438\u0431\u043e \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c\u0441\u044f \u0432 \u043a\u043e\u043d\u0442\u0435\u043a\u0442\u0435 \u043f\u0440\u0435\u0440\u044b\u0432\u0430\u043d\u0438\u044f, \u043b\u0438\u0431\u043e         \/\/ \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u043c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0441\u043e\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b \u0432 \u043e\u0447\u0435\u0440\u0435\u0434\u044c,\u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0432 \u0433\u043b\u0430\u0432\u043d\u043e\u043c \u043f\u043e\u0442\u043e\u043a\u0435. \u0422\u0430\u043a\u0438\u043c         \/\/ \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u0441\u043e\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0430 \u0431\u0443\u0434\u0435\u0442 \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0430 \u0438\u0437 main-\u043f\u043e\u0442\u043e\u043a\u0430.         if (m_transmitContext.restoreInSpiCtx)         {             m_coroHandle.resume();         }         else         {             CoroUtils::CoroQueueMainLoop::GetInstance().pushToLater(m_coroHandle);         }     } }<\/code><\/pre>\n<p>\u0412 \u0446\u0435\u043b\u044f\u0445 \u0443\u043c\u0435\u043d\u044c\u0448\u0435\u043d\u0438\u044f \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u043d\u0430 \u0447\u0442\u0435\u043d\u0438\u0435 \u043a\u043e\u0434\u0430- \u043f\u0440\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0438 <code>transmitBuffer<\/code> \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430 \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u0434\u0440\u0430\u0439\u0432\u0435\u0440\u0435, \u043f\u043e\u0441\u043b\u0435 \u0447\u0435\u0433\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u0440\u0430\u0441\u0441\u0447\u0435\u0442 \u0446\u0435\u043b\u043e\u0433\u043e \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 DMA \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0439 + \u0440\u0430\u0437\u043c\u0435\u0440 \u043e\u0441\u0442\u0430\u0432\u0448\u0435\u0433\u043e\u0441\u044f \u0431\u0443\u0444\u0435\u0440\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0442\u0430\u043a-\u0436\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u0435\u0440\u0435\u0434\u0430\u043d. \u0414\u0430\u043b\u0435\u0435, \u043f\u043e \u043e\u043a\u043e\u043d\u0447\u0430\u043d\u0438\u044e \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438 DMA \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0438 \u0432\u044b\u043f\u043e\u043b\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u0432\u044b\u0437\u043e\u0432 <code>transmitCompleted<\/code> \u0433\u0434\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f<\/p>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-325949","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/325949","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=325949"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/325949\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=325949"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=325949"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=325949"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}