teensy 3.5 SD card mystery

Status
Not open for further replies.
Hi, I'm a bit clueless at how the problem I have occurs. I'll tell something about the idea and then I'll come to the problem:
I'm building a midi footcontroller with a big display full of information. To be able to freely configure the controller without a computer I've decided to store lots of variables on a SD card.
I have an array of strings (words like "play", "drum 1" and so on). In this array there are also some spaces: " " so the teensy compares if at this position of the array is a word or not. If there is only " " (six space bars) instead of a word the display shows the command of a button in a bank (like CC 74). This worked fantastic until the moment I copied the string array to the SD card, emptied the array in the code and then written the string array back from the SD to the teensy. Everything works good EXCEPT the comparison of strings. So I know for sure that the data has been written to the teensy. The teensy is constantly comparing data and has no problem comparing integers, but even if I write "empty" instead of " " and therefore have a word written there it won't recognise it as "empty".
The code is much to large to be shared here, so I'll write the lines of code I'm using to write to the SD and the ones for writing back and the ones to compare values:
<script src="https://pastebin.com/embed_js/T1RSpTcj"></script>

Maybe its a known thing, and I could add another array to tell if the pedal should take the name from the string array or not, but somehow I think this should work without 181 more variables, cause it did work so without the SD card in the middle...
Well, maybe someone can help... thanks in advance!
 
First guess without easy to follow posted or linked code : C strings are null terminated.

The SD write and read needs to account for that, unless the read knows it was not there and can restore the NULL to the proper location.

If that is the issue it would be an issue in either one or both of the Write and Read processes where the data is transferred.
 
Wow, you are fast! But as usual, I don't understand the answer. ;-) what means null terminated?
Do you mean that my method (I just used a method for integers and it worked) does not say "end of transmition" for every string, so it ends up making much longer ones?
edit: I read a bit about it and yes, I think thats the point. BUT what I couldn't find is a good example of how to write and/or read Strings to/from the SD Card and defining this end of transmition other than with the " " signs, witch Ive been using.
 
This shows an example with some details if not seen before :: tutorialspoint.com/cprogramming/c_strings.htm

There are probably better more informative links?

NULL is Zero. A 'c' defined string is a series of char elements where the string can be any value 1-255, but is defined as ended by Zero or Null.

It may not apply to your situation as I didn't look at the linked code pastebin.com/embed_js/T1RSpTcj

But it seems to - - the link above was put in with Ctrl+L or the Globe + Link icon on the toolbar. '<script>' doesn't work here.

So that wasn't much code at all copied below - using the "#" icon;

This would print the entirety of the buttonName[] - with EACH character followed by a '\n':
Code:
    for(int i = 0; i < 181; i++){            
        SD_Card.println(buttonName[i]);              // print every name in a new line inside the generated file
    }

So this read will get a single character of the button name at a time which the while seems to account for?:
Code:
  a = 0;
  while(SD_Card.available()){
    buttonName[a] = SD_Card.readStringUntil(\'\\n\');  // define the data inside the array with one line each - works good
    a++;
  }

So it seems that would find and store then return the NULL as needed.

But this is not a valid test :: if(buttonName == " ")

With the 'text notes' this code hasn't compiled and the existence and value of 'i' is undefined.

That is also not a valid way to compare a string. The above link shows 'strcmp(s1, s2);' - that given the start pointer to two 'c' strings goes through them char by char until they differ or both end with that NULL character. It returns 0 is the NULL ends both the same.

So more like this should work :: if (0 == strcmp( buttonName, " " ) // strings are the same


Code:
#include <SD.h>   // I\'m adding everything relevant for this to work, but note that thats not my code!
 
String buttonName[181];   // for the process of copying data from this array to the SD all 181 Strings are defined, but its          //                           nonsense to paste it entirely here. But once all Strings are at the SD, thats what actually is //                           written in the code
 
File SD_Card;
 
void Setup(){
 
  SD.begin(BUILTIN_SDCARD);   // initialise SD
 
/*  SD.remove("BCOMNAME.txt");                       // get rid of old Stuff
  SD_Card = SD.open("BCOMNAME.txt", FILE_WRITE);     // to have the newest data in the right place
    for(int i = 0; i < 181; i++){            
        SD_Card.println(buttonName[i]);              // print every name in a new line inside the generated file
    }
  SD_Card.close(); */  // since this already happened, its not an active part of the code, its just the way I\'ve used to    //                        write the data to the SD...
 
// now the way to write the data from the SD card to the teensy:
 
  SD_Card = SD.open("BCOMNAME.txt");
  a = 0;
  while(SD_Card.available()){
    buttonName[a] = SD_Card.readStringUntil(\'\\n\');  // define the data inside the array with one line each - works good
    a++;
  }
  SD_Card.close();
 
// now (very simplified!!) the part that works fine if it did not pass thru the SD Card and always fails when the data
// comes from the SD using the method above:
 
if(buttonName[i] == "      ")
  do something;
else                          
  do another thing;
 
// for the ones who want it complete:
  if(buttonName[pages * 6 + state * 30 + i + 1] == "      "){
    if(buttonParams[0][pages * 6 + state * 30 + i + 1] >= 144 && buttonParams[0][pages * 6 + state * 30 + i + 1] <= 159){
      setTextPlusValue(i + 3, noteNames[(buttonParams[1][pages * 6 + state * 30 + i + 1] % 12)], (buttonParams[1][pages * 6 + state * 30 + i + 1] / 12) + octaveActual);
      setTextUpDown(i+3, 0);
      setTextLeftRight(i+3, 1);
      setTextImage(i + 3, 71 + (buttonParams[1][pages * 6 + state * 30 + i + 1] % 12));
    }
    else{
      if(buttonParams[0][pages * 6 + state * 30 + i + 1] >= 176 && buttonParams[0][pages * 6 + state * 30 + i + 1] <= 191)
        setTextPlusValue(i + 3, "CC ", buttonParams[1][pages * 6 + state * 30 + i + 1]);
      if(buttonParams[0][pages * 6 + state * 30 + i + 1] >= 192 && buttonParams[0][pages * 6 + state * 30 + i + 1] <= 207)
        setTextPlusValue(i + 3, "PC ", buttonParams[1][pages * 6 + state * 30 + i + 1]);  
      setTextLeftRight(i+3, (i + 3) % 3);
      if (i <3) setTextUpDown(i+3, 0);
      else      setTextUpDown(i+3, 2);
    }
  }
 
// the thing is, its not important what is written between this and the last comment. It works until it comes from the SD. So I assume that the String is being modified somehow. Ive checked it not using spacebars, writing "empty". Same result. the code recognises it as the word that it is if it doesn\'t come from the SD, but not if so.
 
Hey defragster, I've tried the if (0 == strcmp( buttonName, " " ) thing, but it doesn't compile with it, because this method is used for char only. Also the C String link you shared doesn't handle about the "String" type that is Arduino specific. But as I read that you've tried to compile my code fragments, I've written a small simple code that actually works.

https://pastebin.com/embed_js/gZs3bHpV

As you could see if you run this with a SD card is that first: the "if(test[] == "exampleWord")" works fine. But second: somehow it doesn't if the same line applies to words that came from the SD card. If I got you right, you also assume that the method of writing the String from the SD card to the teensy includes the \0 right?
So I'm still clueless...
 
SOLVED! Found a way to trim the SD output: the string.trim() function.
It's a matter of one line of code and a variable more:

int a = 0;
while(myFile.available()){
buffer = myFile.readStringUntil(\'\\n\');
result[a] = buffer.trim(); //<---- HERE
a++;

That's it. Now it works.
 
Had not tried to compile - just seeing the plaintext there showed it would not. Also didn't look close enough at the code when I popped it open - did not see type String was in use - not a normal " 'c' string "

They can work - but not used them much - they are cleaner in ways and worse in others - mostly not what seems good and right and familiar.
 
I know, I guess you're a programmer since there was no arduino or teensy out there and learned C for other purposes. I'm programming since two years and only for my pedal project, so I've got huge gaps in my C knowledge and all I know is arduino/teensy related.

Thanks for the help.
Happy New year!
 
Happy New Year!

Glad it is working for you.

Indeed learned C in early 80's from "The C Programming Language by Brian W. Kernighan and Dennis M. Ritchie " outside my mainframe classes in a minicomputer lab. Then at work into the 90's as C++ evolved it wasn't allowed due to its 'dynamic nature' in the PC system in use - and here in Teensy'land C++ seems to work well enough these years later - but avoiding still seems better.
 
Status
Not open for further replies.
Back
Top