Shop OBEX P1 Docs P2 Docs Learn Events
Multiple instances of object in Spin 2 — Parallax Forums

Multiple instances of object in Spin 2

kolyurkolyur Posts: 43
edited 2023-09-29 13:31 in PASM2/Spin2 (P2)

I'm configuring a P2 to control a Newhaven LCD with the FT812 video engine. Works great after porting Rayman's code from this thread to Spin 2. The driver basically includes lots of low-level methods for drawing lines, text, buttons, etc. It calls an SPI driver (formerly SPI_Spin but I changed it to gp_asm_spi with same syntax) to communicate with the EVE chip.

I would like to create a separate object with some higher level functions, to draw more complex primitives, so that I can reuse it in other projects. This object would call the low-level EVE methods. So the object hierarchy would be like this:

However, I would still like to be able to call the low level functions from my Main program. So really I need this arrangement:

I'm a bit confused on how to implement this, since there are multiple definitions of the same objects. The EVE driver takes some startup parameters to configure the screen (pin numbers, etc.). I could define these identically in both places, but that seems redundant. My understanding is that if I move the common variables from VAR to DAT, then all calls to either driver object would reference the same values, is this correct?

I'm also not sure how to handle the SPI driver object that they both reference. This driver is directly controlling P2 pins so I would think there could be some pin contention if two instances of the object are defined. Just thinking conceptually it seems like I need something like this:

Or maybe this:

I guess I'm just unclear on how multiple instances of the same object exist together. Method pointers seemed relevant but the description in the manual is brief and I couldn't find any tutorials or further explanation. Object pointers also looked like an option but I'm using Propeller Tool so that might not be possible.

Or I could be going totally down the wrong track--feel free to say so. I would appreciate any suggestions!

EDIT: I should add that everything is running in the same cog.

Comments

  • evanhevanh Posts: 15,278
    edited 2023-09-29 14:03

    I think those are all doable. Yes, first step is moving all the VARs into DAT.

    Second step is the child object's startup function should know to return a good status without doing any of the init working upon second, third and further instance startup calls, This way the object can be attached to multiple parents in the finished build without upsetting what would really be a single instance of the driver.

    So, start by duplicating it into a new object file before making edits.

    PS: There is risks of simultaneous multi-cog use corrupting internal state of the driver. I guess all the critical parts could be bound to locks, but that could be some work to solve.

  • Thank you, moving the variables from VAR to DAT was just the ticket. I created special multi-instance versions of the EVE driver and SPI objects with this change, and made sure that I only called the Start method from one location. After that I was able to call the same object from multiple files and it essentially behaved as one. Since everything runs in one cog there were no worries about locks or data corruption.

  • evanhevanh Posts: 15,278

    Cool.

  • ElectrodudeElectrodude Posts: 1,631
    edited 2023-10-03 14:05

    @cgracey @ersmith Spin2 should let you share one instance of an object between multiple parent objects using something like the object constant override syntax. You'd override an object's child object with your own instance you already have. This way, you wouldn't have to manually move variables from VAR to DAT to achieve this, and you'd be able to do things between having every instance be completely separate and every instance be completely shared - you could e.g. have one instance shared by a few objects and another by a few others.

    Better yet, Spin2 should just have real object pointers. You can't really call a language object-oriented unless objects are actually first-class language features, which they aren't if you can't access them by reference like you can with normal variables.

    EDIT: Related discussion here: https://forums.parallax.com/discussion/175386/

  • @Electrodude said:
    @cgracey @ersmith Spin2 should let you share one instance of an object between multiple parent objects using something like the object constant override syntax. You'd override an object's child object with your own instance you already have. This way, you wouldn't have to manually move variables from VAR to DAT to achieve this, and you'd be able to do things between having every instance be completely separate and every instance be completely shared - you could e.g. have one instance shared by a few objects and another by a few others.

    >

    Better yet, Spin2 should just have real object pointers. You can't really call a language object-oriented unless objects are actually first-class language features, which they aren't if you can't access them by reference like you can with normal variables.

    Object points on their own (without inheritence or subclassing) aren't really enough. Flexspin has object pointers, but hardly anyone uses them, because the child has to declare the object pointer to have the exact type of the parent. It can help in a few cases, but it's far more common for the child object to just want "a generic serial object with tx and rx" rather than "my_specific_serial_driver.spin2". And right now there's no way to express the idea of "a generic serial object with tx and rx" in Spin2, and adding it is likely to complicate the language quite a bit. I can see why Chip is reluctant.

    There are languages available for the P2 with this capability though, e.g. FlexBASIC or C++.

  • Interestingly, I ran into the very same problem just today. For me it's even a bit more complicated as I use C and Spin2 mixed together in one project. I don't want to blame anybody for the oddities of Spin, just some questions:

    1. If I declare a Spin object in C with the struct __using syntax then a new object is instantiated each time, the same as it would if I used that object in a Spin file. But how about C files "included" in Spin code? For example, my main file is written in Spin2 and contains
    OBJ
      disp:   "QB_display.c"
    

    Now if that C file declares local variables at the top level (static int ...) and the same C file is used in another Spin object do I get two copies of the local variables or do they share only one instance?

    1. If a file is listed more than once in the compiler output, for example
    Propeller Spin/PASM Compiler 'FlexSpin' (c) 2011-2023 Total Spectrum Software Inc. and contributors
    Version 6.5.3-beta-v6.5.2-3-g280c716b Compiled on: Oct  6 2023
    QB_main.spin2
    |-boardcfg.qbeast.spin2
    |-QB_display.c
    |-|-display.oled.ssd130x.spin2
    |-|-|-core.con.ssd130x.spin   
    |-|-|-com.i2c.spin2
    |-|-font.5x8.spin2
    |-|-font.8x12.spin2
    |-|-boardcfg.qbeast.spin2
    |-|-QB_inout.spin2
    |-EthPhy_RMII.spin2
    |-|-com.i2c.spin2
    |-QB_inout.spin2
    |-QB_VfdVector.c
    |-|-QB_VfdPower.spin2
    |-QB_parameter.c
    |-|-flash_fs.spin2
    sprintf.c
    QB_VfdVector.c
    |-QB_VfdPower.spin2
    QB_parameter.c
    |-flash_fs.spin2
    fmt.c
    basicfmt.c
    ieee32.c
    vfs.c
    dofmt.c
    posixio.c
    errno.c
    bufio.c
    QB_main.p2asm
    Done.
    Program size is 50080 bytes
    

    ... lists QB_VfdVector.c and QB_VfdPower.spin2 twice. Is this equivalent to the statement "two instances of theese objects are created"?

  • (1) If the exact same C file (e.g. "QB_display.c") is used in two places, then any variables declared static are shared by the instances (just like Spin2 variables declared in a DAT section), whereas variables not declared static are kept separate (just like variables declared in a VAR section in Spin2).

    Note that if two different C files (e.g. "QB_display.c" and "QB_foo2.c") are included, then these will be treated as completely different objects, even if they happen to share some variable or function names. This includes structs and global functions.

    (2) If a file is listed multiple times in the output, then multiple instances are created. However, it's not necessarily the same number of instances as the number of output lines, since for example an array of objects creates multiple instances but will result in only one more line being printed.

  • Thanks, this is very helpful to understand how it works.

    I wonder if it was a good idea to compile all these hints that are spread across different threads in the forum to a "Tips and tricks" manual that should be included in the FlexSpin docs. This would surely be a lot of work and is not necessary for the beginner who wants to get some code running. But it is very useful if an advanced user wants to start a bigger project.

  • evanhevanh Posts: 15,278

    I'm learning documentation is even harder than I feared. Making it detailed, accurate and coherent isn't easy. Secondary school really should be teaching this stuff alongside Maths, instead of English. The novels Smile made me puke.

Sign In or Register to comment.