MUFF WIGGLER Forum Index
 FAQ & Terms of UseFAQ & Terms Of Use   Wiggler RadioMW Radio   Muff Wiggler TwitterTwitter   Support the site @ PatreonPatreon 
 SearchSearch   RegisterSign up   Log inLog in 
WIGGLING 'LITE' IN GUEST MODE

utilizing the SD card
MUFF WIGGLER Forum Index -> nw2s  
Author utilizing the SD card
spacenoodle
I need to save values in two dimensional arrays to the SD card and read them back into the arrays when my sketch loads. Are there any examples of this for the b? If someone could point me in the right direction that would be great. I'm not sure how to read and write a file.
scottwilson
Do you have any code we can look at?

There's three ways...

The first is to store binary data in a file that you write bytes to and read bytes from that gets cast to some memory space. This is the most efficient, but it's the hardest to debug.

The second would be to write the data out as strings in some random format and then parse the strings when you read it in. It's a little easier to debug and edit the files offline. The downside of this is that you have to write your own parsing routines.

The third would be to use the JSON library that we're already using to store data in plain text. The benefit is that it supports complex data structures out of the box. The downside is that JSON libraries are a bit awkward to use at first if you're not used to them, especially when they are pared down for use in embedded systems.

Scannerdarkly is using the JSON library to store config data on the card, so you can look at that code:

https://github.com/nw2s/b/blob/b-1.1.0-unstable/sketches/libraries/nw2 s/GameOfLife.cpp

Code:

void GameOfLife::saveConfig()
{
   aJsonObject *root;
   root = aJson.createObject();
   
   aJsonObject* jsonArray;

   jsonArray = aJson.createArray();
   for (int i = 0; i < 14; i++)
   {
      aJsonObject* item = aJson.createItem(config.gateMode[i]);
      aJson.addItemToArray(jsonArray, item);
   }
   aJson.addItemToObject(root, "gateMode", jsonArray);   

   jsonArray = aJson.createArray();
   for (int i = 0; i < 16; i++)
   {
      aJsonObject* item = aJson.createItem(config.cvMode[i]);
      aJson.addItemToArray(jsonArray, item);
   }
   aJson.addItemToObject(root, "cvMode", jsonArray);   

   jsonArray = aJson.createArray();
   for (int i = 0; i < 16; i++)
   {
      aJsonObject* item = aJson.createItem(config.cvRangeMin[i]);
      aJson.addItemToArray(jsonArray, item);
   }
   aJson.addItemToObject(root, "cvRangeMin", jsonArray);   

   jsonArray = aJson.createArray();
   for (int i = 0; i < 16; i++)
   {
      aJsonObject* item = aJson.createItem(config.cvRangeMax[i]);
      aJson.addItemToArray(jsonArray, item);
   }
   aJson.addItemToObject(root, "cvRangeMax", jsonArray);   
   
   jsonArray = aJson.createArray();
   for (int i = 0; i < 16; i++)
   {
      aJsonObject* item = aJson.createItem(config.noteScale[i]);
      aJson.addItemToArray(jsonArray, item);
   }
   aJson.addItemToObject(root, "noteScale", jsonArray);
   
   aJsonStringStream stringStream(NULL, jsonBuffer, 512);
   aJson.print(root, &stringStream);

   Serial.println("--- config JSON created ----------------------------");
   Serial.println(jsonBuffer);
   Serial.println("------------------------------------------------ ----");
   
   SdFile rootFile = b::getSDRoot();
   SdFile configFolder;
   if (!configFolder.open(rootFile, CONFIG_FOLDER, O_READ))
   {
       if (configFolder.makeDir(rootFile, CONFIG_FOLDER))
      {
         Serial.println("Config folder not found, created");
      }
      else
      {
         Serial.println("Config folder not found and could not create one");
         return;
      }
      if (!configFolder.open(rootFile, CONFIG_FOLDER, O_READ))
      {
         Serial.println("Could not open config folder after creating one");
      }
   }
   
   SdFile configFile;
   if (configFile.open(configFolder, GAME_OF_LIFE_CONFIG_FILE_NAME, O_CREAT | O_WRITE | O_TRUNC))
   {
      configFile.println(jsonBuffer);
      configFile.close();
      Serial.println("Config saved!");
   }
   else
   {
       Serial.print("Could not write config, error opening config file for writing ");
      Serial.println(GAME_OF_LIFE_CONFIG_FILE_NAME);
   }
   
   aJson.deleteItem(root);
}

spacenoodle
Thanks. Here's one example. I've got a function that edits the values in this array. How the values are formatted in the config file visually is pretty important because they are representative of x/y coordinates on a video screen. I'm calibrating the b with all the features of Ming Mecca so that things like collision are being handled on the b side.

Option 2 or 3 should work. JSON isn't in my comfort zone yet but that looks like it might work well for me in this case. Do you agree?

Code:

int tileIndex[12][10] = { //need to store/read these values on card
  {2288,  2311,   2334,   2357,   2370,   2385,   2406,   2434,   2452,   2485},
  {2080,  2093,   2121,   2139,   2172,   2195,   2213,   2231,   2248,   2274},
  {1877,  1895,   1918,   1941,   1961,   1977,   2005,   2023,   2035,   2064},
  {1664,  1687,   1710,   1723,   1746,   1769,   1785,   1806,   1828,   1851},
  {1456,  1479,   1502,   1525,   1547,   1561,   1580,   1607,   1620,   1643},
  {1248,  1271,   1294,   1317,   1340,   1363,   1381,   1399,   1418,   1435},
  {1040,  1063,   1086,   1099,   1127,   1145,   1173,   1191,   1214,   1237},
  {832,   855,   878,   901,   924,   942,   960,   980,   1006,   1029},
  {624,   647,   670,   693,   716,   736,   752,   772,   789,   811},
  {416,   439,   462,   485,   508,   531,   554,   567,   590,   610},
  {213,   234,   254,   277,   300,   318,   346,   359,   388,   408},
  {0,     26,   46,     69,     92,     115,   135,   151,   184,   202}
}

void calibration()
{
  bool left = ps3->getButtonPress(LEFT);
  bool right = ps3->getButtonPress(RIGHT);

  if (left == true && left_released == true || left == true && scrolling == true) {
    last_indx = indx;

    if (indx > 1) {
      indx--;
      cal_printed = false;
    }

    left_released = false;
  }

  if (right == true && right_released == true || right == true && scrolling == true) {
    last_indx = indx;

    if (indx < 120) {
      indx++;
      cal_printed = false;
    }

    right_released = false;
  }

  if (bool up = ps3->getButtonPress(UP) == true && up_released == true) {
    tileIndex[row][column]++;
    cal_printed = false;
    up_released = false;
  }

  if (bool down = ps3->getButtonPress(DOWN) == true && down_released == true) {
    tileIndex[row][column]--;
    cal_printed = false;
    down_released = false;
  }

  if (bool left = ps3->getButtonPress(LEFT) == false) {
    left_released = true;
  }

  if (bool right = ps3->getButtonPress(RIGHT) == false) {
    right_released = true;
  }

  if (bool up = ps3->getButtonPress(UP) == false) {
    up_released = true;
  }

  if (bool down = ps3->getButtonPress(DOWN) == false) {
    down_released = true;
  }

  if (left_released == false || right_released == false) {
    if (scroll_waiting == false) {
      wait = millis();
      scroll_waiting = true;
    }
    else {
      start = millis();

      if (start - wait > 700) {
        scrolling = true;
      }
    }
  }
  else {
    scroll_waiting = false;
    scrolling = false;
  }

  row = (indx / 10);
  column = indx % 10;
  if (column == 0) {
    column = 10;
    row--;
  }
  column--;

  row = abs(row - 11);

  if (cal_printed == false) {
    cal_printed = true;
    printTileIndex(indx, cal, column, row);
  }
  else if (last_cal != cal) {
    printTileIndex(indx, cal, column, row);
  }

  last_cal = cal;

  An06->outputCV(tileIndex[row][column] + comp06);
}
scottwilson
Yeah in your case, the JSON looks like it'll be pretty easy. The sample code stores a number of single dimensional arrays and you will be able to use something like this:

Code:

   jsonArray = aJson.createArray();
   for (int i = 0; i < 14; i++)
   {
      aJsonObject* item = aJson.createItem(config.gateMode[i]);
      aJson.addItemToArray(jsonArray, item);
   }
   aJson.addItemToObject(root, "gateMode", jsonArray);   


but create an inner loop to do the second dimension of array storage.

Then when you save it, I assume it won't be pretty printed, you can use something like http://jsonlint.com/ to pretty print it for you to help debugging.

s
spacenoodle
Thank you. Everything seems to be working as far as loading and saving. Which is wonderful. But my first attempt at a jSON 2d array puts the saved data on a single line with no brackets to define rows. What am I doing wrong here?

This is how I'm reading:
Code:

  for (y = 0; y < 12; y++)
  {
    for (x = 0; x < 10; x++)
    {
      aJsonObject* item = aJson.getArrayItem(jsonArray, (x + (y*10)));
      calTileIndex[y][x] = item->valueint;
    }
  }

And saving:
Code:

jsonArray = aJson.createArray();
  for (int y = 0; y < 12; y++)
  {
    for (int x = 0; x < 10; x++)
    {
      aJsonObject* item = aJson.createItem(calTileIndex[y][x]);
      aJson.addItemToArray(jsonArray, item);
    }
  }
  aJson.addItemToObject(root, "tileIndex", jsonArray);


The saved file looks like:
Code:

{"tileIndex":[2288,2311,2334,2357,2370,2385,2406,2434,2452,2485,2080,2 093,2121,2139,2172,2185,2213,2231,2248,2274,1877,1895,1918,1941,1961,1 977,2005,2023,2035,2054,1664,1687,1710,1723,1746,1759,1785,1806,1828,1 851,1456,1479,1502,1525,1547,1561,1580,1607,1620,1643,1248,1271,1294,1 317,1340,1363,1381,1399,1418,1435,1040,1063,1086,1099,1127,1145,1173,1 191,1214,1237,832,855,878,901,924,942,960,980,1006,1029,624,647,670,69 3,716,736,752,772,789,811,416,439,462,485,508,531,554,567,590,610,213, 234,254,277,300,318,346,359,388,408,0,26,46,69,92,115,135,151,184,202] }


EDIT: I guess the formatting is not a huge deal, as it is working. I was just hoping it could look more like columns and rows.
scottwilson
It works since you have a fixed array size that is known before reading. It wouldn't work as well if the array sizes were arbitrary.

Even though you are looping through the x and y dimensions, you are only creating a single array.

You can update to something like this for saving:

Code:

  jsonArrayY = aJson.createArray();
  for (int y = 0; y < 12; y++)
  {

    jsonArrayX = aJson.createArray();
   
    aJson.addItemToArray(jsonArrayY, jsonArrayX);

    for (int x = 0; x < 10; x++)
    {
      aJsonObject* item = aJson.createItem(calTileIndex[y][x]);
      aJson.addItemToArray(jsonArrayX, item);
    }
  }
  aJson.addItemToObject(root, "tileIndex", jsonArray);


and for reading:

Code:

  for (y = 0; y < 12; y++)
  {
    for (x = 0; x < 10; x++)
    {
      aJsonObject* row = aJson.getArrayItem(jsonArray, y);
      aJsonObject* item = aJson.getArrayItem(row, x);
      calTileIndex[y][x] = item->valueint;
    }
  }
spacenoodle
Thanks Scott. I do appreciate your scripting advice immensely.
MUFF WIGGLER Forum Index -> nw2s  
Page 1 of 1
Powered by phpBB © phpBB Group