PDA

View Full Version : Selection of objects at run time



ftkalcevic
12-12-2009, 05:36 AM
Is it possible to select which object you want loaded into cogs (and the number) at runtime?

I am writing a simple pwm motor controller.· It sends a signal to the motor driver to run the motor.· The signal can be PWM+Direction, Step/Dir, or the two halves of an H-Bridge.· I'd like to be able to write a .spin file (in PASM) for each individual type.· Then, via serial communications, the host pc can configure the type of output, and the main cog can load the one that is required.

Can this be done?

Thanks,
Frank

Mike Green
12-12-2009, 06:09 AM
You want to dynamically configure a program, loading one of a set of low-level I/O drivers from some kind of storage at run-time. It's theoretically possible to do this, but very difficult and you'd have to have a very deep knowledge of the internals of Spin to accomplish this. It would be easier to do if your low-level I/O drivers were written in assembly. In practice, your low-level drivers would not be very complex and would not take much memory, so all the objects could reside in hub memory at the same time and you could just start up a cog or several with the ones you wanted. If they communicate through the same kind of data structure (variables), it wouldn't matter to your higher level routines (in Spin) which one of a set is actually executing in the cog. This scheme is actually pretty straightforward in Spin.

stevenmess2004
12-12-2009, 06:41 AM
If you want to load spin objects from sd cards it is quite possible like Mike says. However without the right tool chain it is really a pain in the neck and extremly prone to errors. I've been working at it on and off for the last year or two. I'm going away on holidays next week (no net access) and will hopefully get it all in a useable state now that we have sphinx.
If all the different code fits in the prop chip than it should fairly easy to do. You can use a trick like this to make it easy. However, if you do this than the methods that you call have to be have the same number of arguments and be in the same order for all of the objects.


OBJ
PWM:"pwmObject"
step:"stepObject"
hbridge:"hbridgeObject" 'these need to be after each other
PUB main|object
object:=getObjectFromPC 'object needs to be 0,1 or 2
PWM[object].start 'start whichever object you want to use. The "[object]" will select the right object and needs to be used
'whenever you call one of the methods.
PWM[object].setSpeed(speed) 'an example
PWM[object.setDirection(direction) 'another example
'...



Post Edited (stevenmess2004) : 12/11/2009 11:54:24 PM GMT

ftkalcevic
12-12-2009, 06:54 AM
Thanks for the replies.

These are small routines, so they should all fit into memory at the same time.

stevenmess2004 (http://forums.parallax.com/member.php?u=51782), what happens with any VAR data that is declared in an object.· If I spin up more than one instance, will they all point to the same VAR data?· Will I need to manage main memory myself?·


Thanks,
Frank
·

Phil Pilgrim (PhiPi)
12-12-2009, 06:58 AM
VAR data are unique for each instance of an object. DAT data are shared.

-Phil

stevenmess2004
12-12-2009, 07:02 AM
Every object declared has it's own set of var variables but the dat variables are shared by all objects of the same type. So for example



OBJ
obj1:"pwmobject"
obj2:"pwmobject"
obj3:"otherobject"



In this code there will be one copy of the spin code and dat variables for pwmobject and two copies of the var variables for pwmobject. other object has its own complete copy of its spin, var variables and dat variables.

(well at least most of the time. If the code in otherobject is exactly the same as pwmobject it will be treated as if it was another copy of pwmobject.)

ftkalcevic
12-12-2009, 07:10 AM
So in the case of dynamically creating multiple instances...



OBJ
obj1: pwmobj
obj2: stepdirobj

PUB main
obj1.Start ' Create instance 1
obj1.Start ' Create a second instance (assumes there's a cognew in Start
obj1.Start ' 3

Will these instances share the same VAR from the obj1?

Do I need to allocate the data myself? ....


OBJ
obj1: pwmobj
obj2: stepdirobj

VAR
long data[8]

PUB main
obj1.Start( @data[0] ) ' Create instance 1
obj1.Start( @data[1] ) ' Create a second instance (assumes there's a cognew in Start
obj1.Start( @data[2] ) ' 3


Post Edited (ftkalcevic) : 12/12/2009 12:15:09 AM GMT

stevenmess2004
12-12-2009, 11:13 AM
Okay, lets try explaining this a little better. In spin all objects are statically allocated (unless you play with stuff that is not supported by any compilers). Using my example above


OBJ
obj1:"pwmobject"
obj2:"pwmobject"
obj3:"otherobject"


The Memory endups looking something like this



DAT overallObject
Spin overallObject - pub and pri methods
DAT pwmObject
Spin pwmObject - pub and pri methods
DAT otherobject
Spin otherobject - pub and pri methods
VAR overallObject
VAR obj1
VAR obj2
VAR obj3



This memory layout remains fixed throughout the life of the program and you can't change it. When I use instance in spin I mean a reference to an object such as obj1 or obj2. It doesn't matter what cog an object is running in, when you access any of the VAR or DAT variables they will still reference the same thing.

Local variables are a different matter though. Because local variables live on the stack and each cog has it's own stack the local variables will be different for each cog.

If you do want to use different data in each cog than you will need to either create different instances (not just start the same instance in a different cog) or write your code to use pointers and then pass in different pointers. Don't forget that you can have an array of objects that will all have their own VAR sections. You could do something like this.


OBJ
obj1:"pwmobj"
obj2:"stepdirobj"

PUB main
obj1[0].start
obj1.start
obj2.start

ftkalcevic
12-12-2009, 12:07 PM
Understood, but I don't think this has answered my original question...

How can I decided the number and types of objects I run at runtime?

I can see this as one solution....



CON
NUM_DEVICES = 7


OBJ
type1[NUM_DEVICES]: "DeviceType1"
type2[NUM_DEVICES]: "DeviceType2"
type3[NUM_DEVICES]: "DeviceType3"
type4[NUM_DEVICES]: "DeviceType4"
type5[NUM_DEVICES]: "DeviceType5"

PUB Start

type1[0].Start
type1[1].Start
type2[0].Start
type3[0].Start
type4[1].Start
type1[2].Start
type1[3].Start
type5[0].Start









Here I allocate storage for the maximum number of each instance.· COGS are only started when Start is called.· This wastes lots of memory.

My other idea, the confusing post above, was to define one object instance of each type, then pass in a pointer to some space allocated to it.· So the object would be...




VAR
long data_ptr


PUB Start( _data_ptr )
data_ptr := _data_ptr

cognew(@main, @data_ptr)

DAT
org 0

main

mov temp, par
rdlong data_addr, temp ' data ptr

' do stuff with data_addr

data_addr res 1



The VAR data_ptr, is only used in starting the·PASM in the COG.· It is a pointer to shared memory, stored in COG memory.· It is then up to me to ensure there is enough longs (shared memory)·allocated for the object.

And I can create COGS by...



OBJ
obj1: pwmobj
obj2: stepdirobj

VAR
long data[8]

PUB main
obj1.Start( @data[0] ) ' Create instance 1. Give 1 long of shared memory.
obj1.Start( @data[1] ) ' Create a second instance (assumes there's a cognew in Start
obj1.Start( @data[2] ) ' 3

stevenmess2004
12-12-2009, 12:32 PM
Yes, that looks right. Just remember that a cognew will chop off the last two bits of your address so it needs to be long aligned. Another alternative would be something like this





PUB Start( _data_ptr )
data_ptr := _data_ptr

cognew(@main, 0)

DAT
org 0

main
' do stuff with data_ptr
data_ptr long 0
data_addr res 1



Just saves a little bit of code and you don't have to worry about it being long aligned.

ftkalcevic
12-12-2009, 12:48 PM
How does that work?· Is data_ptr in COG memory, or main memory?·

Is the spin code changing the DAT section in main memory, amd then copying it into the COG?·
·

stevenmess2004
12-12-2009, 01:03 PM
data_ptr is in hub memory but when you start the assembly cog it gets loaded in with the rest of your code. So when you change in in Start it is in the hub. Then when the cog gets started it gets copied into cog ram and the cog can use it. Because it gets copied into the cog you can then change it (in the hub) for the next cog that you start and everything will be fine.

MagIO2
12-13-2009, 05:26 PM
As I understand your original post there is no need to replace the SPIN-code?! Just the PASM driver has to be replaced on demand.

What I do - mainly to save RAM - is that I put all my PASM-drivers (keyboard, tv, SD ...) into upper part of the 64kB EEPROM. The SPIN-part of the drivers has been changed to load it into a temporary global buffer and start the COG. So, there is no PASM in a DAT section of the drivers any more.
But with this it's also possible to select a driver during startup or replace it during runtime.