Engee documentation
Notebook

Ring buffer with external reset

Once I needed to parse streaming data, and for this I needed a buffer that I could clear according to some condition. There was no such block in Engee, but it doesn't matter, because if I know what I need, then I can always implement it either in C or Julia. Let's see what I've got.

How does an externally reset ring buffer work?

image.png

Buffer Code - we use Working Variables

The simplest approach to implementing something is the best. Therefore, we will use the C Function block.

To implement it, you will need two variables-states.: the buffer itself and the counter. Let's set them up as the working variables of the block.

Working variables are special variables that serve as a statically pre-allocated memory area. When configuring this block parameter, each variable specifies how many bytes to allocate. A separate advantage is that these variables are different for each instance of the block. That is, we can say that this is the "state" of the block.

Let's look at my settings:

It can be seen that 2 variables will be used - an 80-byte buffer buffer and a one-byte counter.

To use these variables in the C Function code, you need to refer to the Work structure.

As a result, the code will look like this:

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;
    }
}

How to work with working variables (C magic)?

Working variables are always of type uint8_t. But C is great because it allows you to work with memory any way you want. And you can also remember that any array in C is just a pointer to a piece of memory, so we can interpret it as we want.:

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

Both ptr and buffer_d_ptr point to the same address in memory, but buffer_d_ptr tells the compiler that there will be a double at this address. We can also work with this pointer as with an array.:

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

Note that we don't use dynamic memory allocation at all!

Testing the block

Let's create a test harness of the form:

image.png

let's run a simulation of the model:

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

And let's look at the results.:

In [ ]:
using DataFrames
df = DataFrame(time=zero(Float64),Buffer=[zeros(Float64,16)],RESET = zero(UInt8))
for i =1:length(RESETEVT.time)
    push!(df,(time   = collect(RESETEVT).time[i],
              Buffer = collect(BUFFER).value[i],
              RESET  = collect(RESETEVT).value[i]))
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

Conclusions

We made a cyclic buffer block with an external reset and learned how to work with working variables, and at the same time remembered how to work with pointers in C.