Shop OBEX P1 Docs P2 Docs Learn Events
Prop Code and Objects — Parallax Forums

Prop Code and Objects

RICoderRICoder Posts: 91
edited 2009-02-02 17:02 in Propeller 1
I'm pretty new to the Prop chip and I'm wondering about the state and constancy of objects. In the normal course of object oriented programming I might instance an object and keep it live, having initiated it with some variables that I store locally. I would like to do the same thing in prop code, and I'll use an example to help me state my question.

Suppose I make a temperature sensor class (i'll call it that, because the code itself is not the object, the INSTANCE of the code is the object), and I want to pass in the DQ, RST and CLK pins on initialize so that when I make subsequent calls to the functions in that class, I don't have to pass those pins in again. Now, lets say I even use START as my function and pass in those values, and store them in locally declared variables LOCAL_DQ, LOCAL_RST and LOCAL_CLK.
Assume I have a OBJ declaration in my main app called TEMPERATURE set to this class.
First question(s):
If I call TEMERATURE.Start (DQ, RST, CLK) and all it does is store them in those local variables, can I be sure they remain there in future uses of the object? (assuming the entirety of the Start code is just assignment of those vars)

Now, lets further say that I want to have multiple instances of this class. So, I name two OBJ vars TEMP1 and TEMP2 as my class.
Next question:
Are they unique? If I use a different pin for DQ in each, can I rely on the fact that the objects are going to store them correctly?

Finally, I want to deal with COGs. I would like the object to use a cog when one of its functions are called. Now it becomes an issue of timing. For my Start code, there is no real need to start a COG and certainly no reason to hold one, since I am only assigning variables.
Next questions:
Can I kick off a new cog in the function calls?
Can I use my locally set variables in that new cog?
Can I kill that cog when I'm done?


Not the easiest questions in the world, I know.

Comments

  • Paul RowntreePaul Rowntree Posts: 49
    edited 2009-02-01 20:10
    These are not like C++ or Delphi objects. An object is a bit of code in memory. If you call a start routine, it should configure the code and any local variables, and launch some code (spin or pasm) into a new cog for independent execution. By definition, these variables are stil lthere for subsequent calls because in fact you have not instantiated the object the way you do in more traditional languages. Depending on the object, you may be able to start multiple copies in multiple cogs, each with a separate definition of the pins (or what ever variables you need).

    Check out the tutorials in the manual. They give very concreate examples of this type of problem.

    Cheers!
    Paul Rowntree
  • StefanL38StefanL38 Posts: 2,292
    edited 2009-02-01 20:24
    Hello RICoder,

    these are VERY good questions that hit the most important things about complex programming in SPIN.
    So the experts in this forum have a challenging question

    local variables defined in the headline of a method like this

    PUB MyMethod | localVar1, localVar2 
    
    
    



    are only accessable INSIDE MyMethod

    global variables defined in the VAR-section of a *.SPIN-File are global in the limits of THIS *.SPIN-file
    If you take a look inside the DS1620 object

    VAR
      word  dpin, cpin, rst, started
    ....
    
    PUB start(data_pin, clock_pin, rst_pin)
    
    '' Initializes DS1620 for free-run with host CPU 
    
      dpin := data_pin
      cpin := clock_pin
      rst := rst_pin
    ....
    
    



    in the PUB start the PIN-Numbers were assigned to the global variables dpin, dpin, rst
    these variables are accessable everywhere inside of THAT instance of the methods of the DS1620.SPIN-file

    So if you define two objects TEMP1, TEMP2 based on the same DS1620.SPIN-file the two objects are independant
    and work on their own with their own variables

    ONE object can use multiple cogs and as long as methods and variables are inside ONE *.SPIN-file you can access these variables
    even ACROSS cogs ! If you do so you have to use a lock/unlock mechanism to make sure that writing to variables is NOT colliding
    with writing to the same variable from another cog. Use the LOCKxxx-commands therefore

    Yes you can start a cog inside any PUB or PRI-method
    by using the command cognew(Methodname,@Stack)

    where Methodname is the name of that method that should run in the new cog
    and
    @stack is a stackvariable that is defined in the VAR-section of the same *.SPIN-file
    and needs a minimum of 9 longs

    example

    VAR
      long stack[noparse][[/noparse]9]
    
    
    



    usually the size of this stackvariable is 20-100 longs depending on various things like paremeter of called methods and nested calls of other methods called from "MethodName"
    EVERY call of cognew needs its own stackvariable

    You should do the cognew inside the same *.SPIN-file where the starting method is located

    locally variables - defined to be local for one method - can only be accessed within that method

    global variables can be accessed within the same *.SPIN-file
    even ACROSS cogs but cannot be accessed directly ACROSS *-SPIN-files

    Therefore you have to pass a pointer pointing to the variable to a VAR-section-variable
    or you have to use variables defined in the DAT-section which work by using pointers anyway (and always only with pointers)
    to get or set values of variables in an other *.SPIN-file you can use methods

    PUB GetVar1 : MyVariableResult
    
    ...
      MyVariableResult := var1
    
    
    PUB SetVar1 (MyValue)
    
      var1 := MyValue
    
    
    



    you can "kill" the cog when you're done. Start a new cog with cognew takes some microseconds
    if your code running in the new cog leaves all loops a cogstop is called automatically
    But you can code a cogstop if you like to

    But why start and stop a cog all the time ?
    As long as things don't HAVE TO run independent and parallel keep your programming sequential,
    which means insert the new code in an existing loop of the same cog.

    It is MUCH MUCH easier to debug sequential running code than parallel running code
    This is a lesson that I have learned from programming controls for automotive production industries

    Of course something like FullDuplexSerial HAVE TO run in its own cog INDEPENDENTLY
    Because the Prop can NOT know when serial data arrives

    But whenever YOU can control the start of events (like read out a temperature or a signal keeps its logic state
    longer than your longest time it takes your loop to start its next looping KEEP THE CODING SEQUENTIAL !

    Oh sorry for so many UPPERCASE letters. The meaning is just emphasising. It is NOT meant that I'm angry or harsh or anything like that
    just emphasising

    So feel free to ask as many more questions as you like about objects, cogs, variables or whatever

    I think a lot of other forum-members will enjoy reading and learning or answering

    best regards

    Stefan

    Post Edited (StefanL38) : 2/1/2009 8:48:54 PM GMT
  • Mike GreenMike Green Posts: 23,101
    edited 2009-02-01 20:27
    Each instance of an object in Spin has its own set of VAR variables. The code is read-only, so can be shared among instances. DAT storage is more complex. This can be used for constants (and assembly code) which is read-only also. It can also be used for variables which are shared among all instances. Note that assembly code in a DAT section is copied into a cog's memory for execution so, in hub memory, it's considered read-only.

    Cogs and objects are not really related. I have several programs that use a main "object" and several library "object"s. I also sometimes use objects just for encapsulation with no use of separate cogs at all. My BoeBotBasic interpreter starts several cogs, sometimes just for a short period of time, then stops them. There is overhead for starting a cog ... about 100us. Depending on your application, that may be prohibitive or it may be fine. If it's too much, then you start a cog during initialization and the cog sits looking for a command to be passed through shared memory, executes the command, and goes back to waiting for a new command to be provided.
  • RICoderRICoder Posts: 91
    edited 2009-02-01 22:08
    Thanks for the responses so far, I think this is worth further discussion, mostly because I have noticed a significant difference in the "style" of programmers doing microcontroller work and the "style" that I am used to, which is software development on a PC (and I think that difference makes sense).

    I attacked each problem separately and my results are these:

    For what I was calling local variables, I chose the wrong words. What I should have said was variables that are global to the object. For example, my 7 Segment LED object (using a 74HCT595 chip):
    VAR
      long                PIN_DATA, PIN_CLOCK, PIN_LATCH          
      byte                bytePattern
      
    PUB Initialize (pinData, pinClock, pinLatch)
    {{
        Initializes the object and stores the pins for data, clock and latch locally
    }}
    
      'Capture the pins for this instance
      PIN_DATA := pinData
      PIN_CLOCK := pinClock
      PIN_LATCH := pinLatch
    
    
    



    In my main object, I have two object definitions:

    OBJ
    
      'Left 7 Segment LED Object
      LeftDisplay                   : "RIC_7SegmentLED"
      RightDisplay                  : "RIC_7SegmentLED"
      Thermostat                    : "RIC_DS1620"                        
      Time                          : "Timing"                        
    
    
    VAR
      long lTempTens, lTempOnes
      long lTemperature
    
    PUB Main
    
      'Init the displays
      LeftDisplay.Initialize (PIN_SPIL_DATA, PIN_SPIL_CLOCK, PIN_SPIL_STORE)
      RightDisplay.Initialize (PIN_SPIR_DATA, PIN_SPIR_CLOCK, PIN_SPIR_STORE)
    
      [noparse][[/noparse]some thermostat code]
    
      Repeat
        [noparse][[/noparse]more thermostat code]
        LeftDisplay.SetValue (lTempTens)
        RightDisplay.SetValue (lTempOnes)
    
    



    With the above code, I can make repeated calls to the left and right display to set values without having to constantly send in the pins, which honestly is just a pain in the butt, and also, IMO, bad programming as it is just another point of failure especially if the code changes.

    Further, I decided to investigate COG control where I would have an object that didn't necessarily need a cog running until there was a function called. What I did, I will explain without the use of actual code because it is just sample code and a little confusing, but I'm interested in what people think of it. I'll use the function "SetValue" from my 7 Segment LED object as an example.

    What I did was create two methods, PUB SetValue (lVal) and PRI SetValueCog (lVal).

    When you call SetValue (lVal) it checks to the cogs in use to make sure it uses the right pointer for stack space. Then it kicks off a new cog calling the method SetValueCog and adds it to the list of cogs in use.
    This way the object is controlling the use of new cogs in context. You cannot initiate SetValueCog (lVal) from outside, as it is private.

    I've not seen any other code around here that treats cogs like this, and I may very well be violating some standard for programming a microcontroller...i'm curious to know what people think.
  • mparkmpark Posts: 1,305
    edited 2009-02-02 05:22
    What you're doing seems completely reasonable to me, fwiw. I don't think microcontrollers inherently have a different standard for programming. A lot of people are probably still coming to grips with Spin and its quasi-object-orientation.
  • RICoderRICoder Posts: 91
    edited 2009-02-02 17:02
    I'm building a thermostat with wireless control via XBee, which is what all of this is for. When I'm done, i'll obviously post it, but importantly I'll post the SPIN code, because it just doesn't do things the way it seems to be done everywhere else.

    As I dig deeper into SPIN I can see the power that is there, but I think there is a lot of room for smarter ways to deal with COGs and objects...certainly ways that are easier to implement and understand.
Sign In or Register to comment.