Сообщество Engee

Буфер с внешним сбросом

Автор
avatar-nikfilaretovnikfilaretov
Notebook

Кольцевой буфер с внешним сбросом

Как-то раз мне понадобилось парсить потоковые данные и для этого мне потребовался буфер, который я мог бы очищать по некоторому условию. В Engee такого блока не оказалось, но это не беда, ведь если я знаю что мне надо, то я всегда могу реализовать это или на Си или на Джулии. Посмотрим, что у меня получилось.

Как работает кольцевой буфер с внешним сбросом?

image.png

Код буфера - используем Рабочие Переменные

Самый простой подход к реализации чего-либо - самый лучший. Поэтому будем использовать блок C Function.

Для реализации понадобится две переменных-состояния: сам буфер и счетчик. Заведем их как рабочие переменные блока.

Рабочие переменные - это специальные переменные, которые служат как предвыделенная статически область памяти. При настройке этого параметра блока для каждой переменной указывается сколько байт надо выделить. Отдельный плюс - эти переменные свои для каждого экземпляра блока. То есть можно говорить, что это "состояние" блока.

Посмотрим на мои настройки:

Видно, что будет использоваться 2 переменных - 80ти байтовый буфер buffer и однобайтовый счетчик.

Чтобы использовать эти переменные в коде C Function надо обратиться к структуре Work.

В итоге код будет выглядеть так:

uint8_t * ptr = &(Work->buffer[0]);
double* buffer_d_ptr = (double *) ptr;
double* output1_ptr = output1;

if (RESET)
{
    memset(buffer_d_ptr, 0, BUFFER_LEN_BYTES);
    memset(output1_ptr, 0, BUFFER_LEN_BYTES);
    (Work->pos[0]) = 0;
}
else
{
    buffer_d_ptr[Work->pos[0]] = byte;
    Work->pos[0]++;
    memcpy(output1_ptr, buffer_d_ptr, BUFFER_LEN_BYTES);
    if (Work->pos[0] > len - 1)
    {
        Work->pos[0] = 0;
    }
}

Как работать с рабочими переменными (магия Си)?

Рабочие переменные всегда имеют тип uint8_t. Но Си прекрасен тем, что позволяет работать с памятью как угодно. А еще можно вспомнить, что любой массив в Си - это просто указатель на кусок памяти, поэтому мы можем интерпретировать его как мы хотим:

uint8_t * ptr = &(Work->buffer[0]);
double* buffer_d_ptr = (double *) ptr;

И ptr и buffer_d_ptr указывают на один и тот же адрес в памяти, но buffer_d_ptr говорит компилятору о том, что по этому адресу будет double. А еще мы можем работать с этим указателем, как с массивом:

buffer_d_ptr[Work->pos[0]] = byte;

Заметьте, что мы вообще не используем динамическое выделение памяти!

Тестируем блок

Создадим тестовую обвязку вида:

image.png

запустим симуляцию модели:

In [ ]:
sys = engee.open(joinpath(@__DIR__,"cirbuf.engee"))
engee.run(sys)
engee.close(;force=true)

И посмотрим на результаты:

In [ ]:
using DataFrames
df = DataFrame(time=zero(Float64),Buffer=[zeros(Float64,16)],RESET = zero(UInt8))
for i in eachindex(workspace_out2)
    push!(df,(time=RESETEVT[i][1],
            Buffer=BUFFER[i][2],
            RESET=RESETEVT[i][2]))
end
show(df, allrows=true, allcols=true)
102×3 DataFrame
 Row │ time     Buffer                             RESET
     │ Float64  Array…                             UInt8
─────┼───────────────────────────────────────────────────
   1 │     0.0  [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0…      0
   2 │     0.0  [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0…      0
   3 │     0.1  [0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0…      0
   4 │     0.2  [0.0, 1.0, 2.0, 0.0, 0.0, 0.0, 0…      0
   5 │     0.3  [0.0, 1.0, 2.0, 3.0, 0.0, 0.0, 0…      0
   6 │     0.4  [0.0, 1.0, 2.0, 3.0, 4.0, 0.0, 0…      0
   7 │     0.5  [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 0…      0
   8 │     0.6  [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6…      0
   9 │     0.7  [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6…      0
  10 │     0.8  [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6…      0
  11 │     0.9  [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6…      0
  12 │     1.0  [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0…      1
  13 │     1.1  [11.0, 0.0, 0.0, 0.0, 0.0, 0.0, …      0
  14 │     1.2  [11.0, 12.0, 0.0, 0.0, 0.0, 0.0,…      0
  15 │     1.3  [11.0, 12.0, 13.0, 0.0, 0.0, 0.0…      0
  16 │     1.4  [11.0, 12.0, 13.0, 14.0, 0.0, 0.…      0
  17 │     1.5  [11.0, 12.0, 13.0, 14.0, 15.0, 0…      0
  18 │     1.6  [11.0, 12.0, 13.0, 14.0, 15.0, 0…      0
  19 │     1.7  [11.0, 12.0, 13.0, 14.0, 15.0, 0…      0
  20 │     1.8  [11.0, 12.0, 13.0, 14.0, 15.0, 0…      0
  21 │     1.9  [11.0, 12.0, 13.0, 14.0, 15.0, 0…      0
  22 │     2.0  [11.0, 12.0, 13.0, 14.0, 15.0, 0…      0
  23 │     2.1  [5.0, 12.0, 13.0, 14.0, 15.0, 0.…      0
  24 │     2.2  [5.0, 6.0, 13.0, 14.0, 15.0, 0.0…      0
  25 │     2.3  [5.0, 6.0, 7.0, 14.0, 15.0, 0.0,…      0
  26 │     2.4  [5.0, 6.0, 7.0, 8.0, 15.0, 0.0, …      0
  27 │     2.5  [5.0, 6.0, 7.0, 8.0, 9.0, 0.0, 1…      0
  28 │     2.6  [5.0, 6.0, 7.0, 8.0, 9.0, 10.0, …      0
  29 │     2.7  [5.0, 6.0, 7.0, 8.0, 9.0, 10.0, …      0
  30 │     2.8  [5.0, 6.0, 7.0, 8.0, 9.0, 10.0, …      0
  31 │     2.9  [5.0, 6.0, 7.0, 8.0, 9.0, 10.0, …      0
  32 │     3.0  [5.0, 6.0, 7.0, 8.0, 9.0, 10.0, …      0
  33 │     3.1  [15.0, 6.0, 7.0, 8.0, 9.0, 10.0,…      0
  34 │     3.2  [15.0, 0.0, 7.0, 8.0, 9.0, 10.0,…      0
  35 │     3.3  [15.0, 0.0, 1.0, 8.0, 9.0, 10.0,…      0
  36 │     3.4  [15.0, 0.0, 1.0, 2.0, 9.0, 10.0,…      0
  37 │     3.5  [15.0, 0.0, 1.0, 2.0, 3.0, 10.0,…      0
  38 │     3.6  [15.0, 0.0, 1.0, 2.0, 3.0, 4.0, …      0
  39 │     3.7  [15.0, 0.0, 1.0, 2.0, 3.0, 4.0, …      0
  40 │     3.8  [15.0, 0.0, 1.0, 2.0, 3.0, 4.0, …      0
  41 │     3.9  [15.0, 0.0, 1.0, 2.0, 3.0, 4.0, …      0
  42 │     4.0  [15.0, 0.0, 1.0, 2.0, 3.0, 4.0, …      0
  43 │     4.1  [9.0, 0.0, 1.0, 2.0, 3.0, 4.0, 5…      0
  44 │     4.2  [9.0, 10.0, 1.0, 2.0, 3.0, 4.0, …      0
  45 │     4.3  [9.0, 10.0, 11.0, 2.0, 3.0, 4.0,…      0
  46 │     4.4  [9.0, 10.0, 11.0, 12.0, 3.0, 4.0…      0
  47 │     4.5  [9.0, 10.0, 11.0, 12.0, 13.0, 4.…      0
  48 │     4.6  [9.0, 10.0, 11.0, 12.0, 13.0, 14…      0
  49 │     4.7  [9.0, 10.0, 11.0, 12.0, 13.0, 14…      0
  50 │     4.8  [9.0, 10.0, 11.0, 12.0, 13.0, 14…      0
  51 │     4.9  [9.0, 10.0, 11.0, 12.0, 13.0, 14…      0
  52 │     5.0  [9.0, 10.0, 11.0, 12.0, 13.0, 14…      0
  53 │     5.1  [3.0, 10.0, 11.0, 12.0, 13.0, 14…      0
  54 │     5.2  [3.0, 4.0, 11.0, 12.0, 13.0, 14.…      0
  55 │     5.3  [3.0, 4.0, 5.0, 12.0, 13.0, 14.0…      0
  56 │     5.4  [3.0, 4.0, 5.0, 6.0, 13.0, 14.0,…      0
  57 │     5.5  [3.0, 4.0, 5.0, 6.0, 7.0, 14.0, …      0
  58 │     5.6  [3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 1…      0
  59 │     5.7  [3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9…      0
  60 │     5.8  [3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9…      0
  61 │     5.9  [3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9…      0
  62 │     6.0  [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0…      1
  63 │     6.1  [13.0, 0.0, 0.0, 0.0, 0.0, 0.0, …      0
  64 │     6.2  [13.0, 14.0, 0.0, 0.0, 0.0, 0.0,…      0
  65 │     6.3  [13.0, 14.0, 15.0, 0.0, 0.0, 0.0…      0
  66 │     6.4  [13.0, 14.0, 15.0, 0.0, 0.0, 0.0…      0
  67 │     6.5  [13.0, 14.0, 15.0, 0.0, 1.0, 0.0…      0
  68 │     6.6  [13.0, 14.0, 15.0, 0.0, 1.0, 2.0…      0
  69 │     6.7  [13.0, 14.0, 15.0, 0.0, 1.0, 2.0…      0
  70 │     6.8  [13.0, 14.0, 15.0, 0.0, 1.0, 2.0…      0
  71 │     6.9  [13.0, 14.0, 15.0, 0.0, 1.0, 2.0…      0
  72 │     7.0  [13.0, 14.0, 15.0, 0.0, 1.0, 2.0…      0
  73 │     7.1  [7.0, 14.0, 15.0, 0.0, 1.0, 2.0,…      0
  74 │     7.2  [7.0, 8.0, 15.0, 0.0, 1.0, 2.0, …      0
  75 │     7.3  [7.0, 8.0, 9.0, 0.0, 1.0, 2.0, 3…      0
  76 │     7.4  [7.0, 8.0, 9.0, 10.0, 1.0, 2.0, …      0
  77 │     7.5  [7.0, 8.0, 9.0, 10.0, 11.0, 2.0,…      0
  78 │     7.6  [7.0, 8.0, 9.0, 10.0, 11.0, 12.0…      0
  79 │     7.7  [7.0, 8.0, 9.0, 10.0, 11.0, 12.0…      0
  80 │     7.8  [7.0, 8.0, 9.0, 10.0, 11.0, 12.0…      0
  81 │     7.9  [7.0, 8.0, 9.0, 10.0, 11.0, 12.0…      0
  82 │     8.0  [7.0, 8.0, 9.0, 10.0, 11.0, 12.0…      0
  83 │     8.1  [1.0, 8.0, 9.0, 10.0, 11.0, 12.0…      0
  84 │     8.2  [1.0, 2.0, 9.0, 10.0, 11.0, 12.0…      0
  85 │     8.3  [1.0, 2.0, 3.0, 10.0, 11.0, 12.0…      0
  86 │     8.4  [1.0, 2.0, 3.0, 4.0, 11.0, 12.0,…      0
  87 │     8.5  [1.0, 2.0, 3.0, 4.0, 5.0, 12.0, …      0
  88 │     8.6  [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 1…      0
  89 │     8.7  [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7…      0
  90 │     8.8  [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7…      0
  91 │     8.9  [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7…      0
  92 │     9.0  [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7…      0
  93 │     9.1  [11.0, 2.0, 3.0, 4.0, 5.0, 6.0, …      0
  94 │     9.2  [11.0, 12.0, 3.0, 4.0, 5.0, 6.0,…      0
  95 │     9.3  [11.0, 12.0, 13.0, 4.0, 5.0, 6.0…      0
  96 │     9.4  [11.0, 12.0, 13.0, 14.0, 5.0, 6.…      0
  97 │     9.5  [11.0, 12.0, 13.0, 14.0, 15.0, 6…      0
  98 │     9.6  [11.0, 12.0, 13.0, 14.0, 15.0, 0…      0
  99 │     9.7  [11.0, 12.0, 13.0, 14.0, 15.0, 0…      0
 100 │     9.8  [11.0, 12.0, 13.0, 14.0, 15.0, 0…      0
 101 │     9.9  [11.0, 12.0, 13.0, 14.0, 15.0, 0…      0
 102 │    10.0  [11.0, 12.0, 13.0, 14.0, 15.0, 0…      0

Выводы

Мы сделали блок циклического буфера с внешним сбросом и научились работать с рабочими переменными, и заодно вспомнили как работать с указателями в Си.