Link to home
Start Free TrialLog in
Avatar of jeansebgrenon
jeansebgrenon

asked on

Run the content of a void function

Hi,

I need to run the content of a void function in the main program. This is an arduino program to get value from MySQL.
The goal of this is to have the of  
r->values[i];

Open in new window

in a global array and to run this function just once at the beginning of the program.

Here is the function:

void do_query(const char *q) {
  column_names *c; // pointer to column values
  row_values *r;   // pointer to row values

  // First, execute query. If it returns a value pointer,
  // we have a result set to process. If not, we exit.
  if (!my_conn.cmd_query(q)) {
    return;
  }

  // Next, we read the column names and display them.
  //
  // NOTICE: You must *always* read the column names even if
  //         you do not use them. This is so the connector can
  //         read the data out of the buffer. Row data follows the
  //         column data and thus must be read first.

  c = my_conn.get_columns();
  for (int i = 0; i < c->num_fields; i++) {
   // Serial.print(c->fields[i]->name);
    if (i < c->num_fields - 1) {
      Serial.print(",");
    }
  }
  Serial.println();

  // Next, we use the get_next_row() iterator and read rows printing
  // the values returned until the get_next_row() returns NULL.

  int num_cols = c->num_fields;
  int rows = 0;
  do {
    r = my_conn.get_next_row();
    if (r) {
      rows++;
      for (int i = 0; i < num_cols; i++) {
      // int variable_test = r->values[i];
      char vtest = r->values[i];

        Serial.println(vtest);
 //   Serial.print(r->values[i]);
       // Serial.print(r->values[i]);
      /*  if (i < num_cols - 1) {
          Serial.print(", ");
        }*/
      }
      Serial.println();

      // Note: we free the row read to free the memory allocated for it.
      // You should do this after you've processed the row.

      my_conn.free_row_buffer();
    }
  } while (r);
  Serial.print(rows);
  Serial.println(" rows in result.");

  // Finally, we are done so we free the column buffers

  my_conn.free_columns_buffer();
}

Open in new window



Now I'm calling the function width:
 
const char HELLO_SQL[] = "SELECT * from arduinowill.arduino";
do_query(HELLO_SQL);

Open in new window


Here is the whole program:

#include <SPI.h>
#include <Ethernet.h>
#include <sha1.h>
//#include <avr/dtostrf.h>  // Add this for the Due if you need drostrf
#include <stdlib.h>
//#include <WiFi.h>  // Use this for WiFi
#include <mysql.h>

byte mac_addr[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress server_addr(97, 74, 31, 63);  // Supply the IP of the MySQL *server* here

char user[] = "arduinowill";         // can be anything but the user must have
char password[] = "******";   // access rights to connect (host must permit it)



Connector my_conn;        // The Connector/Arduino reference



const char HELLO_SQL[] = "SELECT * from arduinowill.arduino";


/**
 * do_query - execute a query and display results
 *
 * This method demonstrates how to execute a query, get the column
 * names and print them, then read rows printing the values. It
 * is a mirror of the show_results() example in the connector class.
 *
 * You can use this method as a template for writing methods that
 * must iterate over rows from a SELECT and operate on the values read.
 *
 */
void do_query(const char *q) {
  column_names *c; // pointer to column values
  row_values *r;   // pointer to row values

  // First, execute query. If it returns a value pointer,
  // we have a result set to process. If not, we exit.
  if (!my_conn.cmd_query(q)) {
    return;
  }

  // Next, we read the column names and display them.
  //
  // NOTICE: You must *always* read the column names even if
  //         you do not use them. This is so the connector can
  //         read the data out of the buffer. Row data follows the
  //         column data and thus must be read first.

  c = my_conn.get_columns();
  for (int i = 0; i < c->num_fields; i++) {
   // Serial.print(c->fields[i]->name);
    if (i < c->num_fields - 1) {
      Serial.print(",");
    }
  }
  Serial.println();

  // Next, we use the get_next_row() iterator and read rows printing
  // the values returned until the get_next_row() returns NULL.

  int num_cols = c->num_fields;
  int rows = 0;
  do {
    r = my_conn.get_next_row();
    if (r) {
      rows++;
      for (int i = 0; i < num_cols; i++) {
      // int variable_test = r->values[i];
      char vtest = r->values[i];

        Serial.println(vtest);
 //   Serial.print(r->values[i]);
       // Serial.print(r->values[i]);
      /*  if (i < num_cols - 1) {
          Serial.print(", ");
        }*/
      }
      Serial.println();

      // Note: we free the row read to free the memory allocated for it.
      // You should do this after you've processed the row.

      my_conn.free_row_buffer();
    }
  } while (r);
  Serial.print(rows);
  Serial.println(" rows in result.");

  // Finally, we are done so we free the column buffers

  my_conn.free_columns_buffer();
}

void setup() {
  Serial.begin(115200);
  while (!Serial); // wait for serial port to connect. Needed for Leonardo only

  Ethernet.begin(mac_addr);

 

  delay(1000);
  Serial.println("Connecting...");
  if (my_conn.mysql_connect(server_addr, 3306, user, password)) {
    delay(1000);
  }
  else
    Serial.println("Connection failed.");

 nformation about how it works.

  do_query(HELLO_SQL);


}

void loop() {
}

Open in new window

Avatar of jkr
jkr
Flag of Germany image

Excuse my ignorance, but what is the part you are having trouble with?
Avatar of jeansebgrenon
jeansebgrenon

ASKER

I have try to run the void function without having to call it (just put the code of the function in the main program), but nothing happen. So I need help to incorporate this function in the program.
You can't run a function without exlicitly calling it. What you can do to ensure the execution of the function before 'main()' would be to create a global object with one instance that calls the function in the constructor, e.g. like

struct StartupHelper {

  StartupHelper() {

    loop(); // asuming the array is iterated in 'loop()'
  };
};

StartupHelper helper; // one single global instance

// rest of your code

Open in new window

In fact the goal of running the content of the function directly in the program is to have the variable of the function to be global. I need to generate more tant 20 variable in this function and I have try a couple of thing and i thought this was the best way. Will creating a global object is going to create global variable as well ?

Ps: Sorry for my bad english !
Hi Jean,

Is your project written in C or C++?  I ask because in C, anything that's global, like variables, can be considered a global object.  But in C++, "object" has a specific meaning and very specific behavior.
using global variables is not a good design.

it would be much better to define a structure which has all these variables as members and then pass a pointer (or in c++ a reference) argument from main to all functions which need the variables:

typedef struct MyGlobals
{
      int g_i;
      char g_sz[32];
      ....
      // in c++ add a constructor MyGlobals() and initialize all members

} MyGlobals;

void getData(MyGlobals * pGlobals) { if (strlen(pGlobals->g_sz) > 0) ... }

int main()
{
        MyGlobals globals = { 0 };   // if c++ you would use the constructor.

        // call the function at begin
        getData(&globals);
        ....

Open in new window


Sara
I think this is C++, but I am not sure. This is for an arduino that can run both. Here is the provenance of the code that I am using: http://drcharlesbell.blogspot.ca/2013/04/introducing-mysql-connectorarduino_6.html.
You can see all the code here: http://bazaar.launchpad.net/~chuck-bell/mysql-arduino/trunk/files.
in c++ the code posted would change to

#include <string>
#include <vector>

struct MyGlobals
{
      int g_i;
      char g_sz[32];
      std::string g_str;
      std::vector<int> g_intarr;
      ....
      // in c++ add a constructor 
     MyGlobals()
          : g_i(-1)
          , g_str("something")
          , g_intarr(100, -1)
     {
           // do some more initializations
           strcpy(g_sz, "datasource");
           ...
     }
     // make getData a member function
     void getData();

};

// get the data from datasource and fill members

void MyGlobals::getData() 
{ 
      if (strlen(g_sz) > 0) 
      {
             // get data from datasource
      }
}

int main()
{
        MyGlobals globals;   // the constructor was called and initializes he members

        // call the function at begin
        globals.getData();
         if (globals.g_intarr.empty() == false)
         {
                 .....

Open in new window

note, even if  a project has mixed c and c++ code, it is much likely that all sources regardless of their extension are compiled with the c++ compiler. I have seen some projects where some c sources were compiled using ansi c compiler and other sources using c++ compiler, but those projects were a rare exception, and doing so has many disadvantages and few advantages.

as c++ is a superset of c you may use only the c++ compiler, but more important is that you should go to an object-oriented programming and design (OOP and OOD) which is the actual power of c++ over c.

Sara
Thank you for your answers, I'm gonna try a couple of think based on your comments and come back to you to tell you how it's going on.

Thank you again !
Hi

Thank you for your answers. Like I said I had try a couple of thing based on your comments, but I haven’t been able to integrate anything correctly in my project.
I need to get the variable
unsigned long vx = 'r->values[x]’;

Open in new window

global, but they are in the do loop of the void function. Can you help me with the following function.

void do_query(const char *q) {
  column_names *c; // pointer to column values
  row_values *r;   // pointer to row values

  // First, execute query. If it returns a value pointer,
  // we have a result set to process. If not, we exit.
  if (!my_conn.cmd_query(q)) {
    return;
  }

  // Next, we read the column names and display them.
  //
  // NOTICE: You must *always* read the column names even if
  //         you do not use them. This is so the connector can
  //         read the data out of the buffer. Row data follows the
  //         column data and thus must be read first.

  c = my_conn.get_columns();
  for (int i = 0; i < c->num_fields; i++) {
   // Serial.print(c->fields[i]->name);
    if (i < c->num_fields - 1) {
      Serial.print(",");
    }
  }
  Serial.println();

  // Next, we use the get_next_row() iterator and read rows printing
  // the values returned until the get_next_row() returns NULL.

  int num_cols = c->num_fields;
  int rows = 0;
  do {
    r = my_conn.get_next_row();
    if (r) {
      rows++;
      for (int i = 0; i < num_cols; i++) {

      unsigned long v1 = 'r->values[0]';
      unsigned long v2 = 'r->values[1]';
      unsigned long v3 = 'r->values[2]';
      unsigned long v4 = 'r->values[3]';
      unsigned long v5 = 'r->values[4]';
      unsigned long v6 = 'r->values[5]';
      unsigned long v7 = 'r->values[6]';
      unsigned long v8 = 'r->values[7]';
      unsigned long v9 = 'r->values[8]';
      unsigned long v10 = 'r->values[9]';


        Serial.println(vtest);

      }
      Serial.println();

      // Note: we free the row read to free the memory allocated for it.
      // You should do this after you've processed the row.

      my_conn.free_row_buffer();
    }
  } while (r);
  Serial.print(rows);
  Serial.println(" rows in result.");

  // Finally, we are done so we free the column buffers

  my_conn.free_columns_buffer();
}

Open in new window

ASKER CERTIFIED SOLUTION
Avatar of trinitrotoluene
trinitrotoluene
Flag of Australia image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Hi Jean,

It probably should be pointed out how the C main() program fits into the C executable.

The O/S loads the program into memory and begins execution at an entry point that is part of the C library, not your main() function.  The initialization process is small an simple.  It does some things so that the user written C program is ready to go.  The stack and heap are initialized, controls for the system streams (STDIN, STDOUT, STDERR) are made ready, etc.  When all of the system initializations are done the main() function get called.

C doesn't have object constructors/destructors like C++ and other object-oriented languages do.  Global data is compiled into a single block that the loader handles by copying it from the file to memory.  This data isn't modified when it's loaded into memory.

To modify the data before the user code (main function) executes you would have to change the C initialization code or define the data so that it has a constructor routine.  You're not likely to change the C initialization and C has no mechanism for defining constructors.

The one thing that might work is to put your constructor in your own main() function and rename the application's main function (perhaps to Main()).  When your main() function completes the desired initializations it call Main().

But injecting code between the C initializations and main() just isn't practical.  To even do that would violate some very strict rules of the language.

Your other choice is very platform dependent.  Through your Make files or loader options files you might be able to build your own main() function that calls Main().  In the loader parameter file equate the symbol main application.o with Main.  The loader will run your main() function and then call main() in the application.


Interesting challenge here....
Kent
the inner for loop in the function is not well defined. if you know that he row has 10 columns it makes no sense to have a for loop on the columns,

anyway, there is no need to use globals for to return a 2d-array to the caller. instead you pass a 2d-array by reference and let the function fill the data;

typedef unsigned int RowData[10];

void do_query(const char *q, std::vector<RowData> & data )
{
       ...
      do {
         r = my_conn.get_next_row();
         if (r) {
           rows++;
           RowData rd;
           for (int n = 0; n < 10; ++n)
           {
               rd[n] = r->values[n];
           }
           data.push_back(rd);
           Serial.println();

           // Note: we free the row read to free the memory allocated for it.
           // You should do this after you've processed the row.

           my_conn.free_row_buffer();
        }
   } while (r);
   ...   

Open in new window



in main you do

...
std::vector<RowData> data;
do_query(q, data);
if (data.empty() == false)
{
     ...
     int nrows = (int)data.size();

Open in new window


and get the result data back in the vector passed as output argument.

as told, i don't know any case where global data really is necessary, especially when using the c++ compiler.

Sara