diff --git a/api/icsneocpp/error.cpp b/api/icsneocpp/error.cpp index 3812458..be6130a 100644 --- a/api/icsneocpp/error.cpp +++ b/api/icsneocpp/error.cpp @@ -59,6 +59,17 @@ static constexpr const char* ERROR_SETTINGS_VERSION = "The settings version is i static constexpr const char* ERROR_SETTINGS_LENGTH = "The settings length is incorrect, please update your firmware with neoVI Explorer."; static constexpr const char* ERROR_SETTINGS_CHECKSUM = "The settings checksum is incorrect, attempting to set defaults may remedy this issue."; static constexpr const char* ERROR_SETTINGS_NOT_AVAILABLE = "Settings are not available for this device."; +static constexpr const char* ERROR_SETTINGS_READONLY = "Settings are read-only for this device."; +static constexpr const char* ERROR_CAN_SETTINGS_NOT_AVAILABLE = "CAN settings are not available for this device."; +static constexpr const char* ERROR_CANFD_SETTINGS_NOT_AVAILABLE = "CANFD settings are not available for this device."; +static constexpr const char* ERROR_LSFTCAN_SETTINGS_NOT_AVAILABLE = "LSFTCAN settings are not available for this device."; +static constexpr const char* ERROR_SWCAN_SETTINGS_NOT_AVAILABLE = "SWCAN settings are not available for this device."; +static constexpr const char* ERROR_BAUDRATE_NOT_FOUND = "The baudrate was not found."; +static constexpr const char* ERROR_BAD_NETWORK_TYPE = "The network type was not found."; +static constexpr const char* ERROR_DEVICE_FIRMWARE_OUT_OF_DATE = "The device firmware is out of date. New API functionality may not be supported."; +static constexpr const char* ERROR_SETTINGS_STRUCTURE_MISMATCH = "Unexpected settings structure for this device."; +static constexpr const char* ERROR_SETTINGS_STRUCTURE_TRUNCATED = "Settings structure is longer than the device supports and will be truncated."; +static constexpr const char* ERROR_NO_DEVICE_RESPONSE = "Expected a response from the device but none were found."; // Transport Errors static constexpr const char* ERROR_FAILED_TO_READ = "A read operation failed."; @@ -108,6 +119,26 @@ const char* APIError::DescriptionForType(ErrorType type) { return ERROR_SETTINGS_CHECKSUM; case SettingsNotAvailable: return ERROR_SETTINGS_NOT_AVAILABLE; + case SettingsReadOnly: + return ERROR_SETTINGS_READONLY; + case CANSettingsNotAvailable: + return ERROR_CAN_SETTINGS_NOT_AVAILABLE; + case CANFDSettingsNotAvailable: + return ERROR_CANFD_SETTINGS_NOT_AVAILABLE; + case LSFTCANSettingsNotAvailable: + return ERROR_LSFTCAN_SETTINGS_NOT_AVAILABLE; + case SWCANSettingsNotAvailable: + return ERROR_SWCAN_SETTINGS_NOT_AVAILABLE; + case BaudrateNotFound: + return ERROR_BAUDRATE_NOT_FOUND; + case DeviceFirmwareOutOfDate: + return ERROR_DEVICE_FIRMWARE_OUT_OF_DATE; + case SettingsStructureMismatch: + return ERROR_SETTINGS_STRUCTURE_MISMATCH; + case SettingsStructureTruncated: + return ERROR_SETTINGS_STRUCTURE_TRUNCATED; + case NoDeviceResponse: + return ERROR_NO_DEVICE_RESPONSE; // Transport Errors case FailedToRead: @@ -145,6 +176,8 @@ APIError::Severity APIError::SeverityForType(ErrorType type) { case DeviceCurrentlyClosed: // Device Warnings case PollingMessageOverflow: + case DeviceFirmwareOutOfDate: + case SettingsStructureTruncated: // Transport Warnings case PCAPCouldNotStart: case PCAPCouldNotFindDevices: @@ -164,6 +197,14 @@ APIError::Severity APIError::SeverityForType(ErrorType type) { case SettingsLengthError: case SettingsChecksumError: case SettingsNotAvailable: + case SettingsReadOnly: + case CANSettingsNotAvailable: + case CANFDSettingsNotAvailable: + case LSFTCANSettingsNotAvailable: + case SWCANSettingsNotAvailable: + case BaudrateNotFound: + case SettingsStructureMismatch: + case NoDeviceResponse: // Transport Errors case FailedToRead: case FailedToWrite: diff --git a/device/idevicesettings.cpp b/device/idevicesettings.cpp index b40bce3..5133b1b 100644 --- a/device/idevicesettings.cpp +++ b/device/idevicesettings.cpp @@ -183,8 +183,20 @@ bool IDeviceSettings::refresh(bool ignoreChecksum) { } bool IDeviceSettings::apply(bool temporary) { - if(!settingsLoaded || disabled || readonly) + if(readonly) { + err(APIError::SettingsReadOnly); return false; + } + + if(disabled) { + err(APIError::SettingsNotAvailable); + return false; + } + + if(!settingsLoaded) { + err(APIError::SettingsReadError); + return false; + } std::vector bytestream; bytestream.resize(7 + settings.size()); @@ -202,7 +214,11 @@ bool IDeviceSettings::apply(bool temporary) { std::shared_ptr msg = com->waitForMessageSync(std::make_shared(Command::SetSettings), std::chrono::milliseconds(1000)); if(!msg || msg->data[0] != 1) { // We did not receive a response - refresh(); // Attempt to get the settings from the device so we're up to date if possible + // Attempt to get the settings from the device so we're up to date if possible + if(refresh()) { + // refresh succeeded but previously there was an error + err(APIError::NoDeviceResponse); + } return false; } @@ -217,7 +233,11 @@ bool IDeviceSettings::apply(bool temporary) { com->sendCommand(Command::SetSettings, bytestream); msg = com->waitForMessageSync(std::make_shared(Command::SetSettings), std::chrono::milliseconds(1000)); if(!msg || msg->data[0] != 1) { - refresh(); + // Attempt to get the settings from the device so we're up to date if possible + if(refresh()) { + // refresh succeeded but previously there was an error + err(APIError::NoDeviceResponse); + } return false; } @@ -228,17 +248,32 @@ bool IDeviceSettings::apply(bool temporary) { refresh(); // Refresh our buffer with what the device has, whether we were successful or not - return (msg && msg->data[0] == 1); // Device sends 0x01 for success + bool ret = (msg && msg->data[0] == 1); // Device sends 0x01 for success + if(!ret) { + err(APIError::FailedToWrite); + } + return ret; } bool IDeviceSettings::applyDefaults(bool temporary) { - if(disabled || readonly) + if(disabled) { + err(APIError::SettingsNotAvailable); return false; + } + + if(readonly) { + err(APIError::SettingsReadOnly); + return false; + } com->sendCommand(Command::SetDefaultSettings); std::shared_ptr msg = com->waitForMessageSync(std::make_shared(Command::SetDefaultSettings), std::chrono::milliseconds(1000)); if(!msg || msg->data[0] != 1) { - refresh(); + // Attempt to get the settings from the device so we're up to date if possible + if(refresh()) { + // refresh succeeded but previously there was an error + err(APIError::NoDeviceResponse); + } return false; } @@ -263,7 +298,11 @@ bool IDeviceSettings::applyDefaults(bool temporary) { com->sendCommand(Command::SetSettings, bytestream); msg = com->waitForMessageSync(std::make_shared(Command::SetSettings), std::chrono::milliseconds(1000)); if(!msg || msg->data[0] != 1) { - refresh(); + // Attempt to get the settings from the device so we're up to date if possible + if(refresh()) { + // refresh succeeded but previously there was an error + err(APIError::NoDeviceResponse); + } return false; } @@ -274,45 +313,79 @@ bool IDeviceSettings::applyDefaults(bool temporary) { refresh(); // Refresh our buffer with what the device has, whether we were successful or not - return (msg && msg->data[0] == 1); // Device sends 0x01 for success + bool ret = (msg && msg->data[0] == 1); // Device sends 0x01 for success + if(!ret) { + err(APIError::FailedToWrite); + } + return ret; } int64_t IDeviceSettings::getBaudrateFor(Network net) const { - if(!settingsLoaded || disabled) + if(disabled) { + err(APIError::SettingsNotAvailable); return -1; + } + + if(!settingsLoaded) { + err(APIError::SettingsReadError); + return -1; + } switch(net.getType()) { case Network::Type::CAN: { const CAN_SETTINGS* cfg = getCANSettingsFor(net); - if(cfg == nullptr) + if(cfg == nullptr) { + err(APIError::CANFDSettingsNotAvailable); return -1; - + } + int64_t baudrate = GetBaudrateValueForEnum((CANBaudrate)cfg->Baudrate); - if(baudrate == -1) + if(baudrate == -1) { + err(APIError::BaudrateNotFound); return -1; + } return baudrate; } default: + err(APIError::BadNetworkType); return -1; } } bool IDeviceSettings::setBaudrateFor(Network net, int64_t baudrate) { - if(!settingsLoaded || disabled || readonly) + if(disabled) { + err(APIError::SettingsNotAvailable); return false; + } + + if(!settingsLoaded) { + err(APIError::SettingsReadError); + return false; + } + + if(readonly) { + err(APIError::SettingsReadOnly); + return false; + } switch(net.getType()) { case Network::Type::CAN: { - if(baudrate > 1000000) // This is an FD baudrate. Use setFDBaudrateFor instead. + if(baudrate > 1000000) { // This is an FD baudrate. Use setFDBaudrateFor instead. + err(APIError::CANFDSettingsNotAvailable); return false; + } CAN_SETTINGS* cfg = getMutableCANSettingsFor(net); - if(cfg == nullptr) + if(cfg == nullptr) { + err(APIError::CANSettingsNotAvailable); return false; - + } + CANBaudrate newBaud = GetEnumValueForBaudrate(baudrate); - if(newBaud == (CANBaudrate)-1) + if(newBaud == (CANBaudrate)-1) { + err(APIError::BaudrateNotFound); return false; + } cfg->Baudrate = (uint8_t)newBaud; cfg->auto_baud = false; cfg->SetBaudrate = AUTO; // Device will use the baudrate value to set the TQ values @@ -320,12 +393,16 @@ bool IDeviceSettings::setBaudrateFor(Network net, int64_t baudrate) { } case Network::Type::LSFTCAN: { CAN_SETTINGS* cfg = getMutableLSFTCANSettingsFor(net); - if(cfg == nullptr) + if(cfg == nullptr) { + err(APIError::LSFTCANSettingsNotAvailable); return false; + } CANBaudrate newBaud = GetEnumValueForBaudrate(baudrate); - if(newBaud == (CANBaudrate)-1) + if(newBaud == (CANBaudrate)-1) { + err(APIError::BaudrateNotFound); return false; + } cfg->Baudrate = (uint8_t)newBaud; cfg->auto_baud = false; cfg->SetBaudrate = AUTO; // Device will use the baudrate value to set the TQ values @@ -333,78 +410,127 @@ bool IDeviceSettings::setBaudrateFor(Network net, int64_t baudrate) { } case Network::Type::SWCAN: { SWCAN_SETTINGS* cfg = getMutableSWCANSettingsFor(net); - if(cfg == nullptr) + if(cfg == nullptr) { + err(APIError::SWCANSettingsNotAvailable); return false; - + } + CANBaudrate newBaud = GetEnumValueForBaudrate(baudrate); - if(newBaud == (CANBaudrate)-1) + if(newBaud == (CANBaudrate)-1) { + err(APIError::BaudrateNotFound); return false; + } cfg->Baudrate = (uint8_t)newBaud; cfg->auto_baud = false; cfg->SetBaudrate = AUTO; // Device will use the baudrate value to set the TQ values return true; } default: + err(APIError::BadNetworkType); return false; } } int64_t IDeviceSettings::getFDBaudrateFor(Network net) const { - if(!settingsLoaded || disabled) + if(disabled) { + err(APIError::SettingsNotAvailable); + } + + if(!settingsLoaded) { + err(APIError::SettingsReadError); return -1; + } switch(net.getType()) { case Network::Type::CAN: { const CANFD_SETTINGS* cfg = getCANFDSettingsFor(net); - if(cfg == nullptr) + if(cfg == nullptr) { + err(APIError::CANFDSettingsNotAvailable); return -1; - + } + int64_t baudrate = GetBaudrateValueForEnum((CANBaudrate)cfg->FDBaudrate); - if(baudrate == -1) + if(baudrate == -1) { + err(APIError::BaudrateNotFound); return -1; + } + return baudrate; } default: + err(APIError::BadNetworkType); return -1; } } bool IDeviceSettings::setFDBaudrateFor(Network net, int64_t baudrate) { - if(!settingsLoaded || disabled || readonly) + if(!settingsLoaded) { + err(APIError::SettingsReadError); return false; + } + + if(disabled) { + err(APIError::SettingsNotAvailable); + return false; + } + + if(readonly) { + err(APIError::SettingsReadOnly); + return false; + } switch(net.getType()) { case Network::Type::CAN: { CANFD_SETTINGS* cfg = getMutableCANFDSettingsFor(net); - if(cfg == nullptr) + if(cfg == nullptr) { + err(APIError::CANFDSettingsNotAvailable); return false; + } CANBaudrate newBaud = GetEnumValueForBaudrate(baudrate); - if(newBaud == (CANBaudrate)-1) + if(newBaud == (CANBaudrate)-1) { + err(APIError::BaudrateNotFound); return false; + } cfg->FDBaudrate = (uint8_t)newBaud; return true; } default: + err(APIError::BadNetworkType); return false; } } template bool IDeviceSettings::applyStructure(const T& newStructure) { - if(!settingsLoaded || disabled || readonly) + if(!settingsLoaded) { + err(APIError::SettingsReadError); return false; - - // This function is only called from C++ so the callers structure size and ours should never differ - if(sizeof(T) != structSize) - return false; // The wrong structure was passed in for the current device + } + if(disabled) { + err(APIError::SettingsNotAvailable); + return false; + } + + if(readonly) { + err(APIError::SettingsReadOnly); + return false; + } + + // This function is only called from C++ so the caller's structure size and ours should never differ + if(sizeof(T) != structSize) { + err(APIError::SettingsStructureMismatch); + return false; // The wrong structure was passed in for the current device + } size_t copySize = sizeof(T); - if(copySize > settings.size()) + if(copySize > settings.size()) { + err(APIError::SettingsStructureTruncated); copySize = settings.size(); // TODO Warn user that their structure is truncated - - // TODO Warn user that the device firmware doesn't support all the settings in the current API - //if(copySize < settings.size()) - + } + // Warn user that the device firmware doesn't support all the settings in the current API + if(copySize < settings.size()) + err(APIError::DeviceFirmwareOutOfDate); + memcpy(settings.data(), &newStructure, structSize); return apply(); } \ No newline at end of file diff --git a/include/icsneo/api/error.h b/include/icsneo/api/error.h index 713be79..f1f5493 100644 --- a/include/icsneo/api/error.h +++ b/include/icsneo/api/error.h @@ -50,6 +50,17 @@ public: SettingsLengthError = 0x2005, SettingsChecksumError = 0x2006, SettingsNotAvailable = 0x2007, + SettingsReadOnly = 0x2008, + CANSettingsNotAvailable = 0x2009, + CANFDSettingsNotAvailable = 0x2010, + LSFTCANSettingsNotAvailable = 0x2011, + SWCANSettingsNotAvailable = 0x2012, + BaudrateNotFound = 0x2013, + BadNetworkType = 0x2014, + DeviceFirmwareOutOfDate = 0x2015, + SettingsStructureMismatch = 0x2016, + SettingsStructureTruncated = 0x2017, + NoDeviceResponse = 0x2018, // Transport Errors FailedToRead = 0x3000, diff --git a/include/icsneo/device/idevicesettings.h b/include/icsneo/device/idevicesettings.h index d748175..08abce3 100644 --- a/include/icsneo/device/idevicesettings.h +++ b/include/icsneo/device/idevicesettings.h @@ -399,13 +399,17 @@ public: const size_t& getSize() const { return structSize; } + // if settings are disabled for this device. always false unless constructed null bool disabled = false; + bool readonly = false; bool disableGSChecksumming = false; protected: std::shared_ptr com; device_errorhandler_t err; size_t structSize; + + // if we hold any local copies of the device settings bool settingsLoaded = false; std::vector settings; // For writing settings to, calling apply() should copy over to device RAM (and EEPROM)