cognew Spin vs C
I have been playing around with the P1 for a few years now, programming it exclusively in C. I decided to finally take a look at Spin, mostly on a whim. The first thing that stood out was that when you called cognew to start a process in a separate cog, you are able to have arguments. When programming in C, using SimpleIDE and the SimpleTools.h library, the cognew does not allow your functions to take any arguments.
One of the first bits of example code in either language is a multicore version of the blinking light "Hello World" program. The C version has two separate blink functions with the delay times hard coded. The Spin version has the blink method take several arguments, including pin number, and the counter ticks for the delay. So the same method can be used for both cogs. There seems to be no way to do this in C or C++.
I never understood why the C version of cognew does not allow your functions to take arguments. I thought it must be using function pointers, which allow you to pass arguments to the function being pointed to. Seeing the cognew in Spin makes me even more confused as to why the C version is that way.
Is there something preventing the C cognew function from allowing the called function to take arguments?
Thanks in advance for any information.
Comments
In Spin, cognew() function only ever takes two arguments -- but they'll change based on the code you're wanting to run. In most cases that will be a PASM block and will look like this
The first parameter is the address of the code to execute (that's in a DAT block), and the second is the address of the hub variable that serves as the "mailbox" (this is called par in the PASM code). We can access other hub variables offset from par.
The other mechanism with cognew looks like this:
There are still just two arguments: the first one is the method to run (along with its arguments, if any), and a pointer to stack space. In this second case we're actually starting another Spin interpreter cog and we have to point at the starting method (which can have parameters). For a manually-launched Spin interpreter, we have to provide a stack (array of longs).
I don't know how the C version of cognew works, but I hope this helps you understand what's going on in Spin. Again, the second version is launching another Spin cog, which would not work in C.
From the P1 manual:
You need to use cogstart, instead. I believe cognew resembles the Spin counterpart to start a cog code. The Spin compiler can understand if you are specifiying a Spin method or Cog code and act accordingly, in C is not possible (unless I'm missing something) because it can't know if the argument is a function or a cog code (it is always an address...).
In C it is also a bit more complicated than Spin, because the argument is a pointer (to void), you can't specify the parameters list, so you need to be aware of this and pass the variables accordingly.
The following example shows how to use a structure to pass the pin number and blink delay.
You can of course pass a single variable as a pointer, like &pin.
I don't remember if the stack can be allocated automatically with only the size.
Hope this helps.
@macca Thanks for the help! Your answer is more along this line of what I was thinking. It looks like cog_run is the function I was thinking of in C. So in Spin it is cognew and in C it is cog_run(). Sorry for the confusion. The description of cog_run() is below.
The example you shared uses arduino IDE names such as pinMode and digitalWrite. I am using SimpleIDE with the simpletools.h header. The C reference does not seem to include cogstart, but I looked at the source code for the cog_run() function and it calls cogstart. I changed the functions in your example to match the names in simpletools.h
/*
Blank Simple Project.c
http://learn.parallax.com/propeller-c-tutorials
*/
include "simpletools.h" // Include simple tools
void blink(void * arg);
struct _param {
int pin;
int delay;
};
uint32_t blink1_stack[128];
uint32_t blink2_stack[128];
struct _param blink1, blink2;
int main()
{
blink1.pin = 0;
blink1.delay = 1000;
blink2.pin = 1;
blink2.delay = 250;
}
void blink(void * arg)
{
uint32_t t = CNT;
struct _param * param = (struct _param *)arg;
}
It worked as intended. So thanks again for the help!
I looked up the source code for cog_run() and it calls the function cogstart(). Unfortunately, only cog_run() is documented in the simpletools.h doxygen HTML page included in the SimpleIDE Learn folder. I will have to dig a little bit see if I can find more information.
Ah yes, I'm using my own library that replicates some of the Arduino functions.
The propeller.h file is your friend:
@macca Thanks again! that should be what I need.
@KevinW,
I didn't like the simplicity of Simple very much and made my own C++ HAL for the Propeller many years ago. You may find
PropWare::Runnable
interesting for your use case: https://david.zemon.name/PropWare/api-develop/classPropWare_1_1Runnable.xhtmlIt may be that installing all of PropWare on your system isn't worth the hassle if you're happy with your current toolset, but you could certainly pull specific pieces out of PropWare that interest you.
@macca is your arduino-ish library available anywhere?
I want to use P2 as a spacecraft simulator student project for an engineering class. However, I don't have time to teach spin2. The point of the class is the spacecraft systems, not the programming required to tie it all together.
Edit: I've looked into propware and libarduino, but I couldn't get them to work with C in flexprop/P2. At the moment I'm really just stuck trying to get I2C working with some arduino libraries (INA219, for example).
@jaspast
I'm attaching the library here, I don't know if it works with flexprop, it was part of a tool I think I never released that used the propeller GCC port (P1 only), so it may well not work at all.
Thanks @macca. I look forward to trying it.