|
From: | Marcus Müller |
Subject: | Re: [Discuss-gnuradio] First Post - Question - GRC Repeat Block |
Date: | Mon, 27 Jul 2015 18:45:21 +0200 |
User-agent: | Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Thunderbird/38.1.0 |
Hi Kevin, On 27.07.2015 17:53, mcquiggi wrote:
Hi Marcus:I'll do that :) Far from it, actually! I think discussions like these are immensely valuable for the community -- people with different backgrounds contributing is one of the strengths of the GNU Radio project, and you are freely investing your time in this; in fact, I think what you're addressing below will be of interest to a lot of mailing list archive readers later on! That's halfway true; if I understand your intention correctly, the block would stay 1:N -- but that N would be subject to change over the lifetime of the block. As far as I know, the normal sync_interpolator mother class can deal with that. oh, no, that's the amount of items that the scheduler allows you to produce, so it's different each time work() is called! It's a parameter, not a result of your work -- what you in fact need to re-calculate is the ratio between number of items you consume and number of items a call to work() produced. In fact, sync_interpolator just overrides general_work like you would in a general block, and calls work(..) from within there -- based on the items work produced (usually, that's just the number work() returns), it calculates the items consumed (by a simple division). So what you need to do when changing the number of repititions is just a) change the value of d_interp, so that repeat's work() does the "right thing" and b) call the set_interpolation method [1] to change the factor that is used behind the scenes to keep the amount of samples flowing in and out correct. repeat_impl is a subclass of repeat (which itself is a subclass of sync_interpolator, which is a sync_block subclass, which is a block subclass, which is a basic_block subclass; C++ inheritance :) ). This is now a bit of a oversimplification of C++, but I think you can deal with this: here, think of these C++ classes as C structs, that inherit all the elements from their mother structs. Methods are basically function pointers in these structs, and when invoked they automatically (and hiddenly) set a parameter "this" to be a pointer to the indidual struct object. That way, you can work with methods that really only operate on a single object's state, and don't have to always carry around a handle to the object to modify (which is a very C thing to do). So, work is such a function, and d_interp is a member of the struct that automatically relates to the "this" parameter, ie. you could also use this->d_interp (which really is a valid alias for d_interp). What happens is that C++ makes sure that when the GNU Radio scheduler calls the general_work of any block, the respective block's implementation's general_work is called (in this case, sync_interpolator has that implementation of general_work). In the case of sync_interpolator, that general_work computes the right in- and output item numbers, and calls its work(), which is overridden by repeat_impl::work. Now that's more software design theory than the average GNU Radio user has. What you need to know is: you implement a work() method; GNU Radio calls that when there's new data available or when there's still data on the input but new output space has become available. There's one caveat that we'll have to address later: GNU Radio is multithreaded, and heavily so. Imagine the segfaults that would happen if you were to change d_interp from 1 to 10^9 in the middle of the for loop in work() running, but there was only output space for input_items[0]*1! C++, boost and GNU Radio have methods of dealing with that problem, and I'll gladly help with it. It's calculated again, again and again, every time before calling your work() method. The idea is that every block has it's (general_)work method, and GNU radio calls them, whenever the circumstances make that sensible, ie. when there is opportunity to generate/process items: Assume you connect block A, B, C: A->B->C when the work method of B returns, the consumed input samples in its input buffer can be overwritten (GNU Radio implements circular buffers), since they already have been processed. Hence, in a different thread A's work() is called, with the info that noutput_items is now larger by exactly that amount of samples. The same happens for C: B::work() returns, and GNU Radio calls C's work() with the info that there's new input available. When C::work() returns, B is notified again that there's output space available, and everything keeps flowing. You're pretty close to the real thing! The C coder is speaking through your questions, but that's absolutely not a bad thing; young "C++ folks" (I might consider myself that) often struggle with things like dealing with memory, pointer casting etc, where that's bread and butter techniques and patterns for C devs. Have I pointed you to the guided tutorials? https://gnuradio.org/redmine/projects/gnuradio/wiki/Guided_Tutorials Especially chapter 4 will be of interest to you. It does assume that you're somewhat proficient with C++, but 4.3.2.4 / Interpolation illustrates what we're dealing with pretty nicely, I think. Best regards, Marcus [1] https://gnuradio.org/doc/doxygen/classgr_1_1sync__interpolator.html#ae4daef83760cfe1951c9cf8a83520352
|
[Prev in Thread] | Current Thread | [Next in Thread] |