Trouble with Output from Spatial 1042

C, C++, and Visual C++
KUWill
Phidgetsian
Posts: 7
Joined: Sun Aug 17, 2014 12:09 am
Contact:

Trouble with Output from Spatial 1042

Postby KUWill » Sun Aug 17, 2014 12:14 am

I'm working on writing a datalogging program. I'm using a PhidgetSBC3 but can't seem to get my logic in right. What I'm doing right now is incrementing a counter as spatial packets come in through the SpatialDataHandler function. I then check that counter against a number in an if. If that counter is equal to the number then it goes into another function in which the file is written. For some reason, the program never reaches the write_file function. Can anyone help? A lot of this stuff is over my head.

EDIT: If someone would also be able to tell me how to change the file that I open when I write data, I'd greatly appreciate that. For instance, if I want to write 10 files at 10kb a piece, I can't give them the same name. However fopen wants a const char*. Any advice? I'm also afraid packets are coming in faster than a file can be written. How can I prevent the arrays that are storing data from being over-written during write_file, but store the packets that are coming in elsewhere?

Code: Select all

#include <stdio.h>
#include <phidget21.h>
using namespace std;
#define datalength 1000


int file_count = 0;

double PlaceholderX[datalength];
double PlaceholderY[datalength];
double PlaceholderZ[datalength];
double PlaceholderTime[datalength];
double AccelData1X[datalength];
double AccelData1Y[datalength];
double AccelData1Z[datalength];
double timelog[datalength];

//callback that will run if the Spatial is attached to the computer
int CCONV AttachHandler(CPhidgetHandle Accel1, void *userptr)
{
   int serialNo;
   CPhidget_getSerialNumber(Accel1, &serialNo);
       printf("%i Attached\n", serialNo);
   
   return 0;
}

//callback that will run if the Spatial is detached from the computer
int CCONV DetachHandler(CPhidgetHandle Accel1, void *userptr)
{
   int serialNo;
   CPhidget_getSerialNumber(Accel1, &serialNo);
   printf("%i Detached, Closing Object!\n", serialNo);
   
   return 0;
}

//callback that will run if the Spatial generates an error
int CCONV ErrorHandler(CPhidgetHandle Accel1, void *userptr, int ErrorCode, const char *unknown)
{
   printf("Error handled. %d - %s \n", ErrorCode, unknown);
   return 0;
}

int write_file(int index_counter)
{
    //Define file pointer
    FILE *fp;

    const char *file_name;
    file_name = "acceldata.csv";
   
    printf("Writing Data....");
    fp = fopen(file_name, "w");
    if (fp == NULL)
    {
           printf("File Failure to Open.\n");
           return 0;
    }
    //Labels for data
    fprintf(NULL, "Timelog,X Axis,Y Axis,Z Axis\n");
   
    //Deposits data in appropriate format for CSV
    for(index_counter <= datalength; index_counter++;)
    {
         fprintf(fp, "%f,", PlaceholderTime[index_counter] );
         fprintf(fp, "%f,", PlaceholderX[index_counter] );
         fprintf(fp, "%f,", PlaceholderY[index_counter] );
         fprintf(fp, "%f\n", PlaceholderZ[index_counter]);
    }
    index_counter = 0;
    file_count++;
    fclose(fp);
    return 0;
}

//callback for PhidgetSpatial to manage the data on it's own.
//Phidget Spatial has control and sends interrupts to SBC as necessary per Data Rate set.
int CCONV SpatialDataHandler(CPhidgetSpatialHandle spatial, void *userptr, CPhidgetSpatial_SpatialEventDataHandle *data, int count)
{
   int i;
   int index_counter;
   //printf("Number of Data Packets in this event: %d\n", count);
   for(i = 0; i < count; i++)
   {
      //printf("=== Data Set: %d ===\n", i);
      //printf("Acceleration> x: %6f  y: %6f  x: %6f\n", data[i]->acceleration[0], data[i]->acceleration[1], data[i]->acceleration[2]);
      //printf("Angular Rate> x: %6f  y: %6f  x: %6f\n", data[i]->angularRate[0], data[i]->angularRate[1], data[i]->angularRate[2]);
      //printf("Magnetic Field> x: %6f  y: %6f  x: %6f\n", data[i]->magneticField[0], data[i]->magneticField[1], data[i]->magneticField[2]);
      //printf("Timestamp> seconds: %d -- microseconds: %d\n", data[i]->timestamp.seconds, data[i]->timestamp.microseconds);
      
      //write accel data from packet to global variables
      AccelData1X[index_counter] = data[i]->acceleration[0];
      AccelData1Y[index_counter] = data[i]->acceleration[1];
      AccelData1Z[index_counter] = data[i]->acceleration[2];
      timelog[index_counter] = data[i]->timestamp.seconds + data[i]->timestamp.microseconds/1000000;
      PlaceholderX[index_counter] = data[i]->acceleration[0];
      PlaceholderY[index_counter] = data[i]->acceleration[1];
      PlaceholderZ[index_counter] = data[i]->acceleration[2];
      PlaceholderTime[index_counter] = data[i]->timestamp.seconds + data[i]->timestamp.microseconds/1000000;
      
      
      //increment index_counter to write to next spot in array so information isn't overwritten when the packet is delivered from the spatial
      index_counter++;
      printf("%i",index_counter);
      
      //check value of index_counter to allow writing into a secondary array during file writing
      if (index_counter == datalength)
      {
         write_file(index_counter = 0);   
      }
      
   }

   //printf("---------------------------------------------\n");

   return 0;
}
           
//Basic Single Spatial program
int phidget_spatial()
{
    int result;
    const char *err;
    int index_counter;
   
    printf("Spatial Function");
    //Create the Handle
    CPhidgetSpatialHandle Accel1 = 0;
   
    //Create an object to link to the handle
    CPhidgetSpatial_create(&Accel1);
   
    //Set Handlers to run
      CPhidget_set_OnAttach_Handler((CPhidgetHandle)Accel1, AttachHandler, NULL);
   CPhidget_set_OnDetach_Handler((CPhidgetHandle)Accel1, DetachHandler, NULL);
   CPhidget_set_OnError_Handler((CPhidgetHandle)Accel1, ErrorHandler, NULL);
   
        //Set Phidget Spatial Data Rate for Minimum Averaging, Poll As Needed. Risks losing data.
   CPhidgetSpatial_setDataRate(Accel1, 1000);

   //Set Handler to manage packets coming from Phidget spatial.
   CPhidgetSpatial_set_OnSpatialData_Handler(Accel1, SpatialDataHandler, NULL);
   
   //Open Phidget Spatial for Operation
   CPhidget_open((CPhidgetHandle)Accel1, -1);
}

main(int argc, char* argv[])
{   
    phidget_spatial();
    getchar();
    return 0;
}     

frodegill
Phidget Mastermind
Posts: 114
Joined: Thu Mar 04, 2010 2:51 am
Contact:

Re: Trouble with Output from Spatial 1042

Postby frodegill » Sun Aug 17, 2014 3:36 am

I'm amazed your compiler actually made an executable of this. But when it did, did you actually try to run it in the debugger? What your program currently does is calling phidget_spatial() to set up the handlers and then return and immediately block in the getchar() function. Basically, your program pauses until you press a key, at which it exits..

(Unless you have a very slow storage media you should not worry about writing data as they arrive. But you should really worry about the code. If you compile using g++, add the "-Wall -Werror" flags to locate the most serious flaws)

KUWill
Phidgetsian
Posts: 7
Joined: Sun Aug 17, 2014 12:09 am
Contact:

Re: Trouble with Output from Spatial 1042

Postby KUWill » Sun Aug 17, 2014 5:07 pm

frodegill, do you mean setting -x in the code? I'm not familiar at all with Linux and barely have a handle on C, let alone C++. Either way, I didn't run it in the debugger initially. I was trying to use printf statements in carefully located positions to understand exactly what was going on. Clearly that wasn't working either.

My problem is I need to write a program that will log the data (not hard when using the SpatialDataHandler) from multiple Phidgets (starting to get harder, multiple handles, writing multiple sets of data to file, etc) and then be able to divide up my files in chosen sizes for analysis later on. Any advice on a good way to do that? I'm already working on rewriting my code so it logs to one file from one Phidget, but eventually I want to do multiple Phidgets into multiple files, based on integers fed through scanf() when the program opens.


EDIT: Added new program that gets me a CSV log from one spatial. How do I add Phidgets (one spatial would be enough to demonstrate the concept) and how do I make the file size configurable/create multiple files as a result of a "Full" file.

Code: Select all

#include <stdio.h>
#include <phidget21.h>
using namespace std;
#define datalength 10000

double AccelData1X[datalength];
double AccelData1Y[datalength];
double AccelData1Z[datalength];
double timelog[datalength];
FILE *fp;

//callback that will run if the Spatial is attached to the computer
int CCONV AttachHandler(CPhidgetHandle Accel1, void *userptr)
{
   int serialNo;
   CPhidget_getSerialNumber(Accel1, &serialNo);
       printf("%i Attached\n", serialNo);
   
   return 0;
}

//callback that will run if the Spatial is detached from the computer
int CCONV DetachHandler(CPhidgetHandle Accel1, void *userptr)
{
   int serialNo;
   CPhidget_getSerialNumber(Accel1, &serialNo);
   printf("%i Detached, Closing Object!\n", serialNo);
   
   return 0;
}

//callback that will run if the Spatial generates an error
int CCONV ErrorHandler(CPhidgetHandle Accel1, void *userptr, int ErrorCode, const char *unknown)
{
   printf("Error handled. %d - %s \n", ErrorCode, unknown);
   return 0;
}


//callback for PhidgetSpatial to manage the data on it's own.
//Phidget Spatial has control and sends interrupts to SBC as necessary per Data Rate set.
int CCONV SpatialDataHandler(CPhidgetSpatialHandle spatial, void *userptr, CPhidgetSpatial_SpatialEventDataHandle *data, int count)
{
   int i;
   int index_counter;
   //printf("Number of Data Packets in this event: %d\n", count);
   for(i = 0; i < count; i++)
   {
      //printf("=== Data Set: %d ===\n", i);
      //printf("Acceleration> x: %6f  y: %6f  x: %6f\n", data[i]->acceleration[0], data[i]->acceleration[1], data[i]->acceleration[2]);
      //printf("Angular Rate> x: %6f  y: %6f  x: %6f\n", data[i]->angularRate[0], data[i]->angularRate[1], data[i]->angularRate[2]);
      //printf("Magnetic Field> x: %6f  y: %6f  x: %6f\n", data[i]->magneticField[0], data[i]->magneticField[1], data[i]->magneticField[2]);
      //printf("Timestamp> seconds: %d -- microseconds: %d\n", data[i]->timestamp.seconds, data[i]->timestamp.microseconds);
      
      //write accel data from packet to global variables
      fprintf(fp,"%f,",data[i]->acceleration[0]);
      fprintf(fp,"%f,",data[i]->acceleration[1]);
      fprintf(fp,"%f,",data[i]->acceleration[2]);
      fprintf(fp,"%f\n",data[i]->timestamp.seconds + data[i]->timestamp.microseconds/1000000);
      
      //increment index_counter to write to next spot in array so information isn't overwritten when the packet is delivered from the spatial
      index_counter++;
      //check value of index_counter to allow writing into a secondary array during file writing
   }

   //printf("---------------------------------------------\n");

   return 0;
}
           
//Basic Single Spatial program
int phidget_spatial()
{
    int result;
    const char *err;
    int index_counter;
   
    printf("Spatial Function");
    //Create the Handle
    CPhidgetSpatialHandle Accel1 = 0;
   
    //Create an object to link to the handle
    CPhidgetSpatial_create(&Accel1);
   
    //Set Handlers to run
      CPhidget_set_OnAttach_Handler((CPhidgetHandle)Accel1, AttachHandler, NULL);
   CPhidget_set_OnDetach_Handler((CPhidgetHandle)Accel1, DetachHandler, NULL);
   CPhidget_set_OnError_Handler((CPhidgetHandle)Accel1, ErrorHandler, NULL);
   
    //Set Phidget Spatial Data Rate for Minimum Averaging, Poll As Needed. Risks losing data.
   CPhidgetSpatial_setDataRate(Accel1, 4);

   //Set Handler to manage packets coming from Phidget spatial.
   CPhidgetSpatial_set_OnSpatialData_Handler(Accel1, SpatialDataHandler, NULL);
   
   //Open Phidget Spatial for Operation
   CPhidget_open((CPhidgetHandle)Accel1, -1);
   
   //Open File to write Phidget Data
   fp = fopen("acceldata.csv", "w");
   
   if(fp == NULL)
   {
          printf("File Failed to Open.");
          return 0;
        }
       
        fprintf(fp,"AccelX,AccelY,AccelZ,Time\n");
}

main(int argc, char* argv[])
{   
    phidget_spatial();
    getchar();
    fclose(fp);
    return 0;
}

frodegill
Phidget Mastermind
Posts: 114
Joined: Thu Mar 04, 2010 2:51 am
Contact:

Re: Trouble with Output from Spatial 1042

Postby frodegill » Sun Aug 17, 2014 11:40 pm

My bad on getchar(), phidget open() forks.. (althought I would very much advice against relying on a getchar() to quit)

First tip: Always check the return value of the open() call.

KUWill wrote:My problem is I need to write a program that will log the data (not hard when using the SpatialDataHandler) from multiple Phidgets (starting to get harder, multiple handles, writing multiple sets of data to file, etc)

If you want to use a separate FILE for each Phidget, you could very well send the FILE as userptr (or, even better, a struct including FILE and whatever else you might need per Phidget)


and then be able to divide up my files in chosen sizes for analysis later on.

fprintf returns how many bytes written, if you want to split on filesize. If you want to split on lines written, this is easy to count yourself.


eventually I want to do multiple Phidgets into multiple files, based on integers fed through scanf() when the program opens.

Not sure what you want to do with scanf. You have all info you need in argv[], don't you?
But use sprintf and a counter to generate filenames, and you should have no problem handling multiple files and multiple Phidgets.

Added new program that gets me a CSV log from one spatial. How do I add Phidgets (one spatial would be enough to demonstrate the concept) and how do I make the file size configurable/create multiple files as a result of a "Full" file.

Insted of FILE *fp;, use something like

Code: Select all

struct FileInfo
{
  File *fp;
  int filecounter;
  size_t filesize;
}


Then generate filenames like

Code: Select all

sprintf(filename, "%d_%d.csv", serialNo, file_info->filecounter++);


send a pointer to a struct object in the CPhidgetSpatial_set_OnSpatialData_Handler call, and you have access to the info you need in the handler

Code: Select all

int CCONV SpatialDataHandler(CPhidgetSpatialHandle spatial, void *userptr, CPhidgetSpatial_SpatialEventDataHandle *data, int count)
{
  FileInfo* file_info = (FileInfo*)userptr;
  ...

User avatar
Patrick
Lead Developer
Posts: 3056
Joined: Mon Jun 20, 2005 8:46 am
Location: Canada
Contact:

Re: Trouble with Output from Spatial 1042

Postby Patrick » Mon Aug 18, 2014 8:31 am

The reason why your 1st program doesn't ever write to a log is because index_counter is an instance variable, so it's value is not saved across calls to SpatialDataHandler() - you need to make it either static or global, and make sure you initialize to it 0 as well.

-Patrick

KUWill
Phidgetsian
Posts: 7
Joined: Sun Aug 17, 2014 12:09 am
Contact:

Re: Trouble with Output from Spatial 1042

Postby KUWill » Tue Aug 26, 2014 11:48 pm

frodegill, Patrick, quick follow up. Thank you for the advice. I resolved a slew of problems as noted by the both of you in my understanding of Phidgets.

Can you explain what the function of the following snippet of code is?

Code: Select all

CPhidgetSpatialHandle Handle = 0;

I'm trying to generate multiple handles because I have several Spatials connected. I'm not exactly sure what the function of the "= 0" section is. Can you explain it? Additionally, is there a way I can create multiple handles without explicitly calling them out? I'm thinking of somehow using the PhidgetManager to count the number of Spatials and then create an iterating name for assigning handles. For example, if I have 3 Spatials connected, the handles would be spatial1, spatial2, spatial3. I'm basically trying to figure out how to generate unique handles from the PhidgetManager data if I don't know what Phidgets are plugged in.

Thanks.

frodegill
Phidget Mastermind
Posts: 114
Joined: Thu Mar 04, 2010 2:51 am
Contact:

Re: Trouble with Output from Spatial 1042

Postby frodegill » Wed Aug 27, 2014 4:07 am

KUWill wrote:Can you explain what the function of the following snippet of code is?

Code: Select all

CPhidgetSpatialHandle Handle = 0;


This is a very basic C/C++ question, not related to Phidgets.
If you look in phidget21.h, you will find

Code: Select all

typedef struct _CPhidgetSpatial *CPhidgetSpatialHandle;

Also note that somewhere in your standard include files, you will have

Code: Select all

#define NULL 0

So a rewrite of the above code could be

Code: Select all

_CPhidgetSpatial *Handle = NULL;

Is this easier to understand?


Additionally, is there a way I can create multiple handles without explicitly calling them out? I'm thinking of somehow using the PhidgetManager to count the number of Spatials and then create an iterating name for assigning handles.

This is possible, and the preferred way if you do not know how many Phidgets you have or their searial numbers.

For example, if I have 3 Spatials connected, the handles would be spatial1, spatial2, spatial3.

Better use an array.

Code: Select all

int count = 3; //or the number you get from PhidgetManager  :-)
CPhidgetSpatialHandle* handles = new CPhidgetSpatialHandle[count];
int i;
for (i=0; i<count; i++)
{
  handles[i] = NULL;
}

When you are ready to initialize a spatial

Code: Select all

CPhidgetSpatial_create(handles[0]); //Initializes struct for first spatial. Array is 0-indexed


Remember to free memory when done

Code: Select all

int i;
for (i=0; i<count; i++)
{
  CPhidget_delete((CPhidgetHandle)handles[i]);
}
delete[] handles;


(note: code may contain errors, I have not tried to compiled it)

KUWill
Phidgetsian
Posts: 7
Joined: Sun Aug 17, 2014 12:09 am
Contact:

Re: Trouble with Output from Spatial 1042

Postby KUWill » Thu Aug 28, 2014 10:20 pm

frodegill, I'm working on figuring all this out. Do I need to worry about asynchronous writes to the file getting mixed up in the respective columns when written to the CSV?

Code: Select all

int CCONV SpatialDataHandler(CPhidgetSpatialHandle spatial, *userptr, CPhidgetSpatial_SpatialEventDataHandle *data, int count)
{
     //Only writes data to file asynchronously according to when the Phidget is opened in Logger
    int i;
    for ( i < 3 )
    {
       fileNames << data[0].acceleration[i] << ",";
       charCount + 3;
    }
    fileNames << data[0].timestamp.seconds << "," << data[0].timestamp.microseconds << "\n";
}


I'd like them to write with spatial 1 data in the first 4 columns, spatial 2 data in the next 4, spatial 3 data in the next 4, then a new line.

Can you confirm that this handler DOES allow the passing of one of the values in an array since an array would still have the CPhidgetSpatialHandle type?

frodegill
Phidget Mastermind
Posts: 114
Joined: Thu Mar 04, 2010 2:51 am
Contact:

Re: Trouble with Output from Spatial 1042

Postby frodegill » Fri Aug 29, 2014 2:23 am

KUWill wrote:I'd like them to write with spatial 1 data in the first 4 columns, spatial 2 data in the next 4, spatial 3 data in the next 4, then a new line.

Phidgets guys will have to confirm this, but I GUESS that when you have 3 spatials connected, and you use CPhidgetSpatial_set_OnSpatialData_Handler, you are NOT guaranteed that the handlers are called in order.
If you need data logged like "<spatial1>,<spatial2>,<spatial3>\n", I would much rather have a timed loop and poll for the values myself (instead of relying on the data handler).

Code: Select all

int axis_count = 3; //X, Y, Z
double acceleration;
int spatial_index, axis_index;
uint64 datarate = 1000; //Once every second
uin64 time_before_logging, time_after_logging;
while(true)
{
  time_before_logging = <whatever your system provides to get high-resolution time>;

  for (spatial_index=0; spatial_index<spatial_count; spatial_index++)
  {
    for (axis_index=0; axis_index<axis_count; axis_index++)
    {
      CPhidgetSpatial_getAcceleration(spatial[spatial_index], axis_index, &acceleration));
      if (!(spatial_index==0 && axis_index==0))
      {
        log_file << ",";
      }
      logfile << acceleration;
    }
  }
  logfile << "\n";

  time_after_logging = <whatever your system provides to get high-resolution time>;
  usleep(datarate - (time_after_logging-time_before_logging);
}

(not compiled code, may contain errors)

If this is not good enough for your task, I fear you will have to housekeep the values in the data handler yourself, and log them Tetris-style (dump a line when you have data for all 3 spatials);

Can you confirm that this handler DOES allow the passing of one of the values in an array since an array would still have the CPhidgetSpatialHandle type?

In userptr, you mean? Userptr is a void*. You set this to whatever value you want when you set the data handler callback, and you get this very same value in all data handler callbacks. No magic involved.

User avatar
Patrick
Lead Developer
Posts: 3056
Joined: Mon Jun 20, 2005 8:46 am
Location: Canada
Contact:

Re: Trouble with Output from Spatial 1042

Postby Patrick » Fri Aug 29, 2014 8:21 am

frodegill is absolutely correct. The SpatialData events will be coming in at a set interval, but with no guarantee of order. Also, they are on separate threads, so it's not safe to access your file handle from them without any locking.

Depending on your data rate, you may be able to log polled data, but it's much better to log the event data as this way you get the corresponding timestamps and guarantee that all the data is from the same time interval.

-Patrick


Return to “C/C++”

Who is online

Users browsing this forum: No registered users and 2 guests