High-Speed OEM Integration Guidance for LabMax-Pro SSIM Meter With PowerMax-Pro in C#


Customers are increasingly using the LabMax-Pro SSIM meter for deep integration, writing custom code to stream high speed data. This type of meter interface requires a high level of competency on the customer’s side to implement, in addition to our technical guidance. This document is intended to provide tools for success.

Identifying the needed tools for the integration.

The Coherent Meter Connection (CMC) software program that we provide for use with our LabMax-Pro SSIM meter is able to read and stream high speed data and export to a file in real-time at 20kHz / 50us sample rates.  The process is intricate and assumes a lot of experience on the user/programmer’s part to be successful. The data provided in this document has enabled success at multiple customers’ sites in the past. Resources needed…

1.  Experienced programmer or software engineer on the customer side to program the interface.

2.  LabMax-Pro SSIM user manual (especially host interface chapter).

3.  CMC application installed and running to view I/O transcripts function.

a.  Shows the SCPI commands for comparable operation settings.

b.  Some commands are sent more than once although not required.

4.  This technical note.

High level overview of the process -important points.

When programming the SSIM meter there are some important points to be used throughout the process. Please refer to the process items below.

1.  Data acquisition can be done in two ways:

a.  Stop On Count – stops automatically after N samples are sent

·  Stop On Count is strongly recommended

b.  Continuous – runs until expressly commanded to stop by host

·  More complicated because meter sends extra records before stopping

2.  Data acquisition can be encoded in two ways:

a.  Binary

·  Binary is strongly recommended!


3.  Both encodings allow a variety of data to be sent

a.  Optimize for speed (don’t send data you don’t need) vs. collect more just in case

b.  Options:

  • Primary (Measurement)
  • X, Y offsets (from LM sensors only)
  • Data Acquisition Flags (always recommended)
  • Sequence ID (only for energy)
  • Pulse Period (only for energy)

c.  Documented in SCPI ref

d.  SSIM does NOT send timestamp information for data samples

Timestamps are normally reconstructed on the receiving end by incrementing a variable by the sample rate.

4.  Handshaking

a.  Useful when interacting with SCPI, you can’t see responses if its off

b.  But generally disabled for Streaming data

c.  Issued as the last command before issuing Start

Data Acquisition Overview.

DAQ may be done in ASCII or Binary – iterate per sample:

  • For binary: simply read the proper number of bytes and pack them into a destination struct per your requested encoding flags. No number conversion is required.
  • Binary streaming USB comes in chunks, and often a single read does not return all the bytes you need. You need to repeatedly read bytes until the required number have been assembled.
  • Binary is recommended because it’s faster and more compact and does not require expensive text to number conversions
  • For ASCII: read one line of text and parse it according to your requested encoding flags

Our CMC software does data acquisition in a separate thread so that the UI is not blocked while the thread is waiting for data to be read. Threading is an advanced topic beyond the scope of this document.

Send setup SCPI commands to configure for your particular measurements

1.  First, at a minimum you need (in any order)

  • Send CONF:MEAS:MODE W to select power or J for energy measurements
  • Send CONF:READ:MODE BINARY to Specify Binary mode (recommended)
  • Send CONF:ITEM PRI,FLAG to specify you want measurements and flag data only. The binary data will consist of a
  1. 4-byte float (IEEE floating point number) Measurement value, followed by
  2. 2-byte unsigned integer flags word
  • Many other commands may be relevant to your circumstances

2.  Last, perform the following steps in order:

i. Send SYST:COMM:HAND OFF to turn off handshakiing

ii. Flush the input buffer – you need to discard any handshaking, error messages or other extraneous input data that accumulated while sending the above commands so that your first read will start with at the beginning of the first data record. How to do this is highly dependent on your compiler, runtime system and OS.

iii. Send START 100

  • To tell the meter to start acquisition, stopping after 100 records
  • Include a record count so the meter sends a fixed number of records. Best to test/debug initially with just a few records.
Then start reading data

1. One record at a time

2. Until the count is exhausted

Things to watch for

Each data record normally includes a flags word. Several of these Measurement Flags should be checked upon each sample:

1. OverTemp = 0x80 – indicates sensor is overheating and acquisition probably should be terminated, and in any case the error should be reported

2. Terminated = 0x8000 – indicates meter detected a fatal error (e.g. sensor disconnected) and must unilaterally terminate acquisition; no more data is forthcoming

3. MissingSamples = 0x100 – the host failed to read data fast enough from the meter, the meter’s internal buffer overran, and some data records were necessarily omitted from the stream. Data ACQ can continue but the flag marks a discontinuity in the data 

C# examples of interface code.

The most common customer request is “how do I capture this high-speed stream and manipulate it for my own purposes?” This next section covers the data acquisition loop required to stream high-speed data.

ThreadBody – the inner loop of data acquisition

The essence of ThreadBody is a while loop that repeatedly calls ReadOneRecord to fetch each data sample. Any errors (exceptions) cause the function to exit. It also implements the optional StopOnCount functionality.

First time through the loop, the ReadOneRecord call is the first data read after the start command is sent. The loop continues until all the data has been loaded and added to the CaptureBuffer.

Data is a global static temporary array, large enough to handle any record.

IsStopping is a global flag that signals all the acquisition code to prematurely terminate.

TerminatedByMeter tests ( record.Flags & MeasurementFlags.Terminated ) != 0 ),
where Terminated = 0x8000 // meter declares unilateral termination

The sections highlighted in blue may be disregarded.


      protected override void ThreadBody()
              // energy mode has to actually wait a while before IsWaiting comes true
              OnDAQ_StateChanged( DAQ_State.Start );
              // fill Data array with the required number of bytes
              while( !IsStopping && ReadOneRecord( Data)) 
              // fill Data array with the required number of bytes
              while( !IsStopping && ReadOneRecord( Data ) )
                          // if we get data while waiting, then we're no longer waiting
                          if( IsWaiting )
                                        IsWaiting = false;
                                       OnDAQ_StateChanged( DAQ_State.Triggered );

                          // copy the binary data into a Data Record
                          Record.Read( Data );
                          Record = new DataRecordSingle( Data );
                          TraceLogger.TraceRead( $"DAQ.HS.Read: {Record.ToString_AsHex()} // {Record.ToStringEx()}" );
                           // if meter sets abort flag, then we have to stop 
                           // (and this record should NOT get added to Capture buffer)
                           if( TerminatedByMeter( Record ) )

                           // Add the data Record to the CaptureBuffer, where a timestamp is assigned
                            CaptureBuffer.TimestampAndAdd( Record );
                            TraceData( "Add[ {0} ]: {1}", RecordsRead, Record.ToString() );

                            if( StopOnCount && Count >= Capacity )
      catch( Exception ex )
                       // all uncaught exceptions are reported and terminate the thread
                       ReportException( ex );
       // all exits from try statement need to exit successfully


ReadOneRecord – the inner loop of data acquisition

ReadOneRecord repeatedly calls a Read function to load the required number of bytes into the destination data array.

The heart of the reader is the first two while loops. Most of the other code pertains to exceptional conditions that may not arise on your system.

If for any reason ReadOneRecord cannot acquire all the data, it returns false and thus terminates the ThreadBody loop. Numerous other exceptional conditions may terminate the loop.

Complexity results because read functions on COM ports do not necessarily return all of the data requested. If they return less than is needed, the inner loop repeatedly fetches successively smaller remainders of the data.

Channel.Read is essentially the .Net SerialPort read function.

The only twist is that the entire destination array is passed in as an argument, the index says where the new data should be placed, and the count is how many bytes are requested. Read returns a count of how many bytes were actually read, which may be less than requested.

IsStopping is a global flag that signals all the acquisition code to prematurely terminate.

protected virtual bool ReadOneRecord( byte[] data )
     int count = data.Length;
	 int index = 0;

	// outer loop repeatedly attempts reading 1 record,
	// restarting an incomplete inner loop after a timeout
	while( count > 0 && !IsStopping )
			// Inner loop reads one record, but
			// possibly times out before completing that read
			while( count > 0 && !IsStopping )
				int actual = Channel.Read( data, index, count );
				if( actual <= 0 )
					// eof "cannot happen" thus fatal error
					return false;

				count -= actual;
				index += actual;

			// if we get here, we have a complete record

			 // stats only for complete records
			BytesRead += data.Length;

		// in Energy mode, we sometimes wait a long time for an energy reading, 
		// so timeout while reading is normal 

		catch( TimeoutException )
			// Stop while Waiting terminates the operation

			if( IsStopping )
				return false;	// terminate DAQ

			// else if timeout when we're not stopping...

			// timeouts are not allowed in power mode
			if( !OperatingMode_IsTrueEnergy
			&& SampleTime.ElapsedMilliseconds > PowerModeMaxElapsed_ms )
				return false;   // terminate DAQ

			// signal TriggerWait first time we start waiting again
			if( !IsWaiting )
				IsWaiting = true;
				OnDAQ_StateChanged( DAQ_State.TriggerWait );

			// ignore timeouts if not stopping or PowerMode timeout
	} // outer while loop

	return ( count == 0 );  // nonzero count signals failure
Contact Coherent

For assistance or additional information, visit our support services page. For example, if you cannot find the calibration cert for your sensor, we can send a replacement.

To arrange for warranty service or annual recalibration, first contact your regional Coherent service center to obtain a Return Material Authorization (RMA) number. Use the shipping box and packaging materials you retained to safely transport the sensor back to the factory, and ship to this address:

Coherent, Inc.
Attn: RMA #
27650 SW 95th Ave.
Wilsonville, OR 97070

Schedule a no-cost consultation to discuss your needs.