Quick char* question..

Working on a c port project. I have a LOT of blocks like these..

prouts((char*)"---WORKING---"); skip(1);
prout((char*)"SELF-DESTRUCT-SEQUENCE-ACTIVATED");
prouts((char*)"   10"); skip(1);
prouts((char*)"       9"); skip(1);
prouts((char*)"          8"); skip(1);
prouts((char*)"             7"); skip(1);
prouts((char*)"                6"); skip(1);
prout((char*)"ENTER-CORRECT-PASSWORD-TO-CONTINUE-");
prout((char*)"SELF-DESTRUCT-SEQUENCE-OTHERWISE-");
prout((char*)"SELF-DESTRUCT-SEQUENCE-WILL-BE-ABORTED");

c strings hard coded as function calls. The question is : If a function has a bunch of these.. Are they loading into RAM? Or, being literal strings, into program memory until called?

I'm beginning to think that, seeing one function has literally pages of this stuff. My crashing issue is probably running out of RAM.

-jim lee

They are stored in program memory and then copied to RAM during initialisation.
You can store them only in PROGMEM with the F macro, but then you will need overrides of your library functions to access them correctly.

I'm running 98%-99% of the program memory already. I don't dare use the F macro on this thing.

Its a giant switch statement that has a bunch of text messages. I think the entire thing is going into RAM at one time when this function is called. My thought was to break it into a bunch of smaller "message" calls. So they are only loaded in one message at a time when needed.

Thanks for the answer.

-jim lee

jimLee:
I'm running 98%-99% of the program memory already. I don't dare use the F macro on this thing.

well it's in flash AND in RAM at the moment, so it won't make things worse.

I'd go flash only and use the F() macro or PROGMEM...

You could modify prouts() so that it takes a PROGMEM pointer instead of a (char*). (which I assume the author added in front of the cString because they declared the prouts() function with a (char*) and not a (const char*) and were getting compiler warnings).

jimLee:
I'm running 98%-99% of the program memory already. I don't dare use the F macro on this thing.

The strings are already stored in program memory, but not in a way that you can access them. As stated in reply #1, they are copied into RAM as part of the initialization, before your code is run. That is how the values of all initialized variables are set. Use of the F() macro would not use any additional program memory for storage of the string, unless the string is an exact duplicate of another. Normally the compiler looks for identical string literals, and only stores a single copy of the string, but that is not done when using the F() macro, so it is advisable to search for duplicates and handle the progmem storage yourself.

The code you posted has some text that is rather repetitive, you could save a bit of memory by printing "SELF-DESTRUCT-SEQUENCE-" separately from the text that follows it (if that is what prout() does). Also the cast to (char *) does not seem necessary, a string literal would pass a const char *, easier to modify the function to accept the const if you are trying to suppress the compiler warnings for an invalid conversion from const char * to char *.

You could modify prouts() so that it takes a PROGMEM pointer instead of a (char*).

That would be a __FlashStringHelper* in the case of the F() macro. Better to overload the function and retain the original that takes char* in case it is needed in other parts of the code, although I would change to const char* which will accept a char* that is not const without generating a compiler warning.

That would be a __FlashStringHelper* in the case of the F() macro. Better to overload the function and retain the original that takes char* in case it is needed in other parts of the code, although I would change to const char* which will accept a char* that is not const without generating a compiler warning.

Yes, that would indeed be a __FlashStringHelper*.
indeed if in other parts of the code the parameter is built dynamically in a char array, then it might be good to keep it around and have another version of that function with a different signature. if it's not the case though, getting rid of it won't hurt (the linker would anyway).

Also the strings that code for the countdown could be coded as a loop and printing of an integer. No string storage required.
Of course it will be debatable if the extra code required to do that is more or less than the string storage required.

I hope while you are hacking this you’ve at a minimum disconnected the red wire from the explosive device…

a7

F Macro is the answer - it won't cost you any more progmem and it will save RAM.

In that particular instance, you can probably also save a bit by refactoring the strings.

This:

prout((char*)"SELF-DESTRUCT-SEQUENCE-ACTIVATED");

Could be:

prout((char*)"SELF-DESTRUCT-SEQUENCE-");
prout((char*)"ACTIVATED");

And the same for similar messages below. I think the compiler will then only maintain one copy of "SELF-DESTRUCT-SEQUENCE-".

I don't know how you emit text, but you can probably get rid of prout too. All it did when I was messing with it is call Serial.print.

wildbill:
F Macro is the answer - it won't cost you any more progmem and it will save RAM.

In that particular instance, you can probably also save a bit by refactoring the strings.

This:

prout((char*)"SELF-DESTRUCT-SEQUENCE-ACTIVATED");

Could be:

prout((char*)"SELF-DESTRUCT-SEQUENCE-");

prout((char*)"ACTIVATED");




And the same for similar messages below. **[u]I think the compiler will then only maintain one copy of "SELF-DESTRUCT-SEQUENCE-".[/u]**

I don't know how you emit text, but you can probably get rid of prout too. All it did when I was messing with it is call Serial.print.

Unfortunately the compiler will create a separate copy of "SELF-DESTRUC-SEQUENCE-" each time it is used with the F() macro, that is why I pointed out that you need to save that text in PROGMEM yourself when there are duplicate strings.

david_2018:
Unfortunately the compiler will create a separate copy of "SELF-DESTRUC-SEQUENCE-" each time it is used with the F() macro, that is why I pointed out that you need to save that text in PROGMEM yourself when there are duplicate strings.

It's possible to use the F() macro and have only one copy of a repeated string:

const __FlashStringHelper *selfDestruct;

void setup() {
  selfDestruct = F("SELF-DESTRUCT-SEQUENCE-");

  Serial.begin(115200);
  delay(1000);
}

void loop() {
  Serial.print(selfDestruct);
  Serial.println(F("ACTIVATED"));
  Serial.print(selfDestruct);
  Serial.println(F("OTHERWISE-"));
  Serial.print(selfDestruct);
  Serial.println(F("WILL-BE-ABORTED"));
  Serial.println();
  delay(1000);
}

alto777:
I hope while you are hacking this you’ve at a minimum disconnected the red wire from the explosive device…

a7

Hahah! Yeah, better yet I can never remember passwords so it never goes off.

@wildbill : (He helped my get this running) What I set up was a ring buffer for the input from the keyboard, and another for the output from the game. getChar() now calls my sleep() function while spinning on the input buffer grabbing chars when it can get them. The output goes into my output ring buffer then, when time is available, scrolls through the screen to be discarded.

So far, most everything is working, except certain deaths (hitting black hole) that just locks everything up solid. It looks like in those certain cases finish() is blowing up my RAM.

finish() contains pages of text, like I showed above. My theory was to break this text out into different functions so it was only loaded into RAM as needed. Instead of all at once.

I think if I can get this big spike of RAM usage knocked down… Everything will be fine.

If not? I’ll load it all into the SD card. This setup will always have one available and I already have most of the code to do that ready to go.

-jim lee

I'd try going through finish.cpp and apply the F macro liberally - there's a great deal of text in there as you observe.

There ought to be RAM to save too by replacing int (four bytes on the Teensy) with uint16_t. I did try it in some of the global arrays, but unexpectedly, it actually used more progmem. I suspect it would have helped eventually, but I didn't pursue it.

Haha! I just came back to apologize, this turned out to be, what I hear, is an X-Y problem. I broke out all the text so it would be only loaded piecewise as needed. Not the issue. Its crashing in score(). If I comment out the scoring routine, everything seems to run fine.

I've not looked at all the arrays and things with the horrible names. I'm actually a bit afraid to tackle some of that stuff because its so difficult to figure out what it all is and how it all works.

Do you happen to have any hardware like a touch screen & teensy?

-jim lee

jimLee:
Do you happen to have any hardware like a touch screen & teensy?

Teensy(s) yes. Touch screen - not so much :frowning:

If I sent you the parts, would you like to build one of these handhelds? I feel I owe you one.

-jim lee

jimLee:
If I sent you the parts, would you like to build one of these handhelds? I feel I owe you one.

I did it for the fun of it, so there is nothing owed. If you would like me to help and it needs hardware to make progress, sure, send it to me, but I'll return it to you when we're done.

However, I'd guess that you can get it working just by a few reductions in RAM utilization - there's a bunch of stuff in finish.cpp that can be reduced e.g. all those printf statements using ? : to deal with needing a plural.

Try changing int to short in struct foo in sst.h. It'll save some RAM, as long as it still works.

I tried doing the same in foo2, but it fails because somewhere, there's a conversion from int to int*. Maybe a bug, but I just left it for now.

Forget about all the discussion on PROGMEM, didn't notice you were using a teensy, I don't believe that has separate address spaces for the program memory and ram.

However, I'd guess that you can get it working just by a few reductions in RAM utilization - there's a bunch of stuff in finish.cpp that can be reduced e.g. all those printf statements using ? : to deal with needing a plural.

Had a look at some of your code after noticing the github link in your signature, you could save a lot of memory in the singular/plural output doing something like this, although on the teensy the patterns should not be going into ram to begin with.

    //original code
    printf(kcaptured > 1 ? "%6d Klingons captured                  %5d\n" : "%6d Klingon captured                   %5d\n",
            kcaptured, 3 * kcaptured);
    

    //single pattern
    printf("%6d %-35s%5d\n", kcaptured, kcaptured > 1 ? "Klingons captured" : "Klingon captured", 3 * kcaptured);

Got it working!

@david_2018 : Actually, you hit the problem on the head with your snippet. "printf" was crashing it. But, not in the way you sugested.

The first call to printf() crashed the machine. Switching the printf( ... ) statements to.. sprintf(buf, .... ) statements. Then dumping the buff to the screen did the trick.

I saw that other bits of this code was using the sprintf to a buffer successfully, so I gave it a go.

I've never gotten all that comfortable with the whole format string thing used by printf and it's siblings. So all the different flavors, besides extremely simple, are lost on me.

I still have to reformat the chart stuff to fit on my screen. And then a lot of cleanup. But as far as I can tell it all works now.

-jim lee