ВходНаше всё Теги codebook 无线电组件 Поиск Опросы Закон Понедельник
9 декабря
1466625
klen (01.10.2024 13:25 - 16:05, просмотров: 9048)
завел такое вот интересное - С++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++


мне кажется это завбавным...