From e124ad28f453b555606bee12d0f08af1056ffdcf Mon Sep 17 00:00:00 2001 From: Paul Hollinsky Date: Fri, 21 Dec 2018 20:24:11 -0500 Subject: [PATCH] Major improvements to the settings API * Allow the raw structure to be manipulated from C and Legacy APIs * Structure is now split between what's on the device and what's on the client so changes will not be visible from read methods until apply() * Allow devices to connect which have slightly different firmware versions than the settings structure --- api/icsneoc/icsneoc.cpp | 70 +++++++++++ api/icsneolegacy/icsneolegacy.cpp | 110 ++++++++++++------ device/device.cpp | 6 +- device/idevicesettings.cpp | 56 ++++----- include/icsneo/device/idevicesettings.h | 34 ++++-- .../device/neovifire/neovifiresettings.h | 2 + .../device/neovifire2/neovifire2settings.h | 4 + .../device/valuecan3/valuecan3settings.h | 2 + .../valuecan4/settings/valuecan4-1settings.h | 2 + .../settings/valuecan4-2elsettings.h | 4 + .../valuecan4/settings/valuecan4-2settings.h | 4 + .../valuecan4/settings/valuecan4-4settings.h | 4 + include/icsneo/icsneoc.h | 58 +++++++++ 13 files changed, 282 insertions(+), 74 deletions(-) diff --git a/api/icsneoc/icsneoc.cpp b/api/icsneoc/icsneoc.cpp index 15ff771..93ac522 100644 --- a/api/icsneoc/icsneoc.cpp +++ b/api/icsneoc/icsneoc.cpp @@ -338,6 +338,76 @@ bool icsneo_settingsApplyDefaultsTemporary(const neodevice_t* device) { return device->device->settings->applyDefaults(true); } +size_t icsneo_settingsReadStructure(const neodevice_t* device, void* structure, size_t structureSize) { + if(!icsneo_isValidNeoDevice(device)) { + ErrorManager::GetInstance().add(APIError::InvalidNeoDevice); + return 0; + } + + size_t readSize = device->device->settings->getSize(); + if(structure == nullptr) // Structure size request + return readSize; + if(readSize > structureSize) { + // Client application has a smaller structure than we do + // It is probably built against an older version of the API + ErrorManager::GetInstance().add(APIError::OutputTruncated); + readSize = structureSize; + } + + const void* deviceStructure = device->device->settings->getRawStructurePointer(); + if(deviceStructure == nullptr) { + ErrorManager::GetInstance().add(APIError::SettingsNotAvailable); + return 0; + } + + memcpy(structure, deviceStructure, readSize); + + if(readSize < structureSize) // Client application is attempting to read more than we have + memset((uint8_t*)structure + readSize, 0, structureSize - readSize); + + return readSize; +} + +// Not exported +static bool icsneo_settingsWriteStructure(const neodevice_t* device, const void* structure, size_t structureSize) { + if(!icsneo_isValidNeoDevice(device)) { + ErrorManager::GetInstance().add(APIError::InvalidNeoDevice); + return false; + } + + if(structure == nullptr) { + ErrorManager::GetInstance().add(APIError::RequiredParameterNull); + return false; + } + + size_t writeSize = device->device->settings->getSize(); + if(writeSize < structureSize) { + ErrorManager::GetInstance().add(APIError::OutputTruncated); + structureSize = writeSize; + } + + void* deviceStructure = device->device->settings->getMutableRawStructurePointer(); + if(deviceStructure == nullptr) { + ErrorManager::GetInstance().add(APIError::SettingsNotAvailable); + return false; + } + + memcpy(deviceStructure, structure, structureSize); + + // If writeSize > structureSize that means that the user has given us a smaller structure + // This is okay, we will keep the end of the structure intact + // TODO Flag an error + return true; +} + +bool icsneo_settingsApplyStructure(const neodevice_t* device, const void* structure, size_t structureSize) { + return icsneo_settingsWriteStructure(device, structure, structureSize) && icsneo_settingsApply(device); +} + +bool icsneo_settingsApplyStructureTemporary(const neodevice_t* device, const void* structure, size_t structureSize) { + return icsneo_settingsWriteStructure(device, structure, structureSize) && icsneo_settingsApplyTemporary(device); +} + int64_t icsneo_getBaudrate(const neodevice_t* device, uint16_t netid) { if(!icsneo_isValidNeoDevice(device)) { ErrorManager::GetInstance().add(APIError::InvalidNeoDevice); diff --git a/api/icsneolegacy/icsneolegacy.cpp b/api/icsneolegacy/icsneolegacy.cpp index 239debc..259eb35 100644 --- a/api/icsneolegacy/icsneolegacy.cpp +++ b/api/icsneolegacy/icsneolegacy.cpp @@ -177,88 +177,132 @@ void icsneoSetISO15765RxParameters(void* hObject, int lNetwork, int lEnable, spy //Device Functions int icsneoGetConfiguration(void* hObject, unsigned char* pData, int* lNumBytes) { - // TODO Implement + // 2G devices are not supported in the new API return false; } int icsneoSendConfiguration(void* hObject, unsigned char* pData, int lNumBytes) { - // TODO Implement + // 2G devices are not supported in the new API return false; } int icsneoGetFireSettings(void* hObject, SFireSettings* pSettings, int iNumBytes) { - // TODO Implement - return false; + if(!icsneoValidateHObject(hObject)) + return false; + neodevice_t* device = (neodevice_t*)hObject; + return !!icsneo_settingsReadStructure(device, pSettings, iNumBytes); } int icsneoSetFireSettings(void* hObject, SFireSettings* pSettings, int iNumBytes, int bSaveToEEPROM) { - // TODO Implement - return false; + if(!icsneoValidateHObject(hObject)) + return false; + neodevice_t* device = (neodevice_t*)hObject; + if(bSaveToEEPROM) + return icsneo_settingsApplyStructure(device, pSettings, iNumBytes); + return icsneo_settingsApplyStructureTemporary(device, pSettings, iNumBytes); } int icsneoGetVCAN3Settings(void* hObject, SVCAN3Settings* pSettings, int iNumBytes) { - // TODO Implement - return false; + if(!icsneoValidateHObject(hObject)) + return false; + neodevice_t* device = (neodevice_t*)hObject; + return !!icsneo_settingsReadStructure(device, pSettings, iNumBytes); } int icsneoSetVCAN3Settings(void* hObject, SVCAN3Settings* pSettings, int iNumBytes, int bSaveToEEPROM) { - // TODO Implement - return false; + if(!icsneoValidateHObject(hObject)) + return false; + neodevice_t* device = (neodevice_t*)hObject; + if(bSaveToEEPROM) + return icsneo_settingsApplyStructure(device, pSettings, iNumBytes); + return icsneo_settingsApplyStructureTemporary(device, pSettings, iNumBytes); } int icsneoGetFire2Settings(void* hObject, SFire2Settings* pSettings, int iNumBytes) { - // TODO Implement - return false; + if(!icsneoValidateHObject(hObject)) + return false; + neodevice_t* device = (neodevice_t*)hObject; + return !!icsneo_settingsReadStructure(device, pSettings, iNumBytes); } int icsneoSetFire2Settings(void* hObject, SFire2Settings* pSettings, int iNumBytes, int bSaveToEEPROM) { - // TODO Implement - return false; + if(!icsneoValidateHObject(hObject)) + return false; + neodevice_t* device = (neodevice_t*)hObject; + if(bSaveToEEPROM) + return icsneo_settingsApplyStructure(device, pSettings, iNumBytes); + return icsneo_settingsApplyStructureTemporary(device, pSettings, iNumBytes); } int icsneoGetVCANRFSettings(void* hObject, SVCANRFSettings* pSettings, int iNumBytes) { - // TODO Implement - return false; + if(!icsneoValidateHObject(hObject)) + return false; + neodevice_t* device = (neodevice_t*)hObject; + return !!icsneo_settingsReadStructure(device, pSettings, iNumBytes); } int icsneoSetVCANRFSettings(void* hObject, SVCANRFSettings* pSettings, int iNumBytes, int bSaveToEEPROM) { - // TODO Implement - return false; + if(!icsneoValidateHObject(hObject)) + return false; + neodevice_t* device = (neodevice_t*)hObject; + if(bSaveToEEPROM) + return icsneo_settingsApplyStructure(device, pSettings, iNumBytes); + return icsneo_settingsApplyStructureTemporary(device, pSettings, iNumBytes); } int icsneoGetVCAN412Settings(void* hObject, SVCAN412Settings* pSettings, int iNumBytes) { - // TODO Implement - return false; + if(!icsneoValidateHObject(hObject)) + return false; + neodevice_t* device = (neodevice_t*)hObject; + return !!icsneo_settingsReadStructure(device, pSettings, iNumBytes); } int icsneoSetVCAN412Settings(void* hObject, SVCAN412Settings* pSettings, int iNumBytes, int bSaveToEEPROM) { - // TODO Implement - return false; + if(!icsneoValidateHObject(hObject)) + return false; + neodevice_t* device = (neodevice_t*)hObject; + if(bSaveToEEPROM) + return icsneo_settingsApplyStructure(device, pSettings, iNumBytes); + return icsneo_settingsApplyStructureTemporary(device, pSettings, iNumBytes); } int icsneoGetRADGalaxySettings(void* hObject, SRADGalaxySettings* pSettings, int iNumBytes) { - // TODO Implement - return false; + if(!icsneoValidateHObject(hObject)) + return false; + neodevice_t* device = (neodevice_t*)hObject; + return !!icsneo_settingsReadStructure(device, pSettings, iNumBytes); } int icsneoSetRADGalaxySettings(void* hObject, SRADGalaxySettings* pSettings, int iNumBytes, int bSaveToEEPROM) { - // TODO Implement - return false; + if(!icsneoValidateHObject(hObject)) + return false; + neodevice_t* device = (neodevice_t*)hObject; + if(bSaveToEEPROM) + return icsneo_settingsApplyStructure(device, pSettings, iNumBytes); + return icsneo_settingsApplyStructureTemporary(device, pSettings, iNumBytes); } int icsneoGetRADStar2Settings(void* hObject, SRADStar2Settings* pSettings, int iNumBytes) { - // TODO Implement - return false; + if(!icsneoValidateHObject(hObject)) + return false; + neodevice_t* device = (neodevice_t*)hObject; + return !!icsneo_settingsReadStructure(device, pSettings, iNumBytes); } int icsneoSetRADStar2Settings(void* hObject, SRADStar2Settings* pSettings, int iNumBytes, int bSaveToEEPROM) { - // TODO Implement - return false; + if(!icsneoValidateHObject(hObject)) + return false; + neodevice_t* device = (neodevice_t*)hObject; + if(bSaveToEEPROM) + return icsneo_settingsApplyStructure(device, pSettings, iNumBytes); + return icsneo_settingsApplyStructureTemporary(device, pSettings, iNumBytes); } int icsneoSetBitRate(void* hObject, int BitRate, int NetworkID) { - // TODO Implement - return false; + if(!icsneoValidateHObject(hObject)) + return false; + neodevice_t* device = (neodevice_t*)hObject; + return icsneo_setBaudrate(device, (uint16_t)NetworkID, BitRate); } int icsneoGetDeviceParameters(void* hObject, char* pParameter, char* pValues, short ValuesLength) { @@ -327,7 +371,7 @@ int icsneoGetDLLVersion(void) { int icsneoGetSerialNumber(void* hObject, unsigned int*iSerialNumber) { if(!icsneoValidateHObject(hObject)) - return false; + return false; neodevice_t* device = (neodevice_t*)hObject; *iSerialNumber = icsneo_serialStringToNum(device->serial); return true; diff --git a/device/device.cpp b/device/device.cpp index 1d6b043..f2bbea7 100644 --- a/device/device.cpp +++ b/device/device.cpp @@ -157,12 +157,8 @@ bool Device::open() { return false; } - bool settingsNecessary = !settings->disabled; - if(settingsNecessary) { + if(!settings->disabled) settings->refresh(); - if(!settings->ok()) - return false; - } internalHandlerCallbackID = com->addMessageCallback(MessageCallback(MessageFilter(Network::Type::Internal), [this](std::shared_ptr message) { handleInternalMessage(message); diff --git a/device/idevicesettings.cpp b/device/idevicesettings.cpp index f8fe7e9..661431f 100644 --- a/device/idevicesettings.cpp +++ b/device/idevicesettings.cpp @@ -170,31 +170,30 @@ bool IDeviceSettings::refresh(bool ignoreChecksum) { } settings = std::move(rxSettings); + settingsInDeviceRAM = settings; settingsLoaded = true; - if(settings.size() != structSize) { - err(APIError::SettingsLengthError); - settingsLoaded = false; - } + // TODO Warn user that their API version differs from the device firmware version + //if(settings.size() != structSize) return settingsLoaded; } bool IDeviceSettings::apply(bool temporary) { - if(disabled || readonly) + if(!settingsLoaded || disabled || readonly) return false; std::vector bytestream; - bytestream.resize(7 + structSize); + bytestream.resize(7 + settings.size()); bytestream[0] = 0x00; bytestream[1] = GS_VERSION; bytestream[2] = GS_VERSION >> 8; - bytestream[3] = (uint8_t)structSize; - bytestream[4] = (uint8_t)(structSize >> 8); + bytestream[3] = (uint8_t)settings.size(); + bytestream[4] = (uint8_t)(settings.size() >> 8); uint16_t gs_checksum = CalculateGSChecksum(settings); bytestream[5] = (uint8_t)gs_checksum; bytestream[6] = (uint8_t)(gs_checksum >> 8); - memcpy(bytestream.data() + 7, getRawStructurePointer(), structSize); + memcpy(bytestream.data() + 7, getMutableRawStructurePointer(), settings.size()); com->sendCommand(Command::SetSettings, bytestream); std::shared_ptr msg = com->waitForMessageSync(std::make_shared(Command::SetSettings), std::chrono::milliseconds(1000)); @@ -210,7 +209,7 @@ bool IDeviceSettings::apply(bool temporary) { gs_checksum = CalculateGSChecksum(settings); bytestream[5] = (uint8_t)gs_checksum; bytestream[6] = (uint8_t)(gs_checksum >> 8); - memcpy(bytestream.data() + 7, getRawStructurePointer(), structSize); + memcpy(bytestream.data() + 7, getMutableRawStructurePointer(), settings.size()); com->sendCommand(Command::SetSettings, bytestream); msg = com->waitForMessageSync(std::make_shared(Command::SetSettings), std::chrono::milliseconds(1000)); @@ -244,16 +243,16 @@ bool IDeviceSettings::applyDefaults(bool temporary) { // The device might modify the settings once they are applied, however in this case it does not update the checksum // We refresh to get these updates, update the checksum, and send it back so it's all in sync std::vector bytestream; - bytestream.resize(7 + structSize); + bytestream.resize(7 + settings.size()); bytestream[0] = 0x00; bytestream[1] = GS_VERSION; bytestream[2] = GS_VERSION >> 8; - bytestream[3] = (uint8_t)structSize; - bytestream[4] = (uint8_t)(structSize >> 8); + bytestream[3] = (uint8_t)settings.size(); + bytestream[4] = (uint8_t)(settings.size() >> 8); uint16_t gs_checksum = CalculateGSChecksum(settings); bytestream[5] = (uint8_t)gs_checksum; bytestream[6] = (uint8_t)(gs_checksum >> 8); - memcpy(bytestream.data() + 7, getRawStructurePointer(), structSize); + memcpy(bytestream.data() + 7, getMutableRawStructurePointer(), settings.size()); com->sendCommand(Command::SetSettings, bytestream); msg = com->waitForMessageSync(std::make_shared(Command::SetSettings), std::chrono::milliseconds(1000)); @@ -273,7 +272,7 @@ bool IDeviceSettings::applyDefaults(bool temporary) { } int64_t IDeviceSettings::getBaudrateFor(Network net) const { - if(disabled) + if(!settingsLoaded || disabled) return -1; switch(net.getType()) { @@ -293,7 +292,7 @@ int64_t IDeviceSettings::getBaudrateFor(Network net) const { } bool IDeviceSettings::setBaudrateFor(Network net, int64_t baudrate) { - if(disabled || readonly) + if(!settingsLoaded || disabled || readonly) return false; switch(net.getType()) { @@ -301,7 +300,7 @@ bool IDeviceSettings::setBaudrateFor(Network net, int64_t baudrate) { if(baudrate > 1000000) // This is an FD baudrate. Use setFDBaudrateFor instead. return false; - CAN_SETTINGS* cfg = getCANSettingsFor(net); + CAN_SETTINGS* cfg = getMutableCANSettingsFor(net); if(cfg == nullptr) return false; @@ -319,7 +318,7 @@ bool IDeviceSettings::setBaudrateFor(Network net, int64_t baudrate) { } int64_t IDeviceSettings::getFDBaudrateFor(Network net) const { - if(disabled) + if(!settingsLoaded || disabled) return -1; switch(net.getType()) { @@ -339,12 +338,12 @@ int64_t IDeviceSettings::getFDBaudrateFor(Network net) const { } bool IDeviceSettings::setFDBaudrateFor(Network net, int64_t baudrate) { - if(disabled || readonly) + if(!settingsLoaded || disabled || readonly) return false; switch(net.getType()) { case Network::Type::CAN: { - CANFD_SETTINGS* cfg = getCANFDSettingsFor(net); + CANFD_SETTINGS* cfg = getMutableCANFDSettingsFor(net); if(cfg == nullptr) return false; @@ -359,16 +358,21 @@ bool IDeviceSettings::setFDBaudrateFor(Network net, int64_t baudrate) { } } -template bool IDeviceSettings::setStructure(const T& newStructure) { - if(disabled || readonly) +template bool IDeviceSettings::applyStructure(const T& newStructure) { + if(!settingsLoaded || disabled || readonly) 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 + + size_t copySize = sizeof(T); + if(copySize > settings.size()) + copySize = settings.size(); // TODO Warn user that their structure is truncated - if(settings.size() != structSize) - settings.resize(structSize); + // TODO Warn user that the device firmware doesn't support all the settings in the current API + //if(copySize < settings.size()) memcpy(settings.data(), &newStructure, structSize); - return true; + return apply(); } \ No newline at end of file diff --git a/include/icsneo/device/idevicesettings.h b/include/icsneo/device/idevicesettings.h index 792da57..1ff413b 100644 --- a/include/icsneo/device/idevicesettings.h +++ b/include/icsneo/device/idevicesettings.h @@ -302,21 +302,33 @@ public: virtual bool setFDBaudrateFor(Network net, int64_t baudrate); virtual const CAN_SETTINGS* getCANSettingsFor(Network net) const { (void)net; return nullptr; } - CAN_SETTINGS* getCANSettingsFor(Network net) { - return const_cast(static_cast(this)->getCANSettingsFor(net)); + CAN_SETTINGS* getMutableCANSettingsFor(Network net) { + if(disabled || readonly) + return nullptr; + const uint8_t* offset = (const uint8_t*)getCANSettingsFor(net); + if(offset == nullptr) + return nullptr; + return static_cast((void*)(settings.data() + (offset - settingsInDeviceRAM.data()))); } virtual const CANFD_SETTINGS* getCANFDSettingsFor(Network net) const { (void)net; return nullptr; } - CANFD_SETTINGS* getCANFDSettingsFor(Network net) { - return const_cast(static_cast(this)->getCANFDSettingsFor(net)); + CANFD_SETTINGS* getMutableCANFDSettingsFor(Network net) { + if(disabled || readonly) + return nullptr; + const uint8_t* offset = (const uint8_t*)getCANFDSettingsFor(net); + if(offset == nullptr) + return nullptr; + return static_cast((void*)(settings.data() + (offset - settingsInDeviceRAM.data()))); } - const void* getRawStructurePointer() const { return settings.data(); } - void* getRawStructurePointer() { return settings.data(); } + const void* getRawStructurePointer() const { return settingsInDeviceRAM.data(); } + void* getMutableRawStructurePointer() { return settings.data(); } template const T* getStructurePointer() const { return static_cast(getRawStructurePointer()); } - template T* getStructurePointer() { return static_cast(getRawStructurePointer()); } - template T getStructureCopy() const { return *getStructurePointer(); } - template bool setStructure(const T& newStructure); + template T* getMutableStructurePointer() { return static_cast(getMutableRawStructurePointer()); } + template T getStructure() const { return *getStructurePointer(); } + template bool applyStructure(const T& newStructure); + + const size_t& getSize() const { return structSize; } bool disabled = false; bool readonly = false; @@ -325,7 +337,9 @@ protected: device_errorhandler_t err; size_t structSize; bool settingsLoaded = false; - std::vector settings; + + std::vector settings; // For writing settings to, calling apply() should copy over to device RAM (and EEPROM) + std::vector settingsInDeviceRAM; // For reading settings from // Parameter createInoperableSettings exists because it is serving as a warning that you probably don't want to do this typedef void* warn_t; diff --git a/include/icsneo/device/neovifire/neovifiresettings.h b/include/icsneo/device/neovifire/neovifiresettings.h index e9ad5b5..77aec68 100644 --- a/include/icsneo/device/neovifire/neovifiresettings.h +++ b/include/icsneo/device/neovifire/neovifiresettings.h @@ -102,6 +102,8 @@ public: NeoVIFIRESettings(std::shared_ptr com) : IDeviceSettings(com, sizeof(neovifire_settings_t)) {} const CAN_SETTINGS* getCANSettingsFor(Network net) const override { auto cfg = getStructurePointer(); + if(cfg == nullptr) + return nullptr; switch(net.getNetID()) { case Network::NetID::HSCAN: return &(cfg->can1); diff --git a/include/icsneo/device/neovifire2/neovifire2settings.h b/include/icsneo/device/neovifire2/neovifire2settings.h index b71ad6c..8477814 100644 --- a/include/icsneo/device/neovifire2/neovifire2settings.h +++ b/include/icsneo/device/neovifire2/neovifire2settings.h @@ -116,6 +116,8 @@ public: NeoVIFIRE2Settings(std::shared_ptr com) : IDeviceSettings(com, sizeof(neovifire2_settings_t)) {} const CAN_SETTINGS* getCANSettingsFor(Network net) const override { auto cfg = getStructurePointer(); + if(cfg == nullptr) + return nullptr; switch(net.getNetID()) { case Network::NetID::HSCAN: return &(cfg->can1); @@ -139,6 +141,8 @@ public: } const CANFD_SETTINGS* getCANFDSettingsFor(Network net) const override { auto cfg = getStructurePointer(); + if(cfg == nullptr) + return nullptr; switch(net.getNetID()) { case Network::NetID::HSCAN: return &(cfg->canfd1); diff --git a/include/icsneo/device/valuecan3/valuecan3settings.h b/include/icsneo/device/valuecan3/valuecan3settings.h index 0fedf1e..04a4089 100644 --- a/include/icsneo/device/valuecan3/valuecan3settings.h +++ b/include/icsneo/device/valuecan3/valuecan3settings.h @@ -38,6 +38,8 @@ public: ValueCAN3Settings(std::shared_ptr com) : IDeviceSettings(com, sizeof(valuecan3_settings_t)) {} const CAN_SETTINGS* getCANSettingsFor(Network net) const override { auto cfg = getStructurePointer(); + if(cfg == nullptr) + return nullptr; switch(net.getNetID()) { case Network::NetID::HSCAN: return &(cfg->can1); diff --git a/include/icsneo/device/valuecan4/settings/valuecan4-1settings.h b/include/icsneo/device/valuecan4/settings/valuecan4-1settings.h index e4c167d..fe38406 100644 --- a/include/icsneo/device/valuecan4/settings/valuecan4-1settings.h +++ b/include/icsneo/device/valuecan4/settings/valuecan4-1settings.h @@ -12,6 +12,8 @@ public: ValueCAN4_1Settings(std::shared_ptr com) : ValueCAN4_1_2Settings(com) {} const CAN_SETTINGS* getCANSettingsFor(Network net) const override { auto cfg = getStructurePointer(); + if(cfg == nullptr) + return nullptr; switch(net.getNetID()) { case Network::NetID::HSCAN: return &(cfg->can1); diff --git a/include/icsneo/device/valuecan4/settings/valuecan4-2elsettings.h b/include/icsneo/device/valuecan4/settings/valuecan4-2elsettings.h index 43aa282..1aa7f4e 100644 --- a/include/icsneo/device/valuecan4/settings/valuecan4-2elsettings.h +++ b/include/icsneo/device/valuecan4/settings/valuecan4-2elsettings.h @@ -13,6 +13,8 @@ public: ValueCAN4_2ELSettings(std::shared_ptr com) : ValueCAN4_4_2ELSettings(com) {} const CAN_SETTINGS* getCANSettingsFor(Network net) const override { auto cfg = getStructurePointer(); + if(cfg == nullptr) + return nullptr; switch(net.getNetID()) { case Network::NetID::HSCAN: return &(cfg->can1); @@ -24,6 +26,8 @@ public: } const CANFD_SETTINGS* getCANFDSettingsFor(Network net) const override { auto cfg = getStructurePointer(); + if(cfg == nullptr) + return nullptr; switch(net.getNetID()) { case Network::NetID::HSCAN: return &(cfg->canfd1); diff --git a/include/icsneo/device/valuecan4/settings/valuecan4-2settings.h b/include/icsneo/device/valuecan4/settings/valuecan4-2settings.h index 023c960..6f87ccf 100644 --- a/include/icsneo/device/valuecan4/settings/valuecan4-2settings.h +++ b/include/icsneo/device/valuecan4/settings/valuecan4-2settings.h @@ -12,6 +12,8 @@ public: ValueCAN4_2Settings(std::shared_ptr com) : ValueCAN4_1_2Settings(com) {} const CAN_SETTINGS* getCANSettingsFor(Network net) const override { auto cfg = getStructurePointer(); + if(cfg == nullptr) + return nullptr; switch(net.getNetID()) { case Network::NetID::HSCAN: return &(cfg->can1); @@ -23,6 +25,8 @@ public: } const CANFD_SETTINGS* getCANFDSettingsFor(Network net) const override { auto cfg = getStructurePointer(); + if(cfg == nullptr) + return nullptr; switch(net.getNetID()) { case Network::NetID::HSCAN: return &(cfg->canfd1); diff --git a/include/icsneo/device/valuecan4/settings/valuecan4-4settings.h b/include/icsneo/device/valuecan4/settings/valuecan4-4settings.h index ddf8e1d..d2afd37 100644 --- a/include/icsneo/device/valuecan4/settings/valuecan4-4settings.h +++ b/include/icsneo/device/valuecan4/settings/valuecan4-4settings.h @@ -13,6 +13,8 @@ public: ValueCAN4_4Settings(std::shared_ptr com) : ValueCAN4_4_2ELSettings(com) {} const CAN_SETTINGS* getCANSettingsFor(Network net) const override { auto cfg = getStructurePointer(); + if(cfg == nullptr) + return nullptr; switch(net.getNetID()) { case Network::NetID::HSCAN: return &(cfg->can1); @@ -28,6 +30,8 @@ public: } const CANFD_SETTINGS* getCANFDSettingsFor(Network net) const override { auto cfg = getStructurePointer(); + if(cfg == nullptr) + return nullptr; switch(net.getNetID()) { case Network::NetID::HSCAN: return &(cfg->canfd1); diff --git a/include/icsneo/icsneoc.h b/include/icsneo/icsneoc.h index 81885d2..3a5e7f2 100644 --- a/include/icsneo/icsneoc.h +++ b/include/icsneo/icsneoc.h @@ -357,6 +357,52 @@ extern bool DLLExport icsneo_settingsApplyDefaults(const neodevice_t* device); */ extern bool DLLExport icsneo_settingsApplyDefaultsTemporary(const neodevice_t* device); +/** + * \brief Apply the default settings structure for a specified device temporarily. + * \param[in] device A pointer to the neodevice_t structure specifying the device to operate on. + * \param[out] structure A pointer to a device settings structure for the current device. + * \param[in] structureSize The size of the current device settings structure in bytes. + * \returns Number of bytes written to structure + * + * See icsneo_settingsApply() for further information about applying settings. See icsneo_settingsApplyDefaults() for further information about applying default settings. + * + * This function sets the default settings such that they will revert to the values saved in non-volatile storage when the device loses power. + * + * If possible, use functions specific to the operation you want to acomplish (such as icsneo_setBaudrate()) instead of modifying the structure directly. + * This allows the client application to work with other hardware. + */ +extern size_t DLLExport icsneo_settingsReadStructure(const neodevice_t* device, void* structure, size_t structureSize); + +/** + * \brief Apply a provided settings structure for a specified device. + * \param[in] device A pointer to the neodevice_t structure specifying the device to operate on. + * \param[in] structure A pointer to a device settings structure for the current device. + * \param[in] structureSize The size of the current device settings structure in bytes. + * \returns True if the settings were applied. + * + * This function immediately applies the provided settings. See icsneo_settingsApplyTemporary() for further information about applying settings. + * + * If possible, use functions specific to the operation you want to acomplish (such as icsneo_setBaudrate()) instead of modifying the structure directly. + * This allows the client application to work with other hardware. + */ +extern bool DLLExport icsneo_settingsApplyStructure(const neodevice_t* device, const void* structure, size_t structureSize); + +/** + * \brief Apply a provided settings structure for a specified device without saving to non-volatile EEPROM. + * \param[in] device A pointer to the neodevice_t structure specifying the device to operate on. + * \param[in] structure A pointer to a device settings structure for the current device. + * \param[in] structureSize The size of the current device settings structure in bytes. + * \returns True if the settings were applied. + * + * This function immediately applies the provided settings. See icsneo_settingsApply() for further information about applying settings. + * + * This function sets the default settings such that they will revert to the values saved in non-volatile storage when the device loses power. + * + * If possible, use functions specific to the operation you want to acomplish (such as icsneo_setBaudrate()) instead of modifying the structure directly. + * This allows the client application to work with other hardware. + */ +extern bool DLLExport icsneo_settingsApplyStructureTemporary(const neodevice_t* device, const void* structure, size_t structureSize); + /** * \brief Get the network baudrate for a specified device. * \param[in] device A pointer to the neodevice_t structure specifying the device to operate on. @@ -649,6 +695,15 @@ fn_icsneo_settingsApplyDefaults icsneo_settingsApplyDefaults; typedef bool(*fn_icsneo_settingsApplyDefaultsTemporary)(const neodevice_t* device); fn_icsneo_settingsApplyDefaultsTemporary icsneo_settingsApplyDefaultsTemporary; +typedef size_t(*fn_icsneo_settingsReadStructure)(const neodevice_t* device, void* structure, size_t structureSize); +fn_icsneo_settingsReadStructure icsneo_settingsReadStructure; + +typedef bool(*fn_icsneo_settingsApplyStructure)(const neodevice_t* device, const void* structure, size_t structureSize); +fn_icsneo_settingsApplyStructure icsneo_settingsApplyStructure; + +typedef bool(*fn_icsneo_settingsApplyStructureTemporary)(const neodevice_t* device, const void* structure, size_t structureSize); +fn_icsneo_settingsApplyStructureTemporary icsneo_settingsApplyStructureTemporary; + typedef int64_t(*fn_icsneo_getBaudrate)(const neodevice_t* device, uint16_t netid); fn_icsneo_getBaudrate icsneo_getBaudrate; @@ -729,6 +784,9 @@ int icsneo_init() { ICSNEO_IMPORTASSERT(icsneo_settingsApplyTemporary); ICSNEO_IMPORTASSERT(icsneo_settingsApplyDefaults); ICSNEO_IMPORTASSERT(icsneo_settingsApplyDefaultsTemporary); + ICSNEO_IMPORTASSERT(icsneo_settingsReadStructure); + ICSNEO_IMPORTASSERT(icsneo_settingsApplyStructure); + ICSNEO_IMPORTASSERT(icsneo_settingsApplyStructureTemporary); ICSNEO_IMPORTASSERT(icsneo_getBaudrate); ICSNEO_IMPORTASSERT(icsneo_setBaudrate); ICSNEO_IMPORTASSERT(icsneo_getFDBaudrate);