Shop OBEX P1 Docs P2 Docs Learn Events
Reading Global variables from any operating Cog — Parallax Forums

Reading Global variables from any operating Cog

kenmackenmac Posts: 96
edited 2007-07-26 10:07 in Propeller 1
Is it possible for independant Cogs to read data in a Global variable which has been set in another Cog, without using the arg/par path?
If so, is there an example on how to do it?

An example of what I mean:
Say there is a controlling Cog (A.spin) that has a variable named NUMBER, and it is continuously varying the value of NUMBER.
The first Cog has called two other Objects(B.spin & C.spin), which in turn start their own Cog.
The purpose of B & C is to monitor the value of NUMBER and react (differently) when it reads a particular value (operates a LED).
How do B & C read the Global variable without a arg/par pass action?

Of course the A Cog could pass the value every time it is updated, but this would mean restarting the Cogs each time.
The situation required is for the B & C Cogs to monitor NUMBER continuously.
This is a simplistic example of course, just a means of discussing/understanding of the Global variables situation.



kenmac

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Perth, Western Australia
Time Zone = GMT + 8
«1

Comments

  • mirrormirror Posts: 322
    edited 2007-07-18 10:50
    You still use arg/par, but not in the way I think you're thinking.

    Use arg/par to pass a pointer to the global variable between the various cogs. The various cogs can then dereference the pointer back to the global variable.

    If you REALLY don't want to use arg/par, then pick a Number (any Number between 0 and 32767) and reference it like this in each of your cogs:

    byte[noparse][[/noparse]Number] := NewValue 'For a byte sized global value
    word[noparse][[/noparse]Number] := NewValue 'For a word sized value, but must be mod 2 (0, 2, 4 ...)
    long[noparse][[/noparse]Number] := NewValue 'For a long sized value, but must be mod 4 (0, 4, 8 ...)

    Just be careful with your choice of Number though, as you're accessing directly into the RAM and are very likely to corrupt your program if you're not careful. (Hence the reason for passing the pointer).

    A pointer to GlobalVariable is quite easy to get: @GlobalVariable

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
  • deSilvadeSilva Posts: 2,967
    edited 2007-07-18 17:16
    Consider:
    (1) COGs and "objects" have nothing to do which each other in any way.
    (2) The DAT area upto 512 LONGSs from the starting point of a COG is copied, thus EVERYTHING you have stored there (statiically or dynamically) will be copied into the COG
    (3) Note however that
    DAT
    x LONG @VARvar
    


    will not work, as the address of a VAR Element cannot be determined at compile time, as there can be multiple instantiations of an object. You cann of course set those values at run time
    X := @@X
    

    smile.gif
    (4) But
    DAT
    x LONG @DATvar
    


    will work fine
    (5) Beware changing that area while the COG is loading (which takes around 102.4 mys)

    Post Edited (deSilva) : 7/18/2007 5:23:04 PM GMT
  • tom90tom90 Posts: 55
    edited 2007-07-18 21:44
    I am having a similar problem as kenmac and am very new to spin, any suggestions will be helpful.

    I am trying to use the propeller to control a pololu serial motor controller. I would like to be able to have one cog(cog 0) control the motor while another cog(cog 1) waits for information(keystrokes) to come in; these keystrokes will modify the motor speed or direction in some way. I have already figured out how to control the motor by sending it four seperate bytes: start byte, motor number, direction, and speed. I would like cog 0 to run the motor while cog 1 is looking for new commands. Then, after cog 1 has proccesed the new commands I would like it to send information back to cog 0 (motor direction and speed).

    If that didn't make any sense, I guess I would just like to know how to pass variables from one cog to another.

    Thanks

    Also, if anybody already has some code written for the pololu controller that would be very helpful.
  • Martin HebelMartin Hebel Posts: 1,239
    edited 2007-07-18 21:52
    There isn't any magic in this. Global variables are accessible from all cogs automatically. Simply use the variable name. It's one of the great things about the prop.

    Something that may get tricky is where you need to read several variables and be sure they are all up to date so you are not getting incomplete writes (say reading X, Y, Z - maybe X has been changed by a cog, but Y and Z are not yet written too). This is where you can start using the locks to ensure one cog doesn't use data that's not ready yet.

    -Martin

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    StampPlot - GUI and Plotting, and XBee Wireless Adapters
    Southern Illinois University Carbondale, Electronic Systems Technologies
  • HarleyHarley Posts: 997
    edited 2007-07-18 22:06
    I've seen the word 'mys' used by several on the forum.

    But Google or Wikipedia didn't explain this word. What does it mean? Never known about it before.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Harley Shanko
    h.a.s. designn
  • mirrormirror Posts: 322
    edited 2007-07-18 23:03
    Martin Hebel said...
    There isn't any magic in this. Global variables are accessible from all cogs automatically. Simply use the variable name. It's one of the great things about the prop.
    Are you sure about this? My understanding is that if you have an object in a different Spin source file, then it doesn't know anything about the variables in the parent's Spin source file.

    I think this is only true if you write your code as a *single* Spin file. By the way, I have considered doing this - 10000+ lines of spin and assembly (one source file) containing all the objects·just to have better/easier shareability of·variables.
  • Martin HebelMartin Hebel Posts: 1,239
    edited 2007-07-18 23:21
    Global variables in Spin are stored in the main RAM.· All cogs running Spin can access the same variable by the name, or be passed the address for ASM.

    I don't know what you mean by 'one spin file'.· Using objects, it's all compiled to be one file.·All variables for Spin are held in main RAM. All cogs have access. If you are saying that lower objects don't know the name of the global variables declared in the top file, this is probably true.

    Even using objects that may not be part of the top file, it's not very hard to pass the address to an object.

    The top spin file can be used to initialize the various cogs with thier spin code and at that time passed the variables locations to use through routines in the top file.
    -Martin


    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    StampPlot - GUI and Plotting, and XBee Wireless Adapters
    Southern Illinois University Carbondale, Electronic Systems Technologies
  • Mike GreenMike Green Posts: 23,101
    edited 2007-07-18 23:22
    mirror,
    You are correct about variable access. One Spin file cannot access the variables in another. It can access the named constants and any public methods.

    There is a "tension" between being able to share things widely and hiding things like internal object variables to help create the abstraction. This is one of the "features" of object oriented programming. It has tremendous value in terms of helping to prevent errors and helping to simplify conceptually a program and its pieces. It's also sometimes an annoyance and sometimes a (small) source of inefficiency.

    After having written many tens of thousands of lines of code in many different programming languages, I would prefer to use all the tools at hand to help with creating abstractions and well-behaved objects that force me to think about how I'm using them and what am I really trying to accomplish at any particular point. Once I have something working as expected, I'm very happy to go back and look for inefficiencies and fix them. Often, they're not what you think they might be.

    I strongly suggest you don't make a 10 thousand+ lines of code program in one piece. Use objects and use them where they fit in functionally. You will find that their use will save you a lot of headaches in a program of that size.
  • mirrormirror Posts: 322
    edited 2007-07-19 00:24
    Mike Green said...
    After having written many tens of thousands of lines of code in many different programming languages, I would prefer to use all the tools at hand to help with creating abstractions and well-behaved objects that force me to think about how I'm using them and what am I really trying to accomplish at any particular point. Once I have something working as expected, I'm very happy to go back and look for inefficiencies and fix them. Often, they're not what you think they might be.

    I strongly suggest you don't make a 10 thousand+ lines of code program in one piece. Use objects and use them where they fit in functionally. You will find that their use will save you a lot of headaches in a program of that size.
    Mike, although I appreciate the sentiment, I'll stand by what I've written. I've also written tens·hundreds of thousands of lines of code over the last 25 years.

    Where I'm able to use the facilities of the language, I have. In other places I've modified existing objects (eg SerialMirror which is a variation on FullDuplexSerial) to make it work·sensibly across multiple objects. Of the 8 cogs used in my current design 2 are spin, the other 6 are highly tuned assembly language (1 of the remaining spin cogs will probably need to go to assembly in the final design, but I'll see later if that's needed). All these various parts (cogs)·build together to make a reasonably high performance data aquisition system. Tying it all together·is about 9 FIFO's (don't forget that even FullDuplexSerial has got 2 FIFO's - otherwise known as circular buffers)·which pump the data between the various·cogs/processes. The FIFO's are used to absorb system latencies - which are significant because of the occassional slow-downs that are inherent when writing to an SD card / Serial Port / Ethernet Chip etc.

    Currently the project is·split into 10 source files. I'll share the 2 ethernet files (ENC28J60 based) and probably my new SD Card driver (based on stuff learned while doing the Ethernet driver) once I'm done. The Ethernet code is an illustration of how to work within the limitations of the language - but you'll just have to believe me for now.

    I did say I was "considering" combining the files into a mega-file - that doesn't mean I've done it. I have found that sharing of global variables is a·place where the code is harder to write and debug. It's all working at the moment, but it's been slow going getting the cogs to talk to each other though all those FIFOs.·If I had more cogs, then I'd porbably use more SPIN cogs to tie the various parts together which would make it a lot easier, but I'm out of cogs, so I just have to make it work as it is. (BTW: no 2 cogs are performing the same function). All debugging has been done using GEAR (which is what drove me to contirbute changes to it) and a serial port.

    I think·I probably have a fair appreciation of how to write a propeller based application considering I started in April.·After using the chip for the last couple of months, I still love it! Some of the code is challenging to write. I wish that SPIN was a bit faster. I wish that there was an option for·easier access to variables across objects.

    I'm interested to see the new C compiler - I suspect that some of these things will be made easier, but that other stuff is going to remain just as obscured.

    ---

    As a little thought exercise, consider FullDuplexSerial. You want a seperate assembly language cog to be able to do some processing and put the results·directly into the TxBuffer of FullDuplexSerial. Using seperate source files, please.··Your time starts now . . . (It's not too difficult, but does expose the challenges of global variables).

    ·
  • kenmackenmac Posts: 96
    edited 2007-07-19 08:09
    mirror,
    Thanks for the info.
    I've read the other replies and it is somewhat confusing.

    Could you please expand a bit re how the receiving Cog uses the "@GlobalVariable" number to read the contents of the variable.

    I assume that the Cog that declares the variable Number does something like "x.start(@Number)...."

    How do we set up the receiving Cog to interpret it to read the value in the variable Number?

    It would have "pub start(xxxx)"
    followed by cognew(checkno, yyyy) ....

    I'm not sure what the parameters xxxx and yyyy should be.
    I've tried a few things but had no success.

    kenmac

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Perth, Western Australia
    Time Zone = GMT + 8
  • mirrormirror Posts: 322
    edited 2007-07-19 10:02
    kenmac,
    You're almost halfway. The next half is what is the less obvious.
    I'd normally declare the start function in the x object as something like:
    PUB start(NumPtr)

    I use a variable name with a Ptr suffix to let me know that it's a pointer. Now for the magic. Access to the variable is as follows:
    byte[noparse][[/noparse]NumPtr] := MyFunc(byte[noparse][[/noparse]NumPtr])··· ' if Number is a byte
    word[noparse][[/noparse]NumPtr] := MyFunc(word[noparse][[/noparse]NumPtr])···' if Number is a word
    long[noparse][[/noparse]NumPtr] := MyFunc(long[noparse][[/noparse]NumPtr])··· ' if Number is a long
    Note: it's up to you to make sure you use the right size access on the variable! In all the above instance, you'll get the value of·variable Number process it using MyFunc (which conveniently for us just happens to return the answer to life the universe and everything) and assign the result back to the·variable Number. Both the read and write of Number are done via the pointer NumPtr.

    Ok, that's the lesson for accessing Number within start (of the x object).

    Part 2: accessing Number from the cog

    How to do it depends on wether your new cog is spin or assembly. I'm assuming from your example that its Spin. Try something like the following:

    VAR
      word NumPtr   'pointer to Number in parent object
      long CogStack[noparse][[/noparse]10]
     
    PUB start(MyNumPtr)
      NumPtr := MyNumPtr             ' keep a copy of the pointer
      CogNew(checkno, @CogStack)
     
    PRI checkno
      repeat
        byte[noparse][[/noparse]NumPtr] := MyFunc(byte[noparse][[/noparse]NumPtr])    ' if Number is a byte  
     
    PRI MyFunc(val)
      return val // 42
     
    

    Note: In this example NumPtr may be a word, but that is just the size of the pointer, it doesn't give any clue as to what it's pointing to!
    What does this cog do - once started?·Everytime you assign a·value to Number, the cog in the x object will grab the value in Number·and replace it with the modulus 42 result. It will do this continuously, but of course nothing happens for numbers from 0 to 41.
    Simple!


    Post Edited (mirror) : 7/19/2007 10:06:49 AM GMT
  • kenmackenmac Posts: 96
    edited 2007-07-19 10:39
    Thanks mirror.
    I'll have a go at it tomorrow and we'll see what happens.

    kenmac

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Perth, Western Australia
    Time Zone = GMT + 8
  • Graham StablerGraham Stabler Posts: 2,510
    edited 2007-07-19 11:18
    Harley said...
    I've seen the word 'mys' used by several on the forum.

    But Google or Wikipedia didn't explain this word. What does it mean? Never known about it before.

    I assumed it is a dyslexic version of ms or millisecond.

    Graham

    p.s. Dyslexic is a cruelly hard word to spell
  • KaioKaio Posts: 253
    edited 2007-07-19 12:05
    Graham Stabler said...
    Harley said...

    I've seen the word 'mys' used by several on the forum.

    But Google or Wikipedia didn't explain this word. What does it mean? Never known about it before.
    I assumed it is a dyslexic version of ms or millisecond.

    Graham

    p.s. Dyslexic is a cruelly hard word to spell
    deSilva is using this abbreviation for microsecond, but it's not right. It should be "µs".

    Mostly people in this forum are using "uS" for that while I think there is no way to type the "µ" on an english keyboard layout.

    Thomas
  • HarleyHarley Posts: 997
    edited 2007-07-19 14:26
    Thank you Graham and Kaio,

    I'd of not guessed that 'mys' was meant for 'µ/microsecond'. Unless reading some thread where various people were writing the latter also.

    Kaio, on the Macintosh the 'µ' symbol is created using the Command key (the key with the Apple symbol). But on my PC laptop (for PIC and Parallax use) I just use the standard 'u' key. Don't know, but maybe there is some way to get the 'µ' from Microsoft's OS.

    Thanks for the clarification. I thought I'd pulled a Rip VanWinkle and missed something in engineering in recent years!

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Harley Shanko
    h.a.s. designn
  • HarleyHarley Posts: 997
    edited 2007-07-19 14:35
    Weird. I just used my PC laptop to view the previous message I wrote. Wadda' you know, there's the 'µ' symbol. So Windows somehow knows to display it. yeah.gif

    My wrong, it is the Option key and 'm' key for the mu symbol on the Mac. Maybe my brain is dyslexic these days. yeah.gif

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Harley Shanko
    h.a.s. designn
  • deSilvadeSilva Posts: 2,967
    edited 2007-07-19 18:46
    Sorry, I didn't follow this thread any longer.. Greek "mikron" means "small", so it's first letter has become an appropriate shortcut for small numbers. The transcription of the Greek µ however shifts from languages to languages and in many of them it is (close to Greek) "my". It slipped my mind that Americans use the transcription "mu" due to some peculiarities of their dialect wink.gif
  • Paul BakerPaul Baker Posts: 6,351
    edited 2007-07-19 21:38
    Fred Hawkins said...
    Windows: assessories, character map. They say you can use alt+0181 but I can't get it work that way. I can copy it though: µ
    To type extended characters make sure NumLock is on, hold down the Alt key and type the 3 digit value,
    mu is 230: µ
    Omega is 234: Ω
    pi is 227: π
    There are·many more useful symbols, all outlined in the bottom table of this page: ·http://www.asciitable.com/

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Paul Baker
    Propeller Applications Engineer

    Parallax, Inc.
  • kenmackenmac Posts: 96
    edited 2007-07-20 05:20
    This thread has been hijacked!
    Back on to the original subject!

    mirror,
    I like the Galaxy touch! (To think that it took a Propeller to find the answer!)

    I have tried the following:

    Controlling Cog
    pub main 
      NumPtr := @number
      x.start(NumPtr)
      start
      repeat
    
    pub start
      number := 8
    



    Receiving Cog
    pub start(MyNumPtr)
      NumPtr := MyNumPtr 
       cognew(checkno, @Stack)  
                             
      
    pri  checkno
      dira[noparse][[/noparse]16]~~
      repeat
        byte[noparse][[/noparse]NumPtr] := MyFunc(byte[noparse][[/noparse]NumPtr])
          
    pri MyFunc(val)
      if val == 8
         !outa[noparse][[/noparse]16]
    



    The requirement was to turn on LED on Pin16 if the number = 8.
    This works and the LED isn't activated if the number <>8 .
    However, if I change the number to be continuously variable, it doesn't trap the required number.

    Controlling Cog
    pub start
      number := 1
      repeat  
        number++                   ' increment number
        waitcnt(5000_000 +cnt) ' set rate of change
    



    Receiving Cog
    pri MyFunc(val)
      if val == 8                     ' if number = 8 then 
         !outa[noparse][[/noparse]16]                    ' turn on LED
    



    Should that work?

    kenmac

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Perth, Western Australia
    Time Zone = GMT + 8
  • kenmackenmac Posts: 96
    edited 2007-07-20 06:45
    mirror,
    Further on your example:
    In the code:
    pri checkno
        repeat
        byte[noparse][[/noparse]NumPtr] := MyFunc(byte[noparse][[/noparse]NumPtr])
    
    pri MyFunc(val)
        return val//42
    



    The actual value held in the Global Variable is = byte[noparse][[/noparse]NumPtr] - is that correct?
    If so, an internal variable could be set as Num = byte[noparse][[/noparse]NumPtr], for further action?
    MyFunc is just an example of a process/return action on that value?
    The "return value" action isn't important at this stage, I just need to be able to monitor a changing variable data in another Cog.
    Once I understand that, the use of multiple Cogs will become much easier.

    Perhaps this subject should be covered in more detail in any supporting documentation - it is important.

    kenmac

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Perth, Western Australia
    Time Zone = GMT + 8
  • kenmackenmac Posts: 96
    edited 2007-07-20 07:13
    mirror,
    I think I have worked it out and answered my own questions.
    The following works:
    pri  checkno
      dira[noparse][[/noparse]16]~~
      repeat
        number := byte[noparse][[/noparse]NumPtr]
        if number == 8                           ' trap number 8
          !outa[noparse][[/noparse]16]
    



    So, having confirmed that, I can move on to other things.
    Thanks for the help.


    kenmac

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Perth, Western Australia
    Time Zone = GMT + 8
  • deSilvadeSilva Posts: 2,967
    edited 2007-07-21 04:52
    Just as an afterthought, as this thread - indeed! - is made of many parts...

    To my impression, there has been a lot of confusion - as always - between (encapsulated) objects and COGs ("thread processors"). Because of the (maybe a little bit overdone) scope rules of SPIN, you have to use pointers to "creep in".

    In contrast to assembly threads, SPIN code has no visible COG internal data, so most of the issues discussed in assembly language related postings here (RD/WR.... vs. MOV) simply do not apply for SPIN. All (user defined) SPIN variables - "local" (ever wondered where you take the "stack" from when starting a SPIn-COG?) or "global" (which is a bad term, as you definitely and always have to distinguish between VAR (static "Object" data) and DAT (static "Class" data) to avoid very tricky pitfalls) - are held in HUB memory and can be accessed in the most simple way, slightly handy-capped by the scope rules..
  • RinksCustomsRinksCustoms Posts: 531
    edited 2007-07-23 01:14
    Harley said...
    I've seen the word 'mys' used by several on the forum.

    But Google or Wikipedia didn't explain this word. What does it mean? Never known about it before.

    they are mis-labeling it, the correct form of microseconds is:

    µS

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    E3 = Thought

    http://folding.stanford.edu/·- Donating some CPU/GPU downtime just might lead to a cure for cancer! The average PC while browsing the internet typically uses less than 30% of it's potential, why not donate a portion of the rest for cancer resaerch?
  • mirrormirror Posts: 322
    edited 2007-07-23 01:40
    they are mis-labeling it, the correct form of microseconds is:

    µS

    RinksCustoms:

    What you have written is micro-siemens, which has got nothing at all to do with time.

    Reference: http://en.wikipedia.org/wiki/Siemens_%28unit%29

    Lowercase "s" for seconds. Uppercase "S" for siemens.

    ·
  • kenmackenmac Posts: 96
    edited 2007-07-23 05:08
    Just when I thought this was understood and finished, more problems!
    The original simple setup where a Controlling Cog calls an Object which starts it's own Cog and then checks a number created as a Global variable, actually worked. (See earlier in this thread)
    However, when I added this function to an existing Object designed to drive an LCD, it no longer works.

    The relevant code is as follows:

    Controlling
    obj
       X:"LCD"
       
    pub main 
      number := 5
      NumPtr := @number
      x.start(NumPtr)
      repeat
    



    Receiving
    pub init  'Initialize the LCD
     {{ This part of the code not shown - it initialises the LCD
    
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
                                                                  }} 
      checkNo
    
    pub start(MyNumPtr)
      NumPtr := MyNumPtr 
      cognew(init, @Stack)  
                                     
      
    pri  checkNo 
      repeat
        num := byte[noparse][[/noparse]NumPtr]         ' read number via pointer
        if num == 5                  ' check number is 5
          dira[noparse][[/noparse]16]~~                 '   if so, turn on LED
          outa[noparse][[/noparse]16]~~
          waitcnt(3000_000 + cnt)
    



    Changing the number in the Controlling has no effect whatsoever.
    I inserted some code in the Receiving/Checkno to display the number on the LCD:

    num := num + 48              ' Ascii for LCD
    write(num)                  ' display number on LCD
    



    The character displayed is the curly bracket "{" , which is Ascii 124.

    Can anyone see what is wrong here?

    kenmac

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Perth, Western Australia
    Time Zone = GMT + 8
  • mirrormirror Posts: 322
    edited 2007-07-23 07:48
    Ahh. The joys of pointers. It all looks like it should work, and then it doesn't. There are two options: (that I use)

    1) GEAR. Step through the code. See what happens to the pointer.

    2) SerialMirror. Use the serial port, and a liberal number of debug messages to track down the source of the bug. The reason for SerialMirror as opposed to FullDuplexSerial is that you can use the same serial port from multiple objects without too much hassle.
    http://forums.parallax.com/showthread.php?p=649541
  • kenmackenmac Posts: 96
    edited 2007-07-23 08:32
    Hi mirror,
    Actually, the LCD character read was incorrect.
    The character now displayed is 0.
    By altering the Ascii adjust number, the displayed number follows, e.g. 55 reads 7.
    So, basically the pointer reading is 0.

    Having passed the pointer to the X.start, then converting it to its own variable NumPtr, all the methods within this Object should be able to access the contents of NumPtr ? It is defined.

    I'll keep playing with it, and hopefully all will be revealed!

    kenmac

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Perth, Western Australia
    Time Zone = GMT + 8
  • mirrormirror Posts: 322
    edited 2007-07-23 22:18
    kenmac,

    Was just thinking this morning that there is an alternate way to solve this problem, although it is only applicable to some applications.

    Define your x object as follows:

    var
      long stack[noparse][[/noparse]20]
      byte Number
     
    PUB Start
      cognew(checkno, @stack)
     
    PUB GetNumber
      return Number
     
    PUB SetNumber(val)
      Number := val
     
    PRI checkno
      repeat
        Number := MyFunc(Number)
    

    Then use x.GetNumber and x.SetNumber from the parent object. Number is not global, but somtimes you can do this to avoid·the pointer magic.

    ·
  • LawsonLawson Posts: 870
    edited 2007-07-23 23:15
    I've also used that method to pass pointers to a parent object.


    var 
      
      long stack[noparse][[/noparse]20] 
      byte Number
    
    PUB Start 
    
      cognew(checkno, @stack) 
    
      
    
    PUB GetNumberPtr      'return the address of Number
    
      return @Number 
      
    
    PRI checkno 
    
      repeat 
    
        Number := MyFunc(Number) 
    
    



    then easy u can access Number from the current object or the parent object using code like this. (ofc, the MyObject part is dropped when accessing GetNumberPtr from the current object)

    BYTE[noparse][[/noparse]MyObject.GetNumberPtr] := something     'write the variable
    temp := BYTE[noparse][[/noparse]MyObject.GetNumberPtr]            'read the variable
    
    

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Lunch cures all problems! have you had lunch?
  • mirrormirror Posts: 322
    edited 2007-07-23 23:34
    Lawson: You're right. I've also done this myself.

    For updating circular buffers I used an even slightly more advanced technique.

    In parent object:

    var
      word BufferStartPtr
      word BufferEndPtr
      word BufferPutPtr
      word BufferGetPtr
     
    PUB SomeFunc
      x.GetBufferPtrs(@BufferStartPtr)
    

    In child object:

    var
      byte Buffer[noparse][[/noparse]100]
      byte BufPut
      byte BufGet
     
    PUB GetBufferPtrs(BufPtrPtr)
      word[noparse][[/noparse]BufPtrPtr][noparse][[/noparse]0] := @Buffer[noparse][[/noparse]0]
      word[noparse][[/noparse]BufPtrPtr][noparse][[/noparse]1] := @Buffer[noparse][[/noparse]100]  'Actually points just past the buffer
      word[noparse][[/noparse]BufPtrPtr][noparse][[/noparse]2] := @BufPut
      word[noparse][[/noparse]BufPtrPtr][noparse][[/noparse]3] := @BufGet
    

    This way:
    1) The memory definition of the FIFO buffer can be kept with the child object. This is really important to me·as I'm becoming *very* memory constrained, and this·a more accurate picture of the memory usage of the object.
    2) It allows the block of pointers to be passed to some other child object. In this way the two child objects can communicate without any intervention from the parent object.

    Disclaimer: The code I've shown here is in concept form only. I normally do BufPut and BufGet as pointers in the child object which allows easier buffer wrapping.
    ·
Sign In or Register to comment.