mirror of
https://github.com/intrepidcs/libicsneo.git
synced 2026-08-05 01:18:36 +02:00
Support software controllable termination
This commit is contained in:
@@ -73,6 +73,9 @@ public:
|
||||
RTRNotSupported = 0x2021,
|
||||
DeviceDisconnected = 0x2022,
|
||||
OnlineNotSupported = 0x2023,
|
||||
TerminationNotSupportedDevice = 0x2024,
|
||||
TerminationNotSupportedNetwork = 0x2025,
|
||||
AnotherInTerminationGroupEnabled = 0x2026,
|
||||
|
||||
// Transport Events
|
||||
FailedToRead = 0x3000,
|
||||
|
||||
@@ -580,6 +580,7 @@ typedef struct {
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include "icsneo/communication/communication.h"
|
||||
#include "icsneo/platform/optional.h"
|
||||
#include <iostream>
|
||||
#include <atomic>
|
||||
|
||||
@@ -587,6 +588,8 @@ namespace icsneo {
|
||||
|
||||
class IDeviceSettings {
|
||||
public:
|
||||
using TerminationGroup = std::vector<Network>;
|
||||
|
||||
static constexpr uint16_t GS_VERSION = 5;
|
||||
static uint16_t CalculateGSChecksum(const std::vector<uint8_t>& settings);
|
||||
static CANBaudrate GetEnumValueForBaudrate(int64_t baudrate);
|
||||
@@ -595,11 +598,11 @@ public:
|
||||
IDeviceSettings(std::shared_ptr<Communication> com, size_t size) : com(com), report(com->report), structSize(size) {}
|
||||
virtual ~IDeviceSettings() {}
|
||||
bool ok() { return !disabled && settingsLoaded; }
|
||||
|
||||
bool refresh(bool ignoreChecksum = false); // Get from device
|
||||
|
||||
virtual bool refresh(bool ignoreChecksum = false); // Get from device
|
||||
|
||||
// Send to device, if temporary device keeps settings in volatile RAM until power cycle, otherwise saved to EEPROM
|
||||
bool apply(bool temporary = false);
|
||||
virtual bool apply(bool temporary = false);
|
||||
bool applyDefaults(bool temporary = false);
|
||||
|
||||
virtual int64_t getBaudrateFor(Network net) const;
|
||||
@@ -648,6 +651,59 @@ public:
|
||||
return reinterpret_cast<SWCAN_SETTINGS*>((void*)(settings.data() + (offset - settingsInDeviceRAM.data())));
|
||||
}
|
||||
|
||||
/**
|
||||
* Some devices have groupings of networks, where software
|
||||
* switchable termination can only be applied to one network
|
||||
* in the group at a time. This function returns those groups
|
||||
* for the given device.
|
||||
*
|
||||
* If a device does not support CAN Termination, an empty vector
|
||||
* is returned.
|
||||
*/
|
||||
virtual std::vector<TerminationGroup> getTerminationGroups() const { return {}; }
|
||||
|
||||
/**
|
||||
* Check whether software switchable termination is supported
|
||||
* for a given network on this device.
|
||||
*
|
||||
* This does not check whether another network in the termination
|
||||
* group has termination enabled, check canTerminationBeEnabledFor
|
||||
* for that.
|
||||
*/
|
||||
bool isTerminationSupportedFor(Network net) const;
|
||||
|
||||
/**
|
||||
* Check whether software switchable termination can currently
|
||||
* be enabled for a given network. If another network in the
|
||||
* group is already enabled, or if termination is not supported
|
||||
* on this network, false is returned and an error will have
|
||||
* been reported in icsneo::getLastError().
|
||||
*/
|
||||
bool canTerminationBeEnabledFor(Network net) const;
|
||||
|
||||
/**
|
||||
* Check whether software switchable termination is currently
|
||||
* enabled for a given network in the currently active device settings.
|
||||
*
|
||||
* Note that if the termination status is set, but not yet
|
||||
* applied to the device, the current device status will be
|
||||
* reflected here rather than the pending status.
|
||||
*/
|
||||
optional<bool> isTerminationEnabledFor(Network net) const;
|
||||
|
||||
/**
|
||||
* Enable or disable software switchable termination for a
|
||||
* given network.
|
||||
*
|
||||
* All other networks in the termination group must be disabled
|
||||
* prior to the call, but the change does not need to be applied
|
||||
* to the device before enqueing the enable.
|
||||
*
|
||||
* Returns true if the call was successful, otherwise an error
|
||||
* will have been reported in icsneo::getLastError().
|
||||
*/
|
||||
bool setTerminationFor(Network net, bool enabled);
|
||||
|
||||
const void* getRawStructurePointer() const { return settingsInDeviceRAM.data(); }
|
||||
void* getMutableRawStructurePointer() { return settings.data(); }
|
||||
template<typename T> const T* getStructurePointer() const { return reinterpret_cast<const T*>(getRawStructurePointer()); }
|
||||
@@ -659,7 +715,7 @@ public:
|
||||
|
||||
// if settings are disabled for this device. always false unless constructed null
|
||||
bool disabled = false;
|
||||
|
||||
|
||||
bool readonly = false;
|
||||
bool disableGSChecksumming = false;
|
||||
|
||||
@@ -679,6 +735,16 @@ protected:
|
||||
typedef void* warn_t;
|
||||
IDeviceSettings(warn_t createInoperableSettings, std::shared_ptr<Communication> com)
|
||||
: disabled(true), readonly(true), report(com->report), structSize(0) { (void)createInoperableSettings; }
|
||||
|
||||
virtual const uint64_t* getTerminationEnables() const { return nullptr; }
|
||||
virtual uint64_t* getMutableTerminationEnables() {
|
||||
if(disabled || readonly)
|
||||
return nullptr;
|
||||
const uint8_t* offset = (const uint8_t*)getTerminationEnables();
|
||||
if(offset == nullptr)
|
||||
return nullptr;
|
||||
return reinterpret_cast<uint64_t*>((void*)(settings.data() + (offset - settingsInDeviceRAM.data())));
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -191,6 +191,31 @@ public:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
virtual std::vector<TerminationGroup> getTerminationGroups() const override {
|
||||
return {
|
||||
{
|
||||
Network(Network::NetID::HSCAN),
|
||||
Network(Network::NetID::HSCAN3),
|
||||
Network(Network::NetID::HSCAN5),
|
||||
Network(Network::NetID::HSCAN7)
|
||||
},
|
||||
{
|
||||
Network(Network::NetID::MSCAN),
|
||||
Network(Network::NetID::HSCAN2),
|
||||
Network(Network::NetID::HSCAN4),
|
||||
Network(Network::NetID::HSCAN6)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected:
|
||||
const uint64_t* getTerminationEnables() const override {
|
||||
auto cfg = getStructurePointer<neovifire2_settings_t>();
|
||||
if(cfg == nullptr)
|
||||
return nullptr;
|
||||
return &cfg->termination_enables;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -152,6 +152,31 @@ public:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
virtual std::vector<TerminationGroup> getTerminationGroups() const override {
|
||||
return {
|
||||
{
|
||||
Network(Network::NetID::HSCAN),
|
||||
Network(Network::NetID::HSCAN3),
|
||||
Network(Network::NetID::HSCAN5),
|
||||
Network(Network::NetID::HSCAN7)
|
||||
},
|
||||
{
|
||||
Network(Network::NetID::MSCAN),
|
||||
Network(Network::NetID::HSCAN2),
|
||||
Network(Network::NetID::HSCAN4),
|
||||
Network(Network::NetID::HSCAN6)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected:
|
||||
const uint64_t* getTerminationEnables() const override {
|
||||
auto cfg = getStructurePointer<radgigalog_settings_t>();
|
||||
if(cfg == nullptr)
|
||||
return nullptr;
|
||||
return &cfg->termination_enables;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -133,6 +133,29 @@ public:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
virtual std::vector<TerminationGroup> getTerminationGroups() const override {
|
||||
return {
|
||||
{
|
||||
Network(Network::NetID::HSCAN),
|
||||
Network(Network::NetID::HSCAN2),
|
||||
Network(Network::NetID::HSCAN3),
|
||||
Network(Network::NetID::HSCAN4)
|
||||
},
|
||||
{
|
||||
Network(Network::NetID::MSCAN),
|
||||
Network(Network::NetID::HSCAN5)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected:
|
||||
const uint64_t* getTerminationEnables() const override {
|
||||
auto cfg = getStructurePointer<radgigastar_settings_t>();
|
||||
if(cfg == nullptr)
|
||||
return nullptr;
|
||||
return &cfg->termination_enables;
|
||||
}
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
|
||||
@@ -37,6 +37,21 @@ public:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
virtual std::vector<TerminationGroup> getTerminationGroups() const override {
|
||||
return {
|
||||
{ Network(Network::NetID::HSCAN) },
|
||||
{ Network(Network::NetID::HSCAN2) }
|
||||
};
|
||||
}
|
||||
|
||||
protected:
|
||||
const uint64_t* getTerminationEnables() const override {
|
||||
auto cfg = getStructurePointer<valuecan4_4_2el_settings_t>();
|
||||
if(cfg == nullptr)
|
||||
return nullptr;
|
||||
return &cfg->termination_enables;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -36,6 +36,21 @@ public:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
virtual std::vector<TerminationGroup> getTerminationGroups() const override {
|
||||
return {
|
||||
{ Network(Network::NetID::HSCAN) },
|
||||
{ Network(Network::NetID::HSCAN2) }
|
||||
};
|
||||
}
|
||||
|
||||
protected:
|
||||
const uint64_t* getTerminationEnables() const override {
|
||||
auto cfg = getStructurePointer<valuecan4_1_2_settings_t>();
|
||||
if(cfg == nullptr)
|
||||
return nullptr;
|
||||
return &cfg->termination_enables;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -45,6 +45,27 @@ public:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
virtual std::vector<TerminationGroup> getTerminationGroups() const override {
|
||||
return {
|
||||
{
|
||||
Network(Network::NetID::HSCAN),
|
||||
Network(Network::NetID::HSCAN3)
|
||||
},
|
||||
{
|
||||
Network(Network::NetID::HSCAN2),
|
||||
Network(Network::NetID::HSCAN4)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected:
|
||||
const uint64_t* getTerminationEnables() const override {
|
||||
auto cfg = getStructurePointer<valuecan4_4_2el_settings_t>();
|
||||
if(cfg == nullptr)
|
||||
return nullptr;
|
||||
return &cfg->termination_enables;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -37,6 +37,21 @@ public:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
virtual std::vector<TerminationGroup> getTerminationGroups() const override {
|
||||
return {
|
||||
{ Network(Network::NetID::HSCAN) },
|
||||
{ Network(Network::NetID::HSCAN2) }
|
||||
};
|
||||
}
|
||||
|
||||
protected:
|
||||
const uint64_t* getTerminationEnables() const override {
|
||||
auto cfg = getStructurePointer<valuecan4_industrial_settings_t>();
|
||||
if(cfg == nullptr)
|
||||
return nullptr;
|
||||
return &cfg->termination_enables;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -82,6 +82,55 @@ public:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
virtual std::vector<TerminationGroup> getTerminationGroups() const override {
|
||||
return {
|
||||
{ Network(Network::NetID::HSCAN) }
|
||||
};
|
||||
}
|
||||
|
||||
bool refresh(bool ignoreChecksum = false) override {
|
||||
// Because VividCAN uses a nonstandard 16-bit termination_enables
|
||||
// we need to keep the standard 64-bit values in memory and update
|
||||
// the structure when applying
|
||||
if(!IDeviceSettings::refresh(ignoreChecksum))
|
||||
return false;
|
||||
auto cfg = getStructurePointer<vividcan_settings_t>();
|
||||
if(cfg == nullptr)
|
||||
return false;
|
||||
activeTerminationEnables = queuedTerminationEnables = cfg->termination_enables;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool apply(bool permanent = true) override {
|
||||
auto cfg = getMutableStructurePointer<vividcan_settings_t>();
|
||||
if(cfg)
|
||||
cfg->termination_enables = uint16_t(queuedTerminationEnables & 0xFFFF);
|
||||
|
||||
const bool success = IDeviceSettings::apply(permanent);
|
||||
if(success)
|
||||
activeTerminationEnables = cfg->termination_enables;
|
||||
return success;
|
||||
}
|
||||
|
||||
protected:
|
||||
const uint64_t* getTerminationEnables() const override {
|
||||
// Check the structure pointer even though we're not using it so
|
||||
// all of the other checks that go along with it are performed
|
||||
if(getStructurePointer<vividcan_settings_t>() == nullptr)
|
||||
return nullptr;
|
||||
return &activeTerminationEnables;
|
||||
}
|
||||
|
||||
uint64_t* getMutableTerminationEnables() override {
|
||||
if(getMutableStructurePointer<vividcan_settings_t>() == nullptr)
|
||||
return nullptr;
|
||||
return &queuedTerminationEnables;
|
||||
}
|
||||
|
||||
private:
|
||||
uint64_t queuedTerminationEnables = 0;
|
||||
uint64_t activeTerminationEnables = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -738,6 +738,60 @@ extern bool DLLExport icsneo_getDigitalIO(const neodevice_t* device, neoio_t typ
|
||||
*/
|
||||
extern bool DLLExport icsneo_setDigitalIO(const neodevice_t* device, neoio_t type, uint32_t number, bool value);
|
||||
|
||||
/**
|
||||
* \brief Check whether software switchable termination is supported for a given network on this device.
|
||||
* \param[in] device A pointer to the neodevice_t structure specifying the device to operate on.
|
||||
* \param[in] netid The network ID to check
|
||||
* \returns True if software switchable termination is supported
|
||||
*
|
||||
* This does not check whether another network in the termination
|
||||
* group has termination enabled, check canTerminationBeEnabledFor
|
||||
* for that.
|
||||
*/
|
||||
extern bool DLLExport icsneo_isTerminationSupportedFor(const neodevice_t* device, uint16_t netid);
|
||||
|
||||
/**
|
||||
* \brief Check whether software switchable termination can currently be enabled for a given network.
|
||||
* \param[in] device A pointer to the neodevice_t structure specifying the device to operate on.
|
||||
* \param[in] netid The network ID to check
|
||||
* \returns True if software switchable termination can currently be enabled
|
||||
*
|
||||
* If another network in the group is already enabled, or if
|
||||
* termination is not supported on this network, false is
|
||||
* returned and an error will have been reported in
|
||||
* icsneo_getLastError().
|
||||
*/
|
||||
extern bool DLLExport icsneo_canTerminationBeEnabledFor(const neodevice_t* device, uint16_t netid);
|
||||
|
||||
/**
|
||||
* \brief Check whether software switchable termination is currently
|
||||
* enabled for a given network in the currently active device settings.
|
||||
* \param[in] device A pointer to the neodevice_t structure specifying the device to operate on.
|
||||
* \param[in] netid The network ID to check
|
||||
* \returns True if software switchable termination is currently enabled
|
||||
*
|
||||
* Note that if the termination status is set, but not yet
|
||||
* applied to the device, the current device status will be
|
||||
* reflected here rather than the pending status.
|
||||
*
|
||||
* False will be returned and an error will be set in
|
||||
* icsneo_getLastError if the setting is unreadable.
|
||||
*/
|
||||
extern bool DLLExport icsneo_isTerminationEnabledFor(const neodevice_t* device, uint16_t netid);
|
||||
|
||||
/**
|
||||
* \brief Enable or disable software switchable termination for a given network.
|
||||
* \param[in] device A pointer to the neodevice_t structure specifying the device to operate on.
|
||||
* \param[in] netid The network ID to affect
|
||||
* \param[in] enabled Whether to enable or disable switchable termination
|
||||
* \returns True if if the call was successful, otherwise an error will have been reported in icsneo_getLastError().
|
||||
*
|
||||
* All other networks in the termination group must be disabled
|
||||
* prior to the call, but the change does not need to be applied
|
||||
* to the device before enqueing the enable.
|
||||
*/
|
||||
extern bool DLLExport icsneo_setTerminationFor(const neodevice_t* device, uint16_t netid, bool enabled);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
@@ -894,6 +948,18 @@ fn_icsneo_getDigitalIO icsneo_getDigitalIO;
|
||||
typedef bool(*fn_icsneo_setDigitalIO)(const neodevice_t* device, neoio_t type, uint32_t number, bool value);
|
||||
fn_icsneo_setDigitalIO icsneo_setDigitalIO;
|
||||
|
||||
typedef bool(*fn_icsneo_isTerminationSupportedFor)(const neodevice_t* device, uint16_t netid);
|
||||
fn_icsneo_isTerminationSupportedFor icsneo_isTerminationSupportedFor;
|
||||
|
||||
typedef bool(*fn_icsneo_canTerminationBeEnabledFor)(const neodevice_t* device, uint16_t netid);
|
||||
fn_icsneo_canTerminationBeEnabledFor icsneo_canTerminationBeEnabledFor;
|
||||
|
||||
typedef bool(*fn_icsneo_isTerminationEnabledFor)(const neodevice_t* device, uint16_t netid);
|
||||
fn_icsneo_isTerminationEnabledFor icsneo_isTerminationEnabledFor;
|
||||
|
||||
typedef bool(*fn_icsneo_setTerminationFor)(const neodevice_t* device, uint16_t netid, bool enabled);
|
||||
fn_icsneo_setTerminationFor icsneo_setTerminationFor;
|
||||
|
||||
#define ICSNEO_IMPORT(func) func = (fn_##func)icsneo_dynamicLibraryGetFunction(icsneo_libraryHandle, #func)
|
||||
#define ICSNEO_IMPORTASSERT(func) if((ICSNEO_IMPORT(func)) == NULL) return 3
|
||||
void* icsneo_libraryHandle = NULL;
|
||||
@@ -958,6 +1024,10 @@ int icsneo_init() {
|
||||
ICSNEO_IMPORTASSERT(icsneo_getTimestampResolution);
|
||||
ICSNEO_IMPORTASSERT(icsneo_getDigitalIO);
|
||||
ICSNEO_IMPORTASSERT(icsneo_setDigitalIO);
|
||||
ICSNEO_IMPORTASSERT(icsneo_isTerminationSupportedFor);
|
||||
ICSNEO_IMPORTASSERT(icsneo_canTerminationBeEnabledFor);
|
||||
ICSNEO_IMPORTASSERT(icsneo_isTerminationEnabledFor);
|
||||
ICSNEO_IMPORTASSERT(icsneo_setTerminationFor);
|
||||
|
||||
icsneo_initialized = true;
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user