Catalina 4.0 is now available

2

Comments

  • Take care Ross!
  • @RossH Sounds like you are having a tough year. I can sympathize with that. We had rain and wind storms last year in the spring and fall that did a lot of damage to our docks and breakwall. Between the that and the virus it looks like there will not be much of a boating season this summer. Hope things get better for us all in the next few months.

    PS you may want to look into an IP phone to replace your land line. I had a phone with Vonage and found it to be quite reliable and very convenient. When I moved it was a simple matter of getting an internet connection and plugging the phone box in to one of the ethernet connections on the router. Took it with me when I moved from Toronto to Edmonton and had it set up the day after I arrived with my original phone number.
  • kwinn wrote: »
    PS you may want to look into an IP phone to replace your land line.

    Our internet is via satellite, so even with an IP phone we suffer typical satellite phone delays. We have tried a satellite phone, and it is very, very difficult when speaking to people who are not used to the delay. We have trouble using Skype (or Zoom) for the same reason. Very few people seem to remember the days when most international calls were via satellite, and you had to take the delay into account!

    A landline (actually it is not a landline, it is a terrestrial radio phone) is really the only workable solution. Unfortunately, the radio relay tower nearest us got burned to the ground and is still being rebuilt.
  • Wingineer19Wingineer19 Posts: 175
    edited 2020-04-19 - 05:58:29
    RossH wrote: »
    Our internet is via satellite, so even with an IP phone we suffer typical satellite phone delays. We have tried a satellite phone, and it is very, very difficult when speaking to people who are not used to the delay.
    Exactly. The latency introduced by the satellite link makes two-way communication quite difficult. Websurfing and streaming movies are one thing, having a telecon is something else entirely.
    A landline (actually it is not a landline, it is a terrestrial radio phone) is really the only workable solution. Unfortunately, the radio relay tower nearest us got burned to the ground and is still being rebuilt.
    My Dad had a (true "twisted pair") landline phone to his house but got tired of paying $60 per month just for local calls. I got him a ZTE Wireless Home Phone Base that uses a cellular network for phone calls for about $20 per month. The device has an RJ-11 phone jack so his existing handset phone just plugs right into it. When you lift the handset you get dialtone just like a true landline, and aside from a slightly longer delay to place the call, it works well. Of course, you need LOS to a cellular tower for it to work, something which you wouldn't have if it burned to the ground like the radio relay tower you mentioned.

    As far as the Catalina programming Loader issue goes, it isn't a big deal right now since I have the workaround. When I get time I still need to modify my code so that it will "read after write" to verify the EEPROMs were burned correctly, as well as try to write blocks larger than 16 bytes. I think your existing loader uses 32 bytes, while Tachyon uses 128. And like I mentioned earlier, I somehow damaged my existing EEPROM carrier board, so I will need to build up a new one in the not too distant future to resume this task.

    Regarding the Prop1 multi-memory model idea, you had mentioned previously you could probably do it by modifying HubRam memory management. The issue then was how could you get the XMM, CMM, or LMM to share variables and information. One idea was to use the registry. Another was using pointers within HubRam. The last one was using Global Variables. All of which would work fine if XMM was using the Small Memory Model. The big question was how to do it if XMM was using the Large Memory Model, because variables could only be shared if they existed within HubRam. And that would require some type of directive to specify which XMM variables were in external memory and which ones were within HubRam...

  • RossHRossH Posts: 4,545
    edited 2020-04-23 - 15:56:18
    .
    RossH wrote: »
    Regarding the Prop1 multi-memory model idea, you had mentioned previously you could probably do it by modifying HubRam memory management. The issue then was how could you get the XMM, CMM, or LMM to share variables and information. One idea was to use the registry. Another was using pointers within HubRam. The last one was using Global Variables. All of which would work fine if XMM was using the Small Memory Model. The big question was how to do it if XMM was using the Large Memory Model, because variables could only be shared if they existed within HubRam. And that would require some type of directive to specify which XMM variables were in external memory and which ones were within HubRam...

    The shared variables are the only tricky part. Each program has to be compiled separately and there is no way (at least not in ANSI C!) to specify the address to be used for a variable.

    I can't remember now what I originally intended, but I am currently thinking of the following ...

    1. The main program can be an XMM LARGE or XMM SMALL program. It will be loaded and started exactly as usual.
    2. Subsidiary programs will be compiled separately and can be either LMM or CMM programs.
    3. Compiled binary versions of each subsidiary program will be included in the main program as "blobs" (binary large objects) - these blobs will be stored in XMM RAM until they are needed, and must be explicitly started by the main program.
    4. The main program must define any variable it wants to share with a subsidiary program as a local variable - to ensure it is allocated in Hub RAM - and must then pass its address to the subsidiary program on startup. To share multiple variables you would instead use a structure, passing its address. This structure could be defined in a header file that is included by both the main program and the subsidiary program. A different structure can be used for each different subsidiary program if required, or the same structure can be used for all subsidiary programs.
    5. A utility function will be provided that allows the main program to load and start a subsidiary program, specifying the Hub RAM space to be used for code, data and stack space - and also the address of the shared variable.
    6. Another utility function will be provided for a subsidiary program to retrieve address of the the shared variable (or structure).
    7. Any synchronization mechanisms required (e.g. locks) can be added over the top of this simple mechanism - e.g. by passing the lock number to use via the shared variable (or within the shared structure).
    8. The main program can start and stop the subsidiary programs at will, re-using the same Hub RAM space. Essentially, this gives you a very simple form of program overlays.

    This is all fairly straightforward. The question is ... would it meet your needs?

    One problem with this simple-minded approach is that it is not possible to make any of the programs "share" common code or data - as they are compiled separately, the main program and each subsidiary program must have its own copy of everything it needs (other than the shared variable). This may be an inefficient use of Hub RAM, so it would be important (for example) to have all I/O done by only one program - typically the main program, but it could also be one of the subsidiary programs.

    Ross.
  • RossH wrote: »
    The shared variables are the only tricky part. Each program has to be compiled separately and there is no way (at least not in ANSI C!) to specify the address to be used for a variable.

    I can't remember now what I originally intended, but I am currently thinking of the following …
    1. The main program can be an XMM LARGE or XMM SMALL program. It will be loaded and started exactly as usual.
    Excellent. I was concerned that XMM SMALL was the only one which could be supported. Given all of the user Menus and interface stuff that's being layered into my Program it's likely I will have to go the XMM LARGE route.
    2. Subsidiary programs will be compiled separately and can be either LMM or CMM programs.
    Sounds good, although I'll probably stick with CMM programs for now.
    3. Compiled binary versions of each subsidiary program will be included in the main program as "blobs" (binary large objects) - these blobs will be stored in XMM RAM until they are needed, and must be explicitly started by the main program.
    So would these subsidiary programs be initiated from the main program via something like the _coginit_c() function?
    4. The main program must define any variable it wants to share with a subsidiary program as a local variable - to ensure it is allocated in Hub RAM - and must then pass its address to the subsidiary program on startup. To share multiple variables you would instead use a structure, passing its address. This structure could be defined in a header file that is included by both the main program and the subsidiary program. A different structure can be used for each different subsidiary program if required, or the same structure can be used for all subsidiary programs.
    Using a Structure which contains a grouping of variables needed by both the XMM and CMM programs sounds like a very clean way of doing things.
    5. A utility function will be provided that allows the main program to load and start a subsidiary program, specifying the Hub RAM space to be used for code, data and stack space - and also the address of the shared variable.
    So I guess this brings me back to something analogous to the _coginit_c() function mentioned above?...
    6. Another utility function will be provided for a subsidiary program to retrieve address of the the shared variable (or structure).
    Will this utility function first be called from within the main program in XMM memory to obtain the address of the shared variable/structure?

    Then this address is placed within the "_coginit_c" type function used to startup the subsidiary program(s) within CMM/LMM?

    Then the subsidiary program would use this utility function to get the address of the shared variable/structure as well? Or would that even be necessary since the address was handed to it by the startup calling function?
    7. Any synchronization mechanisms required (e.g. locks) can be added over the top of this simple mechanism - e.g. by passing the lock number to use via the shared variable (or within the shared structure).
    Indeed, locks will be required to access the shared variable or structure elements, especially since some of these elements are likely to be char arrays up to a couple hundred bytes or so. Don't want contention between XMM and CMM programs trying to access the variables/elements at the same time...
    8. The main program can start and stop the subsidiary programs at will, re-using the same Hub RAM space. Essentially, this gives you a very simple form of program overlays.
    Fantastic. Although the intent would be to startup CMM/LMM programs and keep it/them running for the duration of the powerup cycle, there could be situations where the subsidiary program(s) could freeze and need to be restarted. A simple stop followed by start would remedy this.
    This is all fairly straightforward. The question is ... would it meet your needs?
    Yes it would. It sounds awesome!
    One problem with this simple-minded approach is that it is not possible to make any of the programs "share" common code or data - as they are compiled separately, the main program and each subsidiary program must have its own copy of everything it needs (other than the shared variable).
    I don't see this as a problem. Especially if using XMM LARGE, where code and data couldn't be shared anyway. I'll just have to make sure that the CMM/LMM programs are as clean and compact as possible to minimize use of HubRam, especially considering that the XMM memory will be using 8K of cache.
    This may be an inefficient use of Hub RAM, so it would be important (for example) to have all I/O done by only one program - typically the main program, but it could also be one of the subsidiary programs.

    Ross.
    I'm using the 4-Port Serial Driver with the following settings:
    Port0: Console I/O on P31 and P30
    Port1: GPS I/O on P17 and P16
    Port2: Radio I/O on P15 and P14
    Port3: Spare (Not Used Yet)

    The GPS receiver has a block of binary Messages that will be needed by the XMM program for display to the user. Right now I'm looking at about six unique message types including Position, Time, Heading, Tracking Status, Satellites Tracked, and Satellite position.

    The idea is that the XMM program would handle the user interface and Menus, while the CMM/LMM program(s) would operate "in the background" handling the I/O traffic to the GPS receiver, radio, and Console.

    A CMM/LMM program could directly interface with the GPS receiver, parse its messages, then populate each of the above particular message type within the shared Structure.

    The XMM program could then check the status of each message, and if they've been updated by the CMM program, prep them for output to the user.

    A separate CMM/LMM program could be dedicated to handling I/O traffic to the radio.

    Likewise, another CMM/LMM program could be assigned the Console I/O traffic on P31 and P30 as well.

    My objective, though, is to get a single CMM/LMM program to handle all I/O traffic: Console, GPS, and Radio. This might be doable if the Parsing workload isn't too burdensome.
  • Hello @Wingineer19

    My original thinking may have been to share a common data space among all the programs, which would have meant XMM SMALL would be the only primary** program type that would have been possible without a lot more work, but the way I am now considering doing it - where each program has its own data space and just shares one common variable - means both XMM LARGE and XMM SMALL should work equally well as the primary program.

    Hub RAM limitations on the Propeller 1 mean that the combination that is likely to be most useful is an XMM LARGE primary program, with one or more CMM subsidiary programs.

    And yes, something like _coginit_C() would be used to start each subsidiary, with parameters specifying the blob, the address of the shared variable, and the Hub RAM space to be used for the subsidiary. The shared variable must be allocated in Hub RAM, which can be easily accomplished by just making it a local variable of the main() function within the primary program - If you need to use it elsewhere (e.g. in another function) you will have to pass the address as a variable, or perhaps store it in a global variable.

    I would probably provide two functions to start subsidiary programs - _coginit_CMM() and _coginit_LMM() - rather than just have one function, because that way I will only need one copy of each kernel and can use it to start as many subsidiaries as you need. Otherwise, the kernel would have to be embedded in each blob. As for the subsidiary programs, I can maybe arrange it so that the shared variable address always appears to the subsidiary main() function in argv[1] - so no special function would be needed to fetch it. This seems fairly clean and is (hopefully!) simple to do.

    Note that all this means you could start a subsidiary from within a subsidiary - you could even start an LMM subsidiary from within a CMM subsidiary, or vice-versa ... but doing so would be a hideously inefficient use of Hub RAM! Subsidiaries should generally only be started from the primary program.

    Both the primary program and all the subsidiary programs will share the common registry, which means they can all use any plugins that are loaded (such as the 4 port serial driver). The registry itself takes care of any access contention, but coordinating things like which program uses which port is up to the programs to manage.

    I still have a few details to think through - e.g. whether I will have to pre-allocate the Hub RAM to use for each subsidiary program, or whether I can do that "on the fly" in the primary program.

    Ross.

    ** I realized I should probably use a term such as "primary" program rather than "main" program, because each subsidiary program also has a "main" function!
  • Just some more musings on the multi memory model support ... I find a gin and tonic or two improves the thinking process no end ... :smiley:

    1. I have realized that I will have to pre-allocate the Hub RAM space for each subsidiary program in the primary program, because the code Catalina generates for the Propeller 1 is not relocatable. Luckily, Catalina already accepts command-line options to move the various segments to specific Hub RAM locations, so all I will need to do is add some means to pre-allocate the appropriate Hub RAM in the primary program. I will create a utility that will automatically compile a Catalina program as a subsidiary program and convert it into a blob file that can be included by the primary program, and this utility will also generate symbols that can be used in the primary program to allocate the appropriate Hub RAM for the blob. So while there may be a bit of trial and error involved in the compilation process to accommodate the size of the blob (which will generally not be known in advance) the whole process should be fairly straightforward.

    2. I just realized that you don't want the plugins loaded and unloaded by each subsidiary program, because the individual subsidiary programs don't know when the plugins are no longer required (e.g. the same plugin may be used by multiple subsidiary programs). This complicates things a little, because it means all the plugins will have to be loaded by the primary program - even if it doesn't use them. For example, if a subsidiary program uses floating point, then both the primary program and the subsidiary program will have to be compiled with the same floating point library option, to ensure that (a) the appropriate plugins are loaded and (b) the appropriate library code is included by the plugin. However, I can easily suppress the loading of any actual plugins by the subsidiary programs, so that they will only be loaded by the primary program. But if plugins are required to be dynamically loaded and unloaded then this will have to be done explicitly by the primary program, which is the only one that knows when the plugin are required.

    3. Subsidiary programs should never exit, because exiting restarts the cog, which will just restart the same subsidiary program! Instead, subsidiary programs should explicitly shut down the cog they are in (if they know they are no longer required), or they should just loop, to be shut down by the primary program when they are no longer required.

    I haven't done any real work on the Propeller 1 for quite a while. This should be fun! :)

    Ross.
  • Hi @RossH,

    Well considering how my memory has been "working" recently I think I need a steady stream of gin and tonic. Couldn't make it any worse than it already is. :smile:

    Now wandering down the multi-memory model path a little further...

    1. When using the CMM/LMM memory model under the current version of Catalina, the _cogint_c() function contains the name of a void function (along with some stack info) to be executed in a separate cog upon startup.

    2. When using the XMM LARGE or XMM SMALL memory model, I guess the proposed _coginit_CMM() and _coginit_LMM() functions operate in a similar manner except they call a main() function with parameters passed to it from the Primary program, including int argc and char *argv[]?.

    3. Previously you mentioned that it will also be necessary to pass code, data, and stack space requirements to the _coginit_CMM() or _coginit_LMM() function as well.

    4. Your Utility program will compile the subsidiary program into a "blob" that will be included within the XMM Primary program, so will the "blob" contain the code, data, and stack info needed, or will these still need to be manually entered into the _coginit_CMM() or _coginit_LMM() functions prior to compiling the XMM primary program?

    5. When using the CMM/LMM memory model under the existing version of Catalina, I can differentiate which cog will run which function by using a different function name within _coginit_c(). But how would I do this under _coginit_CMM() or _coginit_LMM() when the only function they can call is main()?

    6. So compiling an XMM program which spawns a CMM/LMM program into a separate cog will be a two stage process? Compile the CMM/LMM subsidiary using the new Utility. Then including the "blob" info into the XMM primary program, and compile it into the final product? Then the Loader will be able to take the resulting binary file and program it into EEPROM or Flash memory (depending upon the loader chosen)?

    7. I agree that loading plugins should be restricted to the XMM primary program only.

    8. I assume your Utility will also need to know which plugins will be used so it can determine how many free cogs remain that can be called by _coginit_CMM() or _coginit_LMM()?

    9. I anticipate using one cog for the XMM kernel, another for XMM cache, two for the math plugin, and one for the 4-Port serial plugin. Thus leaving only 3 free cogs. The math plugin will be used by the XMM primary program. But I want to leave use of the 4-Port plugin to the CMM/LMM subsidiary program(s) so it/they can perform I/O traffic management to the Console, GPS receiver, and Radio and not burden the XMM primary with that task. The only interaction between the XMM primary and CMM/LMM subsidiary is via elements with the shared Structure. For example, the XMM primary will fill a ConsoleOut string within the Structure, then the CMM/LMM subsidiary will grab this string and output it to the Console. Likewise, the CMM/LMM subsidiary will parse the incoming GPS messages, populate various message strings within the Structure, then the XMM primary will grab these messages for processing.

    10. Would you include something like _cogstop_CMM() or _cogstop_LMM() functions to shut down these cogs? Would cog shutdown fall exclusively under the purview of the XMM primary program, or could a subsidiary CMM/LMM program shut itself down via a _cogstop()?



  • Hello @Wingineer19

    I have just finished getting the new "mult-memory model" support working on the Propeller 1. I would like to get it working on the Propeller 2 before I release it, but if you want to have a play with it on the P1, let me know and I can release an interim version.

    To answer your specific questions:
    1. When using the CMM/LMM memory model under the current version of Catalina, the _cogint_c() function contains the name of a void function (along with some stack info) to be executed in a separate cog upon startup.
    I decided to use _cogstart() - which was new for the P2, but I have now ported it back to the P1 - rather than _coginit(), because _cogstart() already accepted an address argument, which I now use for the shared variable address.

    2. When using the XMM LARGE or XMM SMALL memory model, I guess the proposed _coginit_CMM() and _coginit_LMM() functions operate in a similar manner except they call a main() function with parameters passed to it from the Primary program, including int argc and char *argv[]?.
    Correct. However, the address of the shared variable is passed as the only parameter to main(), which (for Catalina) means that if you defined your main function as per the C standard, then argv would be the address of the shared variable, and argc would be undefined. This is perfectly fine, but it might therefore be better to instead define the main() function as:
    void main(void *arg)
    
    Of course, if you know the type of the shared variable, you could define your main function as:
    void main(shared_t *arg)
    

    3. Previously you mentioned that it will also be necessary to pass code, data, and stack space requirements to the _coginit_CMM() or _coginit_LMM() function as well.
    No, I have made it very much simpler. You don't need to call _coginit_CMM() or _coginit_LMM() directly, since Catalina knows if the program is a CMM or LMM program. When you process your compiled subsidiary program (using a new version of spinc), I generate an include file, containing both the blob and a "start" function for you to call, and it does everything else for you - all you do is pass the shared variable address and the cog number you want to use (which can be the predefined value ANY_COG), such as:
    #include "my_program.inc"
       ...
       shared_t var;
       ...
       start_my_program(&var, ANY_COG)
       ...
    
    The only additional complexity is that each subsidiary CMM or LMM program must be compiled to run at a fixed memory address, which must be guaranteed to be unused by the primary program. There are various ways of achieving this - I will include more details (and examples!) in the release.

    4. Your Utility program will compile the subsidiary program into a "blob" that will be included within the XMM Primary program, so will the "blob" contain the code, data, and stack info needed, or will these still need to be manually entered into the _coginit_CMM() or _coginit_LMM() functions prior to compiling the XMM primary program?
    Correct. The utility program is a modified version of the existing spinc utility, since that utility already did almost the same job for Spin and PASM programs. It generates an include file which you just include in your main program. This include file contains both the blob, and a function you can use to start it.

    5. When using the CMM/LMM memory model under the existing version of Catalina, I can differentiate which cog will run which function by using a different function name within _coginit_c(). But how would I do this under _coginit_CMM() or _coginit_LMM() when the only function they can call is main()?
    You can specify the cog when you start the program (or use the predefined value ANY_COG if you don't care which cog it uses). You don't actually "call" the main function directly, you call a function to start the program, and (optionally) pass the address of the shared variable, which ends up in the main function parameter. You can start multiple programs this way - you just specify a different name to the spinc utility for each one, and you will end up with multiple include files, and functions called (for example) start_program_1(), start_program_2() etc.

    6. So compiling an XMM program which spawns a CMM/LMM program into a separate cog will be a two stage process? Compile the CMM/LMM subsidiary using the new Utility. Then including the "blob" info into the XMM primary program, and compile it into the final product? Then the Loader will be able to take the resulting binary file and program it into EEPROM or Flash memory (depending upon the loader chosen)?
    Yes. You compile each subsidiary program to a binary as usual, then use spinc to process each subsidiary binary into an include file, then "#include" those include files in your primary program. Then you compile the primary program as usual. That program can be loaded into Hub RAM, or into XMM RAM or EEPROM. It knows how to load the embedded LMM or CMM programs into Hub RAM for execution.

    7. I agree that loading plugins should be restricted to the XMM primary program only.
    Yes. There is no other way to do it, really. It would be too difficult to keep track of when plugins should be loaded or unloaded otherwise.

    8. I assume your Utility will also need to know which plugins will be used so it can determine how many free cogs remain that can be called by _coginit_CMM() or _coginit_LMM()?
    Not really. In most cases you will just say ANY_COG and everything will work as long as there are enough free cogs. The start function will return the cog actually used, in case you need it later.

    9. I anticipate using one cog for the XMM kernel, another for XMM cache, two for the math plugin, and one for the 4-Port serial plugin. Thus leaving only 3 free cogs. The math plugin will be used by the XMM primary program. But I want to leave use of the 4-Port plugin to the CMM/LMM subsidiary program(s) so it/they can perform I/O traffic management to the Console, GPS receiver, and Radio and not burden the XMM primary with that task. The only interaction between the XMM primary and CMM/LMM subsidiary is via elements with the shared Structure. For example, the XMM primary will fill a ConsoleOut string within the Structure, then the CMM/LMM subsidiary will grab this string and output it to the Console. Likewise, the CMM/LMM subsidiary will parse the incoming GPS messages, populate various message strings within the Structure, then the XMM primary will grab these messages for processing.
    Remember thagt you can choose to use two, one or zero cogs for the maths libraries, so you have some flexibility there. The rest sounds ok. Your shared variable structure could have some fields used for input and others used for returning output (or status). You can have all the subsidiary programs sharing the same shared variable, or have a different variable (or even a different structure) for each one.

    10. Would you include something like _cogstop_CMM() or _cogstop_LMM() functions to shut down these cogs? Would cog shutdown fall exclusively under the purview of the XMM primary program, or could a subsidiary CMM/LMM program shut itself down via a _cogstop()?

    You can just stop the cog number that was returned from the start function using the usual _cogstop() function. Or the cog can shut itself down.

    I have tested all the possibilities on the P1 - i.e. I can now have both CMM and LMM programs being executed by CMM, LMM or XMM SMALL or XMM LARGE programs - but now I want to test them on the P2. On the P2 I only currently support the CMM or NATIVE memory models (no XMM yet!), so the only real use-case for it is if you want your primary program to execute in NATIVE mode for speed, with the subsidiary programs compiled as CMM to save code space.

    Ross.

    P.S. While working on this, I noticed a bug in the compilation of the XMM LARGE libraries on the P1! I'll include this fix - and a few other minor fixes - in the next release.
  • Wingineer19Wingineer19 Posts: 175
    edited 2020-05-01 - 04:35:59
    Hi @RossH,

    Thanks for getting this multi-memory capability incorporated into Catalina so quickly. Very impressive. I guess the gin and tonic worked its magic? :smiley:

    I'm fine with waiting for your latest release before giving it a spin (no pun intended).

    I would like to study the examples that you plan on adding to the demos folder, along with your updated documentation, before I dismember my code and parcel out its responsibilities among the XMM primary and CMM subsidiaries.

    I'm pretty confident that one CMM subsidiary will handle all of the I/O traffic for the Console, GPS receiver, and Radio. Communication with these devices will be performed using the 4-Port serial driver. This CMM subsidiary will use a Structure to exchange information with the XMM primary. Structure contents will include a ConsoleOut string, a ConsoleIn string, anywhere from 6 to 8 GPS binary message strings (up to 100 bytes each), a RadioOut string, RadioIn string, and several characters that will serve as notification flags to inform the recipient that fresh data is ready for processing.

    Both the GPS receiver and the Radio will require communication over an I2C port as well to handle command instructions that won't be sent via the UART serial link. There will also be voltage, power, and current sensors on this I2C bus. Most likely, I will need to activate a separate CMM subsidiary to handle this traffic. It will only communicate with the first CMM subsidiary using a different Structure.

    Finally, I may need a third CMM subsidiary to handle some motor control functions.

    However, if there's a way to get a single CMM subsidiary to handle UART traffic management, I2C communication, and motor control, then that's what I'll aim for.

    I look forward to testing this new multi-memory capability.

    But first, I need to revisit my EEPROM Program Loader Utility, upgrade it to support 128-byte programming blocks, and add a much needed read after write verification feature. Then it should be ready to burn the multi-memory code to EEPROM memory.

    For testing and debugging of the code I can use my USB Project Board, then eventually migrate to the FLiP with the external EEPROM/SPI memory module (after I build a new one to replace the one I damaged, of course)…
  • RossHRossH Posts: 4,545
    edited 2020-05-03 - 12:08:11
    Hello @Wingineer19

    I've just uploaded a Windows-only release candidate of Catalina 4.1, which includes the new Multi-Memory Model support (for the Propeller 1 only at this stage). Anyone who wants to try it out and give feedback here is welcome to do so.

    It is available here - https://sourceforge.net/projects/catalina-c/files/releases/4.1_RC1/Catalina_4.1_RC1_Setup.exe/download

    Here is the README.WhatsNew file:
    Catalina release 4.1 is a full release. You can install this over an 
    existing version of Catalina, but it is recommended that you instead uninstall 
    any previous Catalina release before installing, or install this release to a 
    different location. 
    
    If you are installing under Linux, you should execute the following command 
    to set your permissions correctly after installing (this command is a script 
    in the Catalina bin directory):
    
       Set_Linux_Permissions
    
    The following changes have been made since the previous release of Catalina. 
    If you have not used a previous release of Catalina, you can ignore the
    following list:
    
    RELEASE 4.1
    
    1. Fixed a bug in the Makefiles for compiling the XMM LARGE libraries. Some 
       library functions were being compiled as XMM SMALL, not XMM LARGE.
    
    2. Added a new option (-B) to the spinc utility, for producing blobs from a
       Catalina C binary file. This option accepts a parameter to specify the 
       object, but for Catalina Propeller 1 programs this is generally the second
       object, so it is normally specified as -B2. The existing command-line 
       options -c, -f, -s, -l and -n are also supported for blobs, and the -c 
       option would normally be specified to generate a callable function that 
       can be used to execute the blob as a C program. The -s option can be used
       to specify the runtime space (stack and heap) required. If not specified, 
       then 80 bytes (20 longs) is used, which is sufficient for small programs.
       The output is usually redirected to a header file, which is suitable for
       inclusion in another program. For example:
    
          spinc hello_world.binary -B2 > hello_blob.inc
    
          spinc hello_world.binary -B2 -c -s 1024 > hello_blob.inc
    
    3. Fixed a bug in catalina that meant the -M memory size option (previously
       used mainly when compiling EEPROM programs, but now also useful when 
       generating blobs) was not being specified correctly. This could result
       in the compilation failing.
    
    4. Modified the Catalina -M, -P and -R options to accept hex values as well
       as decimals. A hex value must be preceeded by $ or 0x - e.g. $ABCD or
       0xFFFF. Note that these options also ccepted modifiers - i.e. m or k 
       (or M or K) when using decimal values, but these are not supported for
       hexadecimal values. Examples of acceptable parameter values are:
    
          -M 16k     (or -M16k)
          -M 16384   (or -M16384)
          -M 0x2000  (or -M0x2000)
          -M $2000   (or -M$2000)
          -P 1m      (or -P1m)
          -P 1048576 (or -P1048576)
          -P 0x1000  (or -P0x1000) 
          -P $1000   (or -P$1000)
          -R 8K      (or -R8K)
          -R 8192    (or -R8192)
          -R 0X3000  (or -R0X3000)
          -R $3000   (or -R$3000)
    
       This can be useful when generating blobs that must execute at a specific
       nominated Hub RAM location. Generating a blob is done just by specifying
       the address of the read-only (code and initialized data segments) to a 
       specific value (i.e. using the -R option). The read-write segments will
       follow immediately, and so the -P option does not usually need to be used.
       For example, to generate a version of hello_world that executes at Hub
       RAM location 6000 (hex):
    
          catalina -R 0x6000 -lci hello_world.c
    
       Note that it is the users responsibility to ensure that there is sufficient
       space for the program code and data, and that this does not overlap with 
       the reserved areas in the upper Hub RAM. The amount of reseved space varies
       depending on the memory model, plugins and loader options used, so it is
       recommended that the program itself determine (and check!) this location 
       at run-tine. Examples of how to do this are provided (see the directory 
       demos\multimodel). 
    
    5. Added _cogstart_C (and _cogstart_C_cog) to the P1 libraries, which are 
       compatible with the same functions on the P2 (previously the P1 had only 
       _coginit_C, but the P2 had both _coginit_C and _cogstart_C). 
    
       The difference between _cogstart_C and _coginit_C is that _cogstart_C 
       accepts a parameter, which is passed to the function being started.  
       For backward compatibility, _coginint_C (and also _coginit_C_cog) can 
       still be used if no parameter is required, and _cogstart_C (and also 
       _cogstart_C_cog) can be used where a parameter is required.
    
    6. Added new functions for starting subsidiary programs from within a
       primary program:
    
          _cogstart_CMM()     - start a blob as a CMM program on any available cog
          _cogstart_CMM_cog() - start a blob as a CMM program on a specific cog
          _cogstart_LMM()     - start a blob as an LMM program on any available cog
          _cogstart_LMM_cog() - start a blob as an LMM program on a specific cog
    
       However, note that the functions do not generally need to be called
       directly - when generating a blob that represents a dynamically
       loadable program, the spinc utility can also generate a function
       to start this program, which knows all the program details.
    
    7. Modified the LMM and CMM dynamic kernels to initialize R2, assuming
       this value is passed in. This allows _cogstart_C (and _cogstart_C_cog)
       to be implemented on the P1 the same way it is implemented on the P2, 
       and also allows _cogstart_CMM and _cogstart_LMM to accept the address
       of the shared variable.
    
    8. Allow the -M option to be passed to the assembler when compiling CMM or
       LMM programs (previously, it was only supported for EMM, SMM, XMM etc).
       The reason this was not previously allowed is that it is not possible 
       for CMM or LMM programs to be larger than 32k. However, when compiling
       such programs for dynamic loading, it can occur that the program code
       is to be located in upper Hub RAM, in an area that pushes other things 
       normally included after the program code (such as the kernel) over the
       32k limit. So now this option is permitted. But it should only be
       used for LMM or CMM programs when they are being compiled for dynamic 
       loading via the Multi-Memory Model support (see below). Also, there is
       no reason to ever use a value other than 64k for such purposes.
    
    9. Added a new symbol for the Parallax FLiP Module. The FLiP Module has no
       special configuration options, but in case a user chooses to modify the
       Custom platform, when compiling programs for the FLiP Module the symbol
       FLIP can now be specified on the Catalina command line. For example:
    
          catalina hello_world.c -lci -C FLIP
    
       Note that the symbol used is FLIP, not FLiP! By convention, all Catalina
       symbols are all upper-case.
    
    10. Fixed a minor bug in the dynamic CMM kernel, which was not registering 
        itself properly on startup. 
    
    11. Fixed a problem with spinc on Linux that may have led to a segmentation
        fault when used on some binaries.
    
    12. Added Multi-Memory Model (MMM) support. See the separate section below.
    
    Multi-Memory Model (MMM) support.
    =================================
    
    MMM is new for Catalina 4.1. It allows the Propeller to simulataneously execute 
    LMM, CMM and XMM Catalina programs. Each program is executed on a separate cog,
    and essentially runs independently. However, all programs share the same 
    registry and all programs can use any of the loaded plugins. MMM Support is
    slightly different on the Propeller 1 and the Propeller 2.
    
    There is only one program binary, which contains all the programs. When this 
    binary is loaded and started, it starts the "primary" program, which must then
    explicitly start each of the "subsidiary" programs, which are stored in the 
    memory space of the primary program, and only loaded into Hub RAM when they
    are to be executed. For this reason, MMM is generally most useful when the
    primary program is an XMM (SMALL or LARGE) program, otherwise it would be 
    very wasteful of Hub RAM.
    
    Each subsidiary program can share a variable with the primary program - this 
    variable can either be a simple variable or a structure, if a single variable 
    is not sufficient. Each subsidiary program can use a different variable, or 
    they can all use the same variable.
    
    The compilation process for MMM requires that each subsidiary program be
    compiled first, as either a TINY (LMM) or COMPACT (CMM) program, with all 
    the usual command-line options, plus the following additional options:
    
       -R XXXXXX -C NO_ARGS -M64k 
    
    A binary file must be generated for each subsidiary program. However, this 
    binary is not used directly - it must be processed for inclusion in the 
    binary file of the main program by an updated version of the spinc utility.
     
    The XXXXXX value represents the address at which the subsidiary program is to 
    be loaded for execution, and must be determined according to the size of 
    each subsidiary program, its run-time space requirements, and also by the 
    necessity to not interfere with the reserved memory at the top of Hub RAM - 
    i.e. the registry, cache, plugin data etc. This value may have to be 
    established partly by trial and error, but it can be done by reserving a 
    suitable amount of Hub RAM as a local variable in the main function of the
    primary program, determining where that Hub RAM address is, then using that
    value. An example of doing this is provided in the Multi-Memory Model
    demo programs.
    
    The -C NO_ARGS is required to disable the usual C command-line argument
    processing in the subsidiary program (but not the primary program). 
    Command-line arguments are not supported for programs that are  to be
    dynamically loaded, and it would also interfere with the passing of the 
    parameter that specifies the shared variable address from the primary 
    program to the subsidiary program. 
    
    On the Propeller 1, the -M64k option may be required to allow CMM or LMM 
    code to be compiled in areas of upper Hub RAM that would not normally be 
    allowed for program code. Without this option, specifying a -R option in 
    high Hub RAM can make the LMM or CMM binary size exceed the usual 32k 
    limit - which is not normally supported for LMM or CMM programs on the 
    Propeller 1, but may be required for programs that are to be dynamically 
    loaded. There is no problem in simply always including this option when 
    compiling programs intended to be dynamically loaded on the Propeller 1.
    
    To run MULTIPLE subsidiares simultaneously, you must calculate a different 
    value of XXXXXX for each subsidiary, and ensure they will not overlap when 
    loaded. The runtime size of each subsidiary can be determined as 
    described below.
    
    Each subsidiary program must be compiled, and then turned into a "blob" (i.e.
    a "binary large object", or "binary loadable object") for inclusion in the 
    primary program. 
    
    Producing a blob on the Propeller 1:
    ====================================
    
    On the Propeller 1, this is done using an updated version of the "spinc" 
    utility, using a new command-line option (-B):
    
       spinc -B2 -c subsidiary_1.binary >blob_1.inc
       spinc -B2 -c subsidiary_2.binary >blob_2.inc
    
         (etc)
    
    The new option (-B) specifies that a blob is to be created from one of the
    objects in the binary. It accepts a parameter to specify the object number,
    which (for Catalina binaries) should generally be the SECOND object within 
    the binary. For Catalina binaries the second object will be Catalina.spin - 
    i.e. the object produced by the Catalina compiler from the C source code. 
    So this option should (currently) always be specified as -B2.
    
    The -c option specifies that a function will be generated, suitable for
    starting the C program from within the main program. The name used for the
    function will be the name of the binary (i.e. "start_<<binary file name>>").
    This can be overridden using the -n option if required (for instance, if you
    are generating multiple loadable programs from the same binary). So, for
    example, if your binary file name is hello_world.binary, the start program
    generated would be:
    
       int start_hello_world(void* var_addr, int cog)
    
    This function accepts the address of a shared variable, and a cog number
    on which the subsidiary program will be run (which can be the special 
    constant ANY_COG). The function will return the actual cog number used, 
    which can be used later to stop the subsidiary program. 
    
    If the object cannot be found, or does not have the correct type (it must be 
    an LMM or CMM object) then an error message will be issued. Additional
    runtime space to be allocated for the blob can be specified using the -s 
    option. If no size is specified, 80 bytes (20 longs) is the default. 
    For example, to instead specify run-time space of 200 bytes (50 longs):
    
       spinc -B 2 -s 200 -n my_blob subsidiary.binary >blob.inc
    
    As shown above, the -n option can be used to specify a name for the 
    subsidiary, otherwise the binary file name is used. This name will be
    used for the start function, the blob itself, and all the constants 
    defined for the blob. The output is a C source file, suitable for 
    inclusion in the primary program.
    
    This process must be repeated for each subsidiary program (each one 
    must have a unique name, even if the same binary is used to create them).
    
    For examples of producing and loading blobs, see the demos\multimodel
    directory.
    
    Producing a blob on the Propeller 2:
    ====================================
    
    TBD!
    
    
  • @RossH Is there a release of Catalina for the Mac?
  • David Betz wrote: »
    @RossH Is there a release of Catalina for the Mac?

    Hi David

    The Linux version used to also compile and run on a Mac, but I no longer have even a virtual Mac so I haven't bothered testing that for quite a few releases.

    Ross.
  • RossH wrote: »
    David Betz wrote: »
    @RossH Is there a release of Catalina for the Mac?

    Hi David

    The Linux version used to also compile and run on a Mac, but I no longer have even a virtual Mac so I haven't bothered testing that for quite a few releases.

    Ross.
    Where can I find the source code? I followed the link in your signature but I think I only found executables.

  • Hi @David Betz

    All the source code is always included in every distribution (Windows or Linux), but I haven't posted a Linux version of 4.1 RC1 yet.

    You can find the Linux version of 4.0 here - https://sourceforge.net/projects/catalina-c/files/releases/4.0/Catalina_4.0_Linux.tar.gz/download

    See the README.Linux file for some (fairly rudimentary) instructions on how to build it under Linux. The same build scripts and Makefiles worked on the Mac a few years ago, but I don't know about now - there have been lots of changes since.

    Ross.
  • RossH wrote: »
    Hi @David Betz

    All the source code is always included in every distribution (Windows or Linux), but I haven't posted a Linux version of 4.1 RC1 yet.

    You can find the Linux version of 4.0 here - https://sourceforge.net/projects/catalina-c/files/releases/4.0/Catalina_4.0_Linux.tar.gz/download

    See the README.Linux file for some (fairly rudimentary) instructions on how to build it under Linux. The same build scripts and Makefiles worked on the Mac a few years ago, but I don't know about now - there have been lots of changes since.

    Ross.
    Thanks! I forgot that you include the source in the distribution files. I was looking for a GitHub repository or something like that. I'll download the Linux version and try building it.

  • I tried building Catalina on the Mac and it worked to some extent but for some reason Mac OS X doesn't think it's safe to run the generated binaries. I'm surprised because I use the same tools to build fastspin and it has never complained about running those binaries. I'll have to look at this further at a later time.
  • Hi @RossH,

    Well I started dismembering my code and placing pieces of it into a Subsidiary program. Here's the sample I'm working with:
    //Subsidiary Is GpsMsgs.c
    //Last Revision On 4 May 20
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <stdarg.h>
    #include <math.h>
    #include <string.h>
    #include <time.h>
    #include <propeller.h>
    #include <catalina_rtc.h>
    #include <catalina_serial4.h>
    
    #define     GpsPort                     1
    
    char NmeaStr[200];
    
    struct UBX_RXD_HDR
    {
     unsigned   short              MsgLen;
     unsigned   char               Sync1;                
     unsigned   char               Sync2;                
     unsigned   char               MsgClass;             
     unsigned   char               MsgId;                
     unsigned   short              PayLen;               
    };
    
    struct UBX_NAV_ECEF
    {
       struct   UBX_RXD_HDR        Header;
     unsigned   int                GpsMilliSec;
       signed   int                iEcefX;
       signed   int                iEcefY;
       signed   int                iEcefZ;
     unsigned   int                iPosAcc;
     unsigned   char               ChkA;
     unsigned   char               ChkB;
    };
    
    struct UBX_NAV_LLA             
    {
       struct   UBX_RXD_HDR        Header;
     unsigned   int                GpsMilliSec;
       signed   int                iLon;
       signed   int                iLat;
       signed   int                iAlt;
       signed   int                iMsl;
     unsigned   int                iHorAcc;
     unsigned   int                iVerAcc;
     unsigned   char               ChkA;
     unsigned   char               ChkB;
    };
    
    struct UBX_NAV_VELNED
    {
       struct   UBX_RXD_HDR        Header;
     unsigned   int                GpsMilliSec;
       signed   int                iVelN;
       signed   int                iVelE;
       signed   int                iVelD;
     unsigned   int                iVelocity;
     unsigned   int                iSpeed;
       signed   int                iHeading;
     unsigned   int                iSpeedAcc;
     unsigned   int                iCourseAcc;
     unsigned   char               ChkA;
     unsigned   char               ChkB;
    };
    
    typedef struct
    {
     struct   UBX_RXD_HDR        Header;
     struct   UBX_NAV_ECEF       PosRaw;            // Msg 0x01
     struct   UBX_NAV_LLA        LLARaw;            // Msg 0x02
     struct   UBX_NAV_VELNED     NedRaw;            // Msg 0x12
    }MsgUbx;
    
    void GetNmeaData(char GpsRxD)
    {
     static unsigned char Index=0;
     switch(GpsRxD)
      {
       default:    NmeaStr[Index++]=GpsRxD;
                   if(Index > 199) Index=0;
                   NmeaStr[Index]=0x00;
                   switch(Index)
                    {
                     default: if(NmeaStr[0] != '$') Index=0;
                              break;
                     case 2:  if(NmeaStr[1] == 'G') break;
                              if(NmeaStr[1] == 'E') break;
                              Index=0;
                              break;
                     case 3:  if(NmeaStr[2] == 'N') break;
                              if(NmeaStr[2] == 'P') break;
                              if(NmeaStr[2] == 'I') break;
                              Index=0;
                              break;
                     case 4:  if(NmeaStr[3] == 'D') break;
                              if(NmeaStr[3] == 'G') break;
                              if(NmeaStr[3] == 'R') break;
                              if(NmeaStr[3] == 'T') break;
                              if(NmeaStr[3] == 'V') break;
                              if(NmeaStr[3] == 'Z') break;
                              Index=0;
                              break;
                     case 5:  if(NmeaStr[4] == 'B') break;
                              if(NmeaStr[4] == 'D') break;
                              if(NmeaStr[4] == 'G') break;
                              if(NmeaStr[4] == 'L') break;
                              if(NmeaStr[4] == 'M') break;
                              if(NmeaStr[4] == 'N') break;
                              if(NmeaStr[4] == 'P') break;
                              if(NmeaStr[4] == 'R') break;
                              if(NmeaStr[4] == 'S') break;
                              if(NmeaStr[4] == 'T') break;
                              if(NmeaStr[4] == 'X') break;
                              Index=0;
                     case 6:  if(NmeaStr[5] == 'A') break;
                              if(NmeaStr[5] == 'C') break;
                              if(NmeaStr[5] == 'G') break;
                              if(NmeaStr[5] == 'L') break;
                              if(NmeaStr[5] == 'M') break;
                              if(NmeaStr[5] == 'Q') break;
                              if(NmeaStr[5] == 'S') break;
                              if(NmeaStr[5] == 'T') break;
                              if(NmeaStr[5] == 'V') break;
                              if(NmeaStr[5] == 'W') break;
                              Index=0;
                              break;
                    }
                   break;
       case '\r':  break;
       case '\n':  if(Index < 10) break;
                   Index=0;
                   break;
      }
    }
    
    void main(MsgUbx *UbxMsg)
    {
     int GpsRxDKey=1;
     char GpsRxD;
     for(;;)
      {
       GpsRxDKey=s4_rxcheck(GpsPort);
       if(GpsRxDKey > 0)
        {
         GpsRxD=(char) GpsRxDKey;
         GetNmeaData(GpsRxD);
        }
       }
    }
    
    This code will require use of the 4-Port Serial Driver. I've reviewed Extras.Spin to verify I have it configured correctly, and it appears OK unless there's something I missed:
    {{
    '-------------------------------------------------------------------------------
    '
    ' Extras - This object is loaded by all target files, and can be used to 
    '          include extra platform dependent plugins for all targets (this
    '          avoids the need to edit multiple target files). 
    '
    '          It currently includes the Catalina Gamepad and 4 port serial plugins.
    '          These plugins could also have been loaded and started directly in 
    '          the target files themselves (as is done for other plugins supplied 
    '          with Catalina) - but it is done here as an example. 
    '
    '          Note that the association between the GAMEPAD symbol and the 
    '          inclusion of the Gamepad plugin is only known in this file. This is 
    '          what allows the Gamepad plugin to be included by using a command 
    '          such as:
    '
    '             catalina test_gamepad.c -lci -C GAMEPAD
    '
    '          The 4 port serial plugin uses a slightly different method - this
    '          plugin is enabled by including the access library - e.g:
    '
    '             catalina test_serial4.c -lci -lserial4
    '
    '          Two variations of the "Full Duplex Serial" plugin are enabled in 
    '          a similar manner - e.g:
    '
    '             catalina test_tty.c -lci -ltty
    '             catalina test_tty.c -lci -ltty256
    '
    '
    ' This file is included by the following target files:
    '
    '   lmm_default.spin
    '   emm_default.spin
    '   smm_default.spin
    '   xmm_default.spin
    '   lmm_blackcat.spin
    '   emm_blackcat.spin
    '   smm_blackcat.spin
    '   xmm_blackcat.spin
    '   Catalina_LMM_pod.spin
    '
    ' Version 3.1 - Initial Version by Ross Higson
    ' Version 3.5 - Add 4 port serial plugin (S4)
    ' Version 3.6 - Add Full Duplex serial plugin (TTY)
    ' Version 3.8 - Add Virtual Graphics
    ' Version 3.9 - Add Sound
    ' Version 3.11 - Add padding (used for Catalyst only).
    '
    '-------------------------------------------------------------------------------
    '
    '    Copyright 2011 Ross Higson
    '
    '    This file is part of the Catalina Target Package.
    '
    '    The Catalina Target Package is free software: you can redistribute 
    '    it and/or modify it under the terms of the GNU Lesser General Public 
    '    License as published by the Free Software Foundation, either version 
    '    3 of the License, or (at your option) any later version.
    '
    '    The Catalina Target Package is distributed in the hope that it will
    '    be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
    '    of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
    '    See the GNU Lesser General Public License for more details.
    '
    '    You should have received a copy of the GNU Lesser General Public 
    '    License along with the Catalina Target Package.  If not, see 
    '    <http://www.gnu.org/licenses/>.
    '
    '------------------------------------------------------------------------------
    }}
    
    #ifdef CATALYST
    '
    ' This Padding ensure that when Catalyst is compiled, there is enough
    ' space below the HMI plugin to use for HMI buffer space - a total of 660
    ' longs is enough to allow every HMI option except HiRes VGA. However, if
    ' the minimal set of plugins is loaded, we are still around 40 longs short,
    ' so we add that many longs here. Note that Catalyst must be compiled in
    ' COMPACT mode - the cmm_default.spin file has had the startup sequence
    ' altered to include this Extras object just before the HMI object, and
    ' to setup and start the HMI plugin LAST, allowing it to use space that
    ' was formerly occupied by other spin objects to be re-used by the HMI.
    '
    DAT
    
    Padding long 0[40]
    
    #endif
    
    OBJ
      Common : "Catalina_Common"
    
    '
    ' Select the appropriate plugin objects:
    '
    
    #ifdef GAMEPAD
      GP : "Catalina_GamePad"
    #endif
    '
    #ifdef libserial4
      S4 : "Catalina_FullDuplexSerial4FC"
    #endif
    '
    #ifdef libtty
      TTY : "Catalina_FullDuplexSerial"
    #endif
    '
    #ifdef libtty256
      TTY : "Catalina_FullDuplexSerial256"
    #endif
    '
    #ifdef libvgraphics
      VGI : "Virtual_Graphics"
    #endif
    '
    #ifdef libspi
      SPI : "Catalina_sdspiFemto"
    #endif
    '
    #ifdef libsound
      SND : "Catalina_Sound_drv_052_22khz_16bit"
    #endif
    '
    '
    ' This function is called by the target to allocate data blocks or set up 
    ' other details for the extra plugins. If it does not need to do anything
    ' it can simply be a null routine.
    '   
    PUB Setup
    #ifdef GAMEPAD
      GP.Setup
    #endif
    '
    #ifdef libserial4
      S4.Setup
    
      ' Edit the following AddPort statements to suit your Propeller platform.
      ' By default, they add a single serial port, at 115200 baud, usng the 
      ' normal Parallax serial pins (30 & 31):
    
      S4.AddPort(0,31,30,-1,-1,0,0,115200)
      S4.AddPort(1,17,16,-1,-1,0,0,9600)
      'S4.AddPort(1,17,16,-1,-1,0,0,115200)
      'S4.AddPort(2,15,14,-1,-1,0,0,115200)
      'S4.AddPort(3,13,12,-1,-1,0,0,115200)
      'S4.AddPort(0,rx,tx,cts,rts,threshold,mode,baud)
      'S4.AddPort(1,rx,tx,cts,rts,threshold,mode,baud)
      'S4.AddPort(2,rx,tx,cts,rts,threshold,mode,baud)
      'S4.AddPort(3,rx,tx,cts,rts,threshold,mode,baud)
    #endif
    '
    #ifdef libtty
      TTY.Setup
    
      ' Edit the following Configure statement to suit your Propeller platform.
      ' By default, it configures the serial port at 115200 baud, usng the 
      ' normal Parallax serial pins (30 & 31):
    
      TTY.Configure(31,30,0,115200)
    #endif
    '
    #ifdef libtty256
      TTY.Setup
    
      ' Edit the following Configure statement to suit your Propeller platform.
      ' By default, it configures the serial port at 115200 baud, usng the 
      ' normal Parallax serial pins (30 & 31):
    
      TTY.Configure(31,30,0,115200)
    #endif
    '
    #ifdef libvgraphics
      VGI.Setup
    #endif
    '
    #ifdef libspi
      SPI.Setup
    #endif
    '
    #ifdef libsound
      SND.Setup
      SND.Configure(Common#Sound_PIN)
    '
    #endif
    '
    ' This function will be called by the targets to start the plugins:
    '
    PUB Start
    #ifdef GAMEPAD
      GP.Start
    #endif
    '
    #ifdef libserial4
      S4.Start
    #endif
    '
    #ifdef libtty
      TTY.Start
    #endif
    '
    #ifdef libtty256
      TTY.Start
    #endif
    '
    #ifdef libvgraphics
      VGI.Start
    #endif
    '
    #ifdef libspi
      SPI.Start
    #endif
    '
    #ifdef libsound
      SND.Start
    #endif
    '
    
    I normally don't use the command console to compile programs since Code::Blocks has been so convenient. So, I might have the wrong compile parameters on the command line.
    Now when I attempt to compile the GpsMsgs.c program as a subsidiary, I get this:
    4Serial.jpg
    However, if I comment out GpsRxDKey=s4_rxcheck(GpsPort) like this:
    void main(MsgUbx *UbxMsg)
    {
     int GpsRxDKey=1;
     char GpsRxD;
     for(;;)
      {
       //GpsRxDKey=s4_rxcheck(GpsPort);
       if(GpsRxDKey > 0)
        {
         GpsRxD=(char) GpsRxDKey;
         GetNmeaData(GpsRxD);
        }
       }
    }
    
    And then invoke the compiler again, I get this:
    NoSerial.jpg
    Any idea what is going on with the 4-Port function call?
    738 x 206 - 23K
    737 x 246 - 24K
  • David Betz wrote: »
    I tried building Catalina on the Mac and it worked to some extent but for some reason Mac OS X doesn't think it's safe to run the generated binaries. I'm surprised because I use the same tools to build fastspin and it has never complained about running those binaries. I'll have to look at this further at a later time.

    Yes, I remember I had that problem. Unfortunately, I can't remember the solution :(
  • RossH wrote: »
    David Betz wrote: »
    I tried building Catalina on the Mac and it worked to some extent but for some reason Mac OS X doesn't think it's safe to run the generated binaries. I'm surprised because I use the same tools to build fastspin and it has never complained about running those binaries. I'll have to look at this further at a later time.

    Yes, I remember I had that problem. Unfortunately, I can't remember the solution :(
    Probably the solution has changed since last time anyway. Both Microsoft and Apple continue to tighten up their security measures. I just find it odd that I can run fastspin, openspin, loadp2, and the entire propgcc toolchain and my own BASIC interpreter but not Catalina. They are all compiled with the same version of Xcode.

  • "Security measures", more like they're having a sweet deal with those companies that rip you off on a code signing certificate :wink:
  • Wuerfel_21 wrote: »
    "Security measures", more like they're having a sweet deal with those companies that rip you off on a code signing certificate :wink:
    I really doubt they make much money on the signing certificates. That sounds like a conspiracy theory. :smile:
  • Hi @RossH,

    Any idea what is going on with the 4-Port function call?

    The library options you should use are -lserial4 and -lc not -Clibserial4 or -Clibc - the options you are using just define symbols, without actually linking with the libraries. They should not really be used on the command line.

    Ross.
  • RossH wrote: »

    The library options you should use are -lserial4 and -lc not -Clibserial4 or -Clibc - the options you are using just define symbols, without actually linking with the libraries. They should not really be used on the command line.

    Ross.

    Of course! Thanks for catching that. It compiles fine now.

    I guess I really got pampered by using Code::Blocks and letting it insert the correct library and plugin switches prior to invoking the compiler.

    I've used it exclusively up to now to compile my Catalina code, but to the detriment of actually learning and using the proper switches when compiling directly from the command line. :blush:

  • RossH wrote: »

    The library options you should use are -lserial4 and -lc not -Clibserial4 or -Clibc - the options you are using just define symbols, without actually linking with the libraries. They should not really be used on the command line.

    Ross.

    Of course! Thanks for catching that. It compiles fine now.

    I guess I really got pampered by using Code::Blocks and letting it insert the correct library and plugin switches prior to invoking the compiler.

    I've used it exclusively up to now to compile my Catalina code, but to the detriment of actually learning and using the proper switches when compiling directly from the command line. :blush:

    I had a quick go at trying to get Code::Blocks to compile my demo primary and subsidiary programs, but it turned out to be not so easy. Code::Blocks assumes there is only one binary in each project. If your project has multiple binaries you must create multiple projects in the same workspace - but there is no way to tell it that one project depends on another, so you pretty much end up having to compile the thing manually to get the order correct anyway :(

    I'll have another go before I do the final release. I know Code::Blocks can use a custom makefile, but that seems a bit silly - all you are using Code::Blocks for in that case is as a fancy text editor!

  • Eric has a code certificate so that could be why fastspin and loadp2 work.
  • Cluso99 wrote: »
    Eric has a code certificate so that could be why fastspin and loadp2 work.

    Yes, that might have been it. I seem to remember the solution involved spending money, which seemed to spoil the point of using free software development tools!
  • RossHRossH Posts: 4,545
    edited 2020-05-06 - 05:25:17
    RossH wrote: »
    If your project has multiple binaries you must create multiple projects in the same workspace - but there is no way to tell it that one project depends on another ...

    Turns out I was wrong - you can specify dependencies between projects in Code::Blocks - I never thought to actually look this up! So I will include Code::Blocks projects for the multi-model demos in the full release.
  • Hi @RossH,

    I've trimmed down one of your Multi-Memory examples to help me grasp what it's doing.

    Essentially the "primary.c" program only calls a single subsidiary "subsidiary_1.c". Both are now configured as CMM programs.

    Both compiled fine, but upon execution, the Primary program is showing that the Subsidiary always responds with a "1", regardless of what input value was provided to it. According to the Subsidiary code, it's supposed to return the square of the input.

    I've attached the program components below for your review.

    Also, note that in the "primary.c" code, I've added but then commented out a new variable called "shareptr" which is set to the address of the shared structure.

    I hope this will be acceptable, because in my GPS Project, the Primary main() function will need to pass this pointer to various functions that it calls in order to manipulate and display the data within the shared structure.

    Ditto for the Subsidiary main() function. This main() function will call several other functions to parse, process, reformat, and store the streaming data from the GPS receiver into the shared structure. The only way I know to do this is to pass the pointer that main() received over to these other functions so they can access the structure.

    Within your "primary.c" program you've included a subsidiary memory check feature to verify that the "subsidiary_1.c" program was indeed loaded into the proper location in HubRam. The results of this check are then output to the Console (i.e. default UART port).

    This approach will create a problem in my GPS Project because I'm using the 4-Port serial driver, and the CduPrint() function is contained within the Subsidiary Program, not the Primary Program. So if there's a memory check problem, I will never get a response on the Console port.

    What is the Memory Map of HubRam?

    What location boundaries are acceptable to contain the Subsidiary program?

    Is there any way to compile the Subsidiary program to some default memory location, then have the compiler automatically reposition it to the proper memory location when compiling the Primary program in order to avoid the "hit and miss" approach mentioned above at runtime (and thus requiring a Console port to see the results?)

    Finally, what is the maximum memory size allowed for a single CMM Subsidiary Program if I have it configured to use the 4-Port UART driver and the RTC driver, and the Primary Program is using 8K of cache while operating in the LARGE Memory Model?
Sign In or Register to comment.