завел такое вот интересное - С++20 Coroutine на К1948ВК018,
прикольно. оно работает. можно делать несложне шедуллеры не выбегая
за средства языка. миленько компактненько простенько. Для
контроллеров с озу 2к флеша 8к просто огонь! https://downloads.ctfassets.net/oxjq45e8ilak/4kVoTkxYBiVM9lPBZiG2HO/a5e36dc80fd898885269bd6320c96196/Pavel_Novikov_Uchimsya_gotovit_C_korutiny_na_praktike_2020_06_28_18_49_49.pdf
https://en.cppreference.com/w/cpp/language/coroutines
https://lewissbaker.github.io/2022/08/27/understanding-the-compiler-transform
https://www.scs.stanford.edu/~dm/blog/c++-coroutines.html
https://habr.com/ru/articles/519464/
https://habr.com/ru/articles/798935/
https://habr.com/ru/articles/687266/
класс hrono - взводить асинхронные события для корутин по таймауту системного таймера в прерывании
/*
* hrono.h
*
* Created on: 01 jrn. 2024 г.
* Author: klen
*/
#pragma once
template < typename handlers_t, uint32_t timeout = 1000 >
struct hrono_tt
{
__ai__ hrono_tt()
{
disable();
scr1_tim.time = 0 ;
scr1_tim.compare = timeout ; // 1 КГц
scr1_tim.prescaler = 32-1 ;
mchine_timer_interrupt_enable();
enable();
}
__ai__ auto mtime() noexcept { return scr1_tim.time ; }
__ai__ void generate_event_if()
{
if ( clock_ms%1000 == 0 ) handlers_t::event0_set(); // срабатывание события task0 с периодом 1 сек
if ( clock_ms%2700 == 0 ) handlers_t::event1_set(); // срабатывание события task1 с периодом 2,7 сек
if ( clock_ms%3300 == 0 ) handlers_t::event2_set(); // срабатывание события task2 с периодом 3,3 сек
if ( clock_ms%4000 == 0 ) handlers_t::event3_set(); // срабатывание события task3 с периодом 4 сек
}
__ai__ void enable() { scr1_tim.enable(); }
__ai__ void disable() { scr1_tim.disable(); }
__ai__ void timeout_handler()
{
scr1_tim.compare += timeout ;
clock_ms++ ;
generate_event_if();
}
volatile size_t clock_ms ;
} ;
класс "задач", реализованных по средством корутин и шедуллер который передает им управлние по карусели. каждая задача имеет объект синхронизации - асинхронное событие, по взводу его задачка выполняет одн цикл работы
/*
* co_task.h
*
* Created on: 17 сен. 2024 г.
* Author: klen
*/
#pragma once
#include <coroutine>
class co_event_t
{
using co_handle_t = std::coroutine_handle<>;
struct awaiter
{
co_event_t& event;
co_handle_t handle = nullptr;
__ai__ awaiter(co_event_t& val) noexcept : event(val) {}
__ai__ bool await_ready() const noexcept { return event.state(); }
__ai__ bool await_resume() noexcept { return event.reset(); }
// регистрация потребителя события
__ai__ void await_suspend(co_handle_t val) noexcept
{
handle = val;
event.set_awaiter(this);
}
};
public:
// yстановка (активации) события
__ai__ void set() noexcept { s = true; }
// сброс события, возврат значения перед сбросом
__ai__ bool reset () noexcept { auto const rv = s ; s = false; return rv;}
// проверка состояния события
__ai__ bool state() const noexcept { return s; }
// Метод регистрации потребителя
// Можно реализовать целый список потребителей
__ai__ void set_awaiter(awaiter* val) noexcept { consumer = val; }
// Перегруженный оператор co_await, так как тип event не является awaitable
// Подробное разъяснение необходимости этой перегрузки можно найти в лекции Владимирова
__ai__ awaiter operator co_await() noexcept { return awaiter(*this); }
private:
awaiter* consumer = nullptr;
bool s = false;
};
struct co_task_t
{
struct promise_type
{
using co_handle_t = std::coroutine_handle<promise_type>;
__ai__ auto get_return_object() noexcept { return co_handle_t::from_promise(*this); }
// Изначально задача остановлена
// Хотя можно вернуть suspend_never, чтобы дать возможность проинициализировать всё необходимое
__ais__ auto initial_suspend() noexcept { return std::suspend_always(); }
// Задача будет содержать бесконечный цикл, поэтому в этот метод попадать не должны
__ais__ auto final_suspend() noexcept { return std::suspend_never(); }
// ensure the use of non-throwing operator-new
__ais__ co_task_t get_return_object_on_allocation_failure()
{
__throw_memmgr_error("отказ выделения памятя для объекта co_task_t");
}
__ais__ void return_void() {}
__ais__ void unhandled_exception() {}
// custom non-throwing overload of new
void* operator new(std::size_t n) noexcept
{
if (void* mem = malloc(n)) return mem;
return nullptr; // allocation failure
}
};
using co_handle_t = promise_type::co_handle_t;
__ai__ co_task_t(co_handle_t handle) noexcept : handle(handle) {}
// Деструктор можно не определять, так как он ни разу не будет вызван
__ai__ void resume() const noexcept { handle.resume(); }
__ai__ void destroy() const noexcept { handle.destroy(); }
private:
co_handle_t handle;
};
struct co_scheduller_t
{
template <typename T>
__ains__ void start(const T& tasks) noexcept
{
for(;;) [[likely]] { for (auto& task : tasks) [[likely]] task.resume(); }
}
};
заголовок в котором определены события
/*
* apptypes.h
*
* Created on: 17.09.2024
* Author: klen
*/
#pragma once
#include "platform_config.h"
#include "co_task.h"
#ifdef __CRT_IMPL__
co_event_t event0 ;
co_event_t event1 ;
co_event_t event2 ;
co_event_t event3 ;
#else
extern co_event_t event0 ;
extern co_event_t event1 ;
extern co_event_t event2 ;
extern co_event_t event3 ;
#endif
struct event_handlers_t
{
static void event0_set() noexcept { event0.set(); }
static void event1_set() noexcept { event1.set(); }
static void event2_set() noexcept { event2.set(); }
static void event3_set() noexcept { event3.set(); }
};
#include "hrono.h"
using hrono_t = hrono_tt<event_handlers_t> ;
#ifdef __CRT_IMPL__
hrono_t hrono;
#else
extern hrono_t hrono;
#endif
код приложения
#include "appdefs.h"
co_task_t task0()
{
cout < cout_t::vt100_t::yellow <= " task0->begin\n" ;
size_t ev_counter=0 ;
mem_info();
for(;;)
{
if ( !co_await event0) continue ;
cout < cout_t::vt100_t::white < hrono.clock_ms < cout_t::vt100_t::yellow <= " task0->ev #" < ev_counter++ <= "\n" ;
}
}
co_task_t task1()
{
cout < cout_t::vt100_t::uv <= " task1->begin\n" ;
size_t ev_counter=0 ;
for(;;)
{
if ( !co_await event1) continue ;
cout < cout_t::vt100_t::white < hrono.clock_ms < cout_t::vt100_t::uv <= "\t task1->ev #" < ev_counter++ <= "\n" ;
//if (ev_counter==2) mem_info();
}
}
co_task_t task2()
{
cout < cout_t::vt100_t::ocean <= " task2->begin\n" ;
size_t ev_counter=0 ;
for(;;)
{
if ( !co_await event2) continue ;
{
cout < cout_t::vt100_t::white < hrono.clock_ms < cout_t::vt100_t::ocean <= "\t\t task2->ev #" < ev_counter++ <= "\n" ;
//mem_info();
}
}
}
co_task_t task3()
{
cout < cout_t::vt100_t::ocean <= " task3->begin\n" ;
size_t ev_counter=0 ;
for(;;)
{
if ( !co_await event3) continue ;
cout < cout_t::vt100_t::white < hrono.clock_ms < cout_t::vt100_t::green <= "\t\t\t task3->ev #" < ev_counter++ <= "\n" ;
}
}
int main()
{
const auto tasks = {task0() , task1(), task2(),task3()};
co_scheduller_t::start(tasks);
}
namespace mik32v2
{
__attribute__((aligned(4),interrupt,used,section(".trap"))) void trap_handler() noexcept
{
push_regs();
if (epic.dma_status())
cout.async_write_event_handler();
else
hrono.timeout_handler();
pop_regs();
}
void __init(){}
void __premain()
{
cout.reserve(1024-sizeof(o1heap::fragment_t)) < cout_t::vt100_t::clear <= cout_t::vt100_t::cursor_left_up ;
print_startup_hellow();
}
pm_t::sys_init_status_t sys_init_status = { status_t::undefined, status_t::undefined, status_t::undefined, status_t::undefined };
constexpr pm_t::system_init_profile_t system_init_profile =
{
.oscs= pm_t::system_init_profile_t::oscs_t::all ,
.system_clock_source= pm_t::system_init_profile_t::oscs_t::hse,
.system_clock_source_force= pm_t::ahb_clock_mux_t::force_t::unfixed,
.freq_monitor_clock_source= pm_t::system_init_profile_t::freq_monitor_clock_source_t::auto_select,
.ahb_div= 1,
.apb_m_div=1,
.apb_p_div=1,
.hsi_cal=128,
.lsi_cal=128,
.rtc_clock_source= pm_t::system_init_profile_t::rtc_clock_source_t::auto_select,
.cpu_rtc_clock_source = pm_t::system_init_profile_t::cpu_rtc_clock_source_t::lse
};
}
результат работы - имеем 4 задачи, объекты синхронизации которых взводятся с периодом 1, 2,7 3,3 и 4 секунды соответсвенно, по событию задачки выводят в консоль время в миллисикундах и количество сработок.
зашло в моск не спервого раза, тяжело .. но потом начинаешь ощущать глубину мысли кратеров стандарта C++
мне кажется это завбавным...