Passing an array of elements to a function

Hi Everyone,

I would like to ask you guys for some help in a project I am working.

This is the situation.

In the below code, I get the data from a Bluetooth module and store them in an array of 20 elements.

The thing is that I would like to pass this array of elements to a function, but only the elements the function gets. In other words, at the beginning of the sketch, I define the array with a maximum of 20 elements, but I just want to pass to the function only the elements inside and not the 20.

For instance, if I get the characters "hello" from the Bluetooth, I want to save "hello" in the array. Once "hello" is kept within the array, I would like only to pass to the array and write "hello" on a sdcard file.

So far, I am able to do that, but for some reason that I can not understand yet is why all the 20 elements are written within the sdcard file. That is, "hello" is written on the file of the sdcard but also the rest of the characters that make up the array.

How might I write on the sdcard file only those characters sent by the Bluetooth module and not the whole size of the array?.

Thank you in advance for your help.

Regards.

P.S. I used capital letters (comments) in the sketch to indicate the part of the code related to the above explanation

/*********************************************************************
This is an example for our nRF8001 Bluetooth Low Energy Breakout

  Pick one up today in the adafruit shop!
  ------> http://www.adafruit.com/products/1697

Adafruit invests time and resources providing this open source code, 
please support Adafruit and open-source hardware by purchasing 
products from Adafruit!

Written by Kevin Townsend/KTOWN  for Adafruit Industries.
MIT license, check LICENSE for more information
All text above, and the splash screen below must be included in any redistribution
*********************************************************************/

// This version uses the internal data queing so you can treat it like Serial (kinda)!

#include <SPI.h>
#include <SD.h>
#include "Adafruit_BLE_UART.h"

File myFile;
int i;
char c[20];


//const int sdarray_size = 18;
//char sdarray[sdarray_size];


// Connect CLK/MISO/MOSI to hardware SPI
// e.g. On UNO & compatible: CLK = 13, MISO = 12, MOSI = 11
#define ADAFRUITBLE_REQ 10
#define ADAFRUITBLE_RDY 2     // This should be an interrupt pin, on Uno thats #2 or #3
#define ADAFRUITBLE_RST 9

Adafruit_BLE_UART BTLEserial = Adafruit_BLE_UART(ADAFRUITBLE_REQ, ADAFRUITBLE_RDY, ADAFRUITBLE_RST);
/**************************************************************************/
/*!
    Configure the Arduino and start advertising with the radio
*/
/**************************************************************************/
void setup(void)
{ 
  Serial.begin(9600);
  while(!Serial); // Leonardo/Micro should wait for serial init
  Serial.println(F("Adafruit Bluefruit Low Energy nRF8001 Print echo demo"));

  // BTLEserial.setDeviceName("NEWNAME"); /* 7 characters max! */

  BTLEserial.begin();


 if (!SD.begin(4)) {
      Serial.println("initialization failed!");
      return;
     }
  
}

/**************************************************************************/
/*!
    Constantly checks for new events on the nRF8001
*/
/**************************************************************************/
aci_evt_opcode_t laststatus = ACI_EVT_DISCONNECTED;

void loop()
{
  // Tell the nRF8001 to do whatever it should be working on.
  BTLEserial.pollACI();

  // Ask what is our current status
  aci_evt_opcode_t status = BTLEserial.getState();
  // If the status changed....
  if (status != laststatus) {
    // print it out!
    if (status == ACI_EVT_DEVICE_STARTED) {
        Serial.println(F("* Advertising started"));
    }
    if (status == ACI_EVT_CONNECTED) {
        Serial.println(F("* Connected!"));
    }
    if (status == ACI_EVT_DISCONNECTED) {
        Serial.println(F("* Disconnected or advertising timed out"));
    }
    // OK set the last status change to this one
    laststatus = status;
  }

  if (status == ACI_EVT_CONNECTED) {
    // Lets see if there's any data for us!
    if (BTLEserial.available()) {
      Serial.print("* "); Serial.print(BTLEserial.available()); Serial.println(F(" bytes available from BTLE"));
    }
    // OK while we still have something to read, get a character and print it out
    while (BTLEserial.available()) {
      //char c = BTLEserial.read();

    
     

for (int i=0; i<20; i++)
     {
      c[i] = BTLEserial.read(); //I READ VALUES FROM THE BLUETOOTH MODULE AND KEEP THEM IN AN ARRAY OF 20 ELEMENTS    
      //Serial.print(c[i]);   
     }

     sdcard(c, sizeof(c) / sizeof(c[0]));//I PASS THE ARRAY TO THE FUNCTION WITH THE CHARACTERS (ELEMENTS) SENT BY THE BLUETOOTH MODULE
      
    }


// Next up, see if we have any data to get from the Serial console

    if (Serial.available()) {
      // Read a line from Serial
      Serial.setTimeout(100); // 100 millisecond timeout
      String s = Serial.readString();

      // We need to convert the line to bytes, no more than 20 at this time
      uint8_t sendbuffer[20];
      s.getBytes(sendbuffer, 20);
      char sendbuffersize = min(20, s.length());

      Serial.print(F("\n* Sending -> \"")); Serial.print((char *)sendbuffer); Serial.println("\"");

      
  // write the data
      for (i=0; i>=1; i--) {
      BTLEserial.println("");
      }  
      BTLEserial.write(sendbuffer, sendbuffersize);
      //i++;
      BTLEserial.println("");
     
    
    } 
  }
}


char sdcard(char y[], int siz)//HERE I GOT THE ARRAY AND ITS SIZE WITH THE ELEMENTS 
{

myFile = SD.open("thursday.txt", FILE_WRITE);

// if the file opened okay, write to it:
 if (myFile) {  
   
       Serial.print(y); //AT THIS POINT, I TRY TO PRINT ON THE SERIAL MONITOR THE ARRAY WITH ONLY THOSE ELEMENTS RECEIVED FROM THE BLUETOOH MODULE
       myFile.println(y);// AND STORE THEM IN A .TXT FILE
      
       Serial.println("");
    

       myFile.close();
}
//    Serial.println("done.");
   else {
    // if the file didn't open, print an error:
    Serial.println("error opening sdcard.txt");
  }
}

When dealing with strings of characters you'll need to have a terminating character to know when you are done reading the string. The standard C char to terminate would be '\0'

Hi,

First of all, thank you so much for your reply.

Yes, I already knew that there was a terminating character. My question is, how can I use it within this example? and where should I place it?.

I think it should go in this part of the code:

(myFile) {  
   
       Serial.print(y); //AT THIS POINT, I TRY TO PRINT ON THE SERIAL MONITOR THE ARRAY WITH ONLY THOSE ELEMENTS RECEIVED FROM THE BLUETOOH MODULE
       myFile.println(y);// AND STORE THEM IN A .TXT FILE
      
       Serial.println("");
    

       myFile.close();

However, I am not sure.

Could you help me out?

Thank you again in advance.

Regards.

For the specific case of passing a char array, @Thee_Captain is exactly right. So, if your code is only going to deal with char arrays, then the solution is as stated -- terminate the end of the string (right after the last character) with a null.

For the more general case of passing an array of any type to a function, you must first remember that you’re really just passing a pointer. As such, the receiving function doesn’t know how many elements are in the array. That’s why the standard technique is to pass the size also. Your code, in fact, does this:

char sdcard(char y[], int siz)//HERE I GOT THE ARRAY AND ITS SIZE WITH THE ELEMENTS
{

So, you do pass the array’s size to your function, but then you don’t do anything with that information. What’s the point?

Even worse is this:

for (int i=0; i<20; i++)
     {
      c[i] = BTLEserial.read(); //I READ VALUES FROM THE BLUETOOTH MODULE AND KEEP THEM IN AN ARRAY OF 20 ELEMENTS    
      //Serial.print(c[i]);   
     }

You always try to read 20 characters. How do you know that’s the right number? What if there are less? More?

for (int i=0; i<20; i++)
     {
      c[i] = BTLEserial.read(); //I READ VALUES FROM THE BLUETOOTH MODULE AND KEEP THEM IN AN ARRAY OF 20 ELEMENTS    
      //Serial.print(c[i]);   
     }

As gfvalvo was saying, you don't really want to use a constant for the length of your character array (string). char[20] is just saving (allocating) 20 bytes in a row for the event that you want to store 20 bytes in there (19 chars + 1 '\0').

In this section of code where you are reading in the characters you will want to terminate the string with the null terminator character '\0' Then anytime you want to deal with that string (like when you print to your file) you will loop through each element of your character array (string) until you reach your terminator.

You then know that the characters after the terminator are garbage.

Hi again,

Thank you for your answer.

I used to do this:

    while (BTLEserial.available()) {
        char c = BTLEserial.read();
        sdwrite(c); // Call the function to pass the character and then write on the sdcard

    }

sdwrite();



char sdwrite(char y)
{


myFile = SD.open("sdcard.txt", FILE_WRITE);

// if the file opened okay, write to it:
  if (myFile) {  
    myFile.print(y);
    Serial.print(y);
   
// close the file:
    myFile.close();

   }else {
    // if the file didn't open, print an error:
    Serial.println("error opening sdcard.txt");
  }

}

This is what I used to do. I used to send character by character to a function, but now I would like data to arrive in a single packet, fitting in the 20-byte limit. A single BLE packet can hold up to 20 bytes of data that's why I am using an array of maximum 20 elements.

For this reason. I changed the code in order to get data from the bluetooth module and store them inside an array of maximum 20 elements

for (int i=0; i<20; i++)
     {
      c[i] = BTLEserial.read(); //I READ VALUES FROM THE BLUETOOTH MODULE AND KEEP THEM IN AN ARRAY OF 20 ELEMENTS    
      //Serial.print(c[i]);   
     }

After running the code, I am able to get on the Serial Monitor and on the SDcard file the same characters from the Bluetooth module, but after the sent characters, some other extra characters are added and I do not how to only write those characters sent from the Bluetooth.

That's the reason I am asking you guys because I am stuck at this point.

Thank you again for your feedback.

Regards

Hi,

I understand you guys.

I do not have to use or specify the length of the character array. Got it. However, taking out the length of the elements of the array at the beginning of the sketch, I get this error:

char c[];

"exit status 1
storage size of 'c' isn't known"

How can I fix it?

Thank you again.

Regards.

You can still use your 20 byte buffer. You'll just need to terminate the string. You can find out about C strings online.

For the reasons stated earlier, you are going to want to use the while loop. This isn't completely apparent yet. You'll need to read up on Arduino's Serial functions.

A hint when you get back to using the while( Serial.available() ) construct, you will change the single character to your 20 byte buffer and you will not write the file until you have emptied your Serial buffer into your string buffer. Then you will write that whole string once outside the while loop.

Side note: we are not saying that you should not allocate those 20 bytes. Put that part back in.

I have a function called from my main loop. It loads as much data as is available into the buffer, but also times out. If either the buffer fills, or timeout occurs, it then calls another function to handle the message.

//capture bluetooth data as it comes
void btSerialScan() {
  //see if data is available and process
  //monSerial.print("in btSS: ");monSerial.println(btInBfrPtr);
  if (btSerial.available()) {
    //    monSerial.print("bt available: "); monSerial.print(btSerial.available()); monSerial.print("_: "); monSerial.println(btInBfrPtr);
  }
  //
  //  if (btInBfrPtr && (millis() - btCharTimeout > btLastCharMs)) {
  //    monSerial.print("timeout reached: "); monSerial.print(millis()); monSerial.print("_: "); monSerial.println(btInBfrPtr);Serial.flush();
  //  }



  //check for switching on
  if ( (btSerialStatus == BTAT) && (digitalRead(btSerialStatusPin) == HIGH)) {
    //it has connected
    monSerial.println("we are connected!");
    btSerialStatus = BTON;
  } else if ( (btSerialStatus == BTON) && (digitalRead(btSerialStatusPin) == LOW)) {
    //we have been disconnected!
    monSerial.println("we have been disconnected!!!");
    btSerialStatus = BTAT;
  }



  //check for timeout
  if ((btInBfrPtr > 0) && (millis() - btCharTimeout > btLastCharMs) ) {
    //then it's gone too longe since the last character.  pad the string with null
    //    monSerial.print("padding "); monSerial.print(  btInBfrPtr);
    //    monSerial.print(" - "); monSerial.print(millis());
    //    monSerial.print("_"); monSerial.println(btLastCharMs, DEC);
    //    monSerial.println(btInBfr);
    //    Serial.flush();
    for (btInBfrPtr; btInBfrPtr < btInBfrSiz - 1; btInBfrPtr++) {
      btInBfr[btInBfrPtr] = '\0';
      // monSerial.println(btInBfrPtr);
    }
    //monSerial.println(btInBfrPtr);
  } else {



    while ((btSerial.available() ) &&  (btInBfrPtr < (btInBfrSiz - 1)) ) {
      //this means serial data available from bt.Serial and still space in buffer


      //      monSerial.print("Data coming: "); monSerial.print( btInBfrPtr); monSerial.print("_: ");monSerial.print((char) btSerial.peek());
      //          monSerial.print(" ");monSerial.println(btSerial.peek());

      // add it to the input buffer
      btInBfr[btInBfrPtr] = btSerial.read();
      btInBfrPtr++;

      //log when this happened
      btLastCharMs = millis();
    };        //end while available

  }       //end else

  //if we have reached maximum size in bt buffer, process the command

  if ( btInBfrPtr >= (btInBfrSiz - 1)  ) {

    // monSerial.print("full string!  "); monSerial.print(btInBfrPtr); monSerial.print("  : ");
    //monSerial.println(btInBfr);
    doBtInBfr();

    //reset so that it can go again
    btInBfrPtr = 0;
    //we could re-zero the array, but why?


  }

  // relay the monSerial to the bluetooth
  //this would mean that data is available from the serial monitor
  // monSerial.write("_"); monSerial.write(monSerial.peek());
  //monSerial.println("Sending: ");
  if (monSerial.available()) btSerial.write(monSerial.read());


} //end btSerialScan