Control-Surface icon indicating copy to clipboard operation
Control-Surface copied to clipboard

2 different Banks saving data on SD with Json Structure

Open danilobelpedio opened this issue 1 year ago • 3 comments

First of everything, Pieter thanks for your wonderful job. I Am Danilo from Italy and I have to ask you help for an ideas that arrived from problems during music live performance . I am not a musician (hobby), I am not a programmer (hobby), and I have few times to do a lot of thing that I have in my head. I programmed at university and sometimes at work but when I programmed first time there was the "basic" program language on so I m new in this kind of wonderful system like Arduino. Well, it's the first time I write here and I solved a lot of problems reading here, so thanks also to everyone. My problem is: how I can use two different banks (like bank1 and bank2) for two arrays of encoders saving data on a json structure and alter on a sd?

My code is a mix of your code and other code around the network... I modified also your code (sorry don't be angry and I hope that I done good job...)

Anyways the code below is only for one encoder one bank: (I USE an ARDUINO MEGA... because the code need more memory )

#include <Control_Surface.h> // Include the Control Surface library
#include <SPI.h> 
#include <ArduinoJson.h>
#include <SD.h>

#define SS 53     //Pin del SS del SD Reader

// variabile per la definizione del bottone di write e read
#define write 3          //Pin del pulsante per scrivere i data su SD
#define read 2          //Pin del pulsante per leggere i data salvati su SD

// definisco i Pin del RGBLed per la SD
#define RgbLedRedPin 54   //A0 analogPin
#define RgbLedGreenPin 55 //A1 analogPin
#define RgbLedBluePin 56  //A2 analogPin

//variabili per il debounce dei pulsanti
long Debounce_delay = 100;
long t1 = 0;

const char *filename = "MONITORS.TXT";  // <- SD library uses 8.3 filenames

// Creo l'oggetto JSON 
DynamicJsonDocument doc(1024);
JsonObject obj;

File myFileSDCart;

JsonObject getJSonFromFile(DynamicJsonDocument *doc, String filename, bool forceCleanONJsonError = true ) 
  {
    myFileSDCart = SD.open(filename);     // open the file for reading:
    if (myFileSDCart) {                   // read from the file until there's nothing else in it:
        DeserializationError error = deserializeJson(*doc, myFileSDCart);
        if (error) { 
            Serial.print(F("Error parsing JSON ")); // if the file didn't open, print an error:
            Serial.println(error.c_str());
            if (forceCleanONJsonError){
                return doc->to<JsonObject>();
            }
        }
        myFileSDCart.close();     // close the file:
        return doc->as<JsonObject>();
    } else {
        Serial.print(F("Error opening (or file not exists) "));   // if the file didn't open, print an error:
        Serial.println(filename);
        Serial.println(F("Empty json created"));
        return doc->to<JsonObject>();
    }
}

// Custom callback to handle output for a selector.
class MySelectorCallback {
  uint8_t pickedColor[10][3] ={ // defined Bank Colors R,G,B
    {255,  0,  0},     //rosso
    {200,100, 53},     //giallo limone
    {  0,  0,150},     //blu
    {  0,100,  0},     //verde
    {255,  0,255},     //magenta
    { 10, 50,255},     //azzurro
    {255,255,255},     //bianco
    {100,100,255},     //celeste
    {  0,  0,  0},      //SPENTO
    {128,  0,128},     //viola
  };

  public:
    // Constructor
    MySelectorCallback(pin_t redLED, pin_t greenLED, pin_t blueLED)
      : redLED(redLED), greenLED(greenLED), blueLED(blueLED) {}

    // Begin function is called once by Control Surface.
    // Use it to initialize everything.
    void begin() { //PinMode deleted because are AnalogPin not Digital
      show(0);
    }

    // Update function is called continuously by Control Surface.
    // Use it to implement things like fading, blinking ...
    void update() {}

    // Update function with arguments is called when the setting
    // changes.
    // Use it to update the LEDs.
    void update(setting_t oldSetting, setting_t newSetting) {
      (void) oldSetting; // unused in this example
      show(newSetting);
    }

  private:
    // Show the color of the given setting.
    void show(setting_t setting) {
      uint8_t colorRed = getColorRed(setting);
      uint8_t colorGreen = getColorGreen(setting);
      uint8_t colorBlue = getColorBlue(setting);
      analogWrite(redLED, colorRed); //if were digital pin i should use DigitalWrite 
      analogWrite(greenLED, colorGreen);
      analogWrite(blueLED, colorBlue);
    }

    // Convert the given setting to a 3-bit RGB color value.
    uint8_t getColorRed(setting_t setting) {
      switch (setting) {
        case 0: return pickedColor[setting][0];
        case 1: return pickedColor[setting][0];
        case 2: return pickedColor[setting][0];
        case 3: return pickedColor[setting][0];
        case 4: return pickedColor[setting][0];
        case 5: return pickedColor[setting][0];
        case 6: return pickedColor[setting][0];
        case 7: return pickedColor[setting][0];
//        case 8: return pickedColor[setting][0];
        default: return 0;
      }
    }
     uint8_t getColorGreen(setting_t setting) {
      switch (setting) {
        case 0: return pickedColor[setting][1];
        case 1: return pickedColor[setting][1];
        case 2: return pickedColor[setting][1];
        case 3: return pickedColor[setting][1];
        case 4: return pickedColor[setting][1];
        case 5: return pickedColor[setting][1];
        case 6: return pickedColor[setting][1];
        case 7: return pickedColor[setting][1];
//        case 8: return pickedColor[setting][1];
        default: return 0;
      }
    }
    uint8_t getColorBlue(setting_t setting) {
      switch (setting) {
        case 0: return pickedColor[setting][2];
        case 1: return pickedColor[setting][2];
        case 2: return pickedColor[setting][2];
        case 3: return pickedColor[setting][2];
        case 4: return pickedColor[setting][2];
        case 5: return pickedColor[setting][2];
        case 6: return pickedColor[setting][2];
        case 7: return pickedColor[setting][2];
//        case 8: return pickedColor[setting][2];
        default: return 0;
      }
    }


  private:
    // Member variables to remember the pin numbers of the LEDs.
    pin_t redLED, greenLED, blueLED;
};

// :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: //


//USBMIDI_Interface midi;
USBDebugMIDI_Interface midi;

// Create 8 banks with one track per bank.
Bank<8> bank(1); // 8 musicians, 1 track (encoder) for each musician

// Create a selector that uses our custom callback, to control the bank.
GenericIncrementDecrementSelector<8, MySelectorCallback> selector {
  bank,         // bank to manage
  {5, 6, 7}, // red, green, blue LED pins 
                // (this is the MySelectorCallback constructor defined above)
  {8, 9},       // incr/decr button pins
  Wrap::Wrap,   // wrap around when reaching setting 6
};

// Handy type alias
using  CCAbsEnc = Bankable::CCAbsoluteEncoder<8>;

// Instantiate a CCAbsoluteEncoder object
CCAbsEnc enc[] = {
  {  
  {bank, BankType::CHANGE_ADDRESS},
  {22, 23},       // pins
  {7,CHANNEL_5}, // MIDI address (CC number + optional channel)
  1,            // optional multiplier if the control isn't fast enough
  },
};

void setup() {
  pinMode(RgbLedRedPin, OUTPUT);
  pinMode(RgbLedGreenPin, OUTPUT);
  pinMode(RgbLedBluePin, OUTPUT);
  pinMode(write, INPUT_PULLUP);        // Inizializiamo il pin del pulsante di write
  pinMode(read, INPUT_PULLUP);        // Inizializiamo il pin del pulsante di read
  Control_Surface.begin(); // Initialize Control Surface
  Serial.begin(115200);
  while (!SD.begin(SS)) {   // Initialize SD library
        Serial.println("Failed");
        Serial.println("to initialize");
        Serial.println("SD library");
        for (int i =0; i<4; i++){
          BlinkSdLed(0);
          delay(200);
          BlinkSdLed(1);
          delay(200);
          BlinkSdLed(2);
          delay(200);
        }
        BlinkSdLed(0);
    }

  Serial.println("SD library");
  Serial.println("initialized");
  Serial.println("READY TO WORK!");
  BlinkSdLed(0);
  delay(300);
  BlinkSdLed(1);
  delay(300);
  BlinkSdLed(2);
  delay(300);
  BlinkSdLed(1); 
  readData();
}

void loop() {
  Control_Surface.loop(); // Update the Control Surface
  readFromSD();
  writeOnSD();
}

void BlinkSdLed(int color)
{
  switch(color) {
  case 0:
    digitalWrite(RgbLedRedPin,255);
    digitalWrite(RgbLedGreenPin,0);
    digitalWrite(RgbLedBluePin,0);
  break;
  case 1:
    digitalWrite(RgbLedRedPin,0);
    digitalWrite(RgbLedGreenPin,255);
    digitalWrite(RgbLedBluePin,0);
  break;
    case 2:
    digitalWrite(RgbLedRedPin,0);
    digitalWrite(RgbLedGreenPin,0);
    digitalWrite(RgbLedBluePin,255);
  break;
  }
}

void writeOnSD(){
    if (millis() - t1 > Debounce_delay){                           
    if (digitalRead(write)==LOW) {                                                                      
    obj = getJSonFromFile(&doc, filename);                        
    for (int j = 0; j < 8; j++) {                          
    obj[F("encVals")][j] = enc[0].getValue(j);                            
      }                                                               
    t1 = millis();                                               
    boolean isSaved = saveJSonToAFile(&doc, filename);            
    if (isSaved){
        BlinkSdLed(0);                                                  
        Serial.println("File saved!");
        delay(300);
        BlinkSdLed(1);                                                                                
    }else{
        BlinkSdLed(0);                                                        
        Serial.println("Error on save File!");
        for (int i =0; i<4; i++){
          BlinkSdLed(1);
          delay(200);
          BlinkSdLed(2);
          delay(200);
          BlinkSdLed(0);
          delay(200);
        }
      BlinkSdLed(1);                                                                     
    }    
    }
  }     
}

void readData(){
    obj = getJSonFromFile(&doc, filename);  // riempio l'array dei valori salvati e letti da SD attraverso la struttura Json
  for (int j=0; j < 8; j++) {
      enc[0].setValue(obj[F("encVals")][j],j);
    }
}

void readFromSD(){
  if (millis() - t1 > Debounce_delay){ 
    if (digitalRead(read)==LOW) {
      BlinkSdLed(0);                                                  
      Serial.println("READ DATA...!");
      delay(300);
      BlinkSdLed(1);
      t1 = millis();
      readData();
    }
  }
}

bool saveJSonToAFile(DynamicJsonDocument *doc, String filename) {
    SD.remove(filename);
    myFileSDCart = SD.open(filename, FILE_WRITE); // open the file. note that only one file can be open at a time, so you have to close this one before opening another.
    if (myFileSDCart) {
        serializeJson(*doc, myFileSDCart);
        myFileSDCart.close();   // close the file:
        return true;
    } else {        
        return false;
    }
}

Everything work good in this situation... the Jason structure is something like that: {encVals:{64,64,64,64,64,64,64,64}}

where I save on a file called MONITORS.TXT this structure and I call it every time I need (with a button) (not yet implemented but already ready because used in a previous release of this project) and when I turn on Arduino. 8 values are the 8 banks for 1 encoder... so I need a structure with 11 encoders, so 88 of that structure values... so ... with the code of

  for (int j=0; j < 8; j++) {
      enc[0].setValue(obj[F("encVals")][j],j);
    }

I read values from the json structure

with this code

    for (int j = 0; j < 8; j++) {                          
    obj[F("encVals")][j] = enc[0].getValue(j);                            
      }      

I write values in the json structure later I write date on the SD serializing and deserializing the structure on the SD... Ff course if I need for 11 encoders I need to do another for cycle to from 0 to 11 to save the other encoders value.

well now I have connected at the same Mega other 8 encoders with 9 banks so I will need something like that

Bank<9> bank(8); 

// Create a selector that uses our custom callback, to control the bank.
GenericIncrementDecrementSelector<8, MySelectorCallback> selector1 {
  bank1,         // bank to manage
  ......
};

// Handy type alias
using  CCAbsEnc1 = Bankable::CCAbsoluteEncoder<9>; 

CCAbsEnc1 enc1[] = {
  {  
  {bank1, BankType::CHANGE_ADDRESS},
  .....
};

probably I need something like that but my problem is

  for (int j=0; j < 8; j++) {
      enc[0].setValue(obj[F("encVals")][j],j);
    }

I read values from the json structure

with this code

    for (int j = 0; j < 8; j++) {                          
    obj[F("encVals")][j] = enc[0].getValue(j);                            
      }  

how I can change this code to identify the two different banks?

Thanks for the help... thanks a lot

danilobelpedio avatar Feb 02 '23 10:02 danilobelpedio