Developer Application Interface (ARC API) v4.5.9
ARC, Inc. GenIV Application Interface
Quick Start Guide

The ARC API is a set of modern C++ libraries that provide classes necessary to control, aquire and post process images with the Gen IV controller. These libraries are the hardware interface for the G4 app and may be used by developers for their own data acquisition system.

Features -

  • Uses modern C++ features from GCC 11 and latest Visual Studio
  • Visual Studio Code is now the Linux development environment
  • Compatible with Linux (Ubuntu LTS 20.04 or newer) and Windows 10


General Library Requirements

C++ Version:

20 or latest

Operating Systems:

  • Windows 10
  • Linux ( Ubuntu LTS 20.04 or newer )

Supported Compilers and IDE:
  • Visual Studio Community or Professional 2022 or newer
  • Visual Studio Code and GCC 11 or newer


Introduction

The Gen IV API consists of five independent libraries and a base library, from which the libraries inherit. This means the base library must be linked into your app alongside the library being used. The base library mostly provides utility operations and exception handling.

  • CArcBase4.5.lib ......... library from which the other libraries inherit
  • CArcDevice4.5.lib ....... provides all PCIe and controller communications
  • CArcDispaly4.5.lib ...... displays images using SAO DS9
  • CArcFitsFile4.5.lib ..... provides reading and writing FITS using cfitsio
  • CArcImage4.5.lib ........ provides image processing (such as verifying synthetic image data)
  • CArcVersion4.5.lib ...... provides version details for the API

All controller communications are provided by the CArcDevice class located in the library with the same name. This is the primary class that an app will interact with. All other libraries, except the CArcBase library, provide some utility operation; such as writing FITS files and processing images.

The ARC Gen IV API is written using the latest C++ features available (currently C++20). What features are supported is compiler dependent. Earlier revisions of C++ will be missing the necessary features to compile and link with these libraries. Also, to prevent potential run time errors, the API should be recompiled with the same compiler that the calling application is built with.




CArcDevice

The arc::gen4::CArcDevice is the class used to connect to the ARC Gen IV PCIe device driver and provides all PCIe and controller comminucations.

Requirements
Headers: CArcDevice.h, CArcBase.h
Header Folders: CArcDevice/inc,   CArcBase/inc
Libraries: CArcDevice4.5.lib/.dll/.so,   CArcBase4.5.lib/.dll/.so


All device (PCIe) and controller communications are provided by the CArcDevice class.


Basic Controller Commands and Status

Controller commands are sent using one of the arc::gen4::CArcDevice command() methods. Most of these commands return a status packet, defined by arc::gen4::CArcStatusPacket, containing the controller reply. The returned reply can be obtained by calling the status packet value() method. This method is indexed to allow access to replies that consist of multiple reply values.

A list of the standard (non-array specific) controller commands and status values can be found in the ArcCommandDefs.h header file.

Many commands expect an arc::gen4::status_e::DONE (0x444F4E45) as a reply for success. This can be simply checked by calling the status packet success() method, which will return true if the reply has a done value or false otherwise.

A few of the command() methods are designed to auto check the return value against an expected value (passed as a parameter to command()) and throw an exception if they do not match. This is a more compact way to verify a reply value.

Every packet (control, status, image) has the same basic format.



The payload format depends on the type of packet. For status packets (i.e. replies), the payload format consists of the command that generated the status; followed by any status (reply) values. For example, the following command to write the image dimensions, 'DIM' 1024 1024, will return the following payload in the status packet: 'DIM' 'DONE'.




The following example shows the many ways to send a controller command.

#include <iostream>
#include <memory>
#include <stdexcept>
#include <string>
#include <CArcDevice.h>
#include <ArcCommandDefs.h>
int main( void )
{
// Create a new CArcDevice instance
std::unique_ptr<arc::gen4::CArcDevice> pArcDev( new arc::gen4::CArcDevice );
if ( pArcDev != nullptr )
{
try
{
// Open the default device. By default the common buffer is automatically
// memory mapped by this method. Can be disabled through the second parameter.
pArcDev->open();
// The following four commands show how to send a test data link (arc::gen4::cmds_e::TDL) command
// to the controller using the command methods that return a status packet to the user.
const auto uiTDLValue = static_cast<std::uint32_t>( 0xABCD0001 );
// 1. Using variadic parameter list:
auto pStatusPacket = pArcDev->command( static_cast< std::uint32_t >( arc::gen4::cmds_e::TDL ), uiTDLValue );
// Check the status value
if ( !pStatusPacket->compare( uiTDLValue ) )
{
throw std::runtime_error( "Test data link failed ... values do not match!" );
}
// 2. Using enum command and variadic parameter list:
pStatusPacket = pArcDev->command( arc::gen4::cmds_e::TDL, uiTDLValue );
// Check the status value
if ( !pStatusPacket->compare( uiTDLValue ) )
{
throw std::runtime_error( "Test data link failed ... values do not match!" );
}
// 3. Using std::vector where all command values are of the required unsigned int type:
pStatusPacket = pArcDev->command( std::vector{ static_cast< std::uint32_t >( arc::gen4::cmds_e::TDL ), uiTDLValue } );
// Check the status value
if ( !pStatusPacket->compare( uiTDLValue ) )
{
throw std::runtime_error( "Test data link failed ... values do not match!" );
}
// 4. Using std::vector<std::any> for command list and arguments:
pStatusPacket = pArcDev->command( { arc::gen4::cmds_e::TDL, uiTDLValue } );
// Check the status value
if ( !pStatusPacket->compare( uiTDLValue ) )
{
throw std::runtime_error( "Test data link failed ... values do not match!" );
}
// The following four commands show how to send a test data link (arc::gen4::cmds_e::TDL) command
// to the controller using the command methods that auto verify the status value against the
// expected value.
// 1. Using std::vector where all command values are of the required unsigned int type. This will throw
// if the sent and received values do not match.
pArcDev->command( std::vector{ static_cast< std::uint32_t >( arc::gen4::cmds_e::TDL ), uiTDLValue }, uiTDLValue );
// 2. Using std::vector<std::any> for command list and arguments. This will throw if the sent and
// received values do not match.
pArcDev->command( { arc::gen4::cmds_e::TDL, uiTDLValue }, uiTDLValue );
// The following sends the arc::gen4::cmds_e::DIM command to set the controller image dimensions.
// The status packet success() method is used to verify the return value is set to 'DONE' and not
// one of the error codes.
pStatusPacket = pArcDev->command( arc::gen4::cmds_e::DIM, 4096U, 4096U );
// Check the status value
if ( !pStatusPacket->success() )
{
throw std::runtime_error( "Failed to set image dimensions!" );
}
// While NOT RECOMMENDED, a command packet can be created and manually sent:
// Create the command packet
if ( pCommandPacket != nullptr )
{
// Send the command packet
pStatusPacket = pArcDev->command( pCommandPacket.get() );
// Check the status value
if ( !pStatusPacket->compare( uiTDLValue ) )
{
throw std::runtime_error( "Test data link failed ... values do not match!" );
}
}
}
catch ( const std::exception& e )
{
std::cerr << std::endl << "ERROR: " << e.what() << std::endl;
}
}
}
static CArcPacketFactory & getInstance(void) noexcept
std::unique_ptr< CArcCommandPacket > cmdPacket(const std::uint8_t uiId=0) const


Basic Device Communications and Controller Setup

The following example shows how to open communications and initialize the controller using the CArcDevice class.

#include <iostream>
#include <memory>
#include <stdexcept>
#include <string>
#include <filesystem>
#include <CArcBase.h>
#include <CArcDevice.h>
using namespace std::string_literals;
int main( void )
{
// Create a new CArcDevice instance
std::unique_ptr<arc::gen4::CArcDevice> pArcDev( new arc::gen4::CArcDevice );
if ( pArcDev != nullptr )
{
try
{
// Open the default device. By default the common buffer is automatically
// memory mapped by this method. Can be disabled through the second parameter.
pArcDev->open();
// Setup the timing file and check its existence.
std::filesystem::path tTimingFile = "/somepath/timFile.bin"s;
if ( !std::filesystem::exists( tTimingFile ) )
{
throw std::runtime_error( "File \""s + tTimingFile.string() + "\" doesn't exist!"s );
}
// Setup the controller with the default number of video channels enabled. By default,
// this command will upload the specified timing file and then send 1234 test data link (TDL)
// commands to the controller processor. To disable sending TDL's, set the second parameter
// to zero or use the ::loadFile() method.
pArcDev->setup( tTimingFile );
// The controller is now initialized with all default settings ...
// By default, the controller timing file contains set image dimensions. To override, use the
// setImageDimensions method to modify.
pArcDev->setImageDimensions( 4096, 2048 );
}
catch ( const std::exception& e )
{
std::cerr << std::endl << "ERROR: " << e.what() << std::endl;
}
}
}

The setup() method call in the previous example is functionally equivalent to the following:

// Load the timing file
pArcDev->loadFile( tTimingFile );
// Test the data link
for ( std::uint32_t i = 0; i < 1234; i++ )
{
pArcDev->command( { arc::gen4::cmds_e::TDL, ( 0xABCD0000 + i ) }, ( 0xABCD0000 + i ) );
}
// The controller is now initialized with all default settings ...
// ... NOTE: this is where the number of channels enabled would need to be modified if desired ....
// Set the expected image dimensions of 4096 columns by 2048 rows on the controller.
pArcDev->setImageDimensions( 4096, 2048 );


How to Get the Controller Command List

The following snippet shows how to obtain the string list of available commands from the controller.

// ... open device and setup controller ... then ...
auto pCmdList = pArcDev->getCommandList();
if ( pCmdList.get() != nullptr )
{
for ( std::uint32_t i = 0; i < pCmdList->length(); i++ )
{
std::cout << pCmdList->at( i ) << std::endl;
}
}

Output:

ARC-440 ADC mode control | AMC <boardNumber> <4-bit value>
Assign virtual channels | AVC <boardNumber> [<enableBits> <virtToPhy 0> ...]
Board revision info | BRI <boardNumber>
Change exposure time | CET <10s of microseconds>
Controller ready | CRDY
Get/Set image dimensions | DIM [<columns> <rows>]
Assign default video channels | DVC
.... etc ....


How to Take an Exposure

The following snippet shows how to start an exposure on the controller. The expose method takes optional functions for handling elapsed exposure time, readout pixel count and current system state. By default, unless provided as a parameter, the expose method will issue a command to the controller to read the current system state, which will be used during the exposure/readout and returned in the parameter if it's not null.

#include <thread>
// ... open device and setup controller ... then ...
// Note: since the expose method blocks, we may want to put it into a seperate thread or process.
auto fnExposeRunnable = []()
{
// ...
// Start a 3.45 second exposure
auto pImageBuffer = pArcDev->expose( 3450 );
// The returned image buffer pointer can be used to access the image data via the virtual address member.
// If the exposure produced a set of images, as would be the case for Fowler sampling or up-the-ramp, then
// the returned image buffer will point to the first buffer only. Use the getImageBufferList() or indexed
// getImageBuffer( index ) methods to access the remaining buffers.
if ( pImageBuffer != nullptr && pImageBuffer->pVirtualAddress != nullptr && pImageBuffer->uiSize > 0 )
{
// Do something with the image data
}
// ...
};
std::thread tExposeThread( fnExposeRunnable );
tExposeThread.join();
// ...
// By default, the above call will not provide any feedback about the progress of the exposure or readout.
// This can be changed by adding expose and readout function listeners. Note, the listeners do not have to
// be lambda's, they can be normal functions for class methods.
auto fnExposeListener = []( float fElapsedTime )
{
// Do something with the elapsed exposure time
std::cout << "Elapsed time: " << fElapsedTime << std::endl;
};
auto fnReadListener = []( std::uint32_t uiPixelCount, float fReadTime )
{
// Do something with the pixel count
std::cout << "Pixel count: " << uiPixelCount << std::endl;
};
auto fnExposeRunnable2 = []()
{
auto pImageBuffer = pArcDev->expose( 3450, fnExposeListener, fnReadListener );
if ( pImageBuffer != nullptr && pImageBuffer->pVirtualAddress != nullptr && pImageBuffer->uiSize > 0 )
{
// Do something with the image data
}
// ...
};
std::thread tExposeThread2( fnExposeRunnable2 );
tExposeThread2.join();
// While not necessary, the system state can be obtained by passing an empty sysState_t pointer to the expose method.
pSysState_t pSysState;
auto pImageBuffer = pArcDev->expose( 3450, fnExposeListener, fnReadListener, pSysState );
// pSysState will now contain the current system state. Use the sysStateToString function to
// convert all the state values to a string.
std::cout << arc::gen4::sysStateToString( pSysState ) << std::endl;
// ...
GEN4_CARCDEVICE_API const std::string sysStateToString(pSysState_t pSysState)
std::shared_ptr< sysState_t > pSysState_t
Definition: ArcSysState.h:28


How to Modify Video Channel Selection

The following snippet shows how to modify the default channel selection. There are two types of operations, the first is to enable or disable specific physical video channels. The second is to assign new virtual channel numbers to the physical channels.

// ... open device and setup controller ... then ...
// First, let's assume the images are 4096x4096 and the controller has one ARC-440 video board at board position
// (slot) 9. By default, the controller will have 16 physical channels because there are sixteen channels per
// video board. For this example we'll disable all but two channels, which we'll re-assign to specific channels.
uiCols = 4096;
uiRows = 4096;
uwChannelCount = 2;
uiBoardNumber = 9;
try
{
// Verify the image column size against the number of channels expected to be enabled. The controller hardware
// imposes restrictions on the image dimensions based on the channel count. This method verifies the dimensions
// against the specfied channel count and throws an exception if they are not compatible.
pArcDev->verifyColumnChannelCount( uiCols, uwChannelCount );
// There cannot be duplicate virtual channel numbers. Channel numbers 0, 1, 2, 3 are okay, while 0, 1, 1, 2 are
// not. It's up to the user application to ensure there are no duplicates. Also, the no virtual channel number
// should exceed the total channel count. For example, if there are sixteen physical video channels, virtual channel
// seventeen should not be assigned to any channel.
// Let's assign virtual channels 0 and 1 to physical channels 3 and 14. All other channels will be disabled. The
// channel map will look like this:
// +-------------------------------------------------------------------------------------------+
// | phys chan | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
// +-------------------------------------------------------------------------------------------+
// | virt chan | | | | 0 | | | | | | | | | | | 1 | |
// +-------------------------------------------------------------------------------------------+
// | enabled | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
// +-------------------------------------------------------------------------------------------+
// Based on the above table we get the following:
std::uint32_t uiEnableBits = 0x4008;
std::uint32_t uiVirt0ToPhys3 = ( ( 3 << 16 ) | 0 );
std::uint32_t uiVirt1ToPhys14 = ( ( 14 << 16 ) | 0 );
pArcDev->command( static_cast<std::uint32_t>( arc::gen4::cmds_e::AVC ), uiBoardNumber, uiEnableBits, uiVirt0ToPhys3, uiVirt1ToPhys14 );
}
catch ( const std::exception& e )
{
std::cerr << std::endl << "ERROR: " << e.what() << std::endl;
}


How to Enable HxRG Windowing Mode

The following snippet shows how to HxRG windowing mode. The windowing channel is fixed and dependent on which HxRG device is being used. The H1RG and H2RG use channel 7, while the H4RG uses channel 15. This means only the one channel should be enabled on the controller and all others must be disabled.

// ... open device and setup controller ... then ...
// First, the SWM (set window mode) command value can be obtained by calling the get command list methods.
// For simplicity, I will just define it here by its ascii value, which is how it's defined in the micro-controller
// code.
constexpr auto SWM = 0x0053574DU;
auto uiRowStart = 100U;
auto uiRowEnd = 500U;
auto uiColStart = 100U;
auto uiColEnd = 227U;
try
{
// Assuming H1 or H2RG, then use channel 7
std::cout << arc::gen4::CArcBase::setDots( "Setting window mode to [ "s + std::to_string( uiColEnd - uiColStart ) +
" ] x [ "s + std::to_string( uiRowEnd - uiRowStart ) + " ]"s, uiDotCount );
auto pStatusPacket = pArcDev->command( SWM, 7U, uiRowStart, uiRowEnd, uiColStart, uiColEnd );
std::cout << "done!" << std::endl;
if ( !pStatusPacket->success() )
{
arc::gen4::throwArcGen4Error( "Failed to set window mode! "s + pStatusPacket->errorCodeDescription() );
}
//
// Read the board mapping from the controller
//
auto pBoardMap = pArcDev->getBoardMap();
auto pArc440List = pBoardMap->findBoard( 440 );
auto pLocked = pArc440List.lock();
std::cout << std::endl;
//
// Read the enabled channel bits from all the ARC-440 video boards to verify that only a single channel is enabled
//
std::for_each( pLocked->cbegin(), pLocked->cend(), [ &pStatusPacket ]( const auto& tElem )
{
pStatusPacket = pArcDev->command( arc::gen4::cmds_e::EVC, tElem );
std::cout << "Channels enabled on board #"sv << ( tElem < 10 ? "0"sv : ""sv ) << tElem << " -> 0x"sv << std::hex
<< std::setw( 4 ) << std::setfill( '0' ) << pStatusPacket->value() << std::dec << std::endl;
} );
std::cout << std::endl;
//
// Read the channel assignments from all the ARC-440 video boards to verify that only a single channel is set
//
for ( auto it = pLocked->cbegin(); it != pLocked->cend(); it++ )
{
pStatusPacket = pArcDev->command( arc::gen4::cmds_e::AVC, *it );
for ( decltype( pStatusPacket->valueCount() ) i = 0; i < pStatusPacket->valueCount(); i++ )
{
if ( ( pStatusPacket->value( i ) & 0xFF ) != arc::gen4::CArcDevice::ARC440_INVALID_CHANNEL_ADDRESS )
{
std::cout << "Assigned video channel on board #" << ( *it < 10 ? "0"sv : ""sv ) << *it
<< " -> physical " << ( ( pStatusPacket->value( i ) >> 16 ) & 0xFF )
<< " set to virtual " << ( pStatusPacket->value( i ) & 0xFFFF ) << std::endl;
}
}
}
std::cout << std::endl;
}
catch ( const std::exception& e )
{
std::cerr << std::endl << "ERROR: " << e.what() << std::endl;
}
static std::string setDots(std::string_view svText, const std::size_t uiMaxLength, const char szDot='.')
static constexpr auto ARC440_INVALID_CHANNEL_ADDRESS
Definition: CArcDevice.h:733
void throwArcGen4Error(const throwFormat_t<> tFormat, Args &&... args)
Definition: CArcBase.h:102


Full Example

The following is a simple fully functional program that initializes the controller, takes an exposure and prints out the first, last and middle image buffer values.

#include <iostream>
#include <memory>
#include <stdexcept>
#include <string>
#include <filesystem>
#include <CArcBase.h>
#include <CArcDevice.h>
using namespace std::string_literals;
// MainApp - Initializes the controller, updates the channel count and takes an exposure.
//
// Be sure to:
// 1. link CArcBase4.5.lib and CArcDevice4.5.lib
// 2. on Windows, define the preprocessor value _WINDOWS if not already defined
//
int main( void )
{
// Dot count for pretty output
constexpr auto uiDotCount = 70;
std::cout << std::endl;
// Create a new CArcDevice instance
std::unique_ptr<arc::gen4::CArcDevice> pArcDev( new arc::gen4::CArcDevice );
if ( pArcDev != nullptr )
{
try
{
// Open the default device
std::cout << arc::gen4::CArcBase::setDots( "Opening device"s, uiDotCount );
pArcDev->open();
std::cout << "done!" << std::endl;
// Initialize the timing file details
auto tTimingFile = ( iArgc == 2 ? std::filesystem::path( pszArgs[ 1 ] ) : std::filesystem::path() );
if ( !std::filesystem::exists( tTimingFile ) )
{
throw std::runtime_error( "Cannot find specified file or none was given. Exiting."s );
}
std::cout << std::endl;
// Setup the controller with default video channels enabled. By default, this command will upload
// the specified timing file and then send 1234 test data link ('TDL') commands to the controller
// microcontroller. To disable sending TDL's, set the second parameter to zero. The image dimensions
// are specified by the timing firmware, call ::setImageDimensions() to override.
std::cout << "Initializing controller with file : " << tTimingFile.string() << " .... ";
pArcDev->setup( tTimingFile );
std::cout << "done!" << std::endl;
// The controller is now initialized.
std::cout << "Controller initialized!" << std::endl;
// Define the image dimensions
constexpr auto uiCols = static_cast<std::uint32_t>( 4096 );
constexpr auto uiRows = static_cast<std::uint32_t>( 2048 );
// Override the image dimensions with new values
pArcDev->setImageDimensions( uiCols, uiRows );
std::cout << std::endl;
// Exposure time ( in milliseconds )
constexpr auto uiExpTimeMs = static_cast< std::uint32_t >( 0 );
// Start an exposure
std::cout << arc::gen4::CArcBase::setDots( "Starting exposure for "s + std::to_string( uiExpTimeMs ) + " seconds"s, uiDotCount );
auto pImageBuffer = pArcDev->expose( uiExpTimeMs );
std::cout << "done!" << std::endl;
// Check the resulting bufer
if ( pImageBuffer != nullptr && pImageBuffer->pVirtualAddress != nullptr && pImageBuffer->uiSize > 0 )
{
// Do something with the image data
std::cout << "Image buffer: " << std::endl << pImageBuffer->toString() << std::endl;
auto pU16VA = reinterpret_cast< std::uint16_t* >( pImageBuffer->pVirtualAddress.get() );
std::cout << "Some data values: " << pU16VA[ 0 ] << " " << pU16VA[ ( uiCols * uiRows ) / 2 ] << " " << pU16VA[ ( uiCols * uiRows ) - 1 ] << std::endl;
}
else
{
throw std::runtime_error( "Invalid image buffer [ nullptr ]!"s );
}
}
catch ( const std::exception& e )
{
std::cerr << std::endl << "ERROR: " << e.what() << std::endl;
}
}
else
{
std::cerr << std::endl << "ERROR: Failed to create an instance of CArcDevice!" << std::endl;
}
std::cout << std::endl;
}

Output:

Opening device ........................................................ done!
Initializing controller with file : H1RG\Debug\H1RG.bin .... done!
Controller initialized!
Starting exposure for 0 seconds ....................................... done!
Image buffer:
Virtual address ............... 0x216a3aea040
Size .......................... 38720000
Some data values: 45111 45108 45069




CArcFitsFile

The arc::gen4::CArcFitsFile is the class used to read and write FITS files. There are two available specializations of the class: one for 16-bit data (default) and one for 32-bit data. Currently, GenIV only produces 16-bit data.

Requirements
Headers: CArcFitsFile.h, CArcBase.h
Header Folders: CArcFitsFile/inc,   CArcBase/inc,   cfitsio-3450/include
Libraries: CArcFitsFile4.5.lib/.dll/.so,   CArcBase4.5.lib/.dll/.so


How to Read FITS

The following snippet shows how to read the first image from a 16-bit FITS data cube called "SomeFile.fts".

// Create an instance of the arc::gen4::CArcFitsFile class
std::unique_ptr<arc::gen4::CArcFitsFile<>> pFits( new arc::gen4::CArcFitsFile<>() );
if ( pFits != nullptr )
{
try
{
// Open the FITS file
pFits->open( "SomeFile.fts" );
// Read the first image in the cube.
// pImageData is a std::unique_ptr to 16-bit image data
auto pImageData = pFits->read3D( 0 );
// Do something with the data ....
// Close the file
pFits->close();
}
catch ( const std::exception& e )
{
std::cerr << std::endl << "ERROR: " << e.what() << std::endl;
}
}


How to Write FITS

The following snippet shows how to write an image to a 16-bit FITS data cube called "SomeFile.fts".

// The image properties
constexpr auto uiCols = 4096;
constexpr auto uiRows = 4096;
// Get the default image buffer from an arc::gen4::CArcDevice that was used to take an image.
auto pImageBuffer = pArcDev->getImageBuffer();
// Create an instance of the arc::gen4::CArcFitsFile class
std::unique_ptr<arc::gen4::CArcFitsFile<>> pFits( new arc::gen4::CArcFitsFile<>() );
if ( pFits != nullptr )
{
try
{
// Create the FITS file
pFits->create3D( "SomeFile.fts", uiCols, uiRows );
// Write the first image in the cube.
pFits->write3D( pImageBuffer->pVirtualAddress.get() );
// Close the file
pFits->close();
}
catch ( const std::exception& e )
{
std::cerr << std::endl << "ERROR: " << e.what() << std::endl;
}
}


How to Write a FITS Keyword

The following snippet shows how to write a keyword that is a decimal value called "MyValue" to a 16-bit FITS data cube called "SomeFile.fts".

// Create an instance of the arc::gen4::CArcFitsFile class
std::unique_ptr<arc::gen4::CArcFitsFile<>> pFits( new arc::gen4::CArcFitsFile<>() );
double gValue = 1.2;
if ( pFits != nullptr )
{
try
{
// Open the FITS file
pFits->open( "SomeFile.fts" );
// Write the keyword
pFits->writeKeyword( "MyValue", &gValue, arc::gen4::fits::fitsKeyType_e::FITS_DOUBLE_KEY, "This is my double value" );
// Close the file
pFits->close();
}
catch ( const std::exception& e )
{
std::cerr << std::endl << "ERROR: " << e.what() << std::endl;
}
}


How to Update a FITS Keyword

The following snippet shows how to update the "MyValue" keyword from the previous section.

// Create an instance of the arc::gen4::CArcFitsFile class
std::unique_ptr<arc::gen4::CArcFitsFile<>> pFits( new arc::gen4::CArcFitsFile<>() );
double gValue = 2.1;
if ( pFits != nullptr )
{
try
{
// Open the FITS file
pFits->open( "SomeFile.fts" );
// Update the value
pFits->updateKeyword( "MyValue", &gValue, arc::gen4::fits::fitsKeyType_e::FITS_DOUBLE_KEY, "This is my NEW double value" );
// Close the file
pFits->close();
}
catch ( const std::exception& e )
{
std::cerr << std::endl << "ERROR: " << e.what() << std::endl;
}
}




CArcImage

The arc::gen4::CArcImage is the class used for basic image processing, such as filling an image buffer with a specific pattern, calculating statistics (min, max, mean, standard deviation), data histogram, read rows or columns and more. The classes are static based and cannot be instantiated. There are two available specializations of the class: one for 16-bit data (default) and one for 32-bit data. Currently, GenIV only produces 16-bit data.

Requirements
Headers: CArcImage.h, CArcBase.h
Header Folders: CArcImage/inc,   CArcBase/inc
Libraries: CArcImage4.5.lib/.dll/.so,   CArcBase4.5.lib/.dll/.so


How to Fill a Buffer With a Specific Value

The following snippet shows how to fill the kernel common buffers with a specific value

// Expose using a previously opened arc::gen4::CArcDevice ...
auto pImageBuffer = pArcDev->expose( 0 );
// The 16-bit version is used by default. The following is equivalent to arc::gen4::CArcImage<arc::gen4::BPP_16>
arc::gen4::CArcImage<>::fill( reinterpret_cast<arc::gen4::BPP_16>( pImageBuffer->pVirtualAddress ), pCommonBuffers->uiSize );
static auto fill(T *pBuf, const std::uint32_t uiCols, const std::uint32_t uiRows, const T uiValue) -> void


How to Verify an ARC-440 Synthetic Image

The following snippet shows how to verify that the data in the returned image buffer is a valid ARC-440 synthetic image.

// Get the common buffer list from a previously opened arc::gen4::CArcDevice ...
auto pCommonBuffers = pArcDev->getCommonBuffers();
// Get the system state info, contains items like the image column and row count and the number of columns-per-channel.
auto pSystemState = pArcDev->getSystemState();
// The 16-bit version is used by default. The following is equivalent to arc::gen4::CArcImage<arc::gen4::BPP_16>
arc::gen4::CArcImage<>::containsValidArc440Synthetic( reinterpret_cast<arc::gen4::BPP_16>( pCommonBuffers->pVirtualAddress ), pSystemState->uwColsPerChannel, pSystemState->uiImageCols, pSystemState->uiImageRows );
static auto containsValidArc440Synthetic(const T *pBuf, const std::uint32_t uiPixelsPerChannel, const std::uint32_t uiCols, const std::uint32_t uiRows) -> void