HEM Data Support: Helpful Hints
Navigation

Interpreting HDI’s CalBlock from a Snap-Master FBDF File

Overview

The following table lists the order in which the data appears in the “CALBLOCK&[]” section of a FBDF file header.

Entry Number of bytes Description
“CALBLOCK&[]“ 13 Section Name
comma 1 delimiter
integer string variable length of the section starting at the first byte after the equals.
comma & equals 2 delimiters
string variable Name of DLL whose rescale function is called.
comma 1 delimiter
integer string variable Ordinal number of rescale function.
comma 1 delimiter
sCalBlock structure variable See Note 1.
DEVSCALESTRUCT variable * NumChans One for each channel is written. See Note 1.
array of integers 2 * NumChans List of channel numbers.
CR/LF 2 Carriage return and line feed.

Note 1: These structures have grown with newer versions of HDI. The following sections will show you how to deal with how much of a particular structure is present in an existing FBDF file.

Structures

The following are the 2 structures written to the FBDF header as of HDI v1.60.

typedef struct tagDEVSCALESTRUCT
{
int nLen; // size of the structure
float fFactor; // Scale Factor for channel, used during scaling
float fOffset; // Scale Offset for channel, used during scaling
float fFactor2; // Scale Factor 2, if needed, for channel used during scaling
float fOffset2; // Scale Offset 2, if needed, for channel used during scaling
float CALLBACK (*lpNonLinearScale)(int, lpCalBlock, float );
// OEM supplied callback to support non-linear ranges
} DEVSCALESTRUCT;


typedef struct tagCalBlock
{
float fVersion; // Version of the structure
int nLen; // Size of the structure
int nInterleave; // Number of channels in the raw unsigned buffer
int nFloatInterleave; // Number of channels in the float buffer
long lBufLength; // Size of the buffer
WORD wAndMask; // And mask used with raw data 16-bits or less
WORD wXorMask; // Xor mask used with raw data 16-bits or less
WORD wCalBlockSize; // Size of the structure
WORD wScaleBlockSize; // Size of the scale block array in bytes
LPDEVSCALESTRUCT lpScaleBlock; // Pointer to array of DEVSCALESTRUCT structures. One for each channel
int *lpOffset; // Pointer to array of channel offsets
int *nCh; // Pointer to array of physical channel numbers
enumSAMPLEFORMAT eSampleFormat; // Sample format of the data. Used with enumSAMPLEFORMAT
unsigned long uAndMask32; // And mask used with raw data 32-bits or less
unsigned long uXorMask32; // Xor mask used with raw data 32-bits or less
int nDevice; // Device number the element belongs to
} sCalBlock;

Example Code

The following code excerpt assumes you have already read the header into a buffer called lpBuf and that a “CALBLOCK&[]” section exists.

// declare some variables
sCalBlock CalBlock;
DEVSCALESTRUCT DevScale;


// find the start of the "CALBLOCK&[]" section in lpBuf
char *lpCalBlock = strstr( lpBuf, "\"CALBLOCK&[]\"" );


lpCalBlock += 14; // skip "CALBLOCK&[]",

char *lpTmp = strtok( lpCalBlock, “,” ); // NULL comma after section length

// get section length
int nSectionLen = atoi( lpTmp );

lpTmp = strtok( 0, “,” ); // NULL comma after dll name
lpTmp++; // skip the equal sign

// At this point lpTmp points to the dll name
lpTmp = strtok( 0, “,” ); // NULL comma after ordinal number
int nOrdinal = atoi( lpTmp );

// skip ordinal number
while( *lpTmp )
lpTmp++;

// skip NULL after ordinal number
lpTmp++;

// At this point lpTmp points to the start of the sCalBlock structure.
// Lets get the size of the sCalBlock saved in this file.
// From the structure definition above we know the length is at bytes 4&5.
// Could be smaller than the current structure.
int nCalBlockLen = *((int *)(lpTmp+4));

// copy from byte stream lpTmp into our local CalBlock variable.
memcpy( &CalBlock, lpTmp, nCalBlockLen );

// skip the cal block structure.
lpTmp += CalBlock.nLen;

// At this point lpTmp points to the start of the DEVSCALESTRUCT(s). One per channel.
// Calculate the size of one of these structures saved in this file. Could be smaller than
// the current structure.
int nSBLen = CalBlock.wScaleBlockSize / CalBlock.nInterleave;

// create an array of DEVSCALESTRUCT(s) off of the CalBlock structure. One per channel.
CalBlock.lpScaleBlock = new DEVSCALESTRUCT [ CalBlock.nInterleave ];

// copy from byte stream lpTmp into our local DEVSCALESTRUCT array.
for( int i=0; i < CalBlock.nInterleave; i++ )
{
memcpy( &(CalBlock.lpScaleBlock[i]), lpTmp, nSBLen );
lpTmp += nSBLen; // skip DEVSCALESTRUCT for ith channel.
}

// At this point lpTmp points to the start of the channel numbers.
WORD *lpChs = new WORD [ CalBlock.nInterleave ];

// copy from byte stream lpTmp into our local channel numbers array.
memcpy( lpChs, lpTmp, CalBlock.nInterleave * sizeof( WORD ) );

Scaling the Data

The following code excerpt shows how to scale one sample stored in the unsigned variable uSample. Assume its from channel 0.

float fVal = ((uSample ^ CalBlock.wXorMask) & CalBlock.wAndMask) *
CalBlock.lpScaleBlock[0].fFactor + CalBlock.lpScaleBlock[0].fOffset;