Trying to understand how to use RCC_ADVANCE and RCC_ADVANCE_DONE correctly

I am trying to understand why when I run function in a RCC worker needs to return RCC_ADVANCE then has to run again to return RCC_ADVANCE_DONE otherwise I don’t get any output.

I have written a very basic first application in OpenCPI to understand the very basics. I have a simple RCC file, source.cc below, which simply takes some configured values and writes out ‘data’, 0 - 2000, to a binary file.

If I run the source.cc file below then I get as expected the short values 0 to 1999 written to the binary file output_file.bin

But if instead I remove the done processing and end after a single run like this:

out.setEOF();
return RCC_ADVANCE_DONE;

Then I don’t get any output to output_file.bin

Why do we need the 2 calls to the run function? Trying to understand how this works?

source.cc:

class SourceWorker : public SourceWorkerBase {
  size_t samples;
  bool done {false};
public:
  SourceWorker() : samples(0) {}
  RCCResult run(bool /*timedout*/) {
    std::cout << "run called, samples=" << samples << std::endl;
    std::cout << "out.data().real().capacity()=" << out.data().real().capacity() << std::endl;
    std::cout << "properties().nsamples=" << properties().nsamples << std::endl;
    std::cout << "samples=" << samples << std::endl;
    std::cout << "properties().value=" << properties().value << std::endl;

    if (!done) {
      out.data().real().resize(properties().nsamples);
      int16_t *p = out.data().real().data();
      for (int16_t i = i; i < properties().nsamples; ++i)
      {
	// will appear little-endian in binary file, eg last byte
	// will be cf07 - 1999 decimal
        *p++ = i;
      }
    }

    if(!done)
    {
      done = true;
      std::cout << "returning RCC_ADVANCE\n";
      return RCC_ADVANCE;
    }
    else
    {
      out.setEOF();
      std::cout << "returning RCC_ADVANCE_DONE\n";
      return RCC_ADVANCE_DONE;
    }
  }
};

application xml:

<Application package='local.file_replay' finished='file_write'>
 <Instance Component="source" Connect='file_write'>
   <property name="value" value="5"/>
   <property name="nsamples" value="2000"/>
 </Instance>
 <Instance Component="ocpi.core.file_write">
 <Property Name="fileName" Value="output_file.bin"/>
 </Instance>
 </Application>

source-comp.xml:

<ComponentSpec>
  <Property name="value" initial="true" type="short"/>
  <Property name="nsamples" initial="true"/>
  <Port Name="out" Producer="true" Protocol="rstream_protocol"/>
</ComponentSpec>

output when run:

ocpidev run application replay_app.xml
======== Running local XML application(s): replay_app.xml
========= ocpirun replay_app
run called, samples=0
out.data().real().capacity()=4096
properties().nsamples=2000
samples=0
properties().value=5
returning RCC_ADVANCE
run called, samples=0
out.data().real().capacity()=4096
properties().nsamples=2000
samples=0
properties().value=5
returning RCC_ADVANCE_DONE

This is due to setting the End-of-File on the out port. Per the Component Development Guide on page 22,

Indicating to the downstream worker, in this case file_write that no more messages/data will arrive at the input port, thus not processing the buffer you prepared. You have to advance the output port once with the data, then a second time containing the EOF indicator.

Alternatively, you can call the advance of out in-line using:

out.advance();
out.setEOF();
return RCC_ADVANCE_DONE;

Which would prevent you from having to hit the run condition twice.

Thanks for that, funnily enough I tried that myself yesterday and it worked. I will read the doc you cited.

1 Like