Support software controllable termination
parent
c8bf1f26da
commit
e82b5d15e0
|
|
@ -644,3 +644,31 @@ bool icsneo_setDigitalIO(const neodevice_t* device, neoio_t type, uint32_t numbe
|
||||||
|
|
||||||
return device->device->setDigitalIO(static_cast<icsneo::IO>(type), number, value);
|
return device->device->setDigitalIO(static_cast<icsneo::IO>(type), number, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool icsneo_isTerminationSupportedFor(const neodevice_t* device, uint16_t netid) {
|
||||||
|
if(!icsneo_isValidNeoDevice(device))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return device->device->settings->isTerminationSupportedFor(Network(netid));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool icsneo_canTerminationBeEnabledFor(const neodevice_t* device, uint16_t netid) {
|
||||||
|
if(!icsneo_isValidNeoDevice(device))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return device->device->settings->canTerminationBeEnabledFor(Network(netid));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool icsneo_isTerminationEnabledFor(const neodevice_t* device, uint16_t netid) {
|
||||||
|
if(!icsneo_isValidNeoDevice(device))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return device->device->settings->isTerminationEnabledFor(Network(netid)).value_or(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool icsneo_setTerminationFor(const neodevice_t* device, uint16_t netid, bool enabled) {
|
||||||
|
if(!icsneo_isValidNeoDevice(device))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return device->device->settings->setTerminationFor(Network(netid), enabled);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -96,6 +96,9 @@ static constexpr const char* CANFD_NOT_SUPPORTED = "This device does not support
|
||||||
static constexpr const char* RTR_NOT_SUPPORTED = "RTR is not supported with CANFD.";
|
static constexpr const char* RTR_NOT_SUPPORTED = "RTR is not supported with CANFD.";
|
||||||
static constexpr const char* DEVICE_DISCONNECTED = "The device was disconnected.";
|
static constexpr const char* DEVICE_DISCONNECTED = "The device was disconnected.";
|
||||||
static constexpr const char* ONLINE_NOT_SUPPORTED = "This device does not support going online.";
|
static constexpr const char* ONLINE_NOT_SUPPORTED = "This device does not support going online.";
|
||||||
|
static constexpr const char* TERMINATION_NOT_SUPPORTED_DEVICE = "This device does not support software selectable termination.";
|
||||||
|
static constexpr const char* TERMINATION_NOT_SUPPORTED_NETWORK = "This network does not support software selectable termination on this device.";
|
||||||
|
static constexpr const char* ANOTHER_IN_TERMINATION_GROUP_ENABLED = "A mutually exclusive network already has termination enabled.";
|
||||||
|
|
||||||
// Transport Errors
|
// Transport Errors
|
||||||
static constexpr const char* FAILED_TO_READ = "A read operation failed.";
|
static constexpr const char* FAILED_TO_READ = "A read operation failed.";
|
||||||
|
|
@ -193,6 +196,12 @@ const char* APIEvent::DescriptionForType(Type type) {
|
||||||
return DEVICE_DISCONNECTED;
|
return DEVICE_DISCONNECTED;
|
||||||
case Type::OnlineNotSupported:
|
case Type::OnlineNotSupported:
|
||||||
return ONLINE_NOT_SUPPORTED;
|
return ONLINE_NOT_SUPPORTED;
|
||||||
|
case Type::TerminationNotSupportedDevice:
|
||||||
|
return TERMINATION_NOT_SUPPORTED_DEVICE;
|
||||||
|
case Type::TerminationNotSupportedNetwork:
|
||||||
|
return TERMINATION_NOT_SUPPORTED_NETWORK;
|
||||||
|
case Type::AnotherInTerminationGroupEnabled:
|
||||||
|
return ANOTHER_IN_TERMINATION_GROUP_ENABLED;
|
||||||
|
|
||||||
// Transport Errors
|
// Transport Errors
|
||||||
case Type::FailedToRead:
|
case Type::FailedToRead:
|
||||||
|
|
|
||||||
|
|
@ -517,6 +517,140 @@ bool IDeviceSettings::setFDBaudrateFor(Network net, int64_t baudrate) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IDeviceSettings::isTerminationSupportedFor(Network net) const {
|
||||||
|
for(const auto& group : getTerminationGroups()) {
|
||||||
|
for(const auto& supportedNet : group) {
|
||||||
|
if(net == supportedNet)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IDeviceSettings::canTerminationBeEnabledFor(Network net) const {
|
||||||
|
if(!settingsLoaded) {
|
||||||
|
report(APIEvent::Type::SettingsReadError, APIEvent::Severity::Error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(disabled) {
|
||||||
|
report(APIEvent::Type::SettingsNotAvailable, APIEvent::Severity::Error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Even though we will not be writing here, if the settings are read only the termination will not be enablable
|
||||||
|
if(readonly) {
|
||||||
|
report(APIEvent::Type::SettingsReadOnly, APIEvent::Severity::Error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reference the mutable termination enables as we want to allow a disable/enable within a group without applying
|
||||||
|
const uint64_t* currentQueuedTerminationEnables = const_cast<IDeviceSettings*>(this)->getMutableTerminationEnables();
|
||||||
|
if(currentQueuedTerminationEnables == nullptr) {
|
||||||
|
report(APIEvent::Type::TerminationNotSupportedDevice, APIEvent::Severity::Error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(const auto& group : getTerminationGroups()) {
|
||||||
|
bool found = false;
|
||||||
|
for(const auto& supportedNet : group) {
|
||||||
|
if(net == supportedNet) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(found) {
|
||||||
|
for(const auto& supportedNet : group) {
|
||||||
|
// Allow termination on the current network even if it's already enabled
|
||||||
|
if(net == supportedNet)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const auto cmNet = supportedNet.getCoreMini();
|
||||||
|
if(!cmNet.has_value() || uint64_t(*cmNet) >= 64) {
|
||||||
|
// Hitting this assert means that a supported network has an invalid CoreMini Network ID
|
||||||
|
assert(false);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this network is enabled, it excludes the queried network from being enabled
|
||||||
|
if((*currentQueuedTerminationEnables >> uint64_t(*cmNet)) & 0x1) {
|
||||||
|
report(APIEvent::Type::AnotherInTerminationGroupEnabled, APIEvent::Severity::Error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
optional<bool> IDeviceSettings::isTerminationEnabledFor(Network net) const {
|
||||||
|
if(!settingsLoaded) {
|
||||||
|
report(APIEvent::Type::SettingsReadError, APIEvent::Severity::Error);
|
||||||
|
return nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(disabled) {
|
||||||
|
report(APIEvent::Type::SettingsNotAvailable, APIEvent::Severity::Error);
|
||||||
|
return nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint64_t* terminationEnables = getTerminationEnables();
|
||||||
|
if(terminationEnables == nullptr) {
|
||||||
|
report(APIEvent::Type::TerminationNotSupportedDevice, APIEvent::Severity::Error);
|
||||||
|
return nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto cmNet = net.getCoreMini();
|
||||||
|
if(!cmNet.has_value() || uint64_t(*cmNet) >= 64 || !isTerminationSupportedFor(net)) {
|
||||||
|
report(APIEvent::Type::TerminationNotSupportedNetwork, APIEvent::Severity::Error);
|
||||||
|
return nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (*terminationEnables >> uint64_t(*cmNet)) & 0x1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IDeviceSettings::setTerminationFor(Network net, bool enabled) {
|
||||||
|
if(!settingsLoaded) {
|
||||||
|
report(APIEvent::Type::SettingsReadError, APIEvent::Severity::Error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(disabled) {
|
||||||
|
report(APIEvent::Type::SettingsNotAvailable, APIEvent::Severity::Error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(readonly) {
|
||||||
|
report(APIEvent::Type::SettingsReadOnly, APIEvent::Severity::Error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t* terminationEnables = getMutableTerminationEnables();
|
||||||
|
if(terminationEnables == nullptr) {
|
||||||
|
report(APIEvent::Type::TerminationNotSupportedDevice, APIEvent::Severity::Error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function reports its own error statuses
|
||||||
|
if(!canTerminationBeEnabledFor(net))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const auto cmNet = net.getCoreMini();
|
||||||
|
if(!cmNet.has_value() || uint8_t(*cmNet) >= 64) {
|
||||||
|
report(APIEvent::Type::TerminationNotSupportedNetwork, APIEvent::Severity::Error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint64_t mask = 1ull << uint8_t(*cmNet);
|
||||||
|
if(enabled)
|
||||||
|
*terminationEnables |= mask;
|
||||||
|
else
|
||||||
|
*terminationEnables &= ~mask;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T> bool IDeviceSettings::applyStructure(const T& newStructure) {
|
template<typename T> bool IDeviceSettings::applyStructure(const T& newStructure) {
|
||||||
if(!settingsLoaded) {
|
if(!settingsLoaded) {
|
||||||
report(APIEvent::Type::SettingsReadError, APIEvent::Severity::Error);
|
report(APIEvent::Type::SettingsReadError, APIEvent::Severity::Error);
|
||||||
|
|
|
||||||
|
|
@ -87,6 +87,7 @@ void printMainMenu() {
|
||||||
printf("I - Set HS CAN to 250K\n");
|
printf("I - Set HS CAN to 250K\n");
|
||||||
printf("J - Set HS CAN to 500K\n");
|
printf("J - Set HS CAN to 500K\n");
|
||||||
printf("L - Set Digital IO\n");
|
printf("L - Set Digital IO\n");
|
||||||
|
printf("M - Set HS CAN termination\n");
|
||||||
printf("X - Exit\n");
|
printf("X - Exit\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -236,7 +237,7 @@ int main() {
|
||||||
while(true) {
|
while(true) {
|
||||||
printMainMenu();
|
printMainMenu();
|
||||||
printf("\n");
|
printf("\n");
|
||||||
char input = getCharInput(24, 'A', 'a', 'B', 'b', 'C', 'c', 'D', 'd', 'E', 'e', 'F', 'f', 'G', 'g', 'H', 'h', 'I', 'i', 'J', 'j', 'L', 'l', 'X', 'x');
|
char input = getCharInput(26, 'A', 'a', 'B', 'b', 'C', 'c', 'D', 'd', 'E', 'e', 'F', 'f', 'G', 'g', 'H', 'h', 'I', 'i', 'J', 'j', 'L', 'l', 'M', 'm', 'X', 'x');
|
||||||
printf("\n");
|
printf("\n");
|
||||||
switch(input) {
|
switch(input) {
|
||||||
// List current devices
|
// List current devices
|
||||||
|
|
@ -699,6 +700,50 @@ int main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
// Set HS CAN termination
|
||||||
|
case 'M':
|
||||||
|
case 'm':
|
||||||
|
{
|
||||||
|
// Select a device and get its description
|
||||||
|
if(numDevices == 0) {
|
||||||
|
printf("No devices found! Please scan for new devices.\n\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
selectedDevice = selectDevice();
|
||||||
|
|
||||||
|
// Get the product description for the device
|
||||||
|
char productDescription[ICSNEO_DEVICETYPE_LONGEST_DESCRIPTION] = {};
|
||||||
|
size_t descriptionLength = ICSNEO_DEVICETYPE_LONGEST_DESCRIPTION;
|
||||||
|
icsneo_describeDevice(selectedDevice, productDescription, &descriptionLength);
|
||||||
|
|
||||||
|
printf("Termination is ");
|
||||||
|
const bool val = icsneo_isTerminationEnabledFor(selectedDevice, ICSNEO_NETID_HSCAN);
|
||||||
|
neoevent_t err = {};
|
||||||
|
if(icsneo_getLastError(&err)) {
|
||||||
|
printf("not available at this time: %s\n\n", err.description);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
printf(val ? "currently enabled\n" : "currently disabled\n");
|
||||||
|
|
||||||
|
printf("[0] Disable\n[1] Enable\n[2] Cancel\n\n");
|
||||||
|
char selection2 = getCharInput(3, '0', '1', '2');
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
if(selection2 == '2') {
|
||||||
|
printf("Canceling!\n\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt to set baudrate and apply settings
|
||||||
|
if(icsneo_setTerminationFor(selectedDevice, ICSNEO_NETID_HSCAN, selection2 == '1') && icsneo_settingsApply(selectedDevice)) {
|
||||||
|
printf("Successfully set HS CAN termination for %s!\n\n", productDescription);
|
||||||
|
} else {
|
||||||
|
printf("Failed to set HS CAN termination for %s!\n\n", productDescription);
|
||||||
|
printLastError();
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
// Exit
|
// Exit
|
||||||
case 'X':
|
case 'X':
|
||||||
case 'x':
|
case 'x':
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,7 @@ void printMainMenu() {
|
||||||
std::cout << "J - Set LSFT CAN to 250K" << std::endl;
|
std::cout << "J - Set LSFT CAN to 250K" << std::endl;
|
||||||
std::cout << "K - Add/Remove a message callback" << std::endl;
|
std::cout << "K - Add/Remove a message callback" << std::endl;
|
||||||
std::cout << "L - Set Digital IO" << std::endl;
|
std::cout << "L - Set Digital IO" << std::endl;
|
||||||
|
std::cout << "M - Set HS CAN termination" << std::endl;
|
||||||
std::cout << "X - Exit" << std::endl;
|
std::cout << "X - Exit" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -192,7 +193,7 @@ int main() {
|
||||||
while(true) {
|
while(true) {
|
||||||
printMainMenu();
|
printMainMenu();
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
char input = getCharInput(std::vector<char> {'A', 'a', 'B', 'b', 'C', 'c', 'D', 'd', 'E', 'e', 'F', 'f', 'G', 'g', 'H', 'h', 'I', 'i', 'J', 'j', 'K', 'k', 'L', 'l', 'X', 'x'});
|
char input = getCharInput(std::vector<char> {'A', 'a', 'B', 'b', 'C', 'c', 'D', 'd', 'E', 'e', 'F', 'f', 'G', 'g', 'H', 'h', 'I', 'i', 'J', 'j', 'K', 'k', 'L', 'l', 'M', 'm', 'X', 'x'});
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
|
|
||||||
switch(input) {
|
switch(input) {
|
||||||
|
|
@ -721,6 +722,44 @@ int main() {
|
||||||
std::cout << "Failure! (" << icsneo::GetLastError() << ")" << std::endl << std::endl;
|
std::cout << "Failure! (" << icsneo::GetLastError() << ")" << std::endl << std::endl;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
// Set HS CAN termination
|
||||||
|
case 'M':
|
||||||
|
case 'm':
|
||||||
|
{
|
||||||
|
// Select a device and get its description
|
||||||
|
if(devices.size() == 0) {
|
||||||
|
std::cout << "No devices found! Please scan for new devices." << std::endl << std::endl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
selectedDevice = selectDevice(devices);
|
||||||
|
|
||||||
|
std::cout << "Termination is ";
|
||||||
|
const auto val = selectedDevice->settings->isTerminationEnabledFor(icsneo::Network::NetID::HSCAN);
|
||||||
|
if(!val.has_value()) {
|
||||||
|
std::cout << "not available at this time: " << icsneo::GetLastError() << std::endl << std::endl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
std::cout << (*val ? "currently enabled" : "currently disabled") << std::endl;
|
||||||
|
|
||||||
|
std::cout << "[0] Disable\n[1] Enable\n[2] Cancel" << std::endl << std::endl;
|
||||||
|
char selection2 = getCharInput({ '0', '1', '2' });
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
if(selection2 == '2') {
|
||||||
|
std::cout << "Canceling!" << std::endl << std::endl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt to set termination and apply settings
|
||||||
|
if(selectedDevice->settings->setTerminationFor(icsneo::Network::NetID::HSCAN, selection2 == '1') && selectedDevice->settings->apply()) {
|
||||||
|
std::cout << "Successfully set HS CAN termination for " << selectedDevice->describe() << std::endl;
|
||||||
|
} else {
|
||||||
|
std::cout << "Failed to set HS CAN termination for " << selectedDevice->describe() << std::endl;
|
||||||
|
std::cout << icsneo::GetLastError() << std::endl;;
|
||||||
|
}
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
break;
|
||||||
// Exit
|
// Exit
|
||||||
case 'X':
|
case 'X':
|
||||||
case 'x':
|
case 'x':
|
||||||
|
|
|
||||||
|
|
@ -73,6 +73,9 @@ public:
|
||||||
RTRNotSupported = 0x2021,
|
RTRNotSupported = 0x2021,
|
||||||
DeviceDisconnected = 0x2022,
|
DeviceDisconnected = 0x2022,
|
||||||
OnlineNotSupported = 0x2023,
|
OnlineNotSupported = 0x2023,
|
||||||
|
TerminationNotSupportedDevice = 0x2024,
|
||||||
|
TerminationNotSupportedNetwork = 0x2025,
|
||||||
|
AnotherInTerminationGroupEnabled = 0x2026,
|
||||||
|
|
||||||
// Transport Events
|
// Transport Events
|
||||||
FailedToRead = 0x3000,
|
FailedToRead = 0x3000,
|
||||||
|
|
|
||||||
|
|
@ -580,6 +580,7 @@ typedef struct {
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
#include "icsneo/communication/communication.h"
|
#include "icsneo/communication/communication.h"
|
||||||
|
#include "icsneo/platform/optional.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
|
||||||
|
|
@ -587,6 +588,8 @@ namespace icsneo {
|
||||||
|
|
||||||
class IDeviceSettings {
|
class IDeviceSettings {
|
||||||
public:
|
public:
|
||||||
|
using TerminationGroup = std::vector<Network>;
|
||||||
|
|
||||||
static constexpr uint16_t GS_VERSION = 5;
|
static constexpr uint16_t GS_VERSION = 5;
|
||||||
static uint16_t CalculateGSChecksum(const std::vector<uint8_t>& settings);
|
static uint16_t CalculateGSChecksum(const std::vector<uint8_t>& settings);
|
||||||
static CANBaudrate GetEnumValueForBaudrate(int64_t baudrate);
|
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) {}
|
IDeviceSettings(std::shared_ptr<Communication> com, size_t size) : com(com), report(com->report), structSize(size) {}
|
||||||
virtual ~IDeviceSettings() {}
|
virtual ~IDeviceSettings() {}
|
||||||
bool ok() { return !disabled && settingsLoaded; }
|
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
|
// 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);
|
bool applyDefaults(bool temporary = false);
|
||||||
|
|
||||||
virtual int64_t getBaudrateFor(Network net) const;
|
virtual int64_t getBaudrateFor(Network net) const;
|
||||||
|
|
@ -648,6 +651,59 @@ public:
|
||||||
return reinterpret_cast<SWCAN_SETTINGS*>((void*)(settings.data() + (offset - settingsInDeviceRAM.data())));
|
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(); }
|
const void* getRawStructurePointer() const { return settingsInDeviceRAM.data(); }
|
||||||
void* getMutableRawStructurePointer() { return settings.data(); }
|
void* getMutableRawStructurePointer() { return settings.data(); }
|
||||||
template<typename T> const T* getStructurePointer() const { return reinterpret_cast<const T*>(getRawStructurePointer()); }
|
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
|
// if settings are disabled for this device. always false unless constructed null
|
||||||
bool disabled = false;
|
bool disabled = false;
|
||||||
|
|
||||||
bool readonly = false;
|
bool readonly = false;
|
||||||
bool disableGSChecksumming = false;
|
bool disableGSChecksumming = false;
|
||||||
|
|
||||||
|
|
@ -679,6 +735,16 @@ protected:
|
||||||
typedef void* warn_t;
|
typedef void* warn_t;
|
||||||
IDeviceSettings(warn_t createInoperableSettings, std::shared_ptr<Communication> com)
|
IDeviceSettings(warn_t createInoperableSettings, std::shared_ptr<Communication> com)
|
||||||
: disabled(true), readonly(true), report(com->report), structSize(0) { (void)createInoperableSettings; }
|
: 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;
|
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;
|
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;
|
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 {
|
typedef struct {
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,21 @@ public:
|
||||||
return nullptr;
|
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;
|
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;
|
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;
|
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;
|
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);
|
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
|
#ifdef __cplusplus
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
#endif
|
#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);
|
typedef bool(*fn_icsneo_setDigitalIO)(const neodevice_t* device, neoio_t type, uint32_t number, bool value);
|
||||||
fn_icsneo_setDigitalIO icsneo_setDigitalIO;
|
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_IMPORT(func) func = (fn_##func)icsneo_dynamicLibraryGetFunction(icsneo_libraryHandle, #func)
|
||||||
#define ICSNEO_IMPORTASSERT(func) if((ICSNEO_IMPORT(func)) == NULL) return 3
|
#define ICSNEO_IMPORTASSERT(func) if((ICSNEO_IMPORT(func)) == NULL) return 3
|
||||||
void* icsneo_libraryHandle = NULL;
|
void* icsneo_libraryHandle = NULL;
|
||||||
|
|
@ -958,6 +1024,10 @@ int icsneo_init() {
|
||||||
ICSNEO_IMPORTASSERT(icsneo_getTimestampResolution);
|
ICSNEO_IMPORTASSERT(icsneo_getTimestampResolution);
|
||||||
ICSNEO_IMPORTASSERT(icsneo_getDigitalIO);
|
ICSNEO_IMPORTASSERT(icsneo_getDigitalIO);
|
||||||
ICSNEO_IMPORTASSERT(icsneo_setDigitalIO);
|
ICSNEO_IMPORTASSERT(icsneo_setDigitalIO);
|
||||||
|
ICSNEO_IMPORTASSERT(icsneo_isTerminationSupportedFor);
|
||||||
|
ICSNEO_IMPORTASSERT(icsneo_canTerminationBeEnabledFor);
|
||||||
|
ICSNEO_IMPORTASSERT(icsneo_isTerminationEnabledFor);
|
||||||
|
ICSNEO_IMPORTASSERT(icsneo_setTerminationFor);
|
||||||
|
|
||||||
icsneo_initialized = true;
|
icsneo_initialized = true;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue