PVCAM  3.9.x
Programmable Virtual Camera Access Method library
Fan Speed and Temperature

This sample demonstrates how to read camera sensor temperature, how to set a desired temperature and how to change camera fan speed if available.

Monitoring of the sensor temperature is implemented on a background thread. The thread receives a CameraContext pointer from the main function and uses the context information for synchronization with the main thread. Access to the camera and to the standard output is blocked while interacting with the main thread. This example does not capture images.

Please note that reading the temperature during active acquisition is currently not supported.

void TemperatureThread(CameraContext* ctx)
{
const std::vector<char> progress{ '|', '/', '-', '\\' };
size_t progressIndex = 0;
for (;;)
{
// In this sample, the eofEvent is reused for thread synchronization
std::unique_lock<std::mutex> lock(ctx->eofEvent.mutex);
// Update the temperature 4x per second, if not blocked by the main thread
ctx->eofEvent.cond.wait_for(lock, std::chrono::milliseconds(250),
[ctx]() { return ctx->threadAbortFlag; });
if (ctx->threadAbortFlag)
break;
int16 temperature = 0;
(void*)&temperature))
{
printf("\n");
PrintErrorMessage(pl_error_code(), "pl_get_param(PARAM_TEMP) error");
break;
}
// Keep overwriting the same line
printf("\r%c Current sensor temperature on camera %d is %+7.2f C",
progress[progressIndex], ctx->hcam, temperature / 100.0);
fflush(stdout); // No new line at the end, flush output manually
progressIndex = (progressIndex + 1) % progress.size();
}
}

The code snippet below initializes PVCAM and opens the first available camera. Please, refer to the actual code sample in the SDK installation directory for more details about the common helper functions used in this documentation.

std::vector<CameraContext*> contexts;
if (!InitAndOpenOneCamera(contexts, cSingleCamIndex))
return APP_EXIT_ERROR;
CameraContext* ctx = contexts[cSingleCamIndex];

Since this example does not capture images, we don't need to register termination handlers as described in Terminating the Application section. The code spends most of the time waiting for the user input. We will rely on default ctrl+c to abort gracefully.

Check that we can read the sensor temperature, the application will exit otherwise.

if (!IsParamAvailable(ctx->hcam, PARAM_TEMP, "PARAM_TEMP"))
{
CloseAllCamerasAndUninit(contexts);
return APP_EXIT_ERROR;
}

Check that we can access the sensor temperature setpoint parameter and add a menu item that will allow users to adjust it. Also, cache the range of valid values. Please note that not all cameras support the temperature control. Selected cameras may have the temperature setpoint locked by reporting both min and max values as identical number, essentially preventing the value to be changed.

int16 setpointMin = 0;
int16 setpointMax = 0;
if (IsParamAvailable(ctx->hcam, PARAM_TEMP_SETPOINT, "PARAM_TEMP_SETPOINT"))
{
NVP nvp;
nvp.value = cMenuItemValue_TemperatureSetpoint;
nvp.name = "Change temperature setpoint";
mainMenuItems.push_back(nvp);
// Update minimum setpoint value
(void*)&setpointMin))
{
PrintErrorMessage(pl_error_code(),
"pl_get_param(PARAM_TEMP_SETPOINT, ATTR_MIN) error");
CloseAllCamerasAndUninit(contexts);
return APP_EXIT_ERROR;
}
// Update maximum setpoint value
(void*)&setpointMax))
{
PrintErrorMessage(pl_error_code(),
"pl_get_param(PARAM_TEMP_SETPOINT, ATTR_MAX) error");
CloseAllCamerasAndUninit(contexts);
return APP_EXIT_ERROR;
}
}

Check that we can access the fan speed setpoint parameter and add a menu item. This parameter is an enum-type parameter. Several predefined setpoints are provided by the camera. The ReadEnumeration function calls IsParamAvailable internally.

NVPC fanSpeeds;
if (ReadEnumeration(ctx->hcam, &fanSpeeds, PARAM_FAN_SPEED_SETPOINT,
"PARAM_FAN_SPEED_SETPOINT"))
{
NVP nvp;
nvp.value = cMenuItemValue_FanSpeed;
nvp.name = "Change fan speed";
mainMenuItems.push_back(nvp);
}
Note
Please, refer to the Enumeration Parameters section.

Start the background thread. The thread will periodically display the current temperature.

ctx->threadAbortFlag = false;
ctx->thread = new(std::nothrow) std::thread(TemperatureThread, ctx);
if (!ctx->thread)
{
CloseAllCamerasAndUninit(contexts);
return APP_EXIT_ERROR;
}

Finally, enter the main loop and wait until the user presses <Enter> key to indicate an action. Then, show the menu using the GetMenuSelection function and wait for an input. Exit the application on invalid input.

If the user opts for changing the temperature setpoint, we ask for a new value. Since the PVCAM parameter value is reported and set in hundredths of degrees of Celsius, the code sample does basic input conversion before setting the parameter.

(void*)&setpoint))
{
PrintErrorMessage(pl_error_code(),
"pl_set_param(PARAM_TEMP_SETPOINT) error");
errorOccured = true;
break;
}

If the user opts for changing the fan speed, we need to print out another menu with available presets, using the GetMenuSelection function. The corresponding NVP value is then sent to PVCAM using the pl_set_param function.

if (!GetMenuSelection("Fan speeds", fanSpeeds, selection))
break;
// Set new fan speed
(void*)&selection))
{
PrintErrorMessage(pl_error_code(),
"pl_set_param(PARAM_FAN_SPEED_SETPOINT) error");
errorOccured = true;
break;
}

Before exit, request the background thread to abort, wait for it and initiate a cleanup. Please, refer to the Closing Camera and Uninitializing PVCAM section for more details.

ctx->threadAbortFlag = true;
ctx->eofEvent.mutex.unlock();
ctx->eofEvent.cond.notify_all();
if (ctx->thread->joinable())
ctx->thread->join();
delete ctx->thread;
ctx->thread = nullptr;
CloseAllCamerasAndUninit(contexts);
if (errorOccured)
return APP_EXIT_ERROR;
return 0;