Implementing the firmware update interrupt tests (#164)
Refactors the firmware update tests to make it easier to implement the interrupt tests. Implementing the interrupt tests.
This commit is contained in:
Родитель
7f943693f5
Коммит
e8cec587bd
|
@ -50,7 +50,8 @@ can be run using "ctest -L perf" in the build directory.
|
|||
Firmware tests are used to validate new firmware drops. They are run manually
|
||||
when a new firmware candidate is given and will require hardware. Firmware
|
||||
tests are built using the GoogleTest framework. After compiling, firmware tests
|
||||
can be run using "ctest -L firmware" in the build directory.
|
||||
can be run using "bin\firmware_fw.exe --firmware \<firmware path\>" in the build
|
||||
directory.
|
||||
|
||||
## Running tests
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Windows")
|
|||
|
||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||
|
||||
add_executable(firmware_fw firmware_fw.cpp)
|
||||
add_executable(firmware_fw firmware_helper.cpp firmware_fw.cpp firmware_interrupt_fw.cpp)
|
||||
|
||||
target_link_libraries(firmware_fw PRIVATE
|
||||
k4ainternal::utcommon
|
||||
|
|
|
@ -1,134 +1,43 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#define VC_EXTRALEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
|
||||
#define _CRT_NONSTDC_NO_DEPRECATE
|
||||
#include "firmware_helper.h"
|
||||
|
||||
#include <utcommon.h>
|
||||
#include <ConnEx.h>
|
||||
|
||||
#include <k4ainternal/firmware.h>
|
||||
#include <k4ainternal/logging.h>
|
||||
|
||||
#include <azure_c_shared_utility/tickcounter.h>
|
||||
#include <azure_c_shared_utility/threadapi.h>
|
||||
|
||||
#define UPDATE_TIMEOUT_MS 10 * 60 * 1000 // 10 Minutes should be way more than enough.
|
||||
#define K4A_DEPTH_MODE_NFOV_UNBINNED_EXPECTED_SIZE 737280
|
||||
|
||||
// This will define the path to the new firmware drop to test and the last known good firmware drop. The firmware update
|
||||
// process runs from the current firmware. In order to test the firmware update process, the device must be on the
|
||||
// firmware you want to test and then updated to a different firmware.
|
||||
#define K4A_TEST_FIRMWARE_PATH "..\\..\\tools\\updater\\firmware\\AzureKinectDK_Fw_1.5.886314.bin"
|
||||
#define K4A_LKG_FIRMWARE_PATH "..\\..\\tools\\updater\\firmware\\AzureKinectDK_Fw_1.5.786013.bin"
|
||||
|
||||
static k4a_result_t load_firmware_files(char *firmware_path, uint8_t **firmware_buffer, size_t *firmware_size);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
FIRMWARE_OPERATION_AUDIO,
|
||||
FIRMWARE_OPERATION_DEPTH_CONFIG,
|
||||
FIRMWARE_OPERATION_DEPTH,
|
||||
FIRMWARE_OPERATION_RGB,
|
||||
FIRMWARE_OPERATION_FULL_DEVICE,
|
||||
} firmware_operation_component_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
FIRMWARE_OPERATION_RESET,
|
||||
FIRMWARE_OPERATION_DISCONNECT,
|
||||
} firmware_operation_interruption_t;
|
||||
|
||||
class firmware_fw : public ::testing::Test
|
||||
{
|
||||
public:
|
||||
static void SetUpTestCase()
|
||||
{
|
||||
int port;
|
||||
float voltage;
|
||||
float current;
|
||||
|
||||
k4a_port_number = -1;
|
||||
connEx = new (std::nothrow) connection_exerciser();
|
||||
|
||||
LOG_INFO("Searching for Connection Exerciser...", 0);
|
||||
ASSERT_TRUE(K4A_SUCCEEDED(connEx->find_connection_exerciser()));
|
||||
LOG_INFO("Clearing port...");
|
||||
ASSERT_TRUE(K4A_SUCCEEDED(connEx->set_usb_port(0)));
|
||||
|
||||
LOG_INFO("Searching for device...");
|
||||
|
||||
for (int i = 0; i < CONN_EX_MAX_NUM_PORTS; ++i)
|
||||
{
|
||||
ASSERT_TRUE(K4A_SUCCEEDED(connEx->set_usb_port(i)));
|
||||
port = connEx->get_usb_port();
|
||||
ASSERT_TRUE(port == i);
|
||||
|
||||
voltage = connEx->get_voltage_reading();
|
||||
ASSERT_FALSE(voltage == -1);
|
||||
current = connEx->get_current_reading();
|
||||
ASSERT_FALSE(current == -1);
|
||||
|
||||
if (current < 0)
|
||||
{
|
||||
current = current * -1;
|
||||
}
|
||||
|
||||
if (voltage > 4.5 && voltage < 5.5 && current > 0.1)
|
||||
{
|
||||
ASSERT_TRUE(k4a_port_number == -1) << "More than one device was detected on the connection exerciser.";
|
||||
k4a_port_number = port;
|
||||
}
|
||||
|
||||
printf("On port #%d: %4.2fV %4.2fA\n", port, voltage, current);
|
||||
}
|
||||
|
||||
ASSERT_FALSE(k4a_port_number == -1)
|
||||
<< "The Kinect for Azure was not detected on a port of the connection exerciser.";
|
||||
connEx->set_usb_port(port);
|
||||
|
||||
std::cout << "Loading test firmware package: " << K4A_TEST_FIRMWARE_PATH << std::endl;
|
||||
load_firmware_files(K4A_TEST_FIRMWARE_PATH, &test_firmware_buffer, &test_firmware_size);
|
||||
parse_firmware_package(test_firmware_buffer, test_firmware_size, &test_firmware_package_info);
|
||||
|
||||
std::cout << "Loading LKG firmware package: " << K4A_LKG_FIRMWARE_PATH << std::endl;
|
||||
load_firmware_files(K4A_LKG_FIRMWARE_PATH, &lkg_firmware_buffer, &lkg_firmware_size);
|
||||
parse_firmware_package(lkg_firmware_buffer, lkg_firmware_size, &lkg_firmware_package_info);
|
||||
}
|
||||
|
||||
static void TearDownTestCase()
|
||||
{
|
||||
if (connEx != nullptr)
|
||||
{
|
||||
delete connEx;
|
||||
connEx = nullptr;
|
||||
}
|
||||
|
||||
if (test_firmware_buffer != nullptr)
|
||||
{
|
||||
free(test_firmware_buffer);
|
||||
test_firmware_buffer = nullptr;
|
||||
}
|
||||
|
||||
if (lkg_firmware_buffer != nullptr)
|
||||
{
|
||||
free(lkg_firmware_buffer);
|
||||
lkg_firmware_buffer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
void SetUp() override
|
||||
{
|
||||
ASSERT_EQ(K4A_RESULT_SUCCEEDED, TRACE_CALL(setup_common_test()));
|
||||
const ::testing::TestInfo *const test_info = ::testing::UnitTest::GetInstance()->current_test_info();
|
||||
LOG_INFO("Test %s requires a connection exerciser.", test_info->name());
|
||||
LOG_INFO("Disconnecting the device", 0);
|
||||
connEx->set_usb_port(0);
|
||||
g_connection_exerciser->set_usb_port(0);
|
||||
ThreadAPI_Sleep(500);
|
||||
|
||||
// Make sure that all of the firmwares have loaded correctly.
|
||||
ASSERT_TRUE(g_test_firmware_buffer != nullptr);
|
||||
ASSERT_TRUE(g_test_firmware_size > 0);
|
||||
ASSERT_TRUE(g_candidate_firmware_buffer != nullptr);
|
||||
ASSERT_TRUE(g_candidate_firmware_size > 0);
|
||||
ASSERT_TRUE(g_lkg_firmware_buffer != nullptr);
|
||||
ASSERT_TRUE(g_lkg_firmware_size > 0);
|
||||
ASSERT_TRUE(g_factory_firmware_buffer != nullptr);
|
||||
ASSERT_TRUE(g_factory_firmware_size > 0);
|
||||
|
||||
// Make sure that the Test firmware has all components with a different version when compared to the Release
|
||||
// Candidate firmware.
|
||||
// Depth Sensor isn't expect to change.
|
||||
ASSERT_FALSE(compare_version(g_test_firmware_package_info.audio, g_candidate_firmware_package_info.audio));
|
||||
ASSERT_FALSE(compare_version(g_test_firmware_package_info.depth, g_candidate_firmware_package_info.depth));
|
||||
ASSERT_FALSE(compare_version(g_test_firmware_package_info.rgb, g_candidate_firmware_package_info.rgb));
|
||||
|
||||
// There should be no other devices.
|
||||
uint32_t device_count = 0;
|
||||
usb_cmd_get_device_count(&device_count);
|
||||
|
@ -142,438 +51,144 @@ protected:
|
|||
firmware_destroy(firmware_handle);
|
||||
firmware_handle = nullptr;
|
||||
}
|
||||
|
||||
if (serial_number != nullptr)
|
||||
{
|
||||
free(serial_number);
|
||||
serial_number = nullptr;
|
||||
serial_number_length = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void open_k4a_device();
|
||||
void open_firmware_device();
|
||||
void interrupt_operation(firmware_operation_interruption_t interruption);
|
||||
void reset_device();
|
||||
void interrupt_device_at_update_stage(firmware_operation_component_t component,
|
||||
firmware_operation_interruption_t interruption,
|
||||
firmware_status_summary_t *finalStatus);
|
||||
|
||||
static int k4a_port_number;
|
||||
static connection_exerciser *connEx;
|
||||
|
||||
static uint8_t *test_firmware_buffer;
|
||||
static size_t test_firmware_size;
|
||||
static firmware_package_info_t test_firmware_package_info;
|
||||
|
||||
static uint8_t *lkg_firmware_buffer;
|
||||
static size_t lkg_firmware_size;
|
||||
static firmware_package_info_t lkg_firmware_package_info;
|
||||
|
||||
firmware_t firmware_handle = nullptr;
|
||||
|
||||
k4a_hardware_version_t current_version = { 0 };
|
||||
char *serial_number = nullptr;
|
||||
size_t serial_number_length = 0;
|
||||
};
|
||||
|
||||
int firmware_fw::k4a_port_number = -1;
|
||||
connection_exerciser *firmware_fw::connEx = nullptr;
|
||||
|
||||
uint8_t *firmware_fw::test_firmware_buffer = nullptr;
|
||||
size_t firmware_fw::test_firmware_size = 0;
|
||||
firmware_package_info_t firmware_fw::test_firmware_package_info = { 0 };
|
||||
|
||||
uint8_t *firmware_fw::lkg_firmware_buffer = nullptr;
|
||||
size_t firmware_fw::lkg_firmware_size = 0;
|
||||
firmware_package_info_t firmware_fw::lkg_firmware_package_info = { 0 };
|
||||
|
||||
static k4a_result_t load_firmware_files(char *firmware_path, uint8_t **firmware_buffer, size_t *firmware_size)
|
||||
TEST_F(firmware_fw, DISABLED_update_timing)
|
||||
{
|
||||
RETURN_VALUE_IF_ARG(K4A_RESULT_FAILED, firmware_path == NULL);
|
||||
RETURN_VALUE_IF_ARG(K4A_RESULT_FAILED, firmware_buffer == NULL);
|
||||
RETURN_VALUE_IF_ARG(K4A_RESULT_FAILED, firmware_size == NULL);
|
||||
LOG_INFO("Beginning the manual test to get update timings.", 0);
|
||||
ASSERT_EQ(K4A_RESULT_SUCCEEDED, g_connection_exerciser->set_usb_port(g_k4a_port_number));
|
||||
|
||||
k4a_result_t result = K4A_RESULT_FAILED;
|
||||
FILE *pFirmwareFile = NULL;
|
||||
size_t numRead = 0;
|
||||
uint8_t *tempFirmwareBuffer = NULL;
|
||||
ASSERT_EQ(K4A_RESULT_SUCCEEDED, open_firmware_device(&firmware_handle));
|
||||
|
||||
if ((pFirmwareFile = fopen(firmware_path, "rb")) != NULL)
|
||||
{
|
||||
fseek(pFirmwareFile, 0, SEEK_END);
|
||||
size_t tempFirmwareSize = (size_t)ftell(pFirmwareFile);
|
||||
if (tempFirmwareSize == (size_t)-1L)
|
||||
{
|
||||
std::cout << "ERROR: Failed to get size of the firmware package." << std::endl;
|
||||
return K4A_RESULT_FAILED;
|
||||
}
|
||||
ASSERT_EQ(K4A_BUFFER_RESULT_TOO_SMALL, firmware_get_device_serialnum(firmware_handle, NULL, &serial_number_length));
|
||||
|
||||
fseek(pFirmwareFile, 0, SEEK_SET);
|
||||
serial_number = (char *)malloc(serial_number_length);
|
||||
ASSERT_NE(nullptr, serial_number);
|
||||
|
||||
tempFirmwareBuffer = (uint8_t *)malloc(tempFirmwareSize);
|
||||
if (tempFirmwareBuffer == NULL)
|
||||
{
|
||||
std::cout << "ERROR: Failed to allocate memory." << std::endl;
|
||||
return K4A_RESULT_FAILED;
|
||||
}
|
||||
ASSERT_EQ(K4A_RESULT_SUCCEEDED,
|
||||
firmware_get_device_serialnum(firmware_handle, serial_number, &serial_number_length));
|
||||
|
||||
std::cout << "File size: " << tempFirmwareSize << " bytes" << std::endl;
|
||||
numRead = fread(tempFirmwareBuffer, tempFirmwareSize, 1, pFirmwareFile);
|
||||
fclose(pFirmwareFile);
|
||||
LOG_INFO("Updating the device to the Candidate firmware.");
|
||||
ASSERT_EQ(K4A_RESULT_SUCCEEDED,
|
||||
perform_device_update(&firmware_handle,
|
||||
g_candidate_firmware_buffer,
|
||||
g_candidate_firmware_size,
|
||||
g_candidate_firmware_package_info,
|
||||
true));
|
||||
|
||||
if (numRead != 1)
|
||||
{
|
||||
std::cout << "ERROR: Could not read all data from the file" << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
*firmware_buffer = tempFirmwareBuffer;
|
||||
*firmware_size = tempFirmwareSize;
|
||||
tempFirmwareBuffer = NULL;
|
||||
result = K4A_RESULT_SUCCEEDED;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "ERROR: Cannot Open (" << firmware_path << ") errno=" << errno << std::endl;
|
||||
}
|
||||
ASSERT_TRUE(compare_device_serial_number(firmware_handle, serial_number));
|
||||
|
||||
if (tempFirmwareBuffer)
|
||||
{
|
||||
free(tempFirmwareBuffer);
|
||||
}
|
||||
LOG_INFO("Updating the device to the Test firmware.");
|
||||
ASSERT_EQ(K4A_RESULT_SUCCEEDED,
|
||||
perform_device_update(&firmware_handle,
|
||||
g_test_firmware_buffer,
|
||||
g_test_firmware_size,
|
||||
g_test_firmware_package_info,
|
||||
true));
|
||||
|
||||
return result;
|
||||
ASSERT_TRUE(compare_device_serial_number(firmware_handle, serial_number));
|
||||
}
|
||||
|
||||
static firmware_operation_status_t calculate_overall_component_status(const firmware_component_status_t status)
|
||||
TEST_F(firmware_fw, simple_update_from_lkg)
|
||||
{
|
||||
if (status.overall == FIRMWARE_OPERATION_SUCCEEDED)
|
||||
{
|
||||
return FIRMWARE_OPERATION_SUCCEEDED;
|
||||
}
|
||||
LOG_INFO("Beginning the basic update test from the LKG firmware.", 0);
|
||||
ASSERT_EQ(K4A_RESULT_SUCCEEDED, g_connection_exerciser->set_usb_port(g_k4a_port_number));
|
||||
|
||||
if (status.overall == FIRMWARE_OPERATION_INPROGRESS)
|
||||
{
|
||||
return FIRMWARE_OPERATION_INPROGRESS;
|
||||
}
|
||||
ASSERT_EQ(K4A_RESULT_SUCCEEDED, open_firmware_device(&firmware_handle));
|
||||
|
||||
// If the version check failed, this component's update was skipped. This could because the new version is
|
||||
// an unsafe downgrade or the versions are the same and no update is required.
|
||||
if (status.version_check == FIRMWARE_OPERATION_FAILED)
|
||||
{
|
||||
return FIRMWARE_OPERATION_SUCCEEDED;
|
||||
}
|
||||
ASSERT_EQ(K4A_BUFFER_RESULT_TOO_SMALL, firmware_get_device_serialnum(firmware_handle, NULL, &serial_number_length));
|
||||
|
||||
return FIRMWARE_OPERATION_FAILED;
|
||||
serial_number = (char *)malloc(serial_number_length);
|
||||
ASSERT_NE(nullptr, serial_number);
|
||||
|
||||
ASSERT_EQ(K4A_RESULT_SUCCEEDED,
|
||||
firmware_get_device_serialnum(firmware_handle, serial_number, &serial_number_length));
|
||||
|
||||
LOG_INFO("Updating the device to the LKG firmware.");
|
||||
ASSERT_EQ(K4A_RESULT_SUCCEEDED,
|
||||
perform_device_update(&firmware_handle,
|
||||
g_lkg_firmware_buffer,
|
||||
g_lkg_firmware_size,
|
||||
g_lkg_firmware_package_info,
|
||||
false));
|
||||
|
||||
ASSERT_TRUE(compare_device_serial_number(firmware_handle, serial_number));
|
||||
|
||||
LOG_INFO("Updating the device to the Candidate firmware.");
|
||||
ASSERT_EQ(K4A_RESULT_SUCCEEDED,
|
||||
perform_device_update(&firmware_handle,
|
||||
g_candidate_firmware_buffer,
|
||||
g_candidate_firmware_size,
|
||||
g_candidate_firmware_package_info,
|
||||
false));
|
||||
|
||||
ASSERT_TRUE(compare_device_serial_number(firmware_handle, serial_number));
|
||||
|
||||
LOG_INFO("Updating the device to the Test firmware.");
|
||||
ASSERT_EQ(K4A_RESULT_SUCCEEDED,
|
||||
perform_device_update(&firmware_handle,
|
||||
g_test_firmware_buffer,
|
||||
g_test_firmware_size,
|
||||
g_test_firmware_package_info,
|
||||
false));
|
||||
|
||||
ASSERT_TRUE(compare_device_serial_number(firmware_handle, serial_number));
|
||||
}
|
||||
|
||||
static bool compare_version(k4a_version_t left_version, k4a_version_t right_version)
|
||||
TEST_F(firmware_fw, simple_update_from_factory)
|
||||
{
|
||||
return left_version.major == right_version.major && left_version.minor == right_version.minor &&
|
||||
left_version.iteration == right_version.iteration;
|
||||
LOG_INFO("Beginning the basic update test from the Factory firmware.", 0);
|
||||
ASSERT_EQ(K4A_RESULT_SUCCEEDED, g_connection_exerciser->set_usb_port(g_k4a_port_number));
|
||||
|
||||
ASSERT_EQ(K4A_RESULT_SUCCEEDED, open_firmware_device(&firmware_handle));
|
||||
|
||||
ASSERT_EQ(K4A_BUFFER_RESULT_TOO_SMALL, firmware_get_device_serialnum(firmware_handle, NULL, &serial_number_length));
|
||||
|
||||
serial_number = (char *)malloc(serial_number_length);
|
||||
ASSERT_NE(nullptr, serial_number);
|
||||
|
||||
ASSERT_EQ(K4A_RESULT_SUCCEEDED,
|
||||
firmware_get_device_serialnum(firmware_handle, serial_number, &serial_number_length));
|
||||
|
||||
LOG_INFO("Updating the device to the Factory firmware.");
|
||||
ASSERT_EQ(K4A_RESULT_SUCCEEDED,
|
||||
perform_device_update(&firmware_handle,
|
||||
g_factory_firmware_buffer,
|
||||
g_factory_firmware_size,
|
||||
g_factory_firmware_package_info,
|
||||
false));
|
||||
|
||||
ASSERT_TRUE(compare_device_serial_number(firmware_handle, serial_number));
|
||||
|
||||
LOG_INFO("Updating the device to the Candidate firmware.");
|
||||
ASSERT_EQ(K4A_RESULT_SUCCEEDED,
|
||||
perform_device_update(&firmware_handle,
|
||||
g_candidate_firmware_buffer,
|
||||
g_candidate_firmware_size,
|
||||
g_candidate_firmware_package_info,
|
||||
false));
|
||||
|
||||
ASSERT_TRUE(compare_device_serial_number(firmware_handle, serial_number));
|
||||
|
||||
LOG_INFO("Updating the device to the Test firmware.");
|
||||
ASSERT_EQ(K4A_RESULT_SUCCEEDED,
|
||||
perform_device_update(&firmware_handle,
|
||||
g_test_firmware_buffer,
|
||||
g_test_firmware_size,
|
||||
g_test_firmware_package_info,
|
||||
false));
|
||||
|
||||
ASSERT_TRUE(compare_device_serial_number(firmware_handle, serial_number));
|
||||
}
|
||||
|
||||
static bool compare_version_list(k4a_version_t device_version, uint8_t count, k4a_version_t versions[5])
|
||||
{
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
if (device_version.major == versions[i].major && device_version.minor == versions[i].minor)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void log_firmware_build_config(k4a_firmware_build_t build_config)
|
||||
{
|
||||
std::cout << " Build Config: ";
|
||||
switch (build_config)
|
||||
{
|
||||
case K4A_FIRMWARE_BUILD_RELEASE:
|
||||
std::cout << "Production" << std::endl;
|
||||
break;
|
||||
|
||||
case K4A_FIRMWARE_BUILD_DEBUG:
|
||||
std::cout << "Debug" << std::endl;
|
||||
break;
|
||||
|
||||
default:
|
||||
std::cout << "Unknown" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
static void log_firmware_signature_type(k4a_firmware_signature_t signature_type, bool certificate)
|
||||
{
|
||||
if (certificate)
|
||||
{
|
||||
std::cout << " Certificate Type: ";
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << " Signature Type: ";
|
||||
}
|
||||
|
||||
switch (signature_type)
|
||||
{
|
||||
case K4A_FIRMWARE_SIGNATURE_MSFT:
|
||||
std::cout << "Microsoft" << std::endl;
|
||||
break;
|
||||
|
||||
case K4A_FIRMWARE_SIGNATURE_TEST:
|
||||
std::cout << "Test" << std::endl;
|
||||
break;
|
||||
|
||||
case K4A_FIRMWARE_SIGNATURE_UNSIGNED:
|
||||
std::cout << "Unsigned" << std::endl;
|
||||
break;
|
||||
|
||||
default:
|
||||
std::cout << "Unknown (" << signature_type << ")" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
static void log_firmware_version(firmware_package_info_t firmware_version)
|
||||
{
|
||||
std::cout << "Firmware Package Versions:" << std::endl;
|
||||
std::cout << " RGB camera firmware: " << firmware_version.rgb.major << "." << firmware_version.rgb.minor
|
||||
<< "." << firmware_version.rgb.iteration << std::endl;
|
||||
std::cout << " Depth camera firmware: " << firmware_version.depth.major << "." << firmware_version.depth.minor
|
||||
<< "." << firmware_version.depth.iteration << std::endl;
|
||||
|
||||
std::cout << " Depth config file: ";
|
||||
for (size_t i = 0; i < firmware_version.depth_config_number_versions; i++)
|
||||
{
|
||||
std::cout << firmware_version.depth_config_versions[i].major << "."
|
||||
<< firmware_version.depth_config_versions[i].minor << " ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
|
||||
std::cout << " Audio firmware: " << firmware_version.audio.major << "." << firmware_version.audio.minor
|
||||
<< "." << firmware_version.audio.iteration << std::endl;
|
||||
|
||||
log_firmware_build_config(firmware_version.build_config);
|
||||
|
||||
log_firmware_signature_type(firmware_version.certificate_type, true);
|
||||
log_firmware_signature_type(firmware_version.signature_type, false);
|
||||
}
|
||||
|
||||
static void log_device_version(k4a_hardware_version_t firmware_version)
|
||||
{
|
||||
std::cout << "Current Firmware Versions:" << std::endl;
|
||||
std::cout << " RGB camera firmware: " << (uint16_t)firmware_version.rgb.major << "."
|
||||
<< (uint16_t)firmware_version.rgb.minor << "." << firmware_version.rgb.iteration << std::endl;
|
||||
std::cout << " Depth camera firmware: " << (uint16_t)firmware_version.depth.major << "."
|
||||
<< (uint16_t)firmware_version.depth.minor << "." << firmware_version.depth.iteration << std::endl;
|
||||
std::cout << " Depth config file: " << firmware_version.depth_sensor.major << "."
|
||||
<< firmware_version.depth_sensor.minor << std::endl;
|
||||
std::cout << " Audio firmware: " << (uint16_t)firmware_version.audio.major << "."
|
||||
<< (uint16_t)firmware_version.audio.minor << "." << firmware_version.audio.iteration << std::endl;
|
||||
|
||||
log_firmware_build_config((k4a_firmware_build_t)firmware_version.firmware_build);
|
||||
log_firmware_signature_type((k4a_firmware_signature_t)firmware_version.firmware_signature, true);
|
||||
}
|
||||
|
||||
void firmware_fw::open_firmware_device()
|
||||
{
|
||||
int retry = 0;
|
||||
uint32_t device_count = 0;
|
||||
|
||||
while (device_count == 0 && retry++ < 20)
|
||||
{
|
||||
ThreadAPI_Sleep(500);
|
||||
usb_cmd_get_device_count(&device_count);
|
||||
}
|
||||
|
||||
ASSERT_LE(retry, 20) << "Device never returned.";
|
||||
|
||||
LOG_INFO("Opening firmware device...", 0);
|
||||
ASSERT_EQ(K4A_RESULT_SUCCEEDED, firmware_create(K4A_DEVICE_DEFAULT, &firmware_handle))
|
||||
<< "Couldn't open firmware\n";
|
||||
ASSERT_NE(firmware_handle, nullptr);
|
||||
}
|
||||
|
||||
void firmware_fw::reset_device()
|
||||
{
|
||||
LOG_INFO("Resetting device...", 0);
|
||||
ASSERT_EQ(K4A_RESULT_SUCCEEDED, firmware_reset_device(firmware_handle));
|
||||
|
||||
firmware_destroy(firmware_handle);
|
||||
firmware_handle = nullptr;
|
||||
|
||||
// Re-open the device to ensure it is ready.
|
||||
open_firmware_device();
|
||||
}
|
||||
|
||||
void firmware_fw::interrupt_operation(firmware_operation_interruption_t interruption)
|
||||
{
|
||||
switch (interruption)
|
||||
{
|
||||
case FIRMWARE_OPERATION_RESET:
|
||||
reset_device();
|
||||
break;
|
||||
|
||||
default:
|
||||
ASSERT_TRUE(false) << "Unknown interruption type";
|
||||
}
|
||||
}
|
||||
|
||||
void firmware_fw::interrupt_device_at_update_stage(firmware_operation_component_t component,
|
||||
firmware_operation_interruption_t interruption,
|
||||
firmware_status_summary_t *finalStatus)
|
||||
{
|
||||
ASSERT_NE(nullptr, finalStatus);
|
||||
|
||||
bool all_complete = false;
|
||||
k4a_result_t result = K4A_RESULT_FAILED;
|
||||
|
||||
tickcounter_ms_t start_time_ms, now;
|
||||
|
||||
TICK_COUNTER_HANDLE tick = tickcounter_create();
|
||||
ASSERT_NE(nullptr, tick) << "Failed to create tick counter.";
|
||||
|
||||
ASSERT_EQ(0, tickcounter_get_current_ms(tick, &start_time_ms));
|
||||
|
||||
do
|
||||
{
|
||||
// This is not the necessarily the final status we will get, but at any point could return and the caller needs
|
||||
// to know the state of the update when we return.
|
||||
result = firmware_get_download_status(firmware_handle, finalStatus);
|
||||
if (result == K4A_RESULT_SUCCEEDED)
|
||||
{
|
||||
all_complete = ((finalStatus->audio.overall > FIRMWARE_OPERATION_INPROGRESS) &&
|
||||
(finalStatus->depth_config.overall > FIRMWARE_OPERATION_INPROGRESS) &&
|
||||
(finalStatus->depth.overall > FIRMWARE_OPERATION_INPROGRESS) &&
|
||||
(finalStatus->rgb.overall > FIRMWARE_OPERATION_INPROGRESS));
|
||||
|
||||
// Check to see if now is the correct time to interrupt the device.
|
||||
switch (component)
|
||||
{
|
||||
case FIRMWARE_OPERATION_AUDIO:
|
||||
if (finalStatus->audio.version_check != FIRMWARE_OPERATION_INPROGRESS)
|
||||
{
|
||||
interrupt_operation(interruption);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case FIRMWARE_OPERATION_DEPTH_CONFIG:
|
||||
if (finalStatus->depth_config.version_check != FIRMWARE_OPERATION_INPROGRESS)
|
||||
{
|
||||
interrupt_operation(interruption);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case FIRMWARE_OPERATION_DEPTH:
|
||||
if (finalStatus->depth.version_check != FIRMWARE_OPERATION_INPROGRESS)
|
||||
{
|
||||
interrupt_operation(interruption);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case FIRMWARE_OPERATION_RGB:
|
||||
if (finalStatus->rgb.version_check != FIRMWARE_OPERATION_INPROGRESS)
|
||||
{
|
||||
interrupt_operation(interruption);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Failed to get the status of the update operation. Break out of the loop to attempt to reset the device
|
||||
// and return.
|
||||
EXPECT_TRUE(false) << "ERROR: Failed to get the firmware update status.";
|
||||
break;
|
||||
}
|
||||
|
||||
ASSERT_EQ(0, tickcounter_get_current_ms(tick, &now));
|
||||
|
||||
if (!all_complete && (now - start_time_ms > UPDATE_TIMEOUT_MS))
|
||||
{
|
||||
// The update hasn't completed and too much time as passed. Break out of the loop to attempt to reset the
|
||||
// device and return.
|
||||
EXPECT_TRUE(false) << "ERROR: Timeout waiting for the update to complete.";
|
||||
break;
|
||||
}
|
||||
|
||||
if (!all_complete)
|
||||
{
|
||||
ThreadAPI_Sleep(500);
|
||||
}
|
||||
} while (!all_complete);
|
||||
|
||||
// At this point the update has either completed or timed out. Either way the device needs to be reset after the
|
||||
// update has progressed.
|
||||
interrupt_operation(FIRMWARE_OPERATION_RESET);
|
||||
}
|
||||
|
||||
TEST_F(firmware_fw, simple_update)
|
||||
{
|
||||
firmware_status_summary_t finalStatus;
|
||||
|
||||
LOG_INFO("Beginning the basic update test", 0);
|
||||
connEx->set_usb_port(k4a_port_number);
|
||||
|
||||
open_firmware_device();
|
||||
|
||||
// Update to the test firmware
|
||||
LOG_INFO("Updating the device to the test firmware.");
|
||||
ASSERT_EQ(K4A_RESULT_SUCCEEDED, firmware_get_device_version(firmware_handle, ¤t_version));
|
||||
log_device_version(current_version);
|
||||
log_firmware_version(test_firmware_package_info);
|
||||
|
||||
// Perform upgrade...
|
||||
ASSERT_EQ(K4A_RESULT_SUCCEEDED, firmware_download(firmware_handle, test_firmware_buffer, test_firmware_size));
|
||||
interrupt_device_at_update_stage(FIRMWARE_OPERATION_FULL_DEVICE, FIRMWARE_OPERATION_RESET, &finalStatus);
|
||||
|
||||
ASSERT_EQ(FIRMWARE_OPERATION_SUCCEEDED, calculate_overall_component_status(finalStatus.audio));
|
||||
ASSERT_EQ(FIRMWARE_OPERATION_SUCCEEDED, calculate_overall_component_status(finalStatus.depth_config));
|
||||
ASSERT_EQ(FIRMWARE_OPERATION_SUCCEEDED, calculate_overall_component_status(finalStatus.depth));
|
||||
ASSERT_EQ(FIRMWARE_OPERATION_SUCCEEDED, calculate_overall_component_status(finalStatus.rgb));
|
||||
|
||||
// Check upgrade...
|
||||
ASSERT_EQ(K4A_RESULT_SUCCEEDED, firmware_get_device_version(firmware_handle, ¤t_version));
|
||||
log_device_version(current_version);
|
||||
ASSERT_TRUE(compare_version(current_version.audio, test_firmware_package_info.audio)) << "Audio version mismatch";
|
||||
ASSERT_TRUE(compare_version_list(current_version.depth_sensor,
|
||||
test_firmware_package_info.depth_config_number_versions,
|
||||
test_firmware_package_info.depth_config_versions))
|
||||
<< "Depth Config mismatch";
|
||||
ASSERT_TRUE(compare_version(current_version.depth, test_firmware_package_info.depth)) << "Depth mismatch";
|
||||
ASSERT_TRUE(compare_version(current_version.rgb, test_firmware_package_info.rgb)) << "RGB mismatch";
|
||||
|
||||
// Update back to the LKG firmware
|
||||
LOG_INFO("Updating the device back to the LKG firmware.");
|
||||
ASSERT_EQ(K4A_RESULT_SUCCEEDED, firmware_get_device_version(firmware_handle, ¤t_version));
|
||||
log_device_version(current_version);
|
||||
log_firmware_version(lkg_firmware_package_info);
|
||||
|
||||
// Perform upgrade...
|
||||
ASSERT_EQ(K4A_RESULT_SUCCEEDED, firmware_download(firmware_handle, lkg_firmware_buffer, lkg_firmware_size));
|
||||
interrupt_device_at_update_stage(FIRMWARE_OPERATION_FULL_DEVICE, FIRMWARE_OPERATION_RESET, &finalStatus);
|
||||
|
||||
ASSERT_EQ(FIRMWARE_OPERATION_SUCCEEDED, calculate_overall_component_status(finalStatus.audio));
|
||||
ASSERT_EQ(FIRMWARE_OPERATION_SUCCEEDED, calculate_overall_component_status(finalStatus.depth_config));
|
||||
ASSERT_EQ(FIRMWARE_OPERATION_SUCCEEDED, calculate_overall_component_status(finalStatus.depth));
|
||||
ASSERT_EQ(FIRMWARE_OPERATION_SUCCEEDED, calculate_overall_component_status(finalStatus.rgb));
|
||||
|
||||
// Check upgrade...
|
||||
ASSERT_EQ(K4A_RESULT_SUCCEEDED, firmware_get_device_version(firmware_handle, ¤t_version));
|
||||
log_device_version(current_version);
|
||||
ASSERT_TRUE(compare_version(current_version.audio, lkg_firmware_package_info.audio)) << "Audio version mismatch";
|
||||
ASSERT_TRUE(compare_version_list(current_version.depth_sensor,
|
||||
lkg_firmware_package_info.depth_config_number_versions,
|
||||
lkg_firmware_package_info.depth_config_versions))
|
||||
<< "Depth Config mismatch";
|
||||
ASSERT_TRUE(compare_version(current_version.depth, lkg_firmware_package_info.depth)) << "Depth mismatch";
|
||||
ASSERT_TRUE(compare_version(current_version.rgb, lkg_firmware_package_info.rgb)) << "RGB mismatch";
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
k4a_unittest_init();
|
||||
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
|
@ -0,0 +1,822 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#include "firmware_helper.h"
|
||||
#include <utcommon.h>
|
||||
|
||||
#include <azure_c_shared_utility/tickcounter.h>
|
||||
#include <azure_c_shared_utility/threadapi.h>
|
||||
|
||||
#define K4A_TEST_VERIFY_SUCCEEDED(_result_) \
|
||||
if (K4A_FAILED(TRACE_CALL(_result_))) \
|
||||
{ \
|
||||
return K4A_RESULT_FAILED; \
|
||||
}
|
||||
|
||||
#define K4A_TEST_VERIFY_TRUE(_condition_) \
|
||||
if (!(_condition_)) \
|
||||
{ \
|
||||
LOG_ERROR("\"" #_condition_ "\" was false but was expected to be true."); \
|
||||
return K4A_RESULT_FAILED; \
|
||||
}
|
||||
|
||||
#define K4A_TEST_VERIFY_LE(_val1_, _val2_) \
|
||||
if ((_val1_) > (_val2_)) \
|
||||
{ \
|
||||
LOG_ERROR("\"" #_val1_ "\" > \"" #_val2_ "\" but was expected to be less than or equal."); \
|
||||
std::cout << "\"" #_val1_ "\" = " << (_val1_) << " \"" #_val2_ "\" = " << (_val2_) << std::endl; \
|
||||
return K4A_RESULT_FAILED; \
|
||||
}
|
||||
|
||||
#define K4A_TEST_VERIFY_EQUAL(_val1_, _val2_) \
|
||||
if ((_val1_) != (_val2_)) \
|
||||
{ \
|
||||
LOG_ERROR("\"" #_val1_ "\" != \"" #_val2_ "\" but was expected to be equal."); \
|
||||
std::cout << "\"" #_val1_ "\" = " << (_val1_) << " \"" #_val2_ "\" = " << (_val2_) << std::endl; \
|
||||
return K4A_RESULT_FAILED; \
|
||||
}
|
||||
|
||||
#define K4A_TEST_VERIFY_NOT_EQUAL(_val1_, _val2_) \
|
||||
if ((_val1_) == (_val2_)) \
|
||||
{ \
|
||||
LOG_ERROR("\"" #_val1_ "\" == \"" #_val2_ "\" but was expected to not be equal."); \
|
||||
std::cout << "\"" #_val1_ "\" = " << (_val1_) << " \"" #_val2_ "\" = " << (_val2_) << std::endl; \
|
||||
return K4A_RESULT_FAILED; \
|
||||
}
|
||||
|
||||
char *g_candidate_firmware_path = nullptr;
|
||||
|
||||
int g_k4a_port_number = -1;
|
||||
connection_exerciser *g_connection_exerciser = nullptr;
|
||||
|
||||
uint8_t *g_test_firmware_buffer = nullptr;
|
||||
size_t g_test_firmware_size = 0;
|
||||
firmware_package_info_t g_test_firmware_package_info = { 0 };
|
||||
|
||||
uint8_t *g_candidate_firmware_buffer = nullptr;
|
||||
size_t g_candidate_firmware_size = 0;
|
||||
firmware_package_info_t g_candidate_firmware_package_info = { 0 };
|
||||
|
||||
uint8_t *g_lkg_firmware_buffer = nullptr;
|
||||
size_t g_lkg_firmware_size = 0;
|
||||
firmware_package_info_t g_lkg_firmware_package_info = { 0 };
|
||||
|
||||
uint8_t *g_factory_firmware_buffer = nullptr;
|
||||
size_t g_factory_firmware_size = 0;
|
||||
firmware_package_info_t g_factory_firmware_package_info = { 0 };
|
||||
|
||||
static bool common_initialized = false;
|
||||
|
||||
k4a_result_t setup_common_test()
|
||||
{
|
||||
int port;
|
||||
float voltage;
|
||||
float current;
|
||||
|
||||
if (common_initialized)
|
||||
{
|
||||
return K4A_RESULT_SUCCEEDED;
|
||||
}
|
||||
|
||||
if (g_candidate_firmware_path == nullptr)
|
||||
{
|
||||
std::cout << "The firmware path setting is required and wasn't supplied.\n\n";
|
||||
return K4A_RESULT_FAILED;
|
||||
}
|
||||
|
||||
g_k4a_port_number = -1;
|
||||
g_connection_exerciser = new (std::nothrow) connection_exerciser();
|
||||
|
||||
LOG_INFO("Searching for Connection Exerciser...", 0);
|
||||
K4A_TEST_VERIFY_SUCCEEDED(g_connection_exerciser->find_connection_exerciser());
|
||||
LOG_INFO("Clearing port...");
|
||||
K4A_TEST_VERIFY_SUCCEEDED(g_connection_exerciser->set_usb_port(0));
|
||||
|
||||
LOG_INFO("Searching for device...");
|
||||
|
||||
for (int i = 0; i < CONN_EX_MAX_NUM_PORTS; ++i)
|
||||
{
|
||||
K4A_TEST_VERIFY_SUCCEEDED(g_connection_exerciser->set_usb_port(i));
|
||||
port = g_connection_exerciser->get_usb_port();
|
||||
K4A_TEST_VERIFY_EQUAL(port, i);
|
||||
|
||||
voltage = g_connection_exerciser->get_voltage_reading();
|
||||
K4A_TEST_VERIFY_NOT_EQUAL(voltage, -1);
|
||||
current = g_connection_exerciser->get_current_reading();
|
||||
K4A_TEST_VERIFY_NOT_EQUAL(current, -1);
|
||||
|
||||
if (current < 0)
|
||||
{
|
||||
current = current * -1;
|
||||
}
|
||||
|
||||
if (voltage > 4.5 && voltage < 5.5 && current > 0.1)
|
||||
{
|
||||
if (g_k4a_port_number != -1)
|
||||
{
|
||||
std::cout << "More than one device was detected on the connection exerciser." << std::endl;
|
||||
return K4A_RESULT_FAILED;
|
||||
}
|
||||
g_k4a_port_number = port;
|
||||
}
|
||||
|
||||
printf("On port #%d: %4.2fV %4.2fA\n", port, voltage, current);
|
||||
}
|
||||
|
||||
if (g_k4a_port_number == -1)
|
||||
{
|
||||
std::cout << "The Kinect for Azure was not detected on a port of the connection exerciser." << std::endl;
|
||||
return K4A_RESULT_FAILED;
|
||||
}
|
||||
K4A_TEST_VERIFY_SUCCEEDED(g_connection_exerciser->set_usb_port(0));
|
||||
|
||||
std::cout << "Loading Test firmware package: " << K4A_TEST_FIRMWARE_PATH << std::endl;
|
||||
load_firmware_files(K4A_TEST_FIRMWARE_PATH, &g_test_firmware_buffer, &g_test_firmware_size);
|
||||
parse_firmware_package(g_test_firmware_buffer, g_test_firmware_size, &g_test_firmware_package_info);
|
||||
|
||||
std::cout << "Loading Release Candidate firmware package: " << g_candidate_firmware_path << std::endl;
|
||||
load_firmware_files(g_candidate_firmware_path, &g_candidate_firmware_buffer, &g_candidate_firmware_size);
|
||||
parse_firmware_package(g_candidate_firmware_buffer, g_candidate_firmware_size, &g_candidate_firmware_package_info);
|
||||
|
||||
std::cout << "Loading LKG firmware package: " << K4A_LKG_FIRMWARE_PATH << std::endl;
|
||||
load_firmware_files(K4A_LKG_FIRMWARE_PATH, &g_lkg_firmware_buffer, &g_lkg_firmware_size);
|
||||
parse_firmware_package(g_lkg_firmware_buffer, g_lkg_firmware_size, &g_lkg_firmware_package_info);
|
||||
|
||||
std::cout << "Loading Factory firmware package: " << K4A_FACTORY_FIRMWARE_PATH << std::endl;
|
||||
load_firmware_files(K4A_FACTORY_FIRMWARE_PATH, &g_factory_firmware_buffer, &g_factory_firmware_size);
|
||||
parse_firmware_package(g_factory_firmware_buffer, g_factory_firmware_size, &g_factory_firmware_package_info);
|
||||
|
||||
common_initialized = true;
|
||||
return K4A_RESULT_SUCCEEDED;
|
||||
}
|
||||
|
||||
void tear_down_common_test()
|
||||
{
|
||||
if (g_connection_exerciser != nullptr)
|
||||
{
|
||||
g_k4a_port_number = -1;
|
||||
delete g_connection_exerciser;
|
||||
g_connection_exerciser = nullptr;
|
||||
}
|
||||
|
||||
if (g_test_firmware_buffer != nullptr)
|
||||
{
|
||||
free(g_test_firmware_buffer);
|
||||
g_test_firmware_buffer = nullptr;
|
||||
}
|
||||
|
||||
if (g_candidate_firmware_buffer != nullptr)
|
||||
{
|
||||
free(g_candidate_firmware_buffer);
|
||||
g_candidate_firmware_buffer = nullptr;
|
||||
}
|
||||
|
||||
if (g_lkg_firmware_buffer != nullptr)
|
||||
{
|
||||
free(g_lkg_firmware_buffer);
|
||||
g_lkg_firmware_buffer = nullptr;
|
||||
}
|
||||
|
||||
if (g_factory_firmware_buffer != nullptr)
|
||||
{
|
||||
free(g_factory_firmware_buffer);
|
||||
g_factory_firmware_buffer = nullptr;
|
||||
}
|
||||
|
||||
common_initialized = false;
|
||||
}
|
||||
|
||||
k4a_result_t load_firmware_files(char *firmware_path, uint8_t **firmware_buffer, size_t *firmware_size)
|
||||
{
|
||||
RETURN_VALUE_IF_ARG(K4A_RESULT_FAILED, firmware_path == NULL);
|
||||
RETURN_VALUE_IF_ARG(K4A_RESULT_FAILED, firmware_buffer == NULL);
|
||||
RETURN_VALUE_IF_ARG(K4A_RESULT_FAILED, firmware_size == NULL);
|
||||
|
||||
k4a_result_t result = K4A_RESULT_FAILED;
|
||||
FILE *pFirmwareFile = NULL;
|
||||
size_t numRead = 0;
|
||||
uint8_t *tempFirmwareBuffer = NULL;
|
||||
|
||||
if ((pFirmwareFile = fopen(firmware_path, "rb")) != NULL)
|
||||
{
|
||||
fseek(pFirmwareFile, 0, SEEK_END);
|
||||
size_t tempFirmwareSize = (size_t)ftell(pFirmwareFile);
|
||||
if (tempFirmwareSize == (size_t)-1L)
|
||||
{
|
||||
std::cout << "ERROR: Failed to get size of the firmware package." << std::endl;
|
||||
return K4A_RESULT_FAILED;
|
||||
}
|
||||
|
||||
fseek(pFirmwareFile, 0, SEEK_SET);
|
||||
|
||||
tempFirmwareBuffer = (uint8_t *)malloc(tempFirmwareSize);
|
||||
if (tempFirmwareBuffer == NULL)
|
||||
{
|
||||
std::cout << "ERROR: Failed to allocate memory." << std::endl;
|
||||
return K4A_RESULT_FAILED;
|
||||
}
|
||||
|
||||
std::cout << "File size: " << tempFirmwareSize << " bytes" << std::endl;
|
||||
numRead = fread(tempFirmwareBuffer, tempFirmwareSize, 1, pFirmwareFile);
|
||||
fclose(pFirmwareFile);
|
||||
|
||||
if (numRead != 1)
|
||||
{
|
||||
std::cout << "ERROR: Could not read all data from the file" << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
*firmware_buffer = tempFirmwareBuffer;
|
||||
*firmware_size = tempFirmwareSize;
|
||||
tempFirmwareBuffer = NULL;
|
||||
result = K4A_RESULT_SUCCEEDED;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "ERROR: Cannot Open (" << firmware_path << ") errno=" << errno << std::endl;
|
||||
}
|
||||
|
||||
if (tempFirmwareBuffer)
|
||||
{
|
||||
free(tempFirmwareBuffer);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
firmware_operation_status_t calculate_overall_component_status(const firmware_component_status_t status)
|
||||
{
|
||||
if (status.overall == FIRMWARE_OPERATION_SUCCEEDED)
|
||||
{
|
||||
return FIRMWARE_OPERATION_SUCCEEDED;
|
||||
}
|
||||
|
||||
if (status.overall == FIRMWARE_OPERATION_INPROGRESS)
|
||||
{
|
||||
return FIRMWARE_OPERATION_INPROGRESS;
|
||||
}
|
||||
|
||||
// If the version check failed, this component's update was skipped. This could because the new version is
|
||||
// an unsafe downgrade or the versions are the same and no update is required.
|
||||
if (status.version_check == FIRMWARE_OPERATION_FAILED)
|
||||
{
|
||||
return FIRMWARE_OPERATION_SUCCEEDED;
|
||||
}
|
||||
|
||||
printf("Overall Component Status failed: A:%d V:%d T:%d E:%d W:%d O:%d\n",
|
||||
status.authentication_check,
|
||||
status.version_check,
|
||||
status.image_transfer,
|
||||
status.flash_erase,
|
||||
status.flash_write,
|
||||
status.overall);
|
||||
|
||||
return FIRMWARE_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
bool compare_version(k4a_version_t left_version, k4a_version_t right_version)
|
||||
{
|
||||
return left_version.major == right_version.major && left_version.minor == right_version.minor &&
|
||||
left_version.iteration == right_version.iteration;
|
||||
}
|
||||
|
||||
bool compare_version(k4a_hardware_version_t device_version, firmware_package_info_t firmware_version)
|
||||
{
|
||||
bool are_equal = true;
|
||||
|
||||
if (!compare_version(device_version.audio, firmware_version.audio))
|
||||
{
|
||||
printf("Audio version mismatch.\n");
|
||||
are_equal = false;
|
||||
}
|
||||
|
||||
if (!compare_version_list(device_version.depth_sensor,
|
||||
firmware_version.depth_config_number_versions,
|
||||
firmware_version.depth_config_versions))
|
||||
{
|
||||
printf("Depth sensor does not exist in package.\n");
|
||||
are_equal = false;
|
||||
}
|
||||
|
||||
if (!compare_version(device_version.depth, firmware_version.depth))
|
||||
{
|
||||
printf("Depth version mismatch.\n");
|
||||
are_equal = false;
|
||||
}
|
||||
|
||||
if (!compare_version(device_version.rgb, firmware_version.rgb))
|
||||
{
|
||||
printf("RGB version mismatch.\n");
|
||||
are_equal = false;
|
||||
}
|
||||
|
||||
return are_equal;
|
||||
}
|
||||
|
||||
bool compare_version_list(k4a_version_t device_version, uint8_t count, k4a_version_t versions[5])
|
||||
{
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
if (device_version.major == versions[i].major && device_version.minor == versions[i].minor)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool compare_device_serial_number(firmware_t firmware_handle, char *device_serial_number)
|
||||
{
|
||||
char *serial_number = nullptr;
|
||||
size_t serial_number_length = 0;
|
||||
|
||||
if (K4A_BUFFER_RESULT_TOO_SMALL != firmware_get_device_serialnum(firmware_handle, nullptr, &serial_number_length))
|
||||
{
|
||||
printf("ERROR: Failed to get serial number length\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
serial_number = (char *)malloc(serial_number_length);
|
||||
if (serial_number == nullptr)
|
||||
{
|
||||
printf("ERROR: Failed to allocate memory for serial number (%zu bytes)\n", serial_number_length);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (K4A_BUFFER_RESULT_SUCCEEDED !=
|
||||
firmware_get_device_serialnum(firmware_handle, serial_number, &serial_number_length))
|
||||
{
|
||||
printf("ERROR: Failed to get serial number\n");
|
||||
free(serial_number);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strcmp(device_serial_number, serial_number) != 0)
|
||||
{
|
||||
printf("\'%s\' != \'%s\'", device_serial_number, serial_number);
|
||||
free(serial_number);
|
||||
return false;
|
||||
}
|
||||
|
||||
free(serial_number);
|
||||
return true;
|
||||
}
|
||||
|
||||
void log_firmware_build_config(k4a_firmware_build_t build_config)
|
||||
{
|
||||
std::cout << " Build Config: ";
|
||||
switch (build_config)
|
||||
{
|
||||
case K4A_FIRMWARE_BUILD_RELEASE:
|
||||
std::cout << "Production" << std::endl;
|
||||
break;
|
||||
|
||||
case K4A_FIRMWARE_BUILD_DEBUG:
|
||||
std::cout << "Debug" << std::endl;
|
||||
break;
|
||||
|
||||
default:
|
||||
std::cout << "Unknown" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void log_firmware_signature_type(k4a_firmware_signature_t signature_type, bool certificate)
|
||||
{
|
||||
if (certificate)
|
||||
{
|
||||
std::cout << " Certificate Type: ";
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << " Signature Type: ";
|
||||
}
|
||||
|
||||
switch (signature_type)
|
||||
{
|
||||
case K4A_FIRMWARE_SIGNATURE_MSFT:
|
||||
std::cout << "Microsoft" << std::endl;
|
||||
break;
|
||||
|
||||
case K4A_FIRMWARE_SIGNATURE_TEST:
|
||||
std::cout << "Test" << std::endl;
|
||||
break;
|
||||
|
||||
case K4A_FIRMWARE_SIGNATURE_UNSIGNED:
|
||||
std::cout << "Unsigned" << std::endl;
|
||||
break;
|
||||
|
||||
default:
|
||||
std::cout << "Unknown (" << signature_type << ")" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void log_firmware_version(firmware_package_info_t firmware_version)
|
||||
{
|
||||
printf("Firmware Package Versions:\n");
|
||||
printf(" RGB camera firmware: %d.%d.%d\n",
|
||||
firmware_version.rgb.major,
|
||||
firmware_version.rgb.minor,
|
||||
firmware_version.rgb.iteration);
|
||||
printf(" Depth camera firmware: %d.%d.%d\n",
|
||||
firmware_version.depth.major,
|
||||
firmware_version.depth.minor,
|
||||
firmware_version.depth.iteration);
|
||||
|
||||
printf(" Depth config file: ");
|
||||
for (size_t i = 0; i < firmware_version.depth_config_number_versions; i++)
|
||||
{
|
||||
printf("%d.%d ",
|
||||
firmware_version.depth_config_versions[i].major,
|
||||
firmware_version.depth_config_versions[i].minor);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
printf(" Audio firmware: %d.%d.%d\n",
|
||||
firmware_version.audio.major,
|
||||
firmware_version.audio.minor,
|
||||
firmware_version.audio.iteration);
|
||||
|
||||
log_firmware_build_config(firmware_version.build_config);
|
||||
|
||||
log_firmware_signature_type(firmware_version.certificate_type, true);
|
||||
log_firmware_signature_type(firmware_version.signature_type, false);
|
||||
}
|
||||
|
||||
void log_device_version(k4a_hardware_version_t firmware_version)
|
||||
{
|
||||
printf("Current Firmware Versions:\n");
|
||||
printf(" RGB camera firmware: %d.%d.%d\n",
|
||||
firmware_version.rgb.major,
|
||||
firmware_version.rgb.minor,
|
||||
firmware_version.rgb.iteration);
|
||||
printf(" Depth camera firmware: %d.%d.%d\n",
|
||||
firmware_version.depth.major,
|
||||
firmware_version.depth.minor,
|
||||
firmware_version.depth.iteration);
|
||||
printf(" Depth config file: %d.%d\n",
|
||||
firmware_version.depth_sensor.major,
|
||||
firmware_version.depth_sensor.minor);
|
||||
printf(" Audio firmware: %d.%d.%d\n",
|
||||
firmware_version.audio.major,
|
||||
firmware_version.audio.minor,
|
||||
firmware_version.audio.iteration);
|
||||
|
||||
log_firmware_build_config((k4a_firmware_build_t)firmware_version.firmware_build);
|
||||
log_firmware_signature_type((k4a_firmware_signature_t)firmware_version.firmware_signature, true);
|
||||
}
|
||||
|
||||
k4a_result_t open_firmware_device(firmware_t *firmware_handle)
|
||||
{
|
||||
int retry = 0;
|
||||
uint32_t device_count = 0;
|
||||
|
||||
while (device_count == 0 && retry++ < 20)
|
||||
{
|
||||
ThreadAPI_Sleep(500);
|
||||
K4A_TEST_VERIFY_SUCCEEDED(usb_cmd_get_device_count(&device_count));
|
||||
}
|
||||
|
||||
K4A_TEST_VERIFY_LE(retry, 20);
|
||||
|
||||
LOG_INFO("Opening firmware device...", 0);
|
||||
K4A_TEST_VERIFY_SUCCEEDED(firmware_create(K4A_DEVICE_DEFAULT, firmware_handle));
|
||||
K4A_TEST_VERIFY_TRUE(*firmware_handle != nullptr);
|
||||
|
||||
return K4A_RESULT_SUCCEEDED;
|
||||
}
|
||||
|
||||
k4a_result_t reset_device(firmware_t *firmware_handle)
|
||||
{
|
||||
LOG_INFO("Resetting device...", 0);
|
||||
K4A_TEST_VERIFY_SUCCEEDED(firmware_reset_device(*firmware_handle));
|
||||
|
||||
firmware_destroy(*firmware_handle);
|
||||
*firmware_handle = nullptr;
|
||||
|
||||
// Re-open the device to ensure it is ready for use.
|
||||
return TRACE_CALL(open_firmware_device(firmware_handle));
|
||||
}
|
||||
|
||||
k4a_result_t disconnect_device(firmware_t *firmware_handle)
|
||||
{
|
||||
LOG_INFO("Disconnecting device...", 0);
|
||||
|
||||
K4A_TEST_VERIFY_SUCCEEDED(g_connection_exerciser->set_usb_port(0));
|
||||
|
||||
ThreadAPI_Sleep(500);
|
||||
|
||||
K4A_TEST_VERIFY_SUCCEEDED(g_connection_exerciser->set_usb_port(g_k4a_port_number));
|
||||
|
||||
firmware_destroy(*firmware_handle);
|
||||
*firmware_handle = nullptr;
|
||||
|
||||
// Re-open the device to ensure it is ready for use.
|
||||
return TRACE_CALL(open_firmware_device(firmware_handle));
|
||||
}
|
||||
|
||||
k4a_result_t interrupt_operation(firmware_t *firmware_handle, firmware_operation_interruption_t interruption)
|
||||
{
|
||||
switch (interruption)
|
||||
{
|
||||
case FIRMWARE_INTERRUPTION_RESET:
|
||||
return TRACE_CALL(reset_device(firmware_handle));
|
||||
break;
|
||||
|
||||
case FIRMWARE_INTERRUPTION_DISCONNECT:
|
||||
return TRACE_CALL(disconnect_device(firmware_handle));
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_ERROR("Unknown interruption type");
|
||||
return K4A_RESULT_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
k4a_result_t interrupt_device_at_update_stage(firmware_t *firmware_handle,
|
||||
firmware_operation_component_t component,
|
||||
firmware_operation_interruption_t interruption,
|
||||
firmware_status_summary_t *final_status,
|
||||
bool verbose_logging)
|
||||
{
|
||||
RETURN_VALUE_IF_ARG(K4A_RESULT_FAILED, firmware_handle == nullptr);
|
||||
RETURN_VALUE_IF_ARG(K4A_RESULT_FAILED, final_status == nullptr);
|
||||
|
||||
bool all_complete = false;
|
||||
k4a_result_t result = K4A_RESULT_FAILED;
|
||||
firmware_status_summary_t previous_status = {};
|
||||
|
||||
tickcounter_ms_t start_time_ms, now;
|
||||
|
||||
TICK_COUNTER_HANDLE tick = tickcounter_create();
|
||||
K4A_TEST_VERIFY_TRUE(tick != nullptr);
|
||||
|
||||
K4A_TEST_VERIFY_EQUAL(0, tickcounter_get_current_ms(tick, &start_time_ms));
|
||||
|
||||
do
|
||||
{
|
||||
// This is not necessarily the final status we will get, but at any point could return and the caller needs to
|
||||
// know the state of the update when we return.
|
||||
result = firmware_get_download_status(*firmware_handle, final_status);
|
||||
if (result == K4A_RESULT_SUCCEEDED)
|
||||
{
|
||||
if (verbose_logging)
|
||||
{
|
||||
if (memcmp(&previous_status.audio, &final_status->audio, sizeof(firmware_component_status_t)) != 0)
|
||||
{
|
||||
LOG_INFO("Audio: A:%d V:%d T:%d E:%d W:%d O:%d",
|
||||
final_status->audio.authentication_check,
|
||||
final_status->audio.version_check,
|
||||
final_status->audio.image_transfer,
|
||||
final_status->audio.flash_erase,
|
||||
final_status->audio.flash_write,
|
||||
final_status->audio.overall);
|
||||
}
|
||||
|
||||
if (memcmp(&previous_status.depth_config,
|
||||
&final_status->depth_config,
|
||||
sizeof(firmware_component_status_t)) != 0)
|
||||
{
|
||||
LOG_INFO("Depth Config: A:%d V:%d T:%d E:%d W:%d O:%d",
|
||||
final_status->depth_config.authentication_check,
|
||||
final_status->depth_config.version_check,
|
||||
final_status->depth_config.image_transfer,
|
||||
final_status->depth_config.flash_erase,
|
||||
final_status->depth_config.flash_write,
|
||||
final_status->depth_config.overall);
|
||||
}
|
||||
|
||||
if (memcmp(&previous_status.depth, &final_status->depth, sizeof(firmware_component_status_t)) != 0)
|
||||
{
|
||||
LOG_INFO("Depth: A:%d V:%d T:%d E:%d W:%d O:%d",
|
||||
final_status->depth.authentication_check,
|
||||
final_status->depth.version_check,
|
||||
final_status->depth.image_transfer,
|
||||
final_status->depth.flash_erase,
|
||||
final_status->depth.flash_write,
|
||||
final_status->depth.overall);
|
||||
}
|
||||
|
||||
if (memcmp(&previous_status.rgb, &final_status->rgb, sizeof(firmware_component_status_t)) != 0)
|
||||
{
|
||||
LOG_INFO("RGB: A:%d V:%d T:%d E:%d W:%d O:%d",
|
||||
final_status->rgb.authentication_check,
|
||||
final_status->rgb.version_check,
|
||||
final_status->rgb.image_transfer,
|
||||
final_status->rgb.flash_erase,
|
||||
final_status->rgb.flash_write,
|
||||
final_status->rgb.overall);
|
||||
}
|
||||
|
||||
previous_status = *final_status;
|
||||
}
|
||||
|
||||
all_complete = ((final_status->audio.overall > FIRMWARE_OPERATION_INPROGRESS) &&
|
||||
(final_status->depth_config.overall > FIRMWARE_OPERATION_INPROGRESS) &&
|
||||
(final_status->depth.overall > FIRMWARE_OPERATION_INPROGRESS) &&
|
||||
(final_status->rgb.overall > FIRMWARE_OPERATION_INPROGRESS));
|
||||
|
||||
// Check to see if now is the correct time to interrupt the device.
|
||||
switch (component)
|
||||
{
|
||||
case FIRMWARE_OPERATION_START:
|
||||
// As early as possible reset the device.
|
||||
return TRACE_CALL(interrupt_operation(firmware_handle, interruption));
|
||||
|
||||
case FIRMWARE_OPERATION_AUDIO_ERASE:
|
||||
if (final_status->audio.image_transfer == FIRMWARE_OPERATION_SUCCEEDED)
|
||||
{
|
||||
// The erase takes places after the transfer is complete and takes about 7.8 seconds.
|
||||
int sleepTime = (int)((rand() / (float)RAND_MAX) * 7600);
|
||||
sleepTime = 3800;
|
||||
LOG_INFO("Audio Erase started, waiting %dms.", sleepTime);
|
||||
ThreadAPI_Sleep(sleepTime);
|
||||
TRACE_CALL(firmware_get_download_status(*firmware_handle, final_status));
|
||||
return TRACE_CALL(interrupt_operation(firmware_handle, interruption));
|
||||
}
|
||||
break;
|
||||
|
||||
case FIRMWARE_OPERATION_AUDIO_WRITE:
|
||||
if (final_status->audio.flash_erase == FIRMWARE_OPERATION_SUCCEEDED)
|
||||
{
|
||||
// The write takes places after the erase is complete and takes about 20 seconds.
|
||||
int sleepTime = (int)((rand() / (float)RAND_MAX) * 19700);
|
||||
sleepTime = 9850;
|
||||
LOG_INFO("Audio Write started, waiting %dms.", sleepTime);
|
||||
ThreadAPI_Sleep(sleepTime);
|
||||
TRACE_CALL(firmware_get_download_status(*firmware_handle, final_status));
|
||||
return TRACE_CALL(interrupt_operation(firmware_handle, interruption));
|
||||
}
|
||||
break;
|
||||
|
||||
case FIRMWARE_OPERATION_DEPTH_ERASE:
|
||||
if (final_status->depth.image_transfer == FIRMWARE_OPERATION_SUCCEEDED)
|
||||
{
|
||||
// The erase takes places after the transfer is complete and takes about 0.25 seconds.
|
||||
int sleepTime = (int)((rand() / (float)RAND_MAX) * 100);
|
||||
sleepTime = 50;
|
||||
LOG_INFO("Depth Erase started, waiting %dms.", sleepTime);
|
||||
ThreadAPI_Sleep(sleepTime);
|
||||
TRACE_CALL(firmware_get_download_status(*firmware_handle, final_status));
|
||||
return TRACE_CALL(interrupt_operation(firmware_handle, interruption));
|
||||
}
|
||||
break;
|
||||
|
||||
case FIRMWARE_OPERATION_DEPTH_WRITE:
|
||||
if (final_status->depth.flash_erase == FIRMWARE_OPERATION_SUCCEEDED)
|
||||
{
|
||||
// The write takes places after the transfer is complete and takes about 5.8 seconds.
|
||||
int sleepTime = (int)((rand() / (float)RAND_MAX) * 5700);
|
||||
sleepTime = 2850;
|
||||
LOG_INFO("Depth Write started, waiting %dms.", sleepTime);
|
||||
ThreadAPI_Sleep(sleepTime);
|
||||
TRACE_CALL(firmware_get_download_status(*firmware_handle, final_status));
|
||||
return TRACE_CALL(interrupt_operation(firmware_handle, interruption));
|
||||
}
|
||||
break;
|
||||
|
||||
case FIRMWARE_OPERATION_RGB_ERASE:
|
||||
if (final_status->rgb.image_transfer == FIRMWARE_OPERATION_SUCCEEDED)
|
||||
{
|
||||
// The erase takes places after the transfer is complete and takes about 0.05 seconds.
|
||||
LOG_INFO("RGB erase started...");
|
||||
TRACE_CALL(firmware_get_download_status(*firmware_handle, final_status));
|
||||
return TRACE_CALL(interrupt_operation(firmware_handle, interruption));
|
||||
}
|
||||
break;
|
||||
|
||||
case FIRMWARE_OPERATION_RGB_WRITE:
|
||||
if (final_status->rgb.flash_erase == FIRMWARE_OPERATION_SUCCEEDED)
|
||||
{
|
||||
// The write takes places after the transfer is complete and takes about 6.1 seconds.
|
||||
int sleepTime = (int)((rand() / (float)RAND_MAX) * 6000);
|
||||
sleepTime = 3000;
|
||||
LOG_INFO("RGB Write started, waiting %dms.", sleepTime);
|
||||
ThreadAPI_Sleep(sleepTime);
|
||||
TRACE_CALL(firmware_get_download_status(*firmware_handle, final_status));
|
||||
return TRACE_CALL(interrupt_operation(firmware_handle, interruption));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Failed to get the status of the update operation. Attempt to reset the device and return.
|
||||
LOG_ERROR("Failed to get the firmware update status.");
|
||||
TRACE_CALL(interrupt_operation(firmware_handle, interruption));
|
||||
return K4A_RESULT_FAILED;
|
||||
}
|
||||
|
||||
K4A_TEST_VERIFY_EQUAL(0, tickcounter_get_current_ms(tick, &now));
|
||||
|
||||
if (!all_complete && (now - start_time_ms > UPDATE_TIMEOUT_MS))
|
||||
{
|
||||
// The update hasn't completed and too much time as passed. Attempt to reset the device and return.
|
||||
LOG_ERROR("Timeout waiting for the update to complete.");
|
||||
TRACE_CALL(interrupt_operation(firmware_handle, interruption));
|
||||
return K4A_RESULT_FAILED;
|
||||
}
|
||||
|
||||
if (!all_complete)
|
||||
{
|
||||
ThreadAPI_Sleep(UPDATE_POLL_INTERVAL_MS);
|
||||
}
|
||||
} while (!all_complete);
|
||||
|
||||
// At this point the update has completed, the device needs to be reset after the
|
||||
// update has progressed.
|
||||
return TRACE_CALL(interrupt_operation(firmware_handle, interruption));
|
||||
}
|
||||
|
||||
k4a_result_t perform_device_update(firmware_t *firmware_handle,
|
||||
uint8_t *firmware_buffer,
|
||||
size_t firmware_size,
|
||||
firmware_package_info_t firmware_package_info,
|
||||
bool verbose_logging)
|
||||
{
|
||||
firmware_status_summary_t finalStatus;
|
||||
k4a_hardware_version_t current_version;
|
||||
|
||||
K4A_TEST_VERIFY_SUCCEEDED(firmware_get_device_version(*firmware_handle, ¤t_version));
|
||||
log_device_version(current_version);
|
||||
log_firmware_version(firmware_package_info);
|
||||
|
||||
// Perform upgrade...
|
||||
K4A_TEST_VERIFY_SUCCEEDED(firmware_download(*firmware_handle, firmware_buffer, firmware_size));
|
||||
interrupt_device_at_update_stage(firmware_handle,
|
||||
FIRMWARE_OPERATION_FULL_DEVICE,
|
||||
FIRMWARE_INTERRUPTION_RESET,
|
||||
&finalStatus,
|
||||
verbose_logging);
|
||||
|
||||
K4A_TEST_VERIFY_EQUAL(FIRMWARE_OPERATION_SUCCEEDED, calculate_overall_component_status(finalStatus.audio));
|
||||
K4A_TEST_VERIFY_EQUAL(FIRMWARE_OPERATION_SUCCEEDED, calculate_overall_component_status(finalStatus.depth_config));
|
||||
K4A_TEST_VERIFY_EQUAL(FIRMWARE_OPERATION_SUCCEEDED, calculate_overall_component_status(finalStatus.depth));
|
||||
K4A_TEST_VERIFY_EQUAL(FIRMWARE_OPERATION_SUCCEEDED, calculate_overall_component_status(finalStatus.rgb));
|
||||
|
||||
// Check upgrade...
|
||||
K4A_TEST_VERIFY_SUCCEEDED(firmware_get_device_version(*firmware_handle, ¤t_version));
|
||||
printf("Post full update ");
|
||||
log_device_version(current_version);
|
||||
K4A_TEST_VERIFY_TRUE(compare_version(current_version, firmware_package_info));
|
||||
|
||||
return K4A_RESULT_SUCCEEDED;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
bool error = false;
|
||||
|
||||
srand((unsigned int)time(0)); // use current time as seed for random generator
|
||||
|
||||
k4a_unittest_init();
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
|
||||
for (int i = 1; i < argc; ++i)
|
||||
{
|
||||
char *argument = argv[i];
|
||||
|
||||
for (int j = 0; argument[j]; j++)
|
||||
{
|
||||
argument[j] = (char)tolower(argument[j]);
|
||||
}
|
||||
|
||||
if (strcmp(argument, "--firmware") == 0)
|
||||
{
|
||||
if (i + 1 <= argc)
|
||||
{
|
||||
g_candidate_firmware_path = argv[++i];
|
||||
printf("Setting g_test_firmware_path = %s\n", g_candidate_firmware_path);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Error: firmware path parameter missing\n");
|
||||
error = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ((strcmp(argument, "-h") == 0) || (strcmp(argument, "/h") == 0) || (strcmp(argument, "-?") == 0) ||
|
||||
(strcmp(argument, "/?") == 0))
|
||||
{
|
||||
error = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (error)
|
||||
{
|
||||
printf("\n\nCustom Test Settings:\n");
|
||||
printf(" --firmware <firmware path>\n");
|
||||
printf(" This is the path to the candidate firmware that should be tested.\n");
|
||||
|
||||
return 1; // Indicates an error or warning
|
||||
}
|
||||
|
||||
int result = RUN_ALL_TESTS();
|
||||
|
||||
tear_down_common_test();
|
||||
return result;
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#ifndef FIRMWARE_HELPER_H
|
||||
#define FIRMWARE_HELPER_H
|
||||
|
||||
#include <k4a/k4atypes.h>
|
||||
#include <k4ainternal/firmware.h>
|
||||
#include <ConnEx.h>
|
||||
|
||||
#define UPDATE_TIMEOUT_MS 10 * 60 * 1000 // 10 Minutes should be way more than enough.
|
||||
#define UPDATE_POLL_INTERVAL_MS 5
|
||||
|
||||
// This will define the path to the firmware packages to use in testing the firmware update process. The firmware update
|
||||
// is executed by the firmware that is currently on the device. In order to test the firmware update process for a
|
||||
// candidate, the device must be on the candidate firmware and then updated to a different test firmware where all of
|
||||
// the versions are different.
|
||||
// Factory firmware - This should be the oldest available firmware that we can roll back to.
|
||||
// LKG firmware - This should be the last firmware that was released.
|
||||
// Test firmware - This should be a firmware where all components have different versions than the candidate firmware.
|
||||
// Candidate firmware - This should be the firmware that is being validated. It will be passed in via command line
|
||||
// parameter.
|
||||
#define K4A_FACTORY_FIRMWARE_PATH "D:\\Shares\\Eden\\Public\\AzureKinectDK_Fw_1.5.786013.bin"
|
||||
#define K4A_LKG_FIRMWARE_PATH "D:\\Shares\\Eden\\Public\\AzureKinectDK_Fw_1.5.886314.bin"
|
||||
#define K4A_TEST_FIRMWARE_PATH "D:\\Shares\\Eden\\Public\\AzureKinectDK_Fw_1.5.786013.bin"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
FIRMWARE_OPERATION_START,
|
||||
FIRMWARE_OPERATION_AUDIO_ERASE,
|
||||
FIRMWARE_OPERATION_AUDIO_WRITE,
|
||||
FIRMWARE_OPERATION_DEPTH_ERASE,
|
||||
FIRMWARE_OPERATION_DEPTH_WRITE,
|
||||
FIRMWARE_OPERATION_RGB_ERASE,
|
||||
FIRMWARE_OPERATION_RGB_WRITE,
|
||||
FIRMWARE_OPERATION_FULL_DEVICE,
|
||||
} firmware_operation_component_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
FIRMWARE_INTERRUPTION_RESET,
|
||||
FIRMWARE_INTERRUPTION_DISCONNECT,
|
||||
} firmware_operation_interruption_t;
|
||||
|
||||
extern int g_k4a_port_number;
|
||||
extern connection_exerciser *g_connection_exerciser;
|
||||
|
||||
extern uint8_t *g_test_firmware_buffer;
|
||||
extern size_t g_test_firmware_size;
|
||||
extern firmware_package_info_t g_test_firmware_package_info;
|
||||
|
||||
extern uint8_t *g_candidate_firmware_buffer;
|
||||
extern size_t g_candidate_firmware_size;
|
||||
extern firmware_package_info_t g_candidate_firmware_package_info;
|
||||
|
||||
extern uint8_t *g_lkg_firmware_buffer;
|
||||
extern size_t g_lkg_firmware_size;
|
||||
extern firmware_package_info_t g_lkg_firmware_package_info;
|
||||
|
||||
extern uint8_t *g_factory_firmware_buffer;
|
||||
extern size_t g_factory_firmware_size;
|
||||
extern firmware_package_info_t g_factory_firmware_package_info;
|
||||
|
||||
k4a_result_t setup_common_test();
|
||||
|
||||
k4a_result_t load_firmware_files(char *firmware_path, uint8_t **firmware_buffer, size_t *firmware_size);
|
||||
firmware_operation_status_t calculate_overall_component_status(const firmware_component_status_t status);
|
||||
|
||||
bool compare_version(k4a_version_t left_version, k4a_version_t right_version);
|
||||
bool compare_version_list(k4a_version_t device_version, uint8_t count, k4a_version_t versions[5]);
|
||||
bool compare_device_serial_number(firmware_t firmware_handle, char *device_serial_number);
|
||||
|
||||
void log_firmware_build_config(k4a_firmware_build_t build_config);
|
||||
void log_firmware_signature_type(k4a_firmware_signature_t signature_type, bool certificate);
|
||||
void log_firmware_version(firmware_package_info_t firmware_version);
|
||||
void log_device_version(k4a_hardware_version_t firmware_version);
|
||||
|
||||
k4a_result_t open_firmware_device(firmware_t *firmware_handle);
|
||||
k4a_result_t reset_device(firmware_t *firmware_handle);
|
||||
k4a_result_t interrupt_operation(firmware_t *firmware_handle, firmware_operation_interruption_t interruption);
|
||||
k4a_result_t interrupt_device_at_update_stage(firmware_t *firmware_handle,
|
||||
firmware_operation_component_t component,
|
||||
firmware_operation_interruption_t interruption,
|
||||
firmware_status_summary_t *final_status,
|
||||
bool verbose_logging);
|
||||
k4a_result_t perform_device_update(firmware_t *firmware_handle,
|
||||
uint8_t *firmware_buffer,
|
||||
size_t firmware_size,
|
||||
firmware_package_info_t firmware_package_info,
|
||||
bool verbose_logging);
|
||||
|
||||
#endif /* FIRMWARE_HELPER_H */
|
|
@ -0,0 +1,264 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#define VC_EXTRALEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
|
||||
#define _CRT_NONSTDC_NO_DEPRECATE
|
||||
|
||||
#include "firmware_helper.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <utcommon.h>
|
||||
#include <k4ainternal/logging.h>
|
||||
|
||||
#include <azure_c_shared_utility/tickcounter.h>
|
||||
#include <azure_c_shared_utility/threadapi.h>
|
||||
|
||||
struct firmware_interrupt_parameters
|
||||
{
|
||||
int test_number;
|
||||
const char *test_name;
|
||||
firmware_operation_component_t component;
|
||||
firmware_operation_interruption_t interruption;
|
||||
|
||||
friend std::ostream &operator<<(std::ostream &os, const firmware_interrupt_parameters &obj)
|
||||
{
|
||||
return os << "test " << (int)obj.test_number << ": " << obj.test_name;
|
||||
}
|
||||
};
|
||||
|
||||
class firmware_interrupt_fw : public ::testing::Test,
|
||||
public ::testing::WithParamInterface<firmware_interrupt_parameters>
|
||||
{
|
||||
protected:
|
||||
void SetUp() override
|
||||
{
|
||||
ASSERT_EQ(K4A_RESULT_SUCCEEDED, TRACE_CALL(setup_common_test()));
|
||||
const ::testing::TestInfo *const test_info = ::testing::UnitTest::GetInstance()->current_test_info();
|
||||
LOG_INFO("Test %s requires a connection exerciser.", test_info->name());
|
||||
LOG_INFO("Disconnecting the device", 0);
|
||||
g_connection_exerciser->set_usb_port(0);
|
||||
ThreadAPI_Sleep(500);
|
||||
|
||||
// Make sure that all of the firmwares have loaded correctly.
|
||||
ASSERT_TRUE(g_test_firmware_buffer != nullptr);
|
||||
ASSERT_TRUE(g_test_firmware_size > 0);
|
||||
ASSERT_TRUE(g_candidate_firmware_buffer != nullptr);
|
||||
ASSERT_TRUE(g_candidate_firmware_size > 0);
|
||||
ASSERT_TRUE(g_lkg_firmware_buffer != nullptr);
|
||||
ASSERT_TRUE(g_lkg_firmware_size > 0);
|
||||
|
||||
// Make sure that the Test firmware has all components with a different version when compared to the Release
|
||||
// Candidate firmware.
|
||||
// Depth Sensor isn't expect to change.
|
||||
ASSERT_FALSE(compare_version(g_test_firmware_package_info.audio, g_candidate_firmware_package_info.audio));
|
||||
ASSERT_FALSE(compare_version(g_test_firmware_package_info.depth, g_candidate_firmware_package_info.depth));
|
||||
ASSERT_FALSE(compare_version(g_test_firmware_package_info.rgb, g_candidate_firmware_package_info.rgb));
|
||||
|
||||
// There should be no other devices.
|
||||
uint32_t device_count = 0;
|
||||
usb_cmd_get_device_count(&device_count);
|
||||
ASSERT_EQ((uint32_t)0, device_count);
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
if (firmware_handle != nullptr)
|
||||
{
|
||||
firmware_destroy(firmware_handle);
|
||||
firmware_handle = nullptr;
|
||||
}
|
||||
|
||||
if (serial_number != nullptr)
|
||||
{
|
||||
free(serial_number);
|
||||
serial_number = nullptr;
|
||||
serial_number_length = 0;
|
||||
}
|
||||
}
|
||||
|
||||
firmware_t firmware_handle = nullptr;
|
||||
char *serial_number = nullptr;
|
||||
size_t serial_number_length = 0;
|
||||
k4a_hardware_version_t current_version = { 0 };
|
||||
};
|
||||
|
||||
TEST_P(firmware_interrupt_fw, interrupt_update)
|
||||
{
|
||||
firmware_interrupt_parameters parameters = GetParam();
|
||||
firmware_status_summary_t finalStatus;
|
||||
LOG_INFO("Beginning the \'%s\' test. Stage: %d Interruption: %d",
|
||||
parameters.test_name,
|
||||
parameters.component,
|
||||
parameters.interruption);
|
||||
|
||||
LOG_INFO("Powering on the device...", 0);
|
||||
ASSERT_EQ(K4A_RESULT_SUCCEEDED, g_connection_exerciser->set_usb_port(g_k4a_port_number));
|
||||
|
||||
ASSERT_EQ(K4A_RESULT_SUCCEEDED, open_firmware_device(&firmware_handle));
|
||||
|
||||
ASSERT_EQ(K4A_BUFFER_RESULT_TOO_SMALL, firmware_get_device_serialnum(firmware_handle, NULL, &serial_number_length));
|
||||
|
||||
serial_number = (char *)malloc(serial_number_length);
|
||||
ASSERT_NE(nullptr, serial_number);
|
||||
|
||||
ASSERT_EQ(K4A_RESULT_SUCCEEDED,
|
||||
firmware_get_device_serialnum(firmware_handle, serial_number, &serial_number_length));
|
||||
|
||||
// Update to the Candidate firmware
|
||||
LOG_INFO("Updating the device to the Candidate firmware.");
|
||||
ASSERT_EQ(K4A_RESULT_SUCCEEDED,
|
||||
perform_device_update(&firmware_handle,
|
||||
g_candidate_firmware_buffer,
|
||||
g_candidate_firmware_size,
|
||||
g_candidate_firmware_package_info,
|
||||
false));
|
||||
|
||||
// Update to the Test firmware, but interrupt...
|
||||
LOG_INFO("Beginning of the firmware update to the Test Firmware with interruption...");
|
||||
|
||||
// Prepend the "Firmware Package Versions:\n" with "Test".
|
||||
printf("Test ");
|
||||
log_firmware_version(g_test_firmware_package_info);
|
||||
|
||||
ASSERT_EQ(K4A_RESULT_SUCCEEDED, firmware_download(firmware_handle, g_test_firmware_buffer, g_test_firmware_size));
|
||||
ASSERT_EQ(K4A_RESULT_SUCCEEDED,
|
||||
interrupt_device_at_update_stage(&firmware_handle,
|
||||
parameters.component,
|
||||
parameters.interruption,
|
||||
&finalStatus,
|
||||
false));
|
||||
|
||||
std::cout << "Updated completed with Audio: " << calculate_overall_component_status(finalStatus.audio)
|
||||
<< " Depth Config: " << calculate_overall_component_status(finalStatus.depth_config)
|
||||
<< " Depth: " << calculate_overall_component_status(finalStatus.depth)
|
||||
<< " RGB: " << calculate_overall_component_status(finalStatus.rgb) << std::endl;
|
||||
|
||||
// Check that we are still on the version we expect
|
||||
ASSERT_EQ(K4A_RESULT_SUCCEEDED, firmware_get_device_version(firmware_handle, ¤t_version));
|
||||
log_device_version(current_version);
|
||||
|
||||
ASSERT_TRUE(compare_version_list(current_version.depth_sensor,
|
||||
g_candidate_firmware_package_info.depth_config_number_versions,
|
||||
g_candidate_firmware_package_info.depth_config_versions))
|
||||
<< "Depth sensor does not exist in package.";
|
||||
|
||||
switch (parameters.component)
|
||||
{
|
||||
case FIRMWARE_OPERATION_START:
|
||||
ASSERT_EQ(FIRMWARE_OPERATION_INPROGRESS, calculate_overall_component_status(finalStatus.audio));
|
||||
ASSERT_EQ(FIRMWARE_OPERATION_INPROGRESS, calculate_overall_component_status(finalStatus.depth_config));
|
||||
ASSERT_EQ(FIRMWARE_OPERATION_INPROGRESS, calculate_overall_component_status(finalStatus.depth));
|
||||
ASSERT_EQ(FIRMWARE_OPERATION_INPROGRESS, calculate_overall_component_status(finalStatus.rgb));
|
||||
ASSERT_TRUE(compare_version(current_version.audio, g_candidate_firmware_package_info.audio))
|
||||
<< "Audio version mismatch";
|
||||
ASSERT_TRUE(compare_version(current_version.depth, g_candidate_firmware_package_info.depth))
|
||||
<< "Depth mismatch";
|
||||
ASSERT_TRUE(compare_version(current_version.rgb, g_candidate_firmware_package_info.rgb)) << "RGB mismatch";
|
||||
break;
|
||||
|
||||
case FIRMWARE_OPERATION_AUDIO_ERASE:
|
||||
ASSERT_EQ(FIRMWARE_OPERATION_INPROGRESS, calculate_overall_component_status(finalStatus.audio));
|
||||
ASSERT_EQ(FIRMWARE_OPERATION_INPROGRESS, calculate_overall_component_status(finalStatus.depth_config));
|
||||
ASSERT_EQ(FIRMWARE_OPERATION_INPROGRESS, calculate_overall_component_status(finalStatus.depth));
|
||||
ASSERT_EQ(FIRMWARE_OPERATION_INPROGRESS, calculate_overall_component_status(finalStatus.rgb));
|
||||
ASSERT_TRUE(compare_version(current_version.audio, { 0 })) << "Audio version mismatch";
|
||||
ASSERT_TRUE(compare_version(current_version.depth, g_candidate_firmware_package_info.depth))
|
||||
<< "Depth mismatch";
|
||||
ASSERT_TRUE(compare_version(current_version.rgb, g_candidate_firmware_package_info.rgb)) << "RGB mismatch";
|
||||
break;
|
||||
|
||||
case FIRMWARE_OPERATION_AUDIO_WRITE:
|
||||
ASSERT_EQ(FIRMWARE_OPERATION_INPROGRESS, calculate_overall_component_status(finalStatus.audio));
|
||||
ASSERT_EQ(FIRMWARE_OPERATION_INPROGRESS, calculate_overall_component_status(finalStatus.depth_config));
|
||||
ASSERT_EQ(FIRMWARE_OPERATION_INPROGRESS, calculate_overall_component_status(finalStatus.depth));
|
||||
ASSERT_EQ(FIRMWARE_OPERATION_INPROGRESS, calculate_overall_component_status(finalStatus.rgb));
|
||||
ASSERT_TRUE(compare_version(current_version.audio, g_test_firmware_package_info.audio))
|
||||
<< "Audio version mismatch";
|
||||
ASSERT_TRUE(compare_version(current_version.depth, g_candidate_firmware_package_info.depth))
|
||||
<< "Depth mismatch";
|
||||
ASSERT_TRUE(compare_version(current_version.rgb, g_candidate_firmware_package_info.rgb)) << "RGB mismatch";
|
||||
break;
|
||||
|
||||
case FIRMWARE_OPERATION_DEPTH_ERASE:
|
||||
case FIRMWARE_OPERATION_DEPTH_WRITE:
|
||||
ASSERT_EQ(FIRMWARE_OPERATION_SUCCEEDED, calculate_overall_component_status(finalStatus.audio));
|
||||
ASSERT_EQ(FIRMWARE_OPERATION_SUCCEEDED, calculate_overall_component_status(finalStatus.depth_config));
|
||||
ASSERT_EQ(FIRMWARE_OPERATION_INPROGRESS, calculate_overall_component_status(finalStatus.depth));
|
||||
ASSERT_EQ(FIRMWARE_OPERATION_INPROGRESS, calculate_overall_component_status(finalStatus.rgb));
|
||||
ASSERT_TRUE(compare_version(current_version.audio, g_test_firmware_package_info.audio))
|
||||
<< "Audio version mismatch";
|
||||
ASSERT_TRUE(compare_version(current_version.rgb, g_candidate_firmware_package_info.rgb)) << "RGB mismatch";
|
||||
|
||||
// Don't fail on the Depth version as it appears to be non-deterministic based on when the reset actually
|
||||
// happened.
|
||||
if (!compare_version(current_version.depth, { 0 }))
|
||||
{
|
||||
printf(" The Depth version was not expected\n");
|
||||
}
|
||||
break;
|
||||
|
||||
case FIRMWARE_OPERATION_RGB_ERASE:
|
||||
case FIRMWARE_OPERATION_RGB_WRITE:
|
||||
ASSERT_EQ(FIRMWARE_OPERATION_SUCCEEDED, calculate_overall_component_status(finalStatus.audio));
|
||||
ASSERT_EQ(FIRMWARE_OPERATION_SUCCEEDED, calculate_overall_component_status(finalStatus.depth_config));
|
||||
ASSERT_EQ(FIRMWARE_OPERATION_SUCCEEDED, calculate_overall_component_status(finalStatus.depth));
|
||||
ASSERT_EQ(FIRMWARE_OPERATION_INPROGRESS, calculate_overall_component_status(finalStatus.rgb));
|
||||
|
||||
// Don't fail on the Audio, Depth, and RGB versions as they appear to be non-deterministic based on when the
|
||||
// reset actually happened.
|
||||
if (!compare_version(current_version.audio, g_test_firmware_package_info.audio))
|
||||
{
|
||||
printf(" The Audio version was not expected\n");
|
||||
}
|
||||
if (!compare_version(current_version.depth, g_test_firmware_package_info.depth))
|
||||
{
|
||||
printf(" The Depth version was not expected\n");
|
||||
}
|
||||
if (!compare_version(current_version.rgb, { 0 }))
|
||||
{
|
||||
printf(" The RGB version was not expected\n");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
ASSERT_TRUE(false) << "Unhandled component type. " << parameters.component;
|
||||
}
|
||||
|
||||
// Update back to the LKG firmware to make sure that works.
|
||||
LOG_INFO("Updating the device back to the LKG firmware.");
|
||||
ASSERT_EQ(K4A_RESULT_SUCCEEDED,
|
||||
perform_device_update(&firmware_handle,
|
||||
g_lkg_firmware_buffer,
|
||||
g_lkg_firmware_size,
|
||||
g_lkg_firmware_package_info,
|
||||
false));
|
||||
|
||||
ASSERT_TRUE(compare_device_serial_number(firmware_handle, serial_number));
|
||||
}
|
||||
|
||||
static struct firmware_interrupt_parameters tests_interrupt_reboot[] = {
|
||||
{ 0, "Reset device at update start", FIRMWARE_OPERATION_START, FIRMWARE_INTERRUPTION_RESET },
|
||||
{ 1, "Reset device during Audio erase", FIRMWARE_OPERATION_AUDIO_ERASE, FIRMWARE_INTERRUPTION_RESET },
|
||||
{ 2, "Reset device during Audio write", FIRMWARE_OPERATION_AUDIO_WRITE, FIRMWARE_INTERRUPTION_RESET },
|
||||
{ 3, "Reset device during Depth erase", FIRMWARE_OPERATION_DEPTH_ERASE, FIRMWARE_INTERRUPTION_RESET },
|
||||
{ 4, "Reset device during Depth write", FIRMWARE_OPERATION_DEPTH_WRITE, FIRMWARE_INTERRUPTION_RESET },
|
||||
{ 5, "Reset device during RGB erase", FIRMWARE_OPERATION_RGB_ERASE, FIRMWARE_INTERRUPTION_RESET },
|
||||
{ 6, "Reset device during RGB write", FIRMWARE_OPERATION_RGB_WRITE, FIRMWARE_INTERRUPTION_RESET },
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(interrupt_reboot, firmware_interrupt_fw, ::testing::ValuesIn(tests_interrupt_reboot));
|
||||
|
||||
static struct firmware_interrupt_parameters tests_interrupt_disconnect[] = {
|
||||
{ 0, "Disconnect device at update start", FIRMWARE_OPERATION_START, FIRMWARE_INTERRUPTION_DISCONNECT },
|
||||
{ 1, "Disconnect device during Audio erase", FIRMWARE_OPERATION_AUDIO_ERASE, FIRMWARE_INTERRUPTION_DISCONNECT },
|
||||
{ 2, "Disconnect device during Audio write", FIRMWARE_OPERATION_AUDIO_WRITE, FIRMWARE_INTERRUPTION_DISCONNECT },
|
||||
{ 3, "Disconnect device during Depth erase", FIRMWARE_OPERATION_DEPTH_ERASE, FIRMWARE_INTERRUPTION_DISCONNECT },
|
||||
{ 4, "Disconnect device during Depth write", FIRMWARE_OPERATION_DEPTH_WRITE, FIRMWARE_INTERRUPTION_DISCONNECT },
|
||||
{ 5, "Disconnect device during RGB erase", FIRMWARE_OPERATION_RGB_ERASE, FIRMWARE_INTERRUPTION_DISCONNECT },
|
||||
{ 6, "Disconnect device during RGB write", FIRMWARE_OPERATION_RGB_WRITE, FIRMWARE_INTERRUPTION_DISCONNECT },
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(interrupt_disconnect, firmware_interrupt_fw, ::testing::ValuesIn(tests_interrupt_disconnect));
|
|
@ -254,7 +254,7 @@ k4a_result_t connection_exerciser::find_connection_exerciser()
|
|||
for (int i = 1; i < 10; ++i)
|
||||
{
|
||||
sprintf_s(comPort, "COM%d", i);
|
||||
LOG_ERROR("Opening %s", comPort);
|
||||
LOG_INFO("Opening %s", comPort);
|
||||
state->serialHandle = OpenComPort(comPort);
|
||||
|
||||
if (state->serialHandle != INVALID_HANDLE_VALUE)
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#ifndef CONNECTION_EXERCISER_H
|
||||
#define CONNECTION_EXERCISER_H
|
||||
|
||||
#include <k4a/k4atypes.h>
|
||||
|
||||
// The connection exerciser has 4 active ports plus a everything disconnected "port".
|
||||
|
@ -35,3 +38,5 @@ private:
|
|||
|
||||
pconnection_exerciser_internal_t state;
|
||||
};
|
||||
|
||||
#endif /* CONNECTION_EXERCISER_H */
|
||||
|
|
Загрузка…
Ссылка в новой задаче