Our full technical support staff does not monitor this forum. If you need assistance from a member of our staff, please submit your question from the Ask a Question page.


Log in or register to post/reply in the forum.

Java SDK and .TDF


cbabcock May 23, 2012 04:09 PM

Hi,
I've been working with the Java SDK a little bit and am trying to implement my own data collection in my Java program. I'm going by the demos provided with the SDK and have a question.

Does anyone know where I can find my TDF file with LoggerNet 3.41? I need to find out how many bytes are in the file so I can manually set the raw table definitions for the station before starting the poll.

I'm looking to do this so I can avoid having to do a GetTableDefsTransaction every time that I want to retrieve the data from the DataLogger.

Thanks in advance.


GTProdMgr May 23, 2012 05:04 PM

Of course, there is the .TDF file that is stored on the CR1000/3000/800 logger itself in a place where it doesn't show on the CPU: drive, yet it is there internal memory. As far as I know you have to use GetTableDefsTransaction to get that one (this is the way LoggerNet does it etc.) I think the way LoggerNet and other software does things is to simply keep track whenever a new program is sent, and then keep its own copy of the table defs each time that process occurs.

However, I think what you may be after is a .TDF file that is on your PC's file system and generated when you pre-compile a CRBasic Program. Somewhere around the release of OS 15 for the CR1000 (January 2008) the -z option was added to the pre-compiler (CR1COMP.EXE) This was after the release of LN 3.4.1 (Oct 2007) but you would get a newer compiler if you download a newer OS (15 or higher) from the CSI website.

Later versions of the CRBasic Editor give you the ability to generate this file (or not) at the same time you pre-compile a program. Since you don't have a newer editor, your options would be to upgrade to a newer LoggerNet, PC400, RTDAQ, etc. or to learn how to use the CR1COMP.EXE pre-compiler with command line options. If you use the -z, then you can get the .TDF created, and should be able to read the number of bytes in that file etc, without having to query the logger for its TableDefs. LoggerNet (v4.0 and later, I believe) has a feature for associating that file with a logger so that the "GetTableDefs" process isn't required as much (or at all).


jtrauntvein May 23, 2012 05:35 PM

The table definitions that are generated by the precompiler mentioned by GTProdMgr above are not sufficient for the SDK to collect data. The problem lies in the fact that the pre-compiler has no notion of the memory available in the datalogger and can therefore no predict the number of records for auto-allocated tables. The upshot is that the signature generated from these table definitions does not match signature of the table definitions that are actually generated by the datalogger.

That said, you can use the corascript (cora_cmd.exe) get-file command to obtain the table definitions file from the datalogger as follows:

connect localhost;
get-file <logger> .tdf --save-as=<logger>.tdf;

Replace <logger> with the name of the datalogger object in LoggerNet's network map.


cbabcock May 23, 2012 06:35 PM

Ok, so what I think you're saying jTrauntvein is that when the SDK reads the raw tdf to get the byte length, it is really looking for the byte length of the whole file with regard to the amount of records in the table? (That was confusing let me try to explain it better).

In the TestDataCollect demo, you have the possibility of specifying tdf to indicate a read from a raw tdf file. If the user specifies this the demo opens a FileInputStream to get the byte length of the file and creates a new byte with this length. This byte is then used to set the raw table definitions of the station before polling the station.

Please correct me if that interpretation is wrong.

My question is, what does that byte length obtained from the tdf represent?

Does it represent the table size without records or is it expected that that tdf is going to be constantly changing in size when the datalogger is logging.

Sorry I guess I'm unaware of what the table definition file is used for. I would assume it would be a file used to specify the columns of the table hence why I thought it would be possible to just use a constant value for the set_raw_table_defs method since our table values won't be changing while we're logging data.

I'm also assuming that you're the same Jon Trauntvein who is the author of the code so that's why I'm going into the technicalities. So correct me if I'm wrong there as well.

Maybe this is all too much work just to avoid calling GetTableDefs every time I want to grab the most recent data from the logger? I just see the GetTableDefs as being an expensive call if I'm grabbing data from the logger every second, am I wrong? Could you suggest a better approach?

Sorry for the long windedness of the response. Thanks again!


jtrauntvein May 23, 2012 09:37 PM

The .tdf file generated by the datalogger contains a detailed description of each table defined by the datalogger program. Along with column meta-data, the table definition contains a value that indicates how many records the datalogger is capable of storing in each table. When data collection occurs, the client provides the datalogger with a two byte signature that was calculated on the a table definition. If that signature does not agree with the datalogger's own calculation, the transaction will fail. The number of records in the table is included in that signature. These table definitions will remain static unless the datalogger starts a new program or the program does card storage on a card that gets ejected or replaced (these events will affect the number of records reported for the table).

I assume in your question above, you are referring to the following fragment of code:

if(arguments.has_option("tdf"))
{
String tdf_file_name =arguments.get_option("tdf");
FileInputStream input = new FileInputStream(tdf_file_name);
int input_len = input.available();
byte[] raw_tdf = new byte[input_len];

input.read(raw_tdf);
station.set_raw_table_defs(raw_tdf, input_len);
start_poll(station);
}


The length of the above fragment is merely the length of the table definition file and is used to determine the size of the array and how much to read from the file.

An object of class com.campbellsci.pakbus.Datalogger will cache the last set of table definitions that it received and use these for data collection so you don't have to get table definitions every time you collect unless you are destroying the datalogger object each time. You can access the last .tdf file loaded by the datalogger by calling its get_raw_table_defs() method which returns an object of class Packet. If you want to save this to a file or elsewhere, you can do so by calling that object's get_storage() and get_storage_len() methods.

Finally, I am the author of the SDK and am gratified that you are using it.


cbabcock May 24, 2012 01:22 PM

Ah, now why didn't I think of that (getting the table defs once at the start)? That makes a lot more sense.

Here's a question regarding that code snippet above, why do you do

input.read(raw_tdf);

?

It would appear that input isn't used after this call?

Also, I have another unrelated question so I'll start another thread.

And thanks for writing this SDK!


GTProdMgr May 24, 2012 03:25 PM

It has been pointed out previously that the .TDF file generated by the pre-compiler (CR1Comp.exe) on the PC's file system won't satisfy your original request. However, for anyone who is interested in how to generate this file without the CRBasic Editor, the command-line syntax is :

Prompt> CR1Comp.exe -z <tabledef>.TDF <CRBasicProg>.CR1

where <tabledef> is the name of the .TDF file to be generated and <CRBasicProg> is the name of the existing program being pre-compiled.


GTProdMgr May 24, 2012 03:34 PM

The -l option creates a "human readable" info file containing each table used and all of its fields/columns:

Prompt> CR1Comp.exe -l <TableInfo>.txt <CRBasicProg>.CR1

Use -l and -z together like this:

CR1Comp.exe -z <tabledef>.TDF -l <TableInfo>.txt <CRBasicProg>.CR1


jtrauntvein May 24, 2012 06:45 PM

Here's a question regarding that code snippet above, why do you do
input.read(raw_tdf);
?
It would appear that input isn't used after this call?

The whole purpose of the exercise is to read the contents of the file into a byte buffer (raw_tdf) which can then be passed to the datalogger via the call to set_raw_table_defs(). Once the file has been read, the handle to that file is no longer needed. Similarly, once the raw table definitions have been set to the datalogger, the buffer is no longer needed.

Log in or register to post/reply in the forum.