C++ libraries and SD card in Vexcode IQ

Hi, I was working on my code for autonomous, and I had the idea to write sensor values to a micro SD card so I can improve my autonomous, and also have a copy of the data for notebooking, etc…
Here’s a bit of my code:
FILE* AutoData = fopen(“AutoData.txt”, “a”);
fprintf(AutoData, “Hello World”);
fclose(AutoData);

This works fine, but I need to store floats, and not just strings, so I was trying to use the std::to_string() function, but including the necessary libraries gives me an error, I know that including these libraries works on Vexcode V5 Pro, is there anything I am doing wrong to use it for IQ?

The error is this: windows build for platform vexiq2
“CXX src/main.cpp”
In file included from src/main.cpp:8:
In file included from C:\Program Files (x86)\VEX Robotics\VEXcode IQ\sdk/vexiq2/gcc/include/c++/7.3.1\iostream:39:
In file included from C:\Program Files (x86)\VEX Robotics\VEXcode IQ\sdk/vexiq2/gcc/include/c++/7.3.1\ostream:38:
In file included from C:\Program Files (x86)\VEX Robotics\VEXcode IQ\sdk/vexiq2/gcc/include/c++/7.3.1\ios:42:
In file included from C:\Program Files (x86)\VEX Robotics\VEXcode IQ\sdk/vexiq2/gcc/include/c++/7.3.1\bits/ios_base.h:41:
In file included from C:\Program Files (x86)\VEX Robotics\VEXcode IQ\sdk/vexiq2/gcc/include/c++/7.3.1\bits/locale_classes.h:40:
In file included from C:\Program Files (x86)\VEX Robotics\VEXcode IQ\sdk/vexiq2/gcc/include/c++/7.3.1\string:52:
In file included from C:\Program Files (x86)\VEX Robotics\VEXcode IQ\sdk/vexiq2/gcc/include/c++/7.3.1\bits/basic_string.h:6352:
In file included from C:\Program Files (x86)\VEX Robotics\VEXcode IQ\sdk/vexiq2/gcc/include/c++/7.3.1\ext/string_conversions.h
:41:
C:\Program Files (x86)\VEX Robotics\VEXcode IQ\sdk/vexiq2/gcc/include/c++/7.3.1\cstdlib:75:15: fatal error: ‘stdlib.h’ file not found
#include_next <stdlib.h>
^~~~~~~~~~
1 error generated.
make: *** [vex/mkrules.mk:13: build/src/main.o] Error 1
make process closed with exit code : 2

Thanks for your help

The root cause of this error is the order in which include files are searched, unfortunately you have little control over that using VEXcode, if you had the change would be to update this line in mkenv.mk

TOOL_INC  = -I"$(TOOLCHAIN)/$(PLATFORM)/clang/$(HEADERS)/include" -I"$(TOOLCHAIN)/$(PLATFORM)/gcc/include"  -I"$(TOOLCHAIN)/$(PLATFORM)/gcc/include/c++/7.3.1"  -I"$(TOOLCHAIN)/$(PLATFORM)/gcc/include/c++/7.3.1/arm-none-eabi"

to this

TOOL_INC  = -I"$(TOOLCHAIN)/$(PLATFORM)/clang/$(HEADERS)/include" -I"$(TOOLCHAIN)/$(PLATFORM)/gcc/include/c++/7.3.1" -I"$(TOOLCHAIN)/$(PLATFORM)/gcc/include/c++/7.3.1/arm-none-eabi" -I"$(TOOLCHAIN)/$(PLATFORM)/gcc/include"

The only short term solution would be to switch to using the Vex Robotics VS Code extension.

Now the bad news, IQ2 does not have much memory, your code may build and be small enough but as soon as you use any significant amount of C++ standard library code it will quickly exceed the memory that IQ2 has and linking will fail.

If you want to print floats as strings in a file, just use a format string and skip any C++ std::string use.

fprintf(AutoData,"%8.2f", 12.345);
5 Likes

Ok, That is great, I know a bit of c++, but nothing like this, and where is that file located in the vex code files?

I’m not sure if that file is even able to be updated, it may get created every time the project is built, not sure. As I said, we fixed that in the VS Code extension and will back port to VEXcode at some point in the future, just was not really a priority as C++ standard library use on IQ generation 2 is not really viable anyway. Just stick to using C (which you were anyway with fprintf etc.)

5 Likes

For what it’s worth, when dealing with any of the printf functions, this is my go-to site for all the formatting possibilities:

https://cplusplus.com/reference/cstdio/printf/

3 Likes

Just as a bit of background, in very rough terms because there’s always more to this than can be explained by a single number.

only relating the the user code, not including any vexos use.

IQ generation 1 has 32k of memory for code and 12k of memory (RAM) for all variable use, stacks etc.

IQ generation 2 has 96k of memory (code and variables), however, that memory is separate from any thread stacks. In reality that means a lot more is available for use by user code than IQ generation 1.

EXP has 512k of memory for user code, as above, that does not include memory used by threads.

V5 has 72MB of memory, so several hundred times more than IQ generation 2.

A small C++ program using the C++ standard library is often more than 200k, all depends on what is used.

9 Likes

Thanks for your help in writing to SD Card, I have got that working, Now I am planning on using some different code to read the SD Card, and I am trying to use fgets. VexCode does not recognize it as a valid function, although it is in the same library, any thoughts?

FILE* AutoData = fopen("AutoData.txt", "r");
    //If the fget function has something to read
    //Write to mystring, and only the 1st 99 chars or newline
if (fgets(mystring , 100 , AutoData) != NULL);
      //Something goes here...
     fclose (AutoData);
   
 

This is my code, I get the “No Matching Function to call” Error

what’s mystring ? should be a char array.

3 Likes

Oops, my fault, I forgot to include the length of the char array
Thanks

I also found the mkenv file it is in C:\Program Files (x86)\VEX Robotics\VEXcode IQ\compilerProjects\iq2Project\vex, you were right though, the brain quickly runs out of ram.
It does seem to work, and all my projects still compile.

If you want to play with the build files, it really would be better to move to the visual studio code extension.

4 Likes

Alright, I hope this is the last time, I hope. I have the reader almost working, but my fgets command in a loop will not increment.
This:

 int updatePosDat() {
  FILE* AutoData = fopen("AutoData.txt", "r");
  while (true) {
    //Gets line of file
    if (AutoData == NULL) Brain.Screen.print("SD Card Error\n");
    else {

      //Get Position for Left Wheel
      if (fgets(posstring, 100,AutoData) != NULL)
      posstring[strcspn(posstring, "\n")] = 0;
      printf("Left Wheel: %s\n", posstring);
      lWheelPos = atof(posstring);

      //Get Position for Right Wheel
      fgets (posstring , 100 , AutoData);
      posstring[strcspn(posstring, "\n")] = 0;
      printf("Right Wheel: %s\n", posstring);
      rWheelPos = atof(posstring);
      
      //Get Position for Blue Arm
      fgets (posstring , 100 , AutoData);
      posstring[strcspn(posstring, "\n")] = 0;
      printf("Blue Arm Position: %s\n", posstring);
      blueArmPos = atof(posstring);
      
      //Get Position for Flicker
      fgets (posstring , 100 , AutoData);
      posstring[strcspn(posstring, "\n")] = 0;
      printf("Flicker Position: %s\n", posstring);
      flickerPos = atof(posstring);
      
      //Get Position for Intake
      fgets (posstring , 100 , AutoData);
      posstring[strcspn(posstring, "\n")] = 0;
      printf("Intake Position: %s\n", posstring);
      intakePos = atof(posstring);
      
      //Get Status of flywheel
      fgets (posstring , 100 , AutoData);
      posstring[strcspn(posstring, "\n")] = 0;
      printf("Flywheel Status: %s\n\n", posstring);
      flywheelStatus = atof(posstring);
      wait(precision,msec);
    }
      
    fclose(AutoData);
  }
  return 0;
}

With an SD card with this:

1
2
3
0
5
0
5
4
3
0
1

Returns this:

Left Wheel: 1
Right Wheel: 2
Blue Arm Position: 3
Flicker Position: 0
Intake Position: 5
Flywheel Status: 0

Left Wheel: 0
Right Wheel: 0
Blue Arm Position: 0
Flicker Position: 0
Intake Position: 0
Flywheel Status: 0

The zeroes go on forever if I didn’t stop the code. From what I read, fgets should increment every time I call it within one fopen, but it looks like it doesn’t, I even stripped the \n new line just to see if that would cause a difference. Am I just missing something silly, or something else?
Thanks

What you’re dealing with here is pretty simple: you’ve closed the file after your first loop through, and so fgets has nothing to read from. The fclose needs to be outside the while loop, right before your return.

One recommendation I always harp on new SW engineers, get in the habit of putting an end of line comment on your closing braces, especially for big sections of code where you can’t see the top of the loop. Rather than rely on reading the indentation properly, you can just read your comments.

For instance:

 int updatePosDat() {
  FILE* AutoData = fopen("AutoData.txt", "r");
  while (true) {
    //Gets line of file
    if (AutoData == NULL) Brain.Screen.print("SD Card Error\n");
    else {

      //Get Position for Left Wheel
      if (fgets(posstring, 100,AutoData) != NULL)
      posstring[strcspn(posstring, "\n")] = 0;
.
.
.
      flywheelStatus = atof(posstring);
      wait(precision,msec);
    }    // End else(autoData==NULL)
  } // End while(true)
    fclose(AutoData);
    return 0;
} // End updatePosData()

Also, not sure what’s supposed to exit out of this loop, since you have a while(true), which will never exit. Make sure that’s not going to cause you grief. Probably you need to exit out once you’ve hit the end of the file, or you encounter a -100000 or something that you put in as a marker.

3 Likes