mirror of
https://github.com/intrepidcs/libicsneo.git
synced 2026-08-05 09:28:40 +02:00
Settings: Add GPTP
This commit is contained in:
committed by
Kyle Schwarz
parent
2d0b0c63ed
commit
299766403f
@@ -0,0 +1,6 @@
|
||||
add_executable(libicsneoc2-gptp-example src/main.c)
|
||||
target_link_libraries(libicsneoc2-gptp-example icsneoc2-static)
|
||||
|
||||
if(WIN32)
|
||||
target_compile_definitions(libicsneoc2-gptp-example PRIVATE _CRT_SECURE_NO_WARNINGS)
|
||||
endif()
|
||||
@@ -0,0 +1,330 @@
|
||||
/*
|
||||
* gPTP settings configurator example.
|
||||
*
|
||||
* Lists connected devices and their gPTP support, then lets the user
|
||||
* configure the gPTP profile, role, port, and clock syntonization on any
|
||||
* device that supports it. If --serial is omitted, the first available
|
||||
* gPTP-capable device is used.
|
||||
*/
|
||||
|
||||
#include <icsneo/icsneoc2.h>
|
||||
#include <icsneo/icsneoc2settings.h>
|
||||
#include <icsneo/icsneoc2messages.h>
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef struct {
|
||||
const char* serial;
|
||||
bool list;
|
||||
} args_t;
|
||||
|
||||
/* Maps an icsneoc2_netid_t to its gPTP port index (0 = not a gPTP port). */
|
||||
static uint8_t netid_to_gptp_port(icsneoc2_netid_t netid) {
|
||||
switch(netid) {
|
||||
case icsneoc2_netid_ae_01: return 1;
|
||||
case icsneoc2_netid_ae_02: return 2;
|
||||
case icsneoc2_netid_ae_03: return 3;
|
||||
case icsneoc2_netid_ae_04: return 4;
|
||||
case icsneoc2_netid_ae_05: return 5;
|
||||
case icsneoc2_netid_ae_06: return 6;
|
||||
case icsneoc2_netid_ae_07: return 7;
|
||||
case icsneoc2_netid_ae_08: return 8;
|
||||
case icsneoc2_netid_ae_09: return 9;
|
||||
case icsneoc2_netid_ae_10: return 10;
|
||||
case icsneoc2_netid_ae_11: return 11;
|
||||
case icsneoc2_netid_ae_12: return 12;
|
||||
case icsneoc2_netid_ethernet_01: return 13;
|
||||
case icsneoc2_netid_ethernet_02: return 14;
|
||||
case icsneoc2_netid_ethernet_03: return 15;
|
||||
case icsneoc2_netid_ae_13: return 16;
|
||||
case icsneoc2_netid_ae_14: return 17;
|
||||
case icsneoc2_netid_ae_15: return 18;
|
||||
case icsneoc2_netid_ae_16: return 19;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static const char* gptp_profile_str(icsneoc2_gptp_profile_t p) {
|
||||
switch(p) {
|
||||
case icsneoc2_gptp_profile_standard: return "Standard";
|
||||
case icsneoc2_gptp_profile_automotive: return "Automotive";
|
||||
default: return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
static const char* gptp_role_str(icsneoc2_gptp_role_t r) {
|
||||
switch(r) {
|
||||
case icsneoc2_gptp_role_disabled: return "Disabled";
|
||||
case icsneoc2_gptp_role_passive: return "Passive";
|
||||
case icsneoc2_gptp_role_master: return "Master";
|
||||
case icsneoc2_gptp_role_slave: return "Slave";
|
||||
default: return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static void print_usage(const char* prog) {
|
||||
printf("Usage:\n");
|
||||
printf(" %s --list\n", prog);
|
||||
printf(" %s [--serial SERIAL]\n", prog);
|
||||
printf("\n");
|
||||
printf(" --list List connected devices and their gPTP support.\n");
|
||||
printf(" --serial SERIAL Serial number of the device to configure.\n");
|
||||
printf(" -h, --help Show this message.\n");
|
||||
}
|
||||
|
||||
static int parse_args(int argc, char** argv, args_t* out) {
|
||||
memset(out, 0, sizeof(*out));
|
||||
for(int i = 1; i < argc; ++i) {
|
||||
const char* a = argv[i];
|
||||
if(strcmp(a, "-h") == 0 || strcmp(a, "--help") == 0) {
|
||||
print_usage(argv[0]);
|
||||
exit(0);
|
||||
} else if(strcmp(a, "--list") == 0) {
|
||||
out->list = true;
|
||||
} else if(strcmp(a, "--serial") == 0) {
|
||||
if(i + 1 >= argc) {
|
||||
fprintf(stderr, "error: --serial requires a value\n");
|
||||
return 1;
|
||||
}
|
||||
out->serial = argv[++i];
|
||||
} else {
|
||||
fprintf(stderr, "error: unknown argument '%s'\n", a);
|
||||
print_usage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static icsneoc2_device_info_t* find_device(icsneoc2_device_info_t* list, const char* serial) {
|
||||
for(icsneoc2_device_info_t* cur = list; cur != NULL; cur = icsneoc2_device_info_next(cur)) {
|
||||
if(serial == NULL)
|
||||
return cur;
|
||||
char dev_serial[64] = {0};
|
||||
size_t dev_serial_len = sizeof(dev_serial);
|
||||
if(icsneoc2_device_info_serial_get(cur, dev_serial, &dev_serial_len) != icsneoc2_error_success)
|
||||
continue;
|
||||
if(strcmp(dev_serial, serial) == 0)
|
||||
return cur;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Print a list of available Ethernet/AE networks with their gPTP port indices.
|
||||
* Returns the number of ports printed.
|
||||
*/
|
||||
static size_t print_gptp_ports(icsneoc2_device_t* device) {
|
||||
icsneoc2_netid_t nets[128] = {0};
|
||||
size_t count = sizeof(nets) / sizeof(nets[0]);
|
||||
if(icsneoc2_device_supported_tx_networks_get(device, nets, &count) != icsneoc2_error_success)
|
||||
return 0;
|
||||
|
||||
size_t printed = 0;
|
||||
for(size_t i = 0; i < count; ++i) {
|
||||
uint8_t port = netid_to_gptp_port(nets[i]);
|
||||
if(port == 0)
|
||||
continue;
|
||||
char name[64] = {0};
|
||||
size_t name_len = sizeof(name);
|
||||
icsneoc2_netid_name_get(nets[i], name, &name_len);
|
||||
printf(" [%u] %s\n", (unsigned)port, name);
|
||||
++printed;
|
||||
}
|
||||
return printed;
|
||||
}
|
||||
|
||||
static int list_devices(icsneoc2_device_info_t* list) {
|
||||
size_t index = 0;
|
||||
for(icsneoc2_device_info_t* cur = list; cur != NULL; cur = icsneoc2_device_info_next(cur)) {
|
||||
char serial[64] = {0};
|
||||
size_t serial_len = sizeof(serial);
|
||||
char description[256] = {0};
|
||||
size_t description_len = sizeof(description);
|
||||
icsneoc2_device_info_serial_get(cur, serial, &serial_len);
|
||||
icsneoc2_device_info_description_get(cur, description, &description_len);
|
||||
printf("[%zu] %s (%s)\n", index++, description, serial);
|
||||
|
||||
icsneoc2_device_t* device = NULL;
|
||||
if(icsneoc2_device_create(cur, &device) != icsneoc2_error_success)
|
||||
continue;
|
||||
|
||||
icsneoc2_open_options_t opts = icsneoc2_open_options_default;
|
||||
opts &= ~ICSNEOC2_OPEN_OPTIONS_SYNC_RTC;
|
||||
opts &= ~ICSNEOC2_OPEN_OPTIONS_GO_ONLINE;
|
||||
if(icsneoc2_device_open(device, opts) != icsneoc2_error_success) {
|
||||
icsneoc2_device_free(device);
|
||||
continue;
|
||||
}
|
||||
|
||||
bool supported = false;
|
||||
icsneoc2_device_supports_gptp(device, &supported);
|
||||
printf(" gPTP supported: %s\n", supported ? "yes" : "no");
|
||||
if(supported) {
|
||||
printf(" gPTP ports:\n");
|
||||
print_gptp_ports(device);
|
||||
}
|
||||
|
||||
icsneoc2_device_close(device);
|
||||
icsneoc2_device_free(device);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void print_current_settings(icsneoc2_device_t* device) {
|
||||
icsneoc2_gptp_profile_t profile = icsneoc2_gptp_profile_standard;
|
||||
icsneoc2_gptp_role_t role = icsneoc2_gptp_role_disabled;
|
||||
uint8_t port = 0;
|
||||
bool clock_syntonization = false;
|
||||
|
||||
printf("\nCurrent gPTP settings:\n");
|
||||
if(icsneoc2_settings_gptp_profile_get(device, &profile) == icsneoc2_error_success)
|
||||
printf(" Profile: %s\n", gptp_profile_str(profile));
|
||||
if(icsneoc2_settings_gptp_role_get(device, &role) == icsneoc2_error_success)
|
||||
printf(" Role: %s\n", gptp_role_str(role));
|
||||
if(icsneoc2_settings_gptp_enabled_port_get(device, &port) == icsneoc2_error_success)
|
||||
printf(" Enabled port: %u%s\n", (unsigned)port, port == 0 ? " (disabled)" : "");
|
||||
if(icsneoc2_settings_gptp_clock_syntonization_enabled_get(device, &clock_syntonization) == icsneoc2_error_success)
|
||||
printf(" Clock syntonization: %s\n", clock_syntonization ? "enabled" : "disabled");
|
||||
}
|
||||
|
||||
static long prompt_long(const char* prompt, long default_val, long min, long max) {
|
||||
char buf[32] = {0};
|
||||
printf("%s [%ld]: ", prompt, default_val);
|
||||
fflush(stdout);
|
||||
if(fgets(buf, sizeof(buf), stdin) == NULL || buf[0] == '\n')
|
||||
return default_val;
|
||||
char* end = NULL;
|
||||
long val = strtol(buf, &end, 10);
|
||||
if(end == buf || val < min || val > max) {
|
||||
printf("Invalid input, using %ld.\n", default_val);
|
||||
return default_val;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
static int configure_device(icsneoc2_device_t* device) {
|
||||
icsneoc2_error_t res;
|
||||
|
||||
res = icsneoc2_settings_refresh(device);
|
||||
if(res != icsneoc2_error_success)
|
||||
return print_error_code("Failed to refresh settings", res);
|
||||
|
||||
print_current_settings(device);
|
||||
|
||||
printf("\nAvailable gPTP ports (0 = disabled):\n");
|
||||
printf(" [0] Disabled\n");
|
||||
print_gptp_ports(device);
|
||||
|
||||
printf("\nConfigure gPTP:\n");
|
||||
|
||||
long profile = prompt_long(" Profile (0=Standard, 1=Automotive)", 1, 0, 1);
|
||||
res = icsneoc2_settings_gptp_profile_set(device, (icsneoc2_gptp_profile_t)profile);
|
||||
if(res != icsneoc2_error_success)
|
||||
return print_error_code("Failed to set profile", res);
|
||||
|
||||
long role = prompt_long(" Role (0=Disabled, 1=Passive, 2=Master, 3=Slave)", 3, 0, 3);
|
||||
res = icsneoc2_settings_gptp_role_set(device, (icsneoc2_gptp_role_t)role);
|
||||
if(res != icsneoc2_error_success)
|
||||
return print_error_code("Failed to set role", res);
|
||||
|
||||
long port = prompt_long(" Enabled port index", 0, 0, 19);
|
||||
res = icsneoc2_settings_gptp_enabled_port_set(device, (uint8_t)port);
|
||||
if(res != icsneoc2_error_success)
|
||||
return print_error_code("Failed to set enabled port", res);
|
||||
|
||||
long syntonization = prompt_long(" Clock syntonization (0=disabled, 1=enabled)", 0, 0, 1);
|
||||
res = icsneoc2_settings_gptp_clock_syntonization_enabled_set(device, syntonization != 0);
|
||||
if(res != icsneoc2_error_success)
|
||||
return print_error_code("Failed to set clock syntonization", res);
|
||||
|
||||
printf("\nNote: icsneoc2_settings_apply() persists settings on the device.\n");
|
||||
res = icsneoc2_settings_apply(device);
|
||||
if(res != icsneoc2_error_success)
|
||||
return print_error_code("Failed to apply settings", res);
|
||||
|
||||
printf("\nUpdated gPTP settings:\n");
|
||||
print_current_settings(device);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
args_t args;
|
||||
if(parse_args(argc, argv, &args) != 0)
|
||||
return 1;
|
||||
|
||||
icsneoc2_device_info_t* found_devices = NULL;
|
||||
icsneoc2_error_t res = icsneoc2_device_enumerate(0, &found_devices);
|
||||
if(res != icsneoc2_error_success)
|
||||
return print_error_code("Failed to enumerate devices", res);
|
||||
if(found_devices == NULL) {
|
||||
fprintf(stderr, "error: no devices found\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(args.list) {
|
||||
int rc = list_devices(found_devices);
|
||||
icsneoc2_enumeration_free(found_devices);
|
||||
return rc;
|
||||
}
|
||||
|
||||
icsneoc2_device_info_t* info = find_device(found_devices, args.serial);
|
||||
if(info == NULL) {
|
||||
fprintf(stderr, "error: unable to find device %s\n", args.serial ? args.serial : "(any)");
|
||||
icsneoc2_enumeration_free(found_devices);
|
||||
return 1;
|
||||
}
|
||||
|
||||
char description[256] = {0};
|
||||
size_t description_len = sizeof(description);
|
||||
icsneoc2_device_info_description_get(info, description, &description_len);
|
||||
|
||||
icsneoc2_device_t* device = NULL;
|
||||
res = icsneoc2_device_create(info, &device);
|
||||
if(res != icsneoc2_error_success) {
|
||||
icsneoc2_enumeration_free(found_devices);
|
||||
return print_error_code("Failed to create device", res);
|
||||
}
|
||||
|
||||
printf("Opening %s\n", description);
|
||||
res = icsneoc2_device_open(device, icsneoc2_open_options_default);
|
||||
if(res != icsneoc2_error_success) {
|
||||
icsneoc2_device_free(device);
|
||||
icsneoc2_enumeration_free(found_devices);
|
||||
return print_error_code("Failed to open device", res);
|
||||
}
|
||||
|
||||
bool supported = false;
|
||||
icsneoc2_device_supports_gptp(device, &supported);
|
||||
if(!supported) {
|
||||
fprintf(stderr, "error: device does not support gPTP (%s)\n", description);
|
||||
icsneoc2_device_close(device);
|
||||
icsneoc2_device_free(device);
|
||||
icsneoc2_enumeration_free(found_devices);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int rc = configure_device(device);
|
||||
|
||||
printf("Closing %s\n", description);
|
||||
icsneoc2_device_close(device);
|
||||
icsneoc2_device_free(device);
|
||||
icsneoc2_enumeration_free(found_devices);
|
||||
return rc;
|
||||
}
|
||||
Reference in New Issue
Block a user