4 Commits
Author SHA1 Message Date
Gowtham NanjukuttyandGitHub 2158a9781b Merge 0c9f1c5f3e into 40d83f3b7c 2026-06-25 02:44:47 +00:00
David RebbeandKyle Schwarz 40d83f3b7c C2: Add device_product_name_get() 2026-06-24 16:58:28 -04:00
David RebbeandKyle Schwarz 60918c4b6d C2: Add PerfTest setting 2026-06-24 15:16:51 -04:00
Bryant JonesandKyle Schwarz 749552e443 Device: Fix coremini loading
For:
- RADA2B
- RADComet2
- RADComet3
- RADGalaxy2
- RADMoonT1S
- RADStar2
2026-06-24 13:28:12 -04:00
16 changed files with 268 additions and 28 deletions
+10
View File
@@ -439,6 +439,16 @@ icsneoc2_error_t icsneoc2_device_serial_get(const icsneoc2_device_t* device, cha
return safe_str_copy(value, value_length, dev->getSerial()) ? icsneoc2_error_success : icsneoc2_error_string_copy_failed; return safe_str_copy(value, value_length, dev->getSerial()) ? icsneoc2_error_success : icsneoc2_error_string_copy_failed;
} }
icsneoc2_error_t icsneoc2_device_product_name_get(const icsneoc2_device_t* device, char* value, size_t* value_length) {
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
auto dev = device->device;
// Copy the string into value
return safe_str_copy(value, value_length, dev->getProductName()) ? icsneoc2_error_success : icsneoc2_error_string_copy_failed;
}
icsneoc2_error_t icsneoc2_device_pcb_serial_get(const icsneoc2_device_t* device, uint8_t* value, size_t* value_length) { icsneoc2_error_t icsneoc2_device_pcb_serial_get(const icsneoc2_device_t* device, uint8_t* value, size_t* value_length) {
auto res = icsneoc2_device_is_valid(device); auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) { if(res != icsneoc2_error_success) {
+30
View File
@@ -923,6 +923,36 @@ icsneoc2_error_t icsneoc2_settings_external_wifi_antenna_enabled_set(icsneoc2_de
return icsneoc2_error_success; return icsneoc2_error_success;
} }
icsneoc2_error_t icsneoc2_settings_perf_test_enabled_get(icsneoc2_device_t* device, bool* value) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!value) {
return icsneoc2_error_invalid_parameters;
}
if(auto result = device->device->settings->isPerfTestEnabled(); result.has_value()) {
*value = result.value();
return icsneoc2_error_success;
} else {
*value = false;
return icsneoc2_error_get_settings_failure;
}
}
icsneoc2_error_t icsneoc2_settings_perf_test_enabled_set(icsneoc2_device_t* device, bool value) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!device->device->settings->setPerfTestEnable(value)) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_linux_configuration_port_get(icsneoc2_device_t* device, icsneoc2_linux_configuration_port_t* value) { icsneoc2_error_t icsneoc2_settings_linux_configuration_port_get(icsneoc2_device_t* device, icsneoc2_linux_configuration_port_t* value) {
// Make sure the device is valid // Make sure the device is valid
auto res = icsneoc2_device_is_valid(device); auto res = icsneoc2_device_is_valid(device);
+17 -14
View File
@@ -737,15 +737,17 @@ bool Device::uploadCoremini(std::istream& stream, Disk::MemoryType memType) {
return false; return false;
} }
auto connected = isLogicalDiskConnected(); if (memType == Disk::MemoryType::SD) {
auto connected = isLogicalDiskConnected();
if(!connected) {
return false; // Already added an API error if(!connected) {
} return false; // Already added an API error
}
if(!(*connected)) {
report(APIEvent::Type::DiskNotConnected, APIEvent::Severity::Error); if(!(*connected)) {
return false; report(APIEvent::Type::DiskNotConnected, APIEvent::Severity::Error);
return false;
}
} }
if(!stopScript()) { if(!stopScript()) {
@@ -756,7 +758,6 @@ bool Device::uploadCoremini(std::istream& stream, Disk::MemoryType memType) {
return false; return false;
} }
if(!eraseScriptMemory(memType, static_cast<uint64_t>(bin.size()))) { if(!eraseScriptMemory(memType, static_cast<uint64_t>(bin.size()))) {
return false; return false;
} }
@@ -846,10 +847,12 @@ std::optional<CoreminiHeader> Device::readCoreminiHeader(Disk::MemoryType memTyp
return std::nullopt; return std::nullopt;
} }
auto connected = isLogicalDiskConnected(); if (memType == Disk::MemoryType::SD) {
auto connected = isLogicalDiskConnected();
if(!connected) {
return std::nullopt; // Already added an API error if(!connected) {
return std::nullopt; // Already added an API error
}
} }
#pragma pack(push, 2) #pragma pack(push, 2)
+16
View File
@@ -90,3 +90,19 @@ TC10
.. literalinclude:: ../../examples/c2/tc10/src/main.c .. literalinclude:: ../../examples/c2/tc10/src/main.c
:language: c :language: c
gPTP
====
:download:`Download example <../../examples/c2/gptp/src/main.c>`
.. literalinclude:: ../../examples/c2/gptp/src/main.c
:language: c
PerfTest
========
:download:`Download example <../../examples/c2/perf_test/src/main.c>`
.. literalinclude:: ../../examples/c2/perf_test/src/main.c
:language: c
+5
View File
@@ -15,6 +15,7 @@ option(LIBICSNEO_BUILD_C2_ETHERNET_RECEIVE_EXAMPLE "Build the C2 ethernet receiv
option(LIBICSNEO_BUILD_C2_T1S_LOOPBACK_EXAMPLE "Build the C2 RAD-Comet3 T1S loopback example." ON) option(LIBICSNEO_BUILD_C2_T1S_LOOPBACK_EXAMPLE "Build the C2 RAD-Comet3 T1S loopback example." ON)
option(LIBICSNEO_BUILD_C2_TC10_EXAMPLE "Build the C2 TC10 example." ON) option(LIBICSNEO_BUILD_C2_TC10_EXAMPLE "Build the C2 TC10 example." ON)
option(LIBICSNEO_BUILD_C2_GPTP_EXAMPLE "Build the C2 gPTP settings example." ON) option(LIBICSNEO_BUILD_C2_GPTP_EXAMPLE "Build the C2 gPTP settings example." ON)
option(LIBICSNEO_BUILD_C2_PERF_TEST_EXAMPLE "Build the C2 PerfTest setting example." ON)
option(LIBICSNEO_BUILD_CPP_SIMPLE_EXAMPLE "Build the simple C++ example." ON) option(LIBICSNEO_BUILD_CPP_SIMPLE_EXAMPLE "Build the simple C++ example." ON)
option(LIBICSNEO_BUILD_CPP_DEVICE_INFO_EXAMPLE "Build the C++ device info example." ON) option(LIBICSNEO_BUILD_CPP_DEVICE_INFO_EXAMPLE "Build the C++ device info example." ON)
option(LIBICSNEO_BUILD_CPP_INTERACTIVE_EXAMPLE "Build the command-line interactive C++ example." ON) option(LIBICSNEO_BUILD_CPP_INTERACTIVE_EXAMPLE "Build the command-line interactive C++ example." ON)
@@ -104,6 +105,10 @@ if(LIBICSNEO_BUILD_C2_GPTP_EXAMPLE)
add_subdirectory(c2/gptp) add_subdirectory(c2/gptp)
endif() endif()
if(LIBICSNEO_BUILD_C2_PERF_TEST_EXAMPLE)
add_subdirectory(c2/perf_test)
endif()
if(LIBICSNEO_BUILD_CPP_SIMPLE_EXAMPLE) if(LIBICSNEO_BUILD_CPP_SIMPLE_EXAMPLE)
add_subdirectory(cpp/simple) add_subdirectory(cpp/simple)
endif() endif()
+6
View File
@@ -0,0 +1,6 @@
add_executable(libicsneoc2-perf_test-example src/main.c)
target_link_libraries(libicsneoc2-perf_test-example icsneoc2-static)
if(WIN32)
target_compile_definitions(libicsneoc2-perf_test-example PRIVATE _CRT_SECURE_NO_WARNINGS)
endif()
+137
View File
@@ -0,0 +1,137 @@
/*
* PerfTest setting example.
*
* Opens the first available device, enables the device-global PerfTest mode
* via icsneoc2_settings_perf_test_enabled_set(), reads messages for a few
* seconds while PerfTest is active, then disables PerfTest again. Each step
* reads the value back with icsneoc2_settings_perf_test_enabled_get() to
* confirm the change took effect.
*/
#include <icsneo/icsneoc2.h>
#include <icsneo/icsneoc2settings.h>
#include <icsneo/icsneoc2messages.h>
#include <stdbool.h>
#include <stdio.h>
#include <time.h>
static int print_error_code(const char* message, icsneoc2_error_t error) {
char error_str[64] = {0};
size_t error_str_len = sizeof(error_str);
icsneoc2_error_t res = icsneoc2_error_code_get(error, error_str, &error_str_len);
if(res != icsneoc2_error_success) {
fprintf(stderr, "%s: failed to get string for error code %u\n", message, error);
return (int)res;
}
fprintf(stderr, "%s: \"%s\" (%u)\n", message, error_str, error);
return (int)error;
}
/* Sets PerfTest, applies it to the device, then reads it back to confirm. */
static icsneoc2_error_t set_and_verify_perf_test(icsneoc2_device_t* device, bool enable) {
icsneoc2_error_t res = icsneoc2_settings_perf_test_enabled_set(device, enable);
if(res != icsneoc2_error_success)
return res;
res = icsneoc2_settings_apply(device);
if(res != icsneoc2_error_success)
return res;
/* Re-read settings from the device so the read-back reflects what was
* actually persisted, not just the local settings buffer. */
res = icsneoc2_settings_refresh(device);
if(res != icsneoc2_error_success)
return res;
bool value = !enable;
res = icsneoc2_settings_perf_test_enabled_get(device, &value);
if(res != icsneoc2_error_success)
return res;
printf("\tPerfTest now reads back as: %s\n", value ? "enabled" : "disabled");
if(value != enable) {
fprintf(stderr, "\tERROR: expected PerfTest %s but device reports %s\n",
enable ? "enabled" : "disabled", value ? "enabled" : "disabled");
return icsneoc2_error_get_settings_failure;
}
return icsneoc2_error_success;
}
/* Continuously drains and counts messages for the given wall-clock duration. */
static icsneoc2_error_t read_messages_for(icsneoc2_device_t* device, unsigned seconds) {
size_t total = 0;
printf("\tReading messages for %u seconds...\n", seconds);
time_t start = time(NULL);
while((time_t)(time(NULL) - start) < (time_t)seconds) {
/* Short timeout so an idle bus still lets us re-check the clock,
* while a flooding bus is drained as fast as messages arrive. */
icsneoc2_message_t* message = NULL;
icsneoc2_error_t res = icsneoc2_device_message_get(device, &message, 50);
if(res != icsneoc2_error_success)
return res;
if(message == NULL)
continue;
++total;
icsneoc2_message_free(message);
}
printf("\tReceived %zu messages in %u seconds.\n", total, seconds);
return icsneoc2_error_success;
}
int main(void) {
printf("Opening first available device...\n");
icsneoc2_device_t* device = NULL;
icsneoc2_error_t res = icsneoc2_device_open_first(0, icsneoc2_open_options_default, &device);
if(res != icsneoc2_error_success)
return print_error_code("\tFailed to open first device", res);
char description[255] = {0};
size_t description_length = sizeof(description);
res = icsneoc2_device_description_get(device, description, &description_length);
if(res != icsneoc2_error_success) {
icsneoc2_device_free(device);
return print_error_code("\tFailed to get device description", res);
}
printf("\tOpened device: %s\n", description);
/* Pull the current settings down from the device before reading/modifying them. */
res = icsneoc2_settings_refresh(device);
if(res != icsneoc2_error_success)
goto cleanup;
bool initial = false;
res = icsneoc2_settings_perf_test_enabled_get(device, &initial);
if(res != icsneoc2_error_success) {
print_error_code("\tFailed to read initial PerfTest state (device may not support it)", res);
goto cleanup;
}
printf("\tInitial PerfTest state: %s\n", initial ? "enabled" : "disabled");
printf("Enabling PerfTest...\n");
res = set_and_verify_perf_test(device, true);
if(res != icsneoc2_error_success) {
print_error_code("\tFailed to enable PerfTest", res);
goto cleanup;
}
res = read_messages_for(device, 3);
if(res != icsneoc2_error_success) {
print_error_code("\tFailed while reading messages", res);
goto cleanup;
}
printf("Disabling PerfTest...\n");
res = set_and_verify_perf_test(device, false);
if(res != icsneoc2_error_success) {
print_error_code("\tFailed to disable PerfTest", res);
goto cleanup;
}
printf("PerfTest enable/read/disable cycle completed successfully.\n");
cleanup:
icsneoc2_device_close(device);
icsneoc2_device_free(device);
return (int)res;
}
@@ -96,10 +96,6 @@ protected:
return 15*1024*1024; return 15*1024*1024;
} }
std::optional<MemoryAddress> getCoreminiStartAddressSD() const override {
return 0;
}
}; };
} }
@@ -69,7 +69,7 @@ public:
protected: protected:
RADComet2(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) { RADComet2(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) {
initialize<RADComet2Settings>(makeDriver); initialize<RADComet2Settings, Disk::NeoMemoryDiskDriver, Disk::NeoMemoryDiskDriver>(makeDriver);
} }
void setupPacketizer(Packetizer& packetizer) override { void setupPacketizer(Packetizer& packetizer) override {
@@ -76,7 +76,7 @@ public:
protected: protected:
RADComet3(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) { RADComet3(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) {
initialize<RADComet3Settings>(makeDriver); initialize<RADComet3Settings, Disk::NeoMemoryDiskDriver, Disk::NeoMemoryDiskDriver>(makeDriver);
} }
void setupPacketizer(Packetizer& packetizer) override { void setupPacketizer(Packetizer& packetizer) override {
@@ -131,7 +131,7 @@ protected:
} }
std::optional<MemoryAddress> getCoreminiStartAddressFlash() const override { std::optional<MemoryAddress> getCoreminiStartAddressFlash() const override {
return 512*4; return 92*1024*1024;
} }
std::optional<MemoryAddress> getCoreminiStartAddressSD() const override { std::optional<MemoryAddress> getCoreminiStartAddressSD() const override {
@@ -55,7 +55,7 @@ public:
} }
protected: protected:
RADMoonT1S(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) { RADMoonT1S(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) {
initialize<RADMoonT1SSettings>(makeDriver); initialize<RADMoonT1SSettings, Disk::NeoMemoryDiskDriver, Disk::NeoMemoryDiskDriver>(makeDriver);
} }
void setupPacketizer(Packetizer& packetizer) override { void setupPacketizer(Packetizer& packetizer) override {
@@ -83,6 +83,10 @@ protected:
void setupSupportedTXNetworks(std::vector<Network>& txNetworks) override { void setupSupportedTXNetworks(std::vector<Network>& txNetworks) override {
setupSupportedRXNetworks(txNetworks); setupSupportedRXNetworks(txNetworks);
} }
std::optional<MemoryAddress> getCoreminiStartAddressFlash() const override {
return 32*1024*1024;
}
}; };
} }
@@ -52,7 +52,7 @@ public:
} }
protected: protected:
RADStar2(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) { RADStar2(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) {
initialize<RADStar2Settings>(makeDriver); initialize<RADStar2Settings, Disk::NeoMemoryDiskDriver, Disk::NeoMemoryDiskDriver>(makeDriver);
} }
virtual void setupPacketizer(Packetizer& packetizer) override { virtual void setupPacketizer(Packetizer& packetizer) override {
@@ -80,11 +80,7 @@ protected:
void setupSupportedTXNetworks(std::vector<Network>& txNetworks) override { setupSupportedRXNetworks(txNetworks); } void setupSupportedTXNetworks(std::vector<Network>& txNetworks) override { setupSupportedRXNetworks(txNetworks); }
std::optional<MemoryAddress> getCoreminiStartAddressFlash() const override { std::optional<MemoryAddress> getCoreminiStartAddressFlash() const override {
return 512*4; return 14*1024*1024;
}
std::optional<MemoryAddress> getCoreminiStartAddressSD() const override {
return 0;
} }
bool supportsGetAllMACAddresses() const override { bool supportsGetAllMACAddresses() const override {
+14
View File
@@ -331,6 +331,20 @@ icsneoc2_error_t icsneoc2_device_type_get(const icsneoc2_device_t* device, icsne
*/ */
icsneoc2_error_t icsneoc2_device_serial_get(const icsneoc2_device_t* device, char* value, size_t* value_length); icsneoc2_error_t icsneoc2_device_serial_get(const icsneoc2_device_t* device, char* value, size_t* value_length);
/**
* Get the product name of a device.
*
* This is the device-specific marketing/product name (e.g. "neoVI FIRE 3"), which may differ from the
* generic device-type name. Prefer this where a human-readable product name is needed.
*
* @param[in] device The device to get the product name of.
* @param[out] value Pointer to a buffer to copy the product name into. Null terminated.
* @param[in,out] value_length Size of the value buffer. Modified with the length of the product name.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
icsneoc2_error_t icsneoc2_device_product_name_get(const icsneoc2_device_t* device, char* value, size_t* value_length);
/** /**
* Get the PCB serial of a device. * Get the PCB serial of a device.
* *
+20
View File
@@ -696,6 +696,26 @@ icsneoc2_error_t icsneoc2_settings_external_wifi_antenna_enabled_get(icsneoc2_de
*/ */
icsneoc2_error_t icsneoc2_settings_external_wifi_antenna_enabled_set(icsneoc2_device_t* device, bool value); icsneoc2_error_t icsneoc2_settings_external_wifi_antenna_enabled_set(icsneoc2_device_t* device, bool value);
/**
* Get whether the performance/throughput test mode is enabled.
*
* @param[in] device The device to query.
* @param[out] value Pointer to a bool to copy the value into (true if PerfTest is enabled).
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters or icsneoc2_error_get_settings_failure otherwise.
*/
icsneoc2_error_t icsneoc2_settings_perf_test_enabled_get(icsneoc2_device_t* device, bool* value);
/**
* Set whether the performance/throughput test mode is enabled.
*
* @param[in] device The device to configure.
* @param[in] value true to enable PerfTest, false to disable it.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters or icsneoc2_error_set_settings_failure otherwise.
*/
icsneoc2_error_t icsneoc2_settings_perf_test_enabled_set(icsneoc2_device_t* device, bool value);
/** /**
* Get which Ethernet port(s) are reserved for the Linux configuration interface (Fire3 family devices). * Get which Ethernet port(s) are reserved for the Linux configuration interface (Fire3 family devices).
* *
+3
View File
@@ -214,6 +214,7 @@ TEST(icsneoc2, test_icsneoc2_error_invalid_parameters_and_invalid_device)
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_rtc_get(NULL, (int64_t *)&placeholderUnsignedInteger64)); ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_rtc_get(NULL, (int64_t *)&placeholderUnsignedInteger64));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_rtc_set(NULL, 0)); ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_rtc_set(NULL, 0));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_serial_get(NULL, placeholderStr, &placeholderSizeT)); ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_serial_get(NULL, placeholderStr, &placeholderSizeT));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_product_name_get(NULL, placeholderStr, &placeholderSizeT));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_pcb_serial_get(NULL, &placeholderInteger8, &placeholderSizeT)); ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_pcb_serial_get(NULL, &placeholderInteger8, &placeholderSizeT));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_mac_addresses_enumerate(NULL, NULL)); ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_mac_addresses_enumerate(NULL, NULL));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_mac_network_id_get(NULL, NULL)); ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_mac_network_id_get(NULL, NULL));
@@ -303,6 +304,8 @@ TEST(icsneoc2, test_icsneoc2_error_invalid_parameters_and_invalid_device)
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_settings_linux_boot_enabled_set(NULL, false)); ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_settings_linux_boot_enabled_set(NULL, false));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_settings_external_wifi_antenna_enabled_get(NULL, &placeholderBool)); ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_settings_external_wifi_antenna_enabled_get(NULL, &placeholderBool));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_settings_external_wifi_antenna_enabled_set(NULL, false)); ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_settings_external_wifi_antenna_enabled_set(NULL, false));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_settings_perf_test_enabled_get(NULL, &placeholderBool));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_settings_perf_test_enabled_set(NULL, false));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_settings_linux_configuration_port_get(NULL, &placeholderLinuxConfigPort)); ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_settings_linux_configuration_port_get(NULL, &placeholderLinuxConfigPort));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_settings_linux_configuration_port_set(NULL, placeholderLinuxConfigPort)); ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_settings_linux_configuration_port_set(NULL, placeholderLinuxConfigPort));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_settings_disabled_get(NULL, &placeholderBool)); ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_settings_disabled_get(NULL, &placeholderBool));