457 lines
13 KiB
C
457 lines
13 KiB
C
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||
|
// Licensed under the MIT License.
|
||
|
|
||
|
//************************ Includes *****************************
|
||
|
#include <k4a/k4a.h>
|
||
|
#include <k4ainternal/usbcommand.h>
|
||
|
#include "Cli.h"
|
||
|
#include "Main.h"
|
||
|
#include "k4aCmd.h"
|
||
|
|
||
|
//**************Symbolic Constant Macros (defines) *************
|
||
|
#define CLI_MENU_K4A "k4a"
|
||
|
#define MAX_BUFFER_SIZE 256
|
||
|
#define TIMESTAMP_CONVERSION 1000000
|
||
|
#define ERROR_COUNT_MAX 10
|
||
|
#define FILE_FORMAT_BINARY "wb"
|
||
|
#define FILE_FORMAT_ASCII "w"
|
||
|
|
||
|
//************************ Typedefs *****************************
|
||
|
|
||
|
//************ Declarations (Statics and globals) ***************
|
||
|
static uint8_t data_buffer[MAX_BUFFER_SIZE];
|
||
|
|
||
|
//******************* Function Prototypes ***********************
|
||
|
|
||
|
//*********************** Functions *****************************
|
||
|
|
||
|
/**
|
||
|
* Command to get the serial numbers
|
||
|
*
|
||
|
* @param Argc Number of variables handed in
|
||
|
*
|
||
|
* @param Argv Pointer to variable array
|
||
|
*
|
||
|
* @return
|
||
|
* CLI_SUCCESS If executed properly
|
||
|
* CLI_ERROR If error was detected
|
||
|
*
|
||
|
*/
|
||
|
static CLI_STATUS k4a_serial_num(int Argc, char **Argv)
|
||
|
{
|
||
|
(void)Argc; // unused
|
||
|
(void)Argv; // unused
|
||
|
k4a_device_t handle;
|
||
|
CLI_STATUS status = CLI_SUCCESS;
|
||
|
|
||
|
handle = get_k4a_handle(0);
|
||
|
|
||
|
if (handle != NULL)
|
||
|
{
|
||
|
size_t serial_number_size = MAX_BUFFER_SIZE;
|
||
|
if (k4a_device_get_serialnum(handle, (char *)data_buffer, &serial_number_size) == K4A_BUFFER_RESULT_SUCCEEDED)
|
||
|
{
|
||
|
// display the serial number data
|
||
|
printf("SerialNumber: ");
|
||
|
for (uint8_t loop = 0; loop < 64; loop += 2)
|
||
|
{
|
||
|
if (loop % 32 == 0)
|
||
|
printf("\n ");
|
||
|
uint16_t data = 0;
|
||
|
memcpy(&data, &data_buffer[loop], sizeof(data));
|
||
|
printf("%04X ", data);
|
||
|
}
|
||
|
printf("\n");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
printf("Couldn't read from device\n");
|
||
|
status = CLI_ERROR;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
printf("Device not found\n");
|
||
|
status = CLI_ERROR;
|
||
|
}
|
||
|
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Command to get the version information
|
||
|
*
|
||
|
* @param Argc Number of variables handed in
|
||
|
*
|
||
|
* @param Argv Pointer to variable array
|
||
|
*
|
||
|
* @return
|
||
|
* CLI_SUCCESS If executed properly
|
||
|
* CLI_ERROR If error was detected
|
||
|
*
|
||
|
*/
|
||
|
static CLI_STATUS k4a_version(int Argc, char **Argv)
|
||
|
{
|
||
|
(void)Argc; // unused
|
||
|
(void)Argv; // unused
|
||
|
k4a_device_t handle;
|
||
|
CLI_STATUS status = CLI_SUCCESS;
|
||
|
|
||
|
k4a_hardware_version_t version;
|
||
|
|
||
|
handle = get_k4a_handle(0);
|
||
|
|
||
|
if (handle != NULL)
|
||
|
{
|
||
|
if (k4a_device_get_version(handle, &version) == K4A_RESULT_SUCCEEDED)
|
||
|
{
|
||
|
// display the version
|
||
|
printf("RGB version: %d.%d.%d\n", version.rgb.major, version.rgb.minor, version.rgb.iteration);
|
||
|
printf("Depth version: %d.%d.%d\n", version.depth.major, version.depth.minor, version.depth.iteration);
|
||
|
printf("Audio version: %d.%d.%d\n", version.audio.major, version.audio.minor, version.audio.iteration);
|
||
|
printf("Depth Sequence version: %d.%d\n", version.depth_sensor.major, version.depth_sensor.minor);
|
||
|
printf("%s\n", version.firmware_build == K4A_FIRMWARE_BUILD_RELEASE ? "Release" : "Debug");
|
||
|
if (version.firmware_signature == K4A_FIRMWARE_SIGNATURE_MSFT)
|
||
|
{
|
||
|
printf("MSFT\n");
|
||
|
}
|
||
|
if (version.firmware_signature == K4A_FIRMWARE_SIGNATURE_TEST)
|
||
|
{
|
||
|
printf("TEST\n");
|
||
|
}
|
||
|
if (version.firmware_signature == K4A_FIRMWARE_SIGNATURE_UNSIGNED)
|
||
|
{
|
||
|
printf("No Signature\n");
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
printf("Couldn't read from device\n");
|
||
|
status = CLI_ERROR;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
printf("Device not found\n");
|
||
|
status = CLI_ERROR;
|
||
|
}
|
||
|
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Command to record a number of depth frames to disk
|
||
|
*
|
||
|
* @param Argc Number of variables handed in
|
||
|
*
|
||
|
* @param Argv Pointer to variable array
|
||
|
*
|
||
|
* @return
|
||
|
* CLI_SUCCESS If executed properly
|
||
|
* CLI_ERROR If error was detected
|
||
|
*
|
||
|
*/
|
||
|
static CLI_STATUS k4a_record_depth(int Argc, char **Argv)
|
||
|
{
|
||
|
CLI_STATUS status = CLI_SUCCESS;
|
||
|
uint32_t device_num = 0;
|
||
|
uint32_t stream_count = 0;
|
||
|
uint32_t mode = K4A_DEPTH_MODE_NFOV_UNBINNED;
|
||
|
uint32_t fps = K4A_FRAMES_PER_SECOND_30;
|
||
|
char *file_name = "depth.rec";
|
||
|
k4a_device_configuration_t config = K4A_DEVICE_CONFIG_INIT_DISABLE_ALL;
|
||
|
int32_t timeout_ms = 70;
|
||
|
k4a_capture_t capture;
|
||
|
k4a_device_t device = NULL;
|
||
|
uint32_t wait_error_count = 0;
|
||
|
FILE *p_file;
|
||
|
|
||
|
if (Argc < 3)
|
||
|
{
|
||
|
CliDisplayUsage(k4a_record_depth);
|
||
|
return CLI_ERROR;
|
||
|
}
|
||
|
|
||
|
// Get device number
|
||
|
if (!CliGetStrVal(Argv[1], &device_num))
|
||
|
{
|
||
|
return CLI_ERROR;
|
||
|
}
|
||
|
|
||
|
// Get number of frames to read
|
||
|
if (!CliGetStrVal(Argv[2], &stream_count))
|
||
|
{
|
||
|
return CLI_ERROR;
|
||
|
}
|
||
|
|
||
|
// Get optional operating mode
|
||
|
if ((Argc > 3) && ((!CliGetStrVal(Argv[3], &mode)) || (mode > K4A_DEPTH_MODE_PASSIVE_IR)))
|
||
|
{
|
||
|
return CLI_ERROR;
|
||
|
}
|
||
|
|
||
|
// Get optional FPS
|
||
|
if ((Argc > 4) &&
|
||
|
((!CliGetStrVal(Argv[4], &fps)) ||
|
||
|
(fps != K4A_FRAMES_PER_SECOND_5 && fps != K4A_FRAMES_PER_SECOND_15 && fps != K4A_FRAMES_PER_SECOND_30)))
|
||
|
{
|
||
|
return CLI_ERROR;
|
||
|
}
|
||
|
|
||
|
device = get_k4a_handle(device_num);
|
||
|
|
||
|
// open a file to write to
|
||
|
#ifdef _WIN32
|
||
|
if (fopen_s(&p_file, file_name, FILE_FORMAT_BINARY) == 0)
|
||
|
{
|
||
|
#else
|
||
|
if ((p_file = fopen(file_name, FILE_FORMAT_BINARY)) != NULL)
|
||
|
{
|
||
|
#endif
|
||
|
// start the stream
|
||
|
config.color_format = K4A_IMAGE_FORMAT_COLOR_MJPG;
|
||
|
config.color_resolution = K4A_COLOR_RESOLUTION_OFF;
|
||
|
config.depth_mode = mode;
|
||
|
config.camera_fps = fps;
|
||
|
|
||
|
// start streaming.
|
||
|
if (K4A_FAILED(k4a_device_start_cameras(device, &config)))
|
||
|
{
|
||
|
return CLI_ERROR;
|
||
|
}
|
||
|
|
||
|
// loop through stream data
|
||
|
while (stream_count-- > 0)
|
||
|
{
|
||
|
// Synchronize
|
||
|
if (K4A_WAIT_RESULT_SUCCEEDED == k4a_device_get_capture(device, &capture, timeout_ms))
|
||
|
{
|
||
|
wait_error_count = 0; // reset the error count
|
||
|
|
||
|
uint8_t *buffer;
|
||
|
k4a_image_t image;
|
||
|
|
||
|
image = k4a_capture_get_depth_image(capture);
|
||
|
if (image)
|
||
|
{
|
||
|
buffer = k4a_image_get_buffer(image);
|
||
|
if (buffer)
|
||
|
{
|
||
|
// store to disk
|
||
|
fwrite(buffer, 1, k4a_image_get_size(image), p_file);
|
||
|
}
|
||
|
k4a_image_release(image);
|
||
|
}
|
||
|
|
||
|
image = k4a_capture_get_ir_image(capture);
|
||
|
if (image)
|
||
|
{
|
||
|
buffer = k4a_image_get_buffer(image);
|
||
|
if (buffer)
|
||
|
{
|
||
|
// store to disk
|
||
|
fwrite(buffer, 1, k4a_image_get_size(image), p_file);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
k4a_capture_release(capture);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
wait_error_count++;
|
||
|
if (wait_error_count > ERROR_COUNT_MAX)
|
||
|
{
|
||
|
printf("Failed to receive a frame within %d mSec\n", timeout_ms * ERROR_COUNT_MAX);
|
||
|
status = CLI_ERROR;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
k4a_device_stop_cameras(device);
|
||
|
fclose(p_file);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
printf("Could not open %s to write\n", file_name);
|
||
|
status = CLI_ERROR;
|
||
|
}
|
||
|
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Command to record IMU samples
|
||
|
*
|
||
|
* @param Argc Number of variables handed in
|
||
|
*
|
||
|
* @param Argv Pointer to variable array
|
||
|
*
|
||
|
* @return
|
||
|
* CLI_SUCCESS If executed properly
|
||
|
* CLI_ERROR If error was detected
|
||
|
*
|
||
|
*/
|
||
|
static CLI_STATUS k4a_record_imu(int Argc, char **Argv)
|
||
|
{
|
||
|
CLI_STATUS status = CLI_SUCCESS;
|
||
|
uint32_t stream_count;
|
||
|
uint32_t device_num = 0;
|
||
|
bool csv = false;
|
||
|
FILE *p_file = 0;
|
||
|
k4a_device_t device = NULL;
|
||
|
k4a_wait_result_t result;
|
||
|
char *file_name = "imu.rec";
|
||
|
uint32_t wait_error_count = 0;
|
||
|
int32_t timeout_ms = 150;
|
||
|
k4a_imu_sample_t imu_sample;
|
||
|
char *file_format = FILE_FORMAT_BINARY;
|
||
|
|
||
|
if (Argc < 3)
|
||
|
{
|
||
|
CliDisplayUsage(k4a_record_imu);
|
||
|
return CLI_ERROR;
|
||
|
}
|
||
|
|
||
|
// Get device number
|
||
|
if (!CliGetStrVal(Argv[1], &device_num))
|
||
|
{
|
||
|
return CLI_ERROR;
|
||
|
}
|
||
|
|
||
|
// Get number of samples to record
|
||
|
if (!CliGetStrVal(Argv[2], &stream_count))
|
||
|
{
|
||
|
return CLI_ERROR;
|
||
|
}
|
||
|
|
||
|
// Check if CSV option is selected
|
||
|
if ((Argc > 3) && (memcmp(Argv[3], "csv", 3) == 0))
|
||
|
{
|
||
|
csv = true;
|
||
|
file_format = FILE_FORMAT_ASCII;
|
||
|
file_name = "imu.csv";
|
||
|
}
|
||
|
|
||
|
device = get_k4a_handle(device_num);
|
||
|
|
||
|
// open a file to write to
|
||
|
#ifdef _WIN32
|
||
|
if (fopen_s(&p_file, file_name, file_format) == 0)
|
||
|
{
|
||
|
#else
|
||
|
if ((p_file = fopen(file_name, file_format)) != NULL)
|
||
|
{
|
||
|
#endif
|
||
|
// configure and start stream
|
||
|
if (k4a_device_start_imu(device) == K4A_RESULT_SUCCEEDED)
|
||
|
{
|
||
|
// loop through stream data
|
||
|
if (csv)
|
||
|
{
|
||
|
// Print csv header
|
||
|
fprintf(p_file, "Temp, Accel TS, Accel X, Accel Y, Accel Z, Gyro TS, Gyro X, Gyro Y, Gyro Z\n");
|
||
|
}
|
||
|
while (stream_count-- > 0)
|
||
|
{
|
||
|
result = k4a_device_get_imu_sample(device, &imu_sample, timeout_ms);
|
||
|
if (result == K4A_WAIT_RESULT_TIMEOUT)
|
||
|
{
|
||
|
wait_error_count++;
|
||
|
if (wait_error_count > ERROR_COUNT_MAX)
|
||
|
{
|
||
|
printf("Failed to receive a frame within %d mSec\n", timeout_ms * ERROR_COUNT_MAX);
|
||
|
status = CLI_ERROR;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
else if (result == K4A_WAIT_RESULT_SUCCEEDED)
|
||
|
{
|
||
|
wait_error_count = 0; // reset the error count
|
||
|
|
||
|
// store to disk
|
||
|
if (csv)
|
||
|
{
|
||
|
fprintf(p_file,
|
||
|
"%f, %f, %f, %f, %f, %f, %f, %f, %f\n",
|
||
|
(double)imu_sample.temperature,
|
||
|
(double)imu_sample.acc_timestamp_usec / TIMESTAMP_CONVERSION,
|
||
|
(double)imu_sample.acc_sample.xyz.x,
|
||
|
(double)imu_sample.acc_sample.xyz.y,
|
||
|
(double)imu_sample.acc_sample.xyz.z,
|
||
|
(double)imu_sample.gyro_timestamp_usec / TIMESTAMP_CONVERSION,
|
||
|
(double)imu_sample.gyro_sample.xyz.x,
|
||
|
(double)imu_sample.gyro_sample.xyz.y,
|
||
|
(double)imu_sample.gyro_sample.xyz.z);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
fwrite(&imu_sample, 1, sizeof(imu_sample), p_file);
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
printf("Couldn't start the stream\n");
|
||
|
status = CLI_ERROR;
|
||
|
}
|
||
|
|
||
|
k4a_device_stop_imu(device);
|
||
|
fclose(p_file);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
printf("Could not open %s to write\n", file_name);
|
||
|
status = CLI_ERROR;
|
||
|
}
|
||
|
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* initialization for the K4A command interface
|
||
|
*
|
||
|
*/
|
||
|
void k4a_cmd_init(void)
|
||
|
{
|
||
|
CliRegister(CLI_MENU_K4A,
|
||
|
"serialnum",
|
||
|
k4a_serial_num,
|
||
|
"Display the serial numbers",
|
||
|
"Display the serial numbers\n"
|
||
|
"Syntax: serialnum\n"
|
||
|
"Example: serialnum\n");
|
||
|
CliRegister(CLI_MAIN_MENU,
|
||
|
"version",
|
||
|
k4a_version,
|
||
|
"Display version information",
|
||
|
"Display version information\n"
|
||
|
"Syntax: version\n"
|
||
|
"Example: version\n");
|
||
|
CliRegister(CLI_MENU_K4A,
|
||
|
"recdepth",
|
||
|
k4a_record_depth,
|
||
|
"Record depth frames",
|
||
|
"Store to disk a set number of frames\n"
|
||
|
"Syntax: recdepth <device> <# of frames> [mode] [FPS]\n"
|
||
|
"Example: recdepth 0 60 1 1\n"
|
||
|
"Acceptable modes (Default NFOV_UNBINNED:\n"
|
||
|
" NFOV_2x2BINNED = 0\n"
|
||
|
" NFOV_UNBINNED = 1\n"
|
||
|
" WFOV_2x2BINNED = 2\n"
|
||
|
" WFOV_UNBINNED = 3\n"
|
||
|
" PASSIVE_IR = 4\n"
|
||
|
"Acceptable FPS (Default 30 FPS, depends on mode):\n"
|
||
|
" 30 FPS = 0\n"
|
||
|
" 15 FPS = 1\n"
|
||
|
" 5 FPS = 2\n");
|
||
|
CliRegister(CLI_MENU_K4A,
|
||
|
"recimu",
|
||
|
k4a_record_imu,
|
||
|
"Record IMU stream",
|
||
|
"Store to disk IMU set number of samples\n"
|
||
|
"Syntax: recimu <device> <# of samples>\n"
|
||
|
"Example: recimu 0 100\n");
|
||
|
}
|