AxsunOCTCapture 3.8.2
Captures and buffers streamed imaged data from the Axsun Ethernet/PCIe DAQ and displays or retrieves images to a client application on request.
AxsunOCTCapture_example_NewImageCallback.cpp

This is example source code showing how to retrieve images from the Main Image Buffer using the event-driven New Image Callback functionality of AxsunOCTCapture in a C++ client application. It also shows how to select a capture interface (Ethernet or PCIe), change imaging modes (PCIe only), and use the OpenGL-based image display (Windows only).

// AxsunOCTCapture_example_NewImageCallback.cpp
//
//
// NOTES:
//
// 1. AxsunOCTCapture functions are Standard C and do NOT throw C++ exceptions, but rather
// return an error status of type AxErr. Calls to AxsunOCTCapture functions in this
// example program are typically wrapped in an "if (status != OK) throw AxErr" fashion
// and contained in a try/catch block in order to make the behavior exception-based.
//
// 2. The intent of this example program is to exemplify the capabilities of the
// AxsunOCTCapture library. Program structure is simplified for readability and is not
// intended for "production" use as-is.
//
#include "AxsunOCTCapture.h" // for all AxsunOCTCapture functions, structs, enums, typedefs
#include <iostream> // for std::cout & std::cin; not related to AxsunOCTCapture functionality
#include <chrono> // for loop timer sleep function; not related to AxsunOCTCapture functionality
#include <thread> // for loop timer sleep function; not related to AxsunOCTCapture functionality
#include <vector> // for memory allocation... could new(), malloc(), array[], or whatever you prefer
#ifdef _WIN32
#include <conio.h> // for console keyboard interaction
#include <windows.h> // for Windows event handling
#endif
using namespace std::chrono_literals;
// Define an AxsunOCTCapture class to wrap axStartSession(), axStopSession(), and the session handle in RAII fashion.
// (This will conveniently call axStopSession() in the destructor so that resources are automatically cleaned up.)
class AxsunOCTCapture {
private:
AOChandle session_{ nullptr };
public:
AxsunOCTCapture(float capacity) { if (auto retval = axStartSession(&session_, capacity); retval != AxErr::NO_AxERROR) throw retval; } // C++17
~AxsunOCTCapture() { axStopSession(session_); }
AOChandle operator()() { if (session_) return session_; else throw AxErr::CAPTURE_SESSION_NOT_SETUP; }
};
// A callback function which is invoked whenever a new image is enqueued in the Main Image Buffer.
// This function is registered in the main() function with axRegisterNewImageCallback().
void NewImageArrived(new_image_callback_data_t data, void* user_ptr) {
static uint32_t counter{ 0 };
// Use the 'void* user_ptr' argument to send this callback a pointer to your preallocated
// buffer if you are retrieving the image data rather than only directly displaying it, as well as
// any other client resources needed in this callback (log handles, etc).
//
// Calling AxsunOCTCapture functions other than axRequestImage(), axGetImageInfo(), and axGetStatus()
// in this callback may result in undefined behavior, due to the nature of this callback's
// execution in a concurrent thread with your application's other calls into the AxsunOCTCapture API.
// axRequestImage() should be called in this callback only if not being called concurrently in a
// separate polling loop.
//
// New Image Arrived events are stored in a FIFO queue within the AxsunOCTCapture library.
// If the time spent in this callback exceeds the period of new images enqueued in the Main Image
// Buffer, unprocessed callback events will stack up indefinitely as indicated by the value of
// data.waiting_callbacks.
//
// Force-triggered images will also invoke this callback, with data.image_number = 0.
// cast user_ptr from void* back into a std::vector<uint8_t>
auto& image_vector = *(static_cast<std::vector<uint8_t>*>(user_ptr));
if (auto bytes_allocated = image_vector.size(); bytes_allocated >= data.required_buffer_size) { // insure memory allocation large enough
auto prefs = request_prefs_t{};
#ifdef _WIN32
prefs.which_window = 1;
#else
prefs.request_mode = AxRequestMode::RETRIEVE_TO_CALLER;
#endif
auto info = image_info_t{};
// fetch the image from the Main Image Buffer
auto retval = axRequestImage(data.session, data.image_number, prefs, bytes_allocated, image_vector.data(), &info);
if (!(counter % 50) && retval == AxErr::NO_AxERROR) { // print to console only every 50 invocations
std::cout << "Image # " << info.image_number << "\tWidth: " << info.width;
// print out a few pixel values (as 8-bit)
std::cout << "\tPixels: ";
std::for_each(image_vector.begin(), image_vector.begin() + 10,
[&](const auto& pix) {std::cout << +pix << " "; });
if (info.force_trig)
std::cout << "\tImage_sync too slow or missing!";
else if (info.trig_too_fast)
std::cout << "\tImage_sync too fast!";
std::cout << std::endl;
}
else if (retval != AxErr::NO_AxERROR) {
char error_message[512];
axGetErrorString(retval, error_message);
std::cout << "axRequestImage() reported: " << static_cast<int>(retval) << ' ' << error_message << '\n';
}
}
else
std::cout << "Memory allocation too small for retrieval of image " << data.image_number << '\n';
// increment the number of times this callback has been invoked
++counter;
}
// A callback function which is invoked whenever a new imaging mode is detected by the Main Image Buffer.
// This function is registered in the main() function with axRegisterDAQCallback().
void ModeChanged(int32_t state, void* user_ptr) {
// Use the 'void* user_ptr' argument to send this callback any application state
// synchronization objects as well as any other client resources needed in this callback
// (log handles, etc).
std::cout << "callback: "; // NOTE: not a thread-safe use of std::cout (not production code!)
switch (static_cast<AxDAQEvent>(state)) {
std::cout << "DAQ/buffer state -> STOPPED\n";
break;
std::cout << "DAQ/buffer state -> IMAGING\n";
break;
std::cout << "DAQ/buffer state -> RECORD COMPLETE\n";
break;
std::cout << "DAQ/buffer state -> RECORDING\n";
break;
std::cout << "DAQ/buffer state -> LOADING COMPLETE\n";
break;
std::cout << "DAQ/buffer state -> LOADING FROM DISK\n";
break;
}
}
int main(int argc, char* argv[]) {
char message[512]; // for getting string output from axGetMessage() and axGetErrorString()
try {
std::cout << "Welcome to the AxsunOCTCapture Example Console Application (C++ version).\nPlease select a capture interface by entering 'P' for PCIe or 'E' for Ethernet. Enter 'Q' to quit.\n";
AxInterface desired_interface{ AxInterface::NO_INTERFACE };
char user_input;
std::cin >> user_input;
switch (user_input) {
case 'e':
case 'E':
std::cout << "Selected Ethernet interface. Initializing capture session...\n";
desired_interface = AxInterface::GIGABIT_ETHERNET;
break;
case 'p':
case 'P':
std::cout << "Selected PCIe interface. Initializing capture session...\n";
desired_interface = AxInterface::PCI_EXPRESS;
break;
default:
std::cout << "No interface selected. Quitting.";
std::this_thread::sleep_for(2s);
return 0;
}
// allocate some heap memory in which to fetch the image
auto bytes_allocated = uint32_t{ sizeof(int32_t) * 2048 * 10000 }; // enough for images up to 10000 A-scans wide
auto image_vector = std::vector<uint8_t>(bytes_allocated);
// create a capture session with a 500 MB Main Image Buffer
AxsunOCTCapture AOC(500.0f);
#ifdef _WIN32
if (auto retval = axSetupDisplay(AOC(), 0, 100, 100, 768, 512, 0); retval != AxErr::NO_AxERROR) throw retval;
if (auto retval = axHideWindow(AOC(), 1, 4); retval != AxErr::NO_AxERROR) throw retval;
if (auto retval = axAdjustBrightnessContrast(AOC(), 1, 0.0, 0.0); retval != AxErr::NO_AxERROR) throw retval;
#endif
// set trigger timeout
if (auto retval = axSetTrigTimeout(AOC(), 12); retval != AxErr::NO_AxERROR) throw retval;
// register callback for new image arrival (allocated std::vector is passed as user_data argument)
if (auto retval = axRegisterNewImageCallback(AOC(), NewImageArrived, static_cast<void*>(&image_vector)); retval != AxErr::NO_AxERROR) throw retval;
// register callback for change in mode
if (auto retval = axRegisterDAQCallback(AOC(), ModeChanged, NULL); retval != AxErr::NO_AxERROR) throw retval;
// select capture interface for this session (PCIe or Ethernet per above user selection)
if (auto retval = axSelectInterface(AOC(), desired_interface); retval != AxErr::NO_AxERROR) throw retval;
// print informational message describing current capture interface status
if (auto retval = axGetMessage(AOC(), message); retval != AxErr::NO_AxERROR) throw retval;
std::cout << message << '\n';
if (desired_interface == AxInterface::GIGABIT_ETHERNET) {
std::cout << "Turn Laser Emission -> ON and turn DAQ Imaging Mode -> ON using the Control/Control_LW API, or using the Hardware Control Tool or OCT Host GUI.\n";
}
else { // if PCIe interface, we can turn imaging mode on from here
std::cout << "Turn Laser Emission -> ON using the Control/Control_LW API, or using the Hardware Control Tool or OCT Host GUI.\n";
if (auto retval = axPipelineMode(AOC(), AxPipelineMode::EIGHT_BIT, AxChannelMode::CHAN_1); retval != AxErr::NO_AxERROR) throw retval;
if (auto retval = axImagingCntrlPCIe(AOC(), -1); retval != AxErr::NO_AxERROR) throw retval; // "-1" argument -> LIVE mode
}
// lambda function to occasionally check and report Main Image Buffer status
auto check_status = [&](std::stop_token st) {
while (!st.stop_requested()) {
static uint32_t imaging, last_packet, last_frame, last_image, dropped_packets, frames_since_sync;
if (auto retval = axGetStatus(AOC(), &imaging, &last_packet, &last_frame, &last_image, &dropped_packets, &frames_since_sync); retval == AxErr::NO_AxERROR) {
if (!imaging) {
std::cout << "Imaging mode is off.\n";
}
else {
// print other buffer status information here if desired
// std::cout << "Dropped: " <<dropped_packets << "\n";
}
}
else {
std::cout << "*** Error " << static_cast<int32_t>(retval) << " in axGetStatus().\n";
}
std::this_thread::sleep_for(2s); // loop timer
}
};
// start background thread to check buffer status
std::jthread status_thread(check_status);
// wait for user input
#ifdef _WIN32
MSG msg;
while (!_kbhit()) { // process Win32 events until key is pressed
if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
DispatchMessage(&msg);
}
std::this_thread::sleep_for(100ms);
}
#else
std::cin >> user_input; // wait indefinitely for any user input before exiting
#endif
std::cout << "Quitting...\n\n";
// turn DAQ Imaging Mode -> OFF (idle)
if (desired_interface == AxInterface::PCI_EXPRESS) {
if (auto retval = axImagingCntrlPCIe(AOC(), 0); retval != AxErr::NO_AxERROR) throw retval;
}
} // AOC object goes out of scope here, so axStopSession() is called automatically
catch (const AxErr& e) {
axGetErrorString(e, message);
std::cout << "ERROR: " << message << '\n';
}
catch (...) {
std::cout << "***** UNKNOWN ERROR. Program terminating.\n";
}
std::cout << "Done.\n\n";
} // end of main()
@ CHAN_1
Definition: AxsunCommonEnums.h:229
@ EIGHT_BIT
Definition: AxsunCommonEnums.h:218
AxErr
Error codes returned from AxsunOCTCapture or AxsunOCTControl_LW functions. Use axGetErrorString() in ...
Definition: AxsunCommonEnums.h:40
This header file contains all exported function prototypes, structures, and enums necessary for integ...
AxErr __cdecl axPipelineMode(AOChandle session, AxPipelineMode mode, AxChannelMode channels)
Configures FPGA registers to output the desired data type & location from the processing pipeline via...
struct CaptureSession * AOChandle
Axsun OCT Capture handle - a pointer to the opaque structure used to manage created capture sessions.
Definition: AxsunOCTCapture.h:170
AxErr __cdecl axImagingCntrlPCIe(AOChandle session, int16_t number_of_images)
Control the image streaming behavior of the Axsun PCIe DAQ between Live Imaging, Burst Recording,...
AxErr __cdecl axStopSession(AOChandle session)
Stop a capture session and deallocate all resources, including Main Image Buffer and interfaces.
AxInterface
Available capture interfaces to be selected by axSelectInterface().
Definition: AxsunOCTCapture.h:271
@ PCI_EXPRESS
Definition: AxsunOCTCapture.h:275
@ GIGABIT_ETHERNET
Definition: AxsunOCTCapture.h:273
@ NO_INTERFACE
Definition: AxsunOCTCapture.h:277
AxErr __cdecl axRegisterNewImageCallback(AOChandle session, AxNewImageCallbackFunction_t callback_function, void *user_data)
Registers a callback function to be executed each time a new image is enqueued in the Main Image Buff...
AxErr __cdecl axSelectInterface(AOChandle session, AxInterface which_interface)
Select the data interface (Ethernet, PCIe, or none) for the capture session.
AxErr __cdecl axSetupDisplay(AOChandle session, uint8_t window_style, int32_t w_left, int32_t w_top, int32_t w_width, int32_t w_height, uintptr_t linked_window_handle)
Setup an OpenGL display window for direct rendering of image data. (Windows OS only)
AxErr __cdecl axSetTrigTimeout(AOChandle session, uint32_t framesUntilForceTrig)
Control the behavior of Force Trigger mode.
AxErr __cdecl axStartSession(AOChandle *session, float capacity_MB)
Start an Axsun DAQ imaging session by allocating memory for the Main Image Buffer.
AxErr __cdecl axRequestImage(AOChandle session, uint32_t requested_image, request_prefs_t prefs, uint32_t output_buf_len, uint8_t *image_data_out, image_info_t *image_info)
Retrieve and/or display an image from the Main Image Buffer.
@ RETRIEVE_AND_DISPLAY
Definition: AxsunOCTCapture.h:229
@ RETRIEVE_TO_CALLER
Definition: AxsunOCTCapture.h:225
AxErr __cdecl axHideWindow(AOChandle session, int32_t which_window, uint32_t state)
Hide or unhide the OpenGL image display window. (Windows OS only)
AxErr __cdecl axGetStatus(AOChandle session, uint32_t *imaging, uint32_t *last_packet_in, uint32_t *last_frame_in, uint32_t *last_image_in, uint32_t *dropped_packets, uint32_t *frames_since_sync)
Get imaging mode status and Main Image Buffer statistics.
AxErr __cdecl axAdjustBrightnessContrast(AOChandle session, int32_t which_window, float brightness, float contrast)
Change the brightness and contrast of images displayed in an OpenGL window. (Windows OS only)
void __cdecl axGetErrorString(AxErr errorcode, char *message_out)
Get a description of a specific AxErr error code.
AxErr __cdecl axRegisterDAQCallback(AOChandle session, AxCallbackFunction_t callback_function, void *user_data)
Registers a callback function to be executed upon a change in the DAQ imaging state (e....
AxDAQEvent
Types of transitions in DAQ's operational mode, conveyed via user callback function....
Definition: AxsunOCTCapture.h:239
@ RECORD_START
Definition: AxsunOCTCapture.h:247
@ LOAD_DONE
Definition: AxsunOCTCapture.h:253
@ IMAGING_STOP
Definition: AxsunOCTCapture.h:241
@ IMAGING_START
Definition: AxsunOCTCapture.h:243
@ RECORD_DONE
Definition: AxsunOCTCapture.h:245
@ LOAD_START
Definition: AxsunOCTCapture.h:255
AxErr __cdecl axGetMessage(AOChandle session, char *message_out)
Get a description of the capture session's interface status.
Structure for conveying metadata information about an image.
Definition: AxsunOCTCapture.h:452
Structure for data made available to user in a new image callback event via registered AxNewImageCall...
Definition: AxsunOCTCapture.h:486
AOChandle session
Definition: AxsunOCTCapture.h:488
uint32_t image_number
Definition: AxsunOCTCapture.h:490
uint32_t required_buffer_size
Definition: AxsunOCTCapture.h:492
Structure for image request preferences.
Definition: AxsunOCTCapture.h:386
AxRequestMode request_mode
Definition: AxsunOCTCapture.h:389