c(++) classes and Fastspin
ManAtWork
Posts: 2,176
in Propeller 2
Hi Eric,
it's me, the old nuisance...
I wonder if anybody has tried the class feature of Fastspin, yet. There is not much documantation about it and I haven't found an example. I'm experimenting with digital filters and I think this would be a well fitting application for it. I tried
Second, I don't know how to tell the compiler which function implementation should be linked to the method declaration. __fromfile ("FilterIIR.c") after the declaration doesn't work. And if I just put a definition of Output() and the other functions in the .cpp file the main crashes instantly at the first method call. The compiler doesn't seem to support C++ style namespaces so that iirFiler::Output() could be defined. I'm sure I do something wrong but as long as there's no error message I can't guess what.
Of course I could just give up and do it the standard C way by supplying an explicit "this" argument to each method (implemented as standard function). But an object oriented solution would be more elegant. And there surely was a reason you mentioned classes in the fastspin docs. You just have to tell us how it's meant to be.
My intention was to allow multiple instances of filters to be created with different (private) coefficients. (high pass and low pass, see hp and lp in TestFilter.cpp) My code is likely to be full of stupid errors but I haven't got the chance to really test it much...
it's me, the old nuisance...
I wonder if anybody has tried the class feature of Fastspin, yet. There is not much documantation about it and I haven't found an example. I'm experimenting with digital filters and I think this would be a well fitting application for it. I tried
typedef class { float Output (float in) ; void SetCoefficients (float* ca, float* cb, unsigned int order); void Clear (); unsigned int n; // number of coefficients = order+1 float x[maxCoeff]; // input samples float y[maxCoeff]; // output samples float a[maxCoeff]; // A coefficients float b[maxCoeff]; // B coefficients } iirFilter;But then I run into several problems. First, I get an error message that the methods are private. The compiler does not understand "public:" or "private:" keywords. The docs say that members of classes are always private but that makes no sense for methods. There must be public methods otherwise the class is useless as everything is unaccessable.
Second, I don't know how to tell the compiler which function implementation should be linked to the method declaration. __fromfile ("FilterIIR.c") after the declaration doesn't work. And if I just put a definition of Output() and the other functions in the .cpp file the main crashes instantly at the first method call. The compiler doesn't seem to support C++ style namespaces so that iirFiler::Output() could be defined. I'm sure I do something wrong but as long as there's no error message I can't guess what.
Of course I could just give up and do it the standard C way by supplying an explicit "this" argument to each method (implemented as standard function). But an object oriented solution would be more elegant. And there surely was a reason you mentioned classes in the fastspin docs. You just have to tell us how it's meant to be.
My intention was to allow multiple instances of filters to be created with different (private) coefficients. (high pass and low pass, see hp and lp in TestFilter.cpp) My code is likely to be full of stupid errors but I haven't got the chance to really test it much...
Comments
The C `struct` declaration is extended slightly to allow functions (methods) to be declared. These must be declared like C++ "inline" functions, that is in the struct definition itself, but are not necessarily implemented inline.
So the only way to declare functions is directly in the "class" (or "struct", they are almost the same) declaration, as in the functions setval() and getval() in the example:
Note that the member *variables* are private in classes, but not the methods; so if you changed "struct" to "class" in the code above, then calling "x.getval()" would still be fine, but trying to read to "x.val" would not.
Again, some error message would be helpful. If the method definition must be in the class definition then IMHO the compiler should say something like "method definition expected" or at least "{ expected" after the method declaration.
If I make such a mistake with GCC like giving an implementation the wrong name then usually the linker complains that there is no implementation or label found for a function call. The error messages are also often hard to understand because the error is not detected until the end of the whole compile+link process but at least there is one.
Eric, you could probably add this to the Fastspin examples so nobody has to ask the same questions over and over again.
I have problems understanding the error messages of the compiler. This time it's "unknown symbol __super". It must have something to do with a call of a regular function from within a class method. I checked if that was forbidden but the compiler doesn't complain if I call printf in my method.
As there is no list file generated if the compiler doesn't succeed I have no chance finding out what went wrong. I'm sure it's again just one of my small stupid mistakes. But I fear you have to help me out, Eric.
Unfortunatelly, this makes the classes as they are now pretty useless. There is no inheritance and vitual functions so everything is more or less static. The methods can be replaced by simple function calls. Instead of we can write So it's just a little inconvenience and no big problem.
To be honest, I really would try to avoid inline assembly. For things that you absolutely have to do in inline assembly, keep the inline assembly short and do as much as possible in the high level language. That's kind of the whole reason for having a high level language!
I totally agree when it comes to application code. But when writing low level drivers and math libraries then using assembler provides a performance advantage and sometimes it makes things possible that can't be done otherwise. For example, to use the CORDIC unit pipelined you need to meet exact timing.
The propeller is a great device fo "hardware hacks" and things that need realtime processing. Now we have the P2 which has enough memory for big application software. The real power is to combine the two.
The main reason that I use Fastspin is that it allows mixing languages. I can use existing libraries written in Spin. I can add small hacks in assembler. And I can write long programs in C. Being able to combine that gives us a powerful tool.
So for good programming style, instead of avoiding assembler completely, the I'd phrase it like this: "The use of low level and high level languages should be separated as much as possible, encapsulating the low-level details inside driver and library modules". That's the whole idea of object oriented programming. Encapsulation and "divide and conquer". And sometimes, programming in assembler is just too tempting, especially on the P2. I definitely won't quit it.
But I know what you want to say. "Often we waste too much time trying to save time". We shouldn't dig too deep otherwise we get a stack overflow and the main task never gets completed. I'll try not to bother you as long it's not absolutely necessary.