#include "icsneo/icsneoc2.h" #include "icsneo/icsneoc2messages.h" #include "icsneoc2_internal.h" #include "icsneo/device/device.h" #include "icsneo/device/devicefinder.h" #include "icsneo/icsneocpp.h" #include "icsneo/communication/io.h" #include #include #include #include #include #include #include #include using namespace icsneo; bool safe_str_copy(char* dest, size_t* dest_size, std::string_view src) { if(!dest || !dest_size || *dest_size == 0) { return false; } // Need to save room for the null terminator *dest_size -= 1; try { *dest_size = src.copy(dest, *dest_size, 0); // Null terminate the buffer dest[*dest_size] = '\0'; // If we truncated the string, return false to indicate not all data was copied. if(*dest_size != src.length()) { return false; } return true; } catch (std::out_of_range& ex) { // if pos > size() (void)ex; // Null terminate the buffer dest[0] = '\0'; *dest_size = 0; return false; } } icsneoc2_error_t icsneoc2_error_code_get(icsneoc2_error_t error_code, char* value, size_t* value_length) { static const char* error_strings[] = { "Success", // icsneoc2_error_success "Invalid function parameters", // icsneoc2_error_invalid_parameters "Open failed", // icsneoc2_error_open_failed "Going online failed", // icsneoc2_error_go_online_failed "Enable message polling failed", // icsneoc2_error_enable_message_polling_failed "Synchronizing RTC failed", // icsneoc2_error_sync_rtc_failed "Getting messages failed", // icsneoc2_error_get_messages_failed "Invalid type", // icsneoc2_error_invalid_type "RTC failure", // icsneoc2_error_rtc_failure "Getting settings failed", // icsneoc2_error_get_settings_failure "Setting settings failed", // icsneoc2_error_set_settings_failure "Transmitting message failed", // icsneoc2_error_transmit_message_failed "String copy failed", // icsneoc2_error_string_copy_failed "Invalid device", // icsneoc2_error_invalid_device "Invalid message", // icsneoc2_error_invalid_message "Out of memory", // icsneoc2_error_out_of_memory "Disk format failed", // icsneoc2_error_format_disk_failed "Script start failed", // icsneoc2_error_script_start_failed "Script stop failed", // icsneoc2_error_script_stop_failed "Script clear failed", // icsneoc2_error_script_clear_failed "Script upload failed", // icsneoc2_error_script_upload_failed "Script load prepare failed", // icsneoc2_error_script_load_prepare_failed "Close failed", // icsneoc2_error_close_failed "Reconnect failed", // icsneoc2_error_reconnect_failed }; static_assert(std::size(error_strings) == icsneoc2_error_maxsize, "error_strings is out of sync with _icsneoc2_error_t enum - update both together"); if(error_code >= icsneoc2_error_maxsize) { return icsneoc2_error_invalid_parameters; } if(!value || !value_length) { return icsneoc2_error_invalid_parameters; } return safe_str_copy(value, value_length, error_strings[error_code]) ? icsneoc2_error_success : icsneoc2_error_string_copy_failed; } icsneoc2_error_t icsneoc2_device_type_name_get(icsneoc2_devicetype_t device_type, char* value, size_t* value_length) { if(!value || !value_length) { return icsneoc2_error_invalid_parameters; } return safe_str_copy(value, value_length, DeviceType::GetGenericProductName(static_cast(device_type))) ? icsneoc2_error_success : icsneoc2_error_string_copy_failed; } icsneoc2_error_t icsneoc2_device_enumerate(icsneoc2_devicetype_t device_type, icsneoc2_device_info_t** device_info) { if(!device_info) { return icsneoc2_error_invalid_parameters; } auto found_devices = DeviceFinder::FindAll(); icsneoc2_device_info_t* head = nullptr; icsneoc2_device_info_t* tail = nullptr; for(auto& dev : found_devices) { if(device_type != 0 && static_cast(dev->getType().getDeviceType()) != device_type) { continue; } auto* node = new (std::nothrow) icsneoc2_device_info_t; if(!node) { icsneoc2_enumeration_free(head); return icsneoc2_error_out_of_memory; } node->device = dev; node->next = nullptr; if(!head) { head = node; } else { tail->next = node; } tail = node; } *device_info = head; return icsneoc2_error_success; } void icsneoc2_enumeration_free(icsneoc2_device_info_t* devices) { while(devices) { auto* next = devices->next; delete devices; devices = next; } } icsneoc2_device_info_t* icsneoc2_device_info_next(const icsneoc2_device_info_t* device_info) { if(!device_info) { return nullptr; } return device_info->next; } icsneoc2_error_t icsneoc2_device_info_serial_get(const icsneoc2_device_info_t* device_info, char* serial, size_t* serial_length) { if(!device_info || !device_info->device || !serial || !serial_length) { return icsneoc2_error_invalid_parameters; } return safe_str_copy(serial, serial_length, device_info->device->getSerial()) ? icsneoc2_error_success : icsneoc2_error_string_copy_failed; } icsneoc2_error_t icsneoc2_device_info_type_get(const icsneoc2_device_info_t* device_info, icsneoc2_devicetype_t* type) { if(!device_info || !device_info->device || !type) { return icsneoc2_error_invalid_parameters; } *type = static_cast(device_info->device->getType().getDeviceType()); return icsneoc2_error_success; } icsneoc2_error_t icsneoc2_device_info_type_name_get(const icsneoc2_device_info_t* device_info, char* typeName, size_t* type_name_length) { if(!device_info || !device_info->device || !typeName || !type_name_length) { return icsneoc2_error_invalid_parameters; } return safe_str_copy(typeName, type_name_length, DeviceType::GetGenericProductName(device_info->device->getType().getDeviceType())) ? icsneoc2_error_success : icsneoc2_error_string_copy_failed; } icsneoc2_error_t icsneoc2_device_info_description_get(const icsneoc2_device_info_t* device_info, char* description, size_t* description_length) { if(!device_info || !device_info->device || !description || !description_length) { return icsneoc2_error_invalid_parameters; } return safe_str_copy(description, description_length, device_info->device->describe()) ? icsneoc2_error_success : icsneoc2_error_string_copy_failed; } icsneoc2_error_t icsneoc2_device_is_valid(const icsneoc2_device_t* device) { if(!device) { return icsneoc2_error_invalid_parameters; } if(!device->device) { return icsneoc2_error_invalid_device; } return icsneoc2_error_success; } icsneoc2_error_t icsneoc2_device_is_open(const icsneoc2_device_t* device, bool* is_open) { auto res = icsneoc2_device_is_valid(device); if(res != icsneoc2_error_success) { return res; } if(!is_open) { return icsneoc2_error_invalid_parameters; } auto dev = device->device; *is_open = dev->isOpen(); return icsneoc2_error_success; } icsneoc2_error_t icsneoc2_device_create(const icsneoc2_device_info_t* device_info, icsneoc2_device_t** device) { if(!device_info || !device_info->device || !device) { return icsneoc2_error_invalid_parameters; } auto* new_device = new (std::nothrow) icsneoc2_device_t; if(!new_device) { return icsneoc2_error_out_of_memory; } new_device->device = device_info->device; *device = new_device; return icsneoc2_error_success; } static icsneoc2_error_t open_device_with_options(std::shared_ptr dev, icsneoc2_open_options_t options) { if(!dev) { return icsneoc2_error_invalid_device; } if(!dev->enableMessagePolling(std::make_optional())) { return icsneoc2_error_enable_message_polling_failed; } if(!dev->isOpen() && !dev->open()) { return icsneoc2_error_open_failed; } if((options & ICSNEOC2_OPEN_OPTIONS_SYNC_RTC) && !dev->setRTC(std::chrono::system_clock::now())) { dev->close(); return icsneoc2_error_sync_rtc_failed; } if((options & ICSNEOC2_OPEN_OPTIONS_GO_ONLINE) && !dev->goOnline()) { dev->close(); return icsneoc2_error_go_online_failed; } return icsneoc2_error_success; } icsneoc2_error_t icsneoc2_device_open(const icsneoc2_device_t* device, icsneoc2_open_options_t options) { auto res = icsneoc2_device_is_valid(device); if(res != icsneoc2_error_success) { return res; } return open_device_with_options(device->device, options); } icsneoc2_error_t icsneoc2_device_open_serial(const char* serial, icsneoc2_open_options_t options, icsneoc2_device_t** device) { if(!serial || !device) { return icsneoc2_error_invalid_parameters; } icsneoc2_device_info_t* devs = nullptr; auto res = icsneoc2_device_enumerate(0, &devs); if(res != icsneoc2_error_success) { return res; } std::string_view target(serial); for(auto* cur = devs; cur; cur = cur->next) { if(cur->device && cur->device->getSerial() == target) { if (res = icsneoc2_device_create(cur, device); res != icsneoc2_error_success) { icsneoc2_enumeration_free(devs); return res; } res = open_device_with_options((*device)->device, options); if (res != icsneoc2_error_success) { icsneoc2_device_free(*device); *device = nullptr; } icsneoc2_enumeration_free(devs); return res; } } icsneoc2_enumeration_free(devs); return icsneoc2_error_invalid_device; } icsneoc2_error_t icsneoc2_device_open_first(icsneoc2_devicetype_t device_type, icsneoc2_open_options_t options, icsneoc2_device_t** device) { if(!device) { return icsneoc2_error_invalid_parameters; } icsneoc2_device_info_t* devs = nullptr; auto res = icsneoc2_device_enumerate(device_type, &devs); if(res != icsneoc2_error_success) { return res; } for(auto* cur = devs; cur; cur = cur->next) { if(cur->device && !cur->device->isOpen()) { if (res = icsneoc2_device_create(cur, device); res != icsneoc2_error_success) { icsneoc2_enumeration_free(devs); return res; } res = open_device_with_options((*device)->device, options); if (res != icsneoc2_error_success) { icsneoc2_device_free(*device); *device = nullptr; } icsneoc2_enumeration_free(devs); return res; } } icsneoc2_enumeration_free(devs); return icsneoc2_error_invalid_device; } icsneoc2_error_t icsneoc2_device_reconnect(icsneoc2_device_t* device, icsneoc2_open_options_t options, uint32_t timeout_ms) { auto res = icsneoc2_device_is_valid(device); if(res != icsneoc2_error_success) { return res; } // If the device is currently open, close it first before trying to reconnect if (device->device->isOpen()) { res = icsneoc2_device_close(device); if(res != icsneoc2_error_success) { return res; } } const auto timeout = std::chrono::steady_clock::now() + std::chrono::milliseconds(timeout_ms); while(std::chrono::steady_clock::now() < timeout) { icsneoc2_device_t* new_device = nullptr; res = icsneoc2_device_open_serial(device->device->getSerial().c_str(), options, &new_device); if(res == icsneoc2_error_success) { device->device = new_device->device; delete new_device; return icsneoc2_error_success; } // Avoid busy looping std::this_thread::sleep_for(std::chrono::milliseconds(100)); } return icsneoc2_error_reconnect_failed; } icsneoc2_error_t icsneoc2_device_close(icsneoc2_device_t* device) { auto res = icsneoc2_device_is_valid(device); if(res != icsneoc2_error_success) { return res; } auto dev = device->device; if(!dev->isOpen()) { return icsneoc2_error_success; } return dev->close() ? icsneoc2_error_success : icsneoc2_error_close_failed; } icsneoc2_error_t icsneoc2_device_free(icsneoc2_device_t* device) { auto res = icsneoc2_device_is_valid(device); if(res != icsneoc2_error_success) { return res; } if (device->device->isOpen()) { res = icsneoc2_device_close(device); if(res != icsneoc2_error_success) { return res; } } delete device; return icsneoc2_error_success; } icsneoc2_error_t icsneoc2_device_description_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; } // Copy the string into value return safe_str_copy(value, value_length, device->device->describe()) ? icsneoc2_error_success : icsneoc2_error_string_copy_failed; } icsneoc2_error_t icsneoc2_device_type_get(const icsneoc2_device_t* device, icsneoc2_devicetype_t* value) { auto res = icsneoc2_device_is_valid(device); if(res != icsneoc2_error_success) { return res; } auto dev = device->device; *value = static_cast(dev->getType().getDeviceType()); return icsneoc2_error_success; } icsneoc2_error_t icsneoc2_device_serial_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->getSerial()) ? icsneoc2_error_success : icsneoc2_error_string_copy_failed; } icsneoc2_error_t icsneoc2_device_go_online(const icsneoc2_device_t* device, bool go_online) { auto res = icsneoc2_device_is_valid(device); if(res != icsneoc2_error_success) { return res; } auto dev = device->device; // Go online if(go_online && dev->goOnline()) { return icsneoc2_error_success; } // Go offline if(!go_online && dev->goOffline()) { return icsneoc2_error_success; } return icsneoc2_error_go_online_failed; } icsneoc2_error_t icsneoc2_device_is_online(const icsneoc2_device_t* device, bool* is_online) { auto res = icsneoc2_device_is_valid(device); if(res != icsneoc2_error_success) { return res; } if(!is_online) { return icsneoc2_error_invalid_parameters; } auto dev = device->device; *is_online = dev->isOnline(); return icsneoc2_error_success; } icsneoc2_error_t icsneoc2_device_is_online_supported(const icsneoc2_device_t* device, bool* is_online_supported) { auto res = icsneoc2_device_is_valid(device); if(res != icsneoc2_error_success) { return res; } if(!is_online_supported) { return icsneoc2_error_invalid_parameters; } auto dev = device->device; *is_online_supported = dev->isOnlineSupported(); return icsneoc2_error_success; } icsneoc2_error_t icsneoc2_device_message_polling_limit_set(const icsneoc2_device_t* device, uint32_t limit) { auto res = icsneoc2_device_is_valid(device); if(res != icsneoc2_error_success) { return res; } auto dev = device->device; dev->setPollingMessageLimit(static_cast(limit)); return icsneoc2_error_success; } icsneoc2_error_t icsneoc2_device_message_polling_limit_get(const icsneoc2_device_t* device, uint32_t* limit) { auto res = icsneoc2_device_is_valid(device); if(res != icsneoc2_error_success) { return res; } if(!limit) { return icsneoc2_error_invalid_parameters; } auto dev = device->device; *limit = static_cast(dev->getPollingMessageLimit()); return icsneoc2_error_success; } icsneoc2_error_t icsneoc2_device_timestamp_resolution_get(icsneoc2_device_t* device, uint32_t* resolution) { auto res = icsneoc2_device_is_valid(device); if(res != icsneoc2_error_success) { return res; } if(!resolution) { return icsneoc2_error_invalid_parameters; } auto dev = device->device; *resolution = static_cast(dev->getTimestampResolution()); return icsneoc2_error_success; } icsneoc2_error_t icsneoc2_device_message_get(const icsneoc2_device_t* device, icsneoc2_message_t** message, uint32_t timeout_ms) { auto res = icsneoc2_device_is_valid(device); if(res != icsneoc2_error_success) { return res; } if(!message) { return icsneoc2_error_invalid_parameters; } std::vector> msgs(1); if(!device->device->getMessages(msgs, 1, std::chrono::milliseconds(timeout_ms))) { return icsneoc2_error_get_messages_failed; } if(!msgs.empty()) { *message = new (std::nothrow) icsneoc2_message_t; if(!*message) { return icsneoc2_error_out_of_memory; } (*message)->message = msgs[0]; } else { *message = nullptr; } return icsneoc2_error_success; } icsneoc2_error_t icsneoc2_device_message_transmit(const icsneoc2_device_t* device, const icsneoc2_message_t* message) { auto res = icsneoc2_device_is_valid(device); if(res != icsneoc2_error_success) { return res; } if(!message) { return icsneoc2_error_invalid_parameters; } auto dev = device->device; auto success = dev->transmit(std::static_pointer_cast(message->message)); return success ? icsneoc2_error_success : icsneoc2_error_transmit_message_failed; } icsneoc2_error_t icsneoc2_network_type_name_get(icsneoc2_network_type_t network_type, char* value, size_t* value_length) { if(!value || !value_length) { return icsneoc2_error_invalid_parameters; } auto network_type_str = std::string(Network::GetTypeString(static_cast(network_type))); // Copy the string into value return safe_str_copy(value, value_length, network_type_str) ? icsneoc2_error_success : icsneoc2_error_string_copy_failed; } icsneoc2_error_t icsneoc2_event_get(icsneoc2_event_t** event, const icsneoc2_device_t* device) { if(!event) { return icsneoc2_error_invalid_parameters; } if(device && !device->device) { return icsneoc2_error_invalid_device; } const auto* dev = device ? device->device.get() : nullptr; EventFilter filter(dev); auto events = icsneo::GetEvents(filter, 1); if(events.empty()) { *event = nullptr; return icsneoc2_error_success; } *event = new (std::nothrow) icsneoc2_event_t; if(!*event) { return icsneoc2_error_out_of_memory; } (*event)->event = events.front(); return icsneoc2_error_success; } icsneoc2_error_t icsneoc2_event_free(icsneoc2_event_t* event) { if(!event) { return icsneoc2_error_invalid_parameters; } delete event; return icsneoc2_error_success; } icsneoc2_error_t icsneoc2_event_description_get(const icsneoc2_event_t* event, char* value, size_t* value_length) { if(!event || !value || !value_length) { return icsneoc2_error_invalid_parameters; } // Copy the string into value return safe_str_copy(value, value_length, event->event.describe()) ? icsneoc2_error_success : icsneoc2_error_string_copy_failed; } icsneoc2_error_t icsneoc2_device_rtc_get(const icsneoc2_device_t* device, int64_t* unix_epoch) { if(!unix_epoch) { return icsneoc2_error_invalid_parameters; } auto res = icsneoc2_device_is_valid(device); if(res != icsneoc2_error_success) { return res; } if(auto rtc_time = device->device->getRTC(); rtc_time != std::nullopt) { *unix_epoch = std::chrono::duration_cast(rtc_time->time_since_epoch()).count(); } else { *unix_epoch = 0; return icsneoc2_error_rtc_failure; } return icsneoc2_error_success; } icsneoc2_error_t icsneoc2_device_rtc_set(const icsneoc2_device_t* device, int64_t unix_epoch) { auto res = icsneoc2_device_is_valid(device); if(res != icsneoc2_error_success) { return res; } if(!device->device->setRTC(std::chrono::system_clock::time_point(std::chrono::seconds(unix_epoch)))) { return icsneoc2_error_sync_rtc_failed; } return icsneoc2_error_success; } icsneoc2_error_t icsneoc2_device_supports_tc10(const icsneoc2_device_t* device, bool* supported) { auto res = icsneoc2_device_is_valid(device); if(res != icsneoc2_error_success) { return res; } *supported = device->device->supportsTC10(); return icsneoc2_error_success; } icsneoc2_error_t icsneoc2_device_digital_io_get(const icsneoc2_device_t* device, icsneoc2_io_type_t type, uint32_t number, bool* value) { auto res = icsneoc2_device_is_valid(device); if(res != icsneoc2_error_success) { return res; } if(!value) { return icsneoc2_error_invalid_parameters; } // Convert icsneoc2 IO type to C++ IO enum (they match numerically) auto cpp_io_type = static_cast(type); // Get the digital IO value const std::optional val = device->device->getDigitalIO(cpp_io_type, number); if(!val.has_value()) { return icsneoc2_error_invalid_type; } *value = *val; return icsneoc2_error_success; } icsneoc2_error_t icsneoc2_device_digital_io_set(const icsneoc2_device_t* device, icsneoc2_io_type_t type, uint32_t number, bool value) { auto res = icsneoc2_device_is_valid(device); if(res != icsneoc2_error_success) { return res; } // Convert icsneoc2 IO type to C++ IO enum (they match numerically) auto cpp_io_type = static_cast(type); // Set the digital IO value if(!device->device->setDigitalIO(cpp_io_type, number, value)) { return icsneoc2_error_set_settings_failure; } return icsneoc2_error_success; } icsneoc2_error_t icsneoc2_version_get(char* value, size_t* value_length) { if(!value || !value_length) { return icsneoc2_error_invalid_parameters; } // Get version from libicsneo auto version = icsneo::GetVersion(); // Format version string (e.g., "v1.0.0") std::ostringstream version_stream; version_stream << 'v' << version.major << '.' << version.minor << '.' << version.patch; if(version.metadata[0] != '\0') { version_stream << '+' << version.metadata; } auto version_str = version_stream.str(); return safe_str_copy(value, value_length, version_str) ? icsneoc2_error_success : icsneoc2_error_string_copy_failed; } icsneoc2_error_t icsneoc2_serial_num_to_string(uint32_t num, char* str, size_t* str_length) { if(!str || !str_length) { return icsneoc2_error_invalid_parameters; } // Convert using Device static method auto result = Device::SerialNumToString(num); return safe_str_copy(str, str_length, result) ? icsneoc2_error_success : icsneoc2_error_string_copy_failed; } icsneoc2_error_t icsneoc2_serial_string_to_num(char* str, size_t str_length, uint32_t* num) { if(!str || !num) { return icsneoc2_error_invalid_parameters; } // Convert using Device static method *num = Device::SerialStringToNum(std::string(str, str_length)); return icsneoc2_error_success; } icsneoc2_error_t icsneoc2_device_disk_count_get(const icsneoc2_device_t* device, size_t* count) { auto res = icsneoc2_device_is_valid(device); if(res != icsneoc2_error_success) { return res; } if(!count) { return icsneoc2_error_invalid_parameters; } *count = device->device->getDiskCount(); return icsneoc2_error_success; } icsneoc2_error_t icsneoc2_device_supports_disk_formatting(const icsneoc2_device_t* device, bool* supported) { auto res = icsneoc2_device_is_valid(device); if(res != icsneoc2_error_success) { return res; } if(!supported) { return icsneoc2_error_invalid_parameters; } *supported = device->device->supportsDiskFormatting(); return icsneoc2_error_success; } icsneoc2_error_t icsneoc2_device_disk_details_get(const icsneoc2_device_t* device, icsneoc2_disk_details_t** disk_details) { auto res = icsneoc2_device_is_valid(device); if(res != icsneoc2_error_success) { return res; } if(!disk_details) { return icsneoc2_error_invalid_parameters; } auto details = device->device->getDiskDetails(); if(!details) { return icsneoc2_error_invalid_device; } auto* out = new (std::nothrow) icsneoc2_disk_details_t; if(!out) { return icsneoc2_error_out_of_memory; } out->details = details; *disk_details = out; return icsneoc2_error_success; } void icsneoc2_disk_details_free(icsneoc2_disk_details_t* disk_details) { delete disk_details; } icsneoc2_error_t icsneoc2_disk_details_count_get(const icsneoc2_disk_details_t* disk_details, size_t* count) { if(!disk_details || !disk_details->details || !count) { return icsneoc2_error_invalid_parameters; } *count = disk_details->details->disks.size(); return icsneoc2_error_success; } icsneoc2_error_t icsneoc2_disk_details_layout_get(const icsneoc2_disk_details_t* disk_details, icsneoc2_disk_layout_t* layout) { if(!disk_details || !disk_details->details || !layout) { return icsneoc2_error_invalid_parameters; } *layout = static_cast(disk_details->details->layout); return icsneoc2_error_success; } icsneoc2_error_t icsneoc2_disk_details_layout_set(const icsneoc2_disk_details_t* disk_details, icsneoc2_disk_layout_t layout) { if(!disk_details || !disk_details->details) { return icsneoc2_error_invalid_parameters; } disk_details->details->layout = static_cast(layout); return icsneoc2_error_success; } icsneoc2_error_t icsneoc2_disk_details_flags_get(const icsneoc2_disk_details_t* disk_details, size_t index, icsneoc2_disk_format_flags_t* flags) { if(!disk_details || !disk_details->details || !flags) { return icsneoc2_error_invalid_parameters; } if(index >= disk_details->details->disks.size()) { return icsneoc2_error_invalid_parameters; } const auto& disk = disk_details->details->disks[index]; icsneoc2_disk_format_flags_t result = 0; if(disk.present) result |= ICSNEOC2_DISK_FORMAT_FLAGS_PRESENT; if(disk.initialized) result |= ICSNEOC2_DISK_FORMAT_FLAGS_INITIALIZED; if(disk.formatted) result |= ICSNEOC2_DISK_FORMAT_FLAGS_FORMATTED; *flags = result; return icsneoc2_error_success; } icsneoc2_error_t icsneoc2_disk_details_flags_set(const icsneoc2_disk_details_t* disk_details, size_t index, icsneoc2_disk_format_flags_t flags) { if(!disk_details || !disk_details->details || !flags) { return icsneoc2_error_invalid_parameters; } if(index >= disk_details->details->disks.size()) { return icsneoc2_error_invalid_parameters; } auto& disk = disk_details->details->disks[index]; disk.present = (flags & ICSNEOC2_DISK_FORMAT_FLAGS_PRESENT) != 0; disk.initialized = (flags & ICSNEOC2_DISK_FORMAT_FLAGS_INITIALIZED) != 0; disk.formatted = (flags & ICSNEOC2_DISK_FORMAT_FLAGS_FORMATTED) != 0; return icsneoc2_error_success; } icsneoc2_error_t icsneoc2_disk_details_size_get(const icsneoc2_disk_details_t* disk_details, size_t index, uint64_t* sectors, uint64_t* bytes_per_sector) { if(!disk_details || !disk_details->details || !sectors || !bytes_per_sector) { return icsneoc2_error_invalid_parameters; } if(index >= disk_details->details->disks.size()) { return icsneoc2_error_invalid_parameters; } const auto& disk = disk_details->details->disks[index]; *sectors = disk.sectors; *bytes_per_sector = disk.bytesPerSector; return icsneoc2_error_success; } icsneoc2_error_t icsneoc2_disk_details_full_format_get(const icsneoc2_disk_details_t* disk_details, bool* full_format) { if(!disk_details || !disk_details->details || !full_format) { return icsneoc2_error_invalid_parameters; } *full_format = disk_details->details->fullFormat; return icsneoc2_error_success; } icsneoc2_error_t icsneoc2_disk_details_full_format_set(const icsneoc2_disk_details_t* disk_details, bool full_format) { if(!disk_details || !disk_details->details) { return icsneoc2_error_invalid_parameters; } disk_details->details->fullFormat = full_format; return icsneoc2_error_success; } icsneoc2_error_t icsneoc2_device_format_disk(const icsneoc2_device_t* device, icsneoc2_disk_details_t* disk_details, icsneoc2_disk_format_progress_fn progress_callback, void* user_data) { auto res = icsneoc2_device_is_valid(device); if(res != icsneoc2_error_success) { return res; } if(!disk_details || !disk_details->details) { return icsneoc2_error_invalid_parameters; } Device::DiskFormatProgress handler; if(progress_callback) { handler = [progress_callback, user_data](uint64_t sectorsFormatted, uint64_t sectorsTotal) -> Device::DiskFormatDirective { auto directive = progress_callback(sectorsFormatted, sectorsTotal, user_data); if(directive == icsneoc2_disk_format_directive_stop) { return Device::DiskFormatDirective::Stop; } return Device::DiskFormatDirective::Continue; }; } if(!device->device->formatDisk(*disk_details->details, handler)) { return icsneoc2_error_format_disk_failed; } return icsneoc2_error_success; } static icsneoc2_error_t get_supported_networks(const icsneoc2_device_t* device, const std::vector& nets, icsneoc2_netid_t* networks, size_t* count) { auto res = icsneoc2_device_is_valid(device); if(res != icsneoc2_error_success) { return res; } if(!count) { return icsneoc2_error_invalid_parameters; } if(!networks) { *count = nets.size(); return icsneoc2_error_success; } if(*count < nets.size()) { return icsneoc2_error_invalid_parameters; } size_t to_copy = std::min(*count, nets.size()); for(size_t i = 0; i < to_copy; i++) { networks[i] = static_cast(nets[i].getNetID()); } *count = to_copy; return icsneoc2_error_success; } icsneoc2_error_t icsneoc2_device_supported_rx_networks_get(const icsneoc2_device_t* device, icsneoc2_netid_t* networks, size_t* count) { auto res = icsneoc2_device_is_valid(device); if(res != icsneoc2_error_success) { return res; } return get_supported_networks(device, device->device->getSupportedRXNetworks(), networks, count); } icsneoc2_error_t icsneoc2_device_supported_tx_networks_get(const icsneoc2_device_t* device, icsneoc2_netid_t* networks, size_t* count) { auto res = icsneoc2_device_is_valid(device); if(res != icsneoc2_error_success) { return res; } return get_supported_networks(device, device->device->getSupportedTXNetworks(), networks, count); } icsneoc2_error_t icsneoc2_device_supports_coremini_script(const icsneoc2_device_t* device, bool* supported) { auto res = icsneoc2_device_is_valid(device); if(res != icsneoc2_error_success) { return res; } if(!supported) { return icsneoc2_error_invalid_parameters; } *supported = device->device->supportsCoreminiScript(); return icsneoc2_error_success; } static Disk::MemoryType to_memory_type(icsneoc2_memory_type_t type) { switch(type) { case icsneoc2_memory_type_flash: return Disk::MemoryType::Flash; case icsneoc2_memory_type_sd: default: return Disk::MemoryType::SD; } } icsneoc2_error_t icsneoc2_device_script_start(const icsneoc2_device_t* device, icsneoc2_memory_type_t memory_type) { auto res = icsneoc2_device_is_valid(device); if(res != icsneoc2_error_success) { return res; } if(!device->device->startScript(to_memory_type(memory_type))) { return icsneoc2_error_script_start_failed; } return icsneoc2_error_success; } icsneoc2_error_t icsneoc2_device_script_stop(const icsneoc2_device_t* device) { auto res = icsneoc2_device_is_valid(device); if(res != icsneoc2_error_success) { return res; } if(!device->device->stopScript()) { return icsneoc2_error_script_stop_failed; } return icsneoc2_error_success; } icsneoc2_error_t icsneoc2_device_script_clear(const icsneoc2_device_t* device, icsneoc2_memory_type_t memory_type) { auto res = icsneoc2_device_is_valid(device); if(res != icsneoc2_error_success) { return res; } if(!device->device->clearScript(to_memory_type(memory_type))) { return icsneoc2_error_script_clear_failed; } return icsneoc2_error_success; } icsneoc2_error_t icsneoc2_device_script_prepare_load(const icsneoc2_device_t* device, int8_t* status) { auto res = icsneoc2_device_is_valid(device); if(res != icsneoc2_error_success) { return res; } if(!status) { return icsneoc2_error_invalid_parameters; } *status = device->device->prepareScriptLoad(); return icsneoc2_error_success; } icsneoc2_error_t icsneoc2_device_coremini_upload_file(const icsneoc2_device_t* device, const char* path, icsneoc2_memory_type_t memory_type) { auto res = icsneoc2_device_is_valid(device); if(res != icsneoc2_error_success) { return res; } if(!path) { return icsneoc2_error_invalid_parameters; } std::ifstream ifs(path, std::ios::binary); if(!ifs.is_open()) { return icsneoc2_error_invalid_parameters; } if(!device->device->uploadCoremini(ifs, to_memory_type(memory_type))) { return icsneoc2_error_script_upload_failed; } return icsneoc2_error_success; } icsneoc2_error_t icsneoc2_device_coremini_upload(const icsneoc2_device_t* device, const uint8_t* data, size_t length, icsneoc2_memory_type_t memory_type) { auto res = icsneoc2_device_is_valid(device); if(res != icsneoc2_error_success) { return res; } if(!data || length == 0) { return icsneoc2_error_invalid_parameters; } std::string buf(reinterpret_cast(data), length); std::istringstream iss(buf, std::ios::binary); if(!device->device->uploadCoremini(iss, to_memory_type(memory_type))) { return icsneoc2_error_script_upload_failed; } return icsneoc2_error_success; } icsneoc2_error_t icsneoc2_device_script_status_get(const icsneoc2_device_t* device, icsneoc2_script_status_t** script_status) { auto res = icsneoc2_device_is_valid(device); if(res != icsneoc2_error_success) { return res; } if(!script_status) { return icsneoc2_error_invalid_parameters; } auto status = device->device->getScriptStatus(); if(!status) { return icsneoc2_error_invalid_device; } auto* out = new (std::nothrow) icsneoc2_script_status_t; if(!out) { return icsneoc2_error_out_of_memory; } out->status = status; *script_status = out; return icsneoc2_error_success; } void icsneoc2_script_status_free(icsneoc2_script_status_t* script_status) { delete script_status; } icsneoc2_error_t icsneoc2_script_status_is_coremini_running(const icsneoc2_script_status_t* script_status, bool* value) { if(!script_status || !script_status->status || !value) { return icsneoc2_error_invalid_parameters; } *value = script_status->status->isCoreminiRunning; return icsneoc2_error_success; } icsneoc2_error_t icsneoc2_script_status_is_encrypted(const icsneoc2_script_status_t* script_status, bool* value) { if(!script_status || !script_status->status || !value) { return icsneoc2_error_invalid_parameters; } *value = script_status->status->isEncrypted; return icsneoc2_error_success; } icsneoc2_error_t icsneoc2_script_status_sector_overflows_get(const icsneoc2_script_status_t* script_status, uint32_t* value) { if(!script_status || !script_status->status || !value) { return icsneoc2_error_invalid_parameters; } *value = script_status->status->sectorOverflows; return icsneoc2_error_success; } icsneoc2_error_t icsneoc2_script_status_remaining_sector_buffers_get(const icsneoc2_script_status_t* script_status, uint32_t* value) { if(!script_status || !script_status->status || !value) { return icsneoc2_error_invalid_parameters; } *value = script_status->status->numRemainingSectorBuffers; return icsneoc2_error_success; } icsneoc2_error_t icsneoc2_script_status_last_sector_get(const icsneoc2_script_status_t* script_status, uint32_t* value) { if(!script_status || !script_status->status || !value) { return icsneoc2_error_invalid_parameters; } *value = script_status->status->lastSector; return icsneoc2_error_success; } icsneoc2_error_t icsneoc2_script_status_read_bin_size_get(const icsneoc2_script_status_t* script_status, uint32_t* value) { if(!script_status || !script_status->status || !value) { return icsneoc2_error_invalid_parameters; } *value = script_status->status->readBinSize; return icsneoc2_error_success; } icsneoc2_error_t icsneoc2_script_status_min_sector_get(const icsneoc2_script_status_t* script_status, uint32_t* value) { if(!script_status || !script_status->status || !value) { return icsneoc2_error_invalid_parameters; } *value = script_status->status->minSector; return icsneoc2_error_success; } icsneoc2_error_t icsneoc2_script_status_max_sector_get(const icsneoc2_script_status_t* script_status, uint32_t* value) { if(!script_status || !script_status->status || !value) { return icsneoc2_error_invalid_parameters; } *value = script_status->status->maxSector; return icsneoc2_error_success; } icsneoc2_error_t icsneoc2_script_status_current_sector_get(const icsneoc2_script_status_t* script_status, uint32_t* value) { if(!script_status || !script_status->status || !value) { return icsneoc2_error_invalid_parameters; } *value = script_status->status->currentSector; return icsneoc2_error_success; } icsneoc2_error_t icsneoc2_script_status_coremini_create_time_get(const icsneoc2_script_status_t* script_status, uint64_t* value) { if(!script_status || !script_status->status || !value) { return icsneoc2_error_invalid_parameters; } *value = script_status->status->coreminiCreateTime; return icsneoc2_error_success; } icsneoc2_error_t icsneoc2_script_status_file_checksum_get(const icsneoc2_script_status_t* script_status, uint16_t* value) { if(!script_status || !script_status->status || !value) { return icsneoc2_error_invalid_parameters; } *value = script_status->status->fileChecksum; return icsneoc2_error_success; } icsneoc2_error_t icsneoc2_script_status_coremini_version_get(const icsneoc2_script_status_t* script_status, uint16_t* value) { if(!script_status || !script_status->status || !value) { return icsneoc2_error_invalid_parameters; } *value = script_status->status->coreminiVersion; return icsneoc2_error_success; } icsneoc2_error_t icsneoc2_script_status_coremini_header_size_get(const icsneoc2_script_status_t* script_status, uint16_t* value) { if(!script_status || !script_status->status || !value) { return icsneoc2_error_invalid_parameters; } *value = script_status->status->coreminiHeaderSize; return icsneoc2_error_success; } icsneoc2_error_t icsneoc2_script_status_diagnostic_error_code_get(const icsneoc2_script_status_t* script_status, uint8_t* value) { if(!script_status || !script_status->status || !value) { return icsneoc2_error_invalid_parameters; } *value = script_status->status->diagnosticErrorCode; return icsneoc2_error_success; } icsneoc2_error_t icsneoc2_script_status_diagnostic_error_code_count_get(const icsneoc2_script_status_t* script_status, uint8_t* value) { if(!script_status || !script_status->status || !value) { return icsneoc2_error_invalid_parameters; } *value = script_status->status->diagnosticErrorCodeCount; return icsneoc2_error_success; } icsneoc2_error_t icsneoc2_script_status_max_coremini_size_kb_get(const icsneoc2_script_status_t* script_status, uint16_t* value) { if(!script_status || !script_status->status || !value) { return icsneoc2_error_invalid_parameters; } *value = script_status->status->maxCoreminiSizeKB; return icsneoc2_error_success; }