Object crashing the axo


#1

Hi,

I'm making a custom object to send text to tiar/HW/OLED128x64nice
I took look at the tiar/HW/strbar object to know what output my object should give to have the same behaviour, but something weird happens. When I send it to line 2 of the display, it is more or less correctly displayed. But whenever I send the same output to either line 1,3 or 4 the axo crashes.

The object that works has a float connector and a string attribute and then creates a string with some bits set so the tiar object knows what to do with it. I tried recreating this, but must be making a mistake somewhere.

original object code:
"Local Data"

char c[2 + strlen("attr_prefix")];

"init code"

strcpy(&c[2], "attr_prefix");
c[0] = 1; //string bar mode

"k-rate code"

int32_t v = __SSAT(inlet_in,28)>>21;
if(v >= 0)
  c[1] = (uint8_t)(v + 1); // must not be zero !
else 
  c[1] = (uint8_t)(256 + v); 
outlet_out = c;

my object code:

    //append int tot str
   char* addItoS(int i, char* s){
	int32_t v = __SSAT(i,28)>>21;
    	char c[2]; /// this shows "amamp" but I want it to display "amp" 
    //	char c[2 + strlen(s)]; /// for some reason this shows "UUUUU" instead of "amamp"
    	c[0] = 1; /// this is needed so the tiar object shows the value v as a bar in the display
    	if(v >= 0)
      		c[1] = (uint8_t)(v + 1); // must not be zero !
    	else 
      		c[1] = (uint8_t)(256 + v); 
    	strcat(&c[2],s);
    	return c;
    }

I call this from K-rate code and a potentiometer is assigned to changing the value, it changes the bar correspondingly in size.

outlet_S1L2 = addItoS(rev_dec_hold,"amp");

this is what happens:

Whenever I use a different screen line the display line becomes garbage and the axo crashes...


#2

The str functions (strlen, strcat, strcpy, etc) expect zero-terminated inputs.


#3

c needs to be one byte longer.
c[0] and c[1] contain data, then comes the string, and at the end there needs to be a zero-byte to mark the end of the string.
strlen() does not count the zero-byte, so c[] is now one byte too short.


#4

Ok, I'm a C noob, but I looked into it.
As far as I understand strcat creates zero-terminated input. How should I add it myself explicitly? like in the code below?

Something else I observed is that if I use strcpy it renders correctly, but is no longer interactive like when I use strcat.
I kept fiddling with it, but I'm stuck.

Other thing that bugs me is that a lot of garbage seems to be added at the end of the string.
I don't see it on the display but if I print it to the console it looks like this:

actually all the output after the first "amp" is all I need.
I then tried making a partial copy using strncpy

char k[5];
strncpy(k,c,5);
k[5] = '\0';
return k;

even adding the terminating zero...
still no luck. What am I doing wrong?


#5

I also noticed that I might not be writing the "amp" to the string correctly as uploading fresh code apparently does not clear the display memory. I have to powercycle the display/axo and that might even complicate things further.


#6

strcat(dst, src) does create a zero-terminated string, BUT dst must already be a zero-terminated string. This is for concatenating - appending a string to another string.

To create a new, zero-terminated string, use strcpy(dst, src);

The strn (strncat, strncpy, etc) functions are more specialized

When you think garbage is being added to the end of the string, most likely cause is that the string isn't zero-terminated.

Also,

char k[5];
strncpy(k,c,5);
k[5] = '\0';

is an error. 'char k[5]' only has indices 0-4.


#7

Ok, I'm getting somewhere. It's a scope problem. I can correctly generate the string I need, but only one instance. Once I move it out of the function, into the "local data" it seems to work. but as soon as I create a second parameter, it just overwrites the first one, leaving me with 2 duplicate lines where there should be two different lines.

the structure I use is

"local data"
char c[10]; /// a full display line length

char* addItoS(int i, char* s){
    int32_t v = __SSAT(i,28)>>21;
    strcpy(&c[2],s);
    c[0] = 1;
    if(v >= 0)
	c[1] = (uint8_t)(v + 1); // must not be zero !
    else 
  	c[1] = (uint8_t)(256 + v);
    return c; 

}

I then call this function twice from
K-rate Code

outlet_S1L2 = addItoS(rev_amp_hold,"amp");
outlet_S1L3 = addItoS(rev_dec_hold,"dec");

resulting in the display correctly showing line 3, but line 2 is the exact same as line 3.

If I move the char c[10]; to the function body, I get garbage and crashes...


#8

Yes, variables created inside a function are only valid until that function returns. Results are undefined if you pass them to another function which tries to access them later, but likely to cause unexpected results.

Sounds to me like you need two buffers, one for each line, defined outside of any function.


#9

Ok, it all works now!
Thanks for the guidance