From 5f16adc103f880708b3bd0093a2e96fe03f59c26 Mon Sep 17 00:00:00 2001 From: Thomas Stoddard Date: Wed, 28 Jan 2026 21:00:39 +0000 Subject: [PATCH] Device: RADComet3: Add Ethernet settings --- .../icsneopy/device/idevicesettings.cpp | 30 +- include/icsneo/device/idevicesettings.h | 222 +++++++++++- .../device/tree/radcomet3/radcomet3settings.h | 342 +++++++++++++++++- .../tree/radepsilon/radepsilonsettings.h | 53 +-- 4 files changed, 588 insertions(+), 59 deletions(-) diff --git a/bindings/python/icsneopy/device/idevicesettings.cpp b/bindings/python/icsneopy/device/idevicesettings.cpp index 6f9c2a3..96a92cf 100644 --- a/bindings/python/icsneopy/device/idevicesettings.cpp +++ b/bindings/python/icsneopy/device/idevicesettings.cpp @@ -12,7 +12,6 @@ namespace icsneo { struct DeviceSettingsNamespace { using EthLinkMode = AELinkMode; - using LinkSpeed = EthLinkSpeed; }; void init_idevicesettings(pybind11::module_& m) { @@ -23,13 +22,17 @@ void init_idevicesettings(pybind11::module_& m) { .value("Slave", DeviceSettingsNamespace::EthLinkMode::AE_LINK_SLAVE) .value("Master", DeviceSettingsNamespace::EthLinkMode::AE_LINK_MASTER); - pybind11::enum_(settings, "EthernetLinkSpeed") - .value("Speed10M", DeviceSettingsNamespace::LinkSpeed::ETH_SPEED_10) - .value("Speed100M", DeviceSettingsNamespace::LinkSpeed::ETH_SPEED_100) - .value("Speed1G", DeviceSettingsNamespace::LinkSpeed::ETH_SPEED_1000) - .value("Speed2_5G", DeviceSettingsNamespace::LinkSpeed::ETH_SPEED_2500) - .value("Speed5G", DeviceSettingsNamespace::LinkSpeed::ETH_SPEED_5000) - .value("Speed10G", DeviceSettingsNamespace::LinkSpeed::ETH_SPEED_10000); + pybind11::enum_(settings, "PhyLinkMode") + .value("ETH_LINK_MODE_AUTO_NEGOTIATION", ETH_LINK_MODE_AUTO_NEGOTIATION) + .value("ETH_LINK_MODE_10MBPS_HALFDUPLEX", ETH_LINK_MODE_10MBPS_HALFDUPLEX) + .value("ETH_LINK_MODE_10MBPS_FULLDUPLEX", ETH_LINK_MODE_10MBPS_FULLDUPLEX) + .value("ETH_LINK_MODE_100MBPS_HALFDUPLEX", ETH_LINK_MODE_100MBPS_HALFDUPLEX) + .value("ETH_LINK_MODE_100MBPS_FULLDUPLEX", ETH_LINK_MODE_100MBPS_FULLDUPLEX) + .value("ETH_LINK_MODE_1GBPS_HALFDUPLEX", ETH_LINK_MODE_1GBPS_HALFDUPLEX) + .value("ETH_LINK_MODE_1GBPS_FULLDUPLEX", ETH_LINK_MODE_1GBPS_FULLDUPLEX) + .value("ETH_LINK_MODE_2_5GBPS_FULLDUPLEX", ETH_LINK_MODE_2_5GBPS_FULLDUPLEX) + .value("ETH_LINK_MODE_5GBPS_FULLDUPLEX", ETH_LINK_MODE_5GBPS_FULLDUPLEX) + .value("ETH_LINK_MODE_10GBPS_FULLDUPLEX", ETH_LINK_MODE_10GBPS_FULLDUPLEX); pybind11::enum_(settings, "LINMode") .value("Sleep", LINMode::SLEEP_MODE) @@ -63,7 +66,7 @@ void init_idevicesettings(pybind11::module_& m) { .def("get_lin_commander_response_time", &IDeviceSettings::getLINCommanderResponseTimeFor, pybind11::call_guard()) .def("set_lin_commander_response_time", &IDeviceSettings::setLINCommanderResponseTimeFor, pybind11::call_guard()) - // Ethernet PHY methods + // Ethernet PHY methods (index-based for switch devices) .def("get_phy_enable", &IDeviceSettings::getPhyEnable, pybind11::call_guard()) .def("get_phy_mode", &IDeviceSettings::getPhyMode, pybind11::call_guard()) .def("get_phy_speed", &IDeviceSettings::getPhySpeed, pybind11::call_guard()) @@ -71,6 +74,15 @@ void init_idevicesettings(pybind11::module_& m) { .def("set_phy_mode", &IDeviceSettings::setPhyMode, pybind11::call_guard()) .def("set_phy_speed", &IDeviceSettings::setPhySpeed, pybind11::call_guard()) + // Ethernet PHY methods (network-based for multi-interface devices) + .def("get_phy_enable_for", &IDeviceSettings::getPhyEnableFor, pybind11::call_guard()) + .def("get_phy_role_for", &IDeviceSettings::getPhyRoleFor, pybind11::call_guard()) + .def("get_phy_link_mode_for", &IDeviceSettings::getPhyLinkModeFor, pybind11::call_guard()) + .def("set_phy_enable_for", &IDeviceSettings::setPhyEnableFor, pybind11::call_guard()) + .def("set_phy_role_for", &IDeviceSettings::setPhyRoleFor, pybind11::call_guard()) + .def("set_phy_link_mode_for", &IDeviceSettings::setPhyLinkModeFor, pybind11::call_guard()) + .def("get_supported_phy_link_modes_for", &IDeviceSettings::getSupportedPhyLinkModesFor, pybind11::call_guard()) + // 10BASE-T1S methods .def("is_t1s_plca_enabled", &IDeviceSettings::isT1SPLCAEnabledFor, pybind11::call_guard()) .def("set_t1s_plca", &IDeviceSettings::setT1SPLCAFor, pybind11::call_guard()) diff --git a/include/icsneo/device/idevicesettings.h b/include/icsneo/device/idevicesettings.h index 35443c7..251dca8 100644 --- a/include/icsneo/device/idevicesettings.h +++ b/include/icsneo/device/idevicesettings.h @@ -54,14 +54,18 @@ enum AELinkMode AE_LINK_SLAVE }; -enum EthLinkSpeed +enum EthPhyLinkMode { - ETH_SPEED_10 = 0, - ETH_SPEED_100, - ETH_SPEED_1000, - ETH_SPEED_2500, - ETH_SPEED_5000, - ETH_SPEED_10000, + ETH_LINK_MODE_AUTO_NEGOTIATION = 0, + ETH_LINK_MODE_10MBPS_HALFDUPLEX, + ETH_LINK_MODE_10MBPS_FULLDUPLEX, + ETH_LINK_MODE_100MBPS_HALFDUPLEX, + ETH_LINK_MODE_100MBPS_FULLDUPLEX, + ETH_LINK_MODE_1GBPS_HALFDUPLEX, + ETH_LINK_MODE_1GBPS_FULLDUPLEX, + ETH_LINK_MODE_2_5GBPS_FULLDUPLEX, + ETH_LINK_MODE_5GBPS_FULLDUPLEX, + ETH_LINK_MODE_10GBPS_FULLDUPLEX }; typedef struct @@ -69,7 +73,7 @@ typedef struct uint16_t networkId; uint8_t linkStatus; uint8_t linkFullDuplex; - uint8_t linkSpeed; // see EthLinkSpeed + uint8_t linkSpeed; // 0=10Mbps, 1=100Mbps, 2=1Gbps, 3=2.5Gbps, 4=5Gbps, 5=10Gbps int8_t linkMode; // for automotive networks - see AELinkMode } EthernetNetworkStatus; @@ -366,6 +370,11 @@ typedef struct SERDESGEN_SETTINGS_t #define ETHERNET_SETTINGS2_FLAG_DEVICE_HOSTING_ENABLE 0x10 #define ETHERNET_SETTINGS2_FLAG_COMM_IN_USE 0x80 +// ETHERNET_SETTINGS2 flags2 bit definitions +#define ETHERNET_SETTINGS2_FLAGS2_LINK_MODE_SLAVE 0x01 // bit0: 0=master, 1=slave +#define ETHERNET_SETTINGS2_FLAGS2_PHY_MODE_LEGACY 0x02 // bit1: 0=IEEE, 1=legacy +#define ETHERNET_SETTINGS2_FLAGS2_LINK_MODE_AUTO 0x04 // bit2: auto master/slave negotiation + typedef struct ETHERNET_SETTINGS2_t { /* bit0: 0=half duplex, 1=full duplex @@ -379,7 +388,13 @@ typedef struct ETHERNET_SETTINGS2_t uint32_t ip_addr; uint32_t netmask; uint32_t gateway; - uint8_t rsvd[2]; + /* FLAGS2 + * bit0: link mode - 0=master, 1=slave + * bit1: PHY mode - 0=IEEE, 1=legacy + * bit2: auto master/slave + */ + uint8_t flags2; + uint8_t rsvd; } ETHERNET_SETTINGS2; #define ETHERNET_SETTINGS2_SIZE 16 @@ -808,6 +823,26 @@ public: return reinterpret_cast((void*)(settings.data() + (offset - settingsInDeviceRAM.data()))); } + virtual const ETHERNET_SETTINGS2* getEthernetSettingsFor(Network net) const { (void)net; return nullptr; } + ETHERNET_SETTINGS2* getMutableEthernetSettingsFor(Network net) { + if(disabled || readonly) + return nullptr; + const uint8_t* offset = (const uint8_t*)getEthernetSettingsFor(net); + if(offset == nullptr) + return nullptr; + return reinterpret_cast((void*)(settings.data() + (offset - settingsInDeviceRAM.data()))); + } + + virtual const AE_SETTINGS* getAESettingsFor(Network net) const { (void)net; return nullptr; } + AE_SETTINGS* getMutableAESettingsFor(Network net) { + if(disabled || readonly) + return nullptr; + const uint8_t* offset = (const uint8_t*)getAESettingsFor(net); + if(offset == nullptr) + return nullptr; + return reinterpret_cast((void*)(settings.data() + (offset - settingsInDeviceRAM.data()))); + } + /** * Some devices have groupings of networks, where software * switchable termination can only be applied to one network @@ -908,39 +943,176 @@ public: */ bool setLINCommanderResponseTimeFor(Network net, uint8_t bits); + /** + * Set PHY role (Master/Slave/Auto) for switch devices (Epsilon/XL, Jupiter, etc) using port index. + * For all other devices, use setPhyRoleFor() instead. + * + * @param index Port index (0-based) + * @param mode Master/Slave/Auto role + * @return true if successful + */ virtual bool setPhyMode(uint8_t index, AELinkMode mode) { (void)index, (void)mode; return false; } + /** + * Enable/disable PHY for switch devices (Epsilon/XL, Jupiter, etc) using port index. + * For all other devices, use setPhyEnableFor() instead. + * + * @param index Port index (0-based) + * @param enable True to enable, false to disable + * @return true if successful + */ virtual bool setPhyEnable(uint8_t index, bool enable) { (void)index, (void)enable; return false; } - virtual bool setPhySpeed(uint8_t index, EthLinkSpeed speed) { - (void)index, (void)speed; + /** + * Set PHY link mode (speed and duplex) for switch devices (Epsilon/XL, Jupiter, etc) using port index. + * For all other devices, use setPhyLinkModeFor() instead. + * + * @param index Port index (0-based) + * @param mode Link mode (speed + duplex combination) + * @return true if successful + */ + virtual bool setPhySpeed(uint8_t index, EthPhyLinkMode mode) { + (void)index, (void)mode; return false; } + /** + * Get PHY role (Master/Slave/Auto) for switch devices (Epsilon/XL, Jupiter, etc) using port index. + * For all other devices, use getPhyRoleFor() instead. + * + * @param index Port index (0-based) + * @return Current role, or nullopt if not available + */ virtual std::optional getPhyMode(uint8_t index) { (void)index; report(APIEvent::Type::SettingNotAvaiableDevice, APIEvent::Severity::EventWarning); return std::nullopt; } + /** + * Get PHY enable state for switch devices (Epsilon/XL, Jupiter, etc) using port index. + * For all other devices, use getPhyEnableFor() instead. + * + * @param index Port index (0-based) + * @return True if enabled, false if disabled, nullopt if not available + */ virtual std::optional getPhyEnable(uint8_t index) { (void)index; report(APIEvent::Type::SettingNotAvaiableDevice, APIEvent::Severity::EventWarning); return std::nullopt; } - virtual std::optional getPhySpeed(uint8_t index) { + /** + * Get PHY link mode (speed and duplex) for switch devices (Epsilon/XL, Jupiter, etc) using port index. + * For all other devices, use getPhyLinkModeFor() instead. + * + * @param index Port index (0-based) + * @return Current link mode, or nullopt if not available + */ + virtual std::optional getPhySpeed(uint8_t index) { (void)index; report(APIEvent::Type::SettingNotAvaiableDevice, APIEvent::Severity::EventWarning); return std::nullopt; } + /** + * Set PHY role (Master/Slave/Auto) for network-based devices. + * For switch devices, use setPhyMode() with port index instead. + * + * @param net Network ID + * @param mode Master/Slave/Auto role + * @return true if successful + */ + virtual bool setPhyRoleFor(Network net, AELinkMode mode) { + (void)net, (void)mode; + report(APIEvent::Type::SettingNotAvaiableDevice, APIEvent::Severity::EventWarning); + return false; + } + + /** + * Enable/disable PHY for network-based devices. + * For switch devices, use setPhyEnable() with port index instead. + * + * @param net Network ID + * @param enable True to enable, false to disable + * @return true if successful + */ + virtual bool setPhyEnableFor(Network net, bool enable) { + (void)net, (void)enable; + report(APIEvent::Type::SettingNotAvaiableDevice, APIEvent::Severity::EventWarning); + return false; + } + + /** + * Get PHY role (Master/Slave/Auto) for network-based devices. + * For switch devices, use getPhyMode() with port index instead. + * + * @param net Network ID + * @return Current role, or nullopt if not available + */ + virtual std::optional getPhyRoleFor(Network net) const { + (void)net; + report(APIEvent::Type::SettingNotAvaiableDevice, APIEvent::Severity::EventWarning); + return std::nullopt; + } + + /** + * Get PHY enable state for network-based devices. + + * For switch devices, use getPhyEnable() with port index instead. + * + * @param net Network ID + * @return True if enabled, false if disabled, nullopt if not available + */ + virtual std::optional getPhyEnableFor(Network net) const { + (void)net; + report(APIEvent::Type::SettingNotAvaiableDevice, APIEvent::Severity::EventWarning); + return std::nullopt; + } + + /** + * Get supported PHY link modes (combined speed+duplex) for a network. + * Each mode represents a valid hardware configuration. + * + * @param net The network to query + * @return Vector of supported modes, empty if network doesn't support PHY settings + */ + virtual std::vector getSupportedPhyLinkModesFor(Network net) const { + (void)net; + return {}; // Default: no PHY support + } + + /** + * Set PHY link mode (speed and duplex together). + * + * @param net The network to configure + * @param mode The link mode to set + * @return true if successful, false if mode not supported or error occurred + */ + virtual bool setPhyLinkModeFor(Network net, EthPhyLinkMode mode) { + (void)net; (void)mode; + report(APIEvent::Type::SettingNotAvaiableDevice, APIEvent::Severity::EventWarning); + return false; + } + + /** + * Get current PHY link mode. + * + * @param net The network to query + * @return Current link mode, or nullopt if not available or not configured + */ + virtual std::optional getPhyLinkModeFor(Network net) const { + (void)net; + report(APIEvent::Type::SettingNotAvaiableDevice, APIEvent::Severity::EventWarning); + return std::nullopt; + } + virtual std::optional isT1SPLCAEnabledFor(Network net) const { (void)net; report(APIEvent::Type::SettingNotAvaiableDevice, APIEvent::Severity::EventWarning); @@ -1049,6 +1221,32 @@ protected: return nullptr; return reinterpret_cast((void*)(settings.data() + (offset - settingsInDeviceRAM.data()))); } + + static bool SetNetworkEnabled(uint64_t* bitfields, size_t count, uint64_t networkID) { + const size_t index = networkID / 64; + const size_t offset = networkID & 0x3F; + if (index >= count) + return false; + bitfields[index] |= (1ULL << offset); + return true; + } + + static bool ClearNetworkEnabled(uint64_t* bitfields, size_t count, uint64_t networkID) { + const size_t index = networkID / 64; + const size_t offset = networkID & 0x3F; + if (index >= count) + return false; + bitfields[index] &= ~(1ULL << offset); + return true; + } + + static bool GetNetworkEnabled(const uint64_t* bitfields, size_t count, uint64_t networkID) { + const size_t index = networkID / 64; + const size_t offset = networkID & 0x3F; + if (index >= count) + return false; + return (bitfields[index] & (1ULL << offset)) != 0; + } }; } diff --git a/include/icsneo/device/tree/radcomet3/radcomet3settings.h b/include/icsneo/device/tree/radcomet3/radcomet3settings.h index d2d6fb5..6bec32f 100644 --- a/include/icsneo/device/tree/radcomet3/radcomet3settings.h +++ b/include/icsneo/device/tree/radcomet3/radcomet3settings.h @@ -114,11 +114,49 @@ public: } } + const ETHERNET_SETTINGS2* getEthernetSettingsFor(Network net) const override { + auto cfg = getStructurePointer(); + if(cfg == nullptr) + return nullptr; + switch(net.getNetID()) { + case Network::NetID::ETHERNET_01: + return &(cfg->ethernet); + case Network::NetID::AE_01: + return &(cfg->ethT1); + case Network::NetID::AE_02: + return &(cfg->ethT1s1); + case Network::NetID::AE_03: + return &(cfg->ethT1s2); + case Network::NetID::AE_04: + return &(cfg->ethT1s3); + case Network::NetID::AE_05: + return &(cfg->ethT1s4); + case Network::NetID::AE_06: + return &(cfg->ethT1s5); + case Network::NetID::AE_07: + return &(cfg->ethT1s6); + default: + return nullptr; + } + } + + const AE_SETTINGS* getAESettingsFor(Network net) const override { + auto cfg = getStructurePointer(); + if(cfg == nullptr) + return nullptr; + switch(net.getNetID()) { + case Network::NetID::AE_01: + return &(cfg->ae_01); + default: + return nullptr; + } + } + std::optional isT1SPLCAEnabledFor(Network net) const override { const ETHERNET10T1S_SETTINGS* t1s = getT1SSettingsFor(net); if(t1s == nullptr) return std::nullopt; - + return std::make_optional((t1s->flags & ETHERNET10T1S_SETTINGS_FLAG_ENABLE_PLCA) != 0); } @@ -126,12 +164,12 @@ public: ETHERNET10T1S_SETTINGS* t1s = getMutableT1SSettingsFor(net); if(t1s == nullptr) return false; - + if(enable) t1s->flags |= ETHERNET10T1S_SETTINGS_FLAG_ENABLE_PLCA; else t1s->flags &= ~ETHERNET10T1S_SETTINGS_FLAG_ENABLE_PLCA; - + return true; } @@ -139,7 +177,7 @@ public: const ETHERNET10T1S_SETTINGS* t1s = getT1SSettingsFor(net); if(t1s == nullptr) return std::nullopt; - + return std::make_optional(t1s->local_id); } @@ -147,7 +185,7 @@ public: ETHERNET10T1S_SETTINGS* t1s = getMutableT1SSettingsFor(net); if(t1s == nullptr) return false; - + t1s->local_id = id; return true; } @@ -156,7 +194,7 @@ public: const ETHERNET10T1S_SETTINGS* t1s = getT1SSettingsFor(net); if(t1s == nullptr) return std::nullopt; - + return std::make_optional(t1s->max_num_nodes); } @@ -164,7 +202,7 @@ public: ETHERNET10T1S_SETTINGS* t1s = getMutableT1SSettingsFor(net); if(t1s == nullptr) return false; - + t1s->max_num_nodes = nodes; return true; } @@ -173,7 +211,7 @@ public: const ETHERNET10T1S_SETTINGS* t1s = getT1SSettingsFor(net); if(t1s == nullptr) return std::nullopt; - + return std::make_optional(t1s->to_timer); } @@ -181,7 +219,7 @@ public: ETHERNET10T1S_SETTINGS* t1s = getMutableT1SSettingsFor(net); if(t1s == nullptr) return false; - + t1s->to_timer = timer; return true; } @@ -190,7 +228,7 @@ public: const ETHERNET10T1S_SETTINGS* t1s = getT1SSettingsFor(net); if(t1s == nullptr) return std::nullopt; - + return std::make_optional(t1s->max_burst_count); } @@ -198,7 +236,7 @@ public: ETHERNET10T1S_SETTINGS* t1s = getMutableT1SSettingsFor(net); if(t1s == nullptr) return false; - + t1s->max_burst_count = burst; return true; } @@ -207,7 +245,7 @@ public: const ETHERNET10T1S_SETTINGS* t1s = getT1SSettingsFor(net); if(t1s == nullptr) return std::nullopt; - + return std::make_optional(t1s->burst_timer); } @@ -215,17 +253,291 @@ public: ETHERNET10T1S_SETTINGS* t1s = getMutableT1SSettingsFor(net); if(t1s == nullptr) return false; - + t1s->burst_timer = timer; return true; } + bool setPhyRoleFor(Network net, AELinkMode mode) override { + if (mode != AE_LINK_AUTO && mode != AE_LINK_MASTER && mode != AE_LINK_SLAVE) { + report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error); + return false; + } + + AE_SETTINGS* ae = getMutableAESettingsFor(net); + if (ae == nullptr) { + report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error); + return false; + } + + ae->ucConfigMode = static_cast(mode); + + ETHERNET_SETTINGS2* ethSettings = getMutableEthernetSettingsFor(net); + if (ethSettings == nullptr) { + return false; + } + + uint8_t& flags2 = ethSettings->flags2; + + switch (mode) { + case AE_LINK_AUTO: + flags2 |= ETHERNET_SETTINGS2_FLAGS2_LINK_MODE_AUTO; + break; + case AE_LINK_MASTER: + flags2 &= ~ETHERNET_SETTINGS2_FLAGS2_LINK_MODE_AUTO; + flags2 &= ~ETHERNET_SETTINGS2_FLAGS2_LINK_MODE_SLAVE; + break; + case AE_LINK_SLAVE: + flags2 &= ~ETHERNET_SETTINGS2_FLAGS2_LINK_MODE_AUTO; + flags2 |= ETHERNET_SETTINGS2_FLAGS2_LINK_MODE_SLAVE; + break; + } + + return true; + } + + bool setPhyEnableFor(Network net, bool enable) override { + auto cfg = getMutableStructurePointer(); + if (cfg == nullptr) + return false; + + if (net.getType() != Network::Type::Ethernet && net.getType() != Network::Type::AutomotiveEthernet) { + report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error); + return false; + } + + auto coreMini = net.getCoreMini(); + if (!coreMini.has_value()) { + report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error); + return false; + } + + const uint64_t networkID = static_cast(coreMini.value()); + uint64_t bitfields[2] = { cfg->network_enables, cfg->network_enables_2 }; + const bool success = enable ? + SetNetworkEnabled(bitfields, 2, networkID) : + ClearNetworkEnabled(bitfields, 2, networkID); + + if (!success) { + report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error); + return false; + } + + cfg->network_enables = bitfields[0]; + cfg->network_enables_2 = bitfields[1]; + + return true; + } + + std::optional getPhyRoleFor(Network net) const override { + const AE_SETTINGS* ae = getAESettingsFor(net); + if (ae == nullptr) { + report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error); + return std::nullopt; + } + + switch (ae->ucConfigMode) { + case 0: + return std::make_optional(AE_LINK_AUTO); + case 1: + return std::make_optional(AE_LINK_MASTER); + case 2: + return std::make_optional(AE_LINK_SLAVE); + default: + return std::make_optional(AE_LINK_AUTO); + } + } + + std::optional getPhyEnableFor(Network net) const override { + auto cfg = getStructurePointer(); + if (cfg == nullptr) { + report(APIEvent::Type::SettingsReadError, APIEvent::Severity::Error); + return std::nullopt; + } + + if (net.getType() != Network::Type::Ethernet && net.getType() != Network::Type::AutomotiveEthernet) { + report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error); + return std::nullopt; + } + + auto coreMini = net.getCoreMini(); + if (!coreMini.has_value()) { + report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error); + return std::nullopt; + } + + const uint64_t networkID = static_cast(coreMini.value()); + const uint64_t bitfields[2] = { cfg->network_enables, cfg->network_enables_2 }; + return GetNetworkEnabled(bitfields, 2, networkID); + } + + std::vector getSupportedPhyLinkModesFor(Network net) const override { + switch(net.getNetID()) { + case Network::NetID::ETHERNET_01: + return { + ETH_LINK_MODE_AUTO_NEGOTIATION, + ETH_LINK_MODE_10MBPS_FULLDUPLEX, + ETH_LINK_MODE_100MBPS_FULLDUPLEX, + ETH_LINK_MODE_1GBPS_FULLDUPLEX + }; + + case Network::NetID::AE_01: + return { + ETH_LINK_MODE_AUTO_NEGOTIATION, + ETH_LINK_MODE_100MBPS_FULLDUPLEX, + ETH_LINK_MODE_1GBPS_FULLDUPLEX + }; + + case Network::NetID::AE_02: + case Network::NetID::AE_03: + case Network::NetID::AE_04: + case Network::NetID::AE_05: + case Network::NetID::AE_06: + case Network::NetID::AE_07: + return {ETH_LINK_MODE_10MBPS_HALFDUPLEX}; + + default: + return {}; + } + } + + bool setPhyLinkModeFor(Network net, EthPhyLinkMode mode) override { + auto supported = getSupportedPhyLinkModesFor(net); + if (std::find(supported.begin(), supported.end(), mode) == supported.end()) { + report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error); + return false; + } + + auto cfg = getMutableStructurePointer(); + if (cfg == nullptr) + return false; + + if (net.getNetID() == Network::NetID::AE_01) { + AE_SETTINGS* ae = getMutableAESettingsFor(net); + if (ae == nullptr) { + report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error); + return false; + } + + switch (mode) { + case ETH_LINK_MODE_AUTO_NEGOTIATION: + ae->link_spd = 3; + cfg->ethT1.link_speed = 2; + cfg->ethT1.flags |= ETHERNET_SETTINGS2_FLAG_AUTO_NEG; + cfg->ethT1.flags |= ETHERNET_SETTINGS2_FLAG_FULL_DUPLEX; + break; + case ETH_LINK_MODE_100MBPS_FULLDUPLEX: + ae->link_spd = 1; + cfg->ethT1.link_speed = 1; + cfg->ethT1.flags &= ~ETHERNET_SETTINGS2_FLAG_AUTO_NEG; + cfg->ethT1.flags |= ETHERNET_SETTINGS2_FLAG_FULL_DUPLEX; + break; + case ETH_LINK_MODE_1GBPS_FULLDUPLEX: + ae->link_spd = 2; + cfg->ethT1.link_speed = 2; + cfg->ethT1.flags &= ~ETHERNET_SETTINGS2_FLAG_AUTO_NEG; + cfg->ethT1.flags |= ETHERNET_SETTINGS2_FLAG_FULL_DUPLEX; + break; + default: + report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error); + return false; + } + + } else if (net.getNetID() == Network::NetID::ETHERNET_01) { + switch (mode) { + case ETH_LINK_MODE_AUTO_NEGOTIATION: + cfg->ethernet.flags |= ETHERNET_SETTINGS2_FLAG_AUTO_NEG; + cfg->ethernet.link_speed = 2; + cfg->ethernet.flags |= ETHERNET_SETTINGS2_FLAG_FULL_DUPLEX; + break; + case ETH_LINK_MODE_10MBPS_FULLDUPLEX: + cfg->ethernet.link_speed = 0; + cfg->ethernet.flags &= ~ETHERNET_SETTINGS2_FLAG_AUTO_NEG; + cfg->ethernet.flags |= ETHERNET_SETTINGS2_FLAG_FULL_DUPLEX; + break; + case ETH_LINK_MODE_100MBPS_FULLDUPLEX: + cfg->ethernet.link_speed = 1; + cfg->ethernet.flags &= ~ETHERNET_SETTINGS2_FLAG_AUTO_NEG; + cfg->ethernet.flags |= ETHERNET_SETTINGS2_FLAG_FULL_DUPLEX; + break; + case ETH_LINK_MODE_1GBPS_FULLDUPLEX: + cfg->ethernet.link_speed = 2; + cfg->ethernet.flags &= ~ETHERNET_SETTINGS2_FLAG_AUTO_NEG; + cfg->ethernet.flags |= ETHERNET_SETTINGS2_FLAG_FULL_DUPLEX; + break; + default: + report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error); + return false; + } + } + + return true; + } + + std::optional getPhyLinkModeFor(Network net) const override { + auto cfg = getStructurePointer(); + if (cfg == nullptr) { + report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error); + return std::nullopt; + } + + if (net.getNetID() == Network::NetID::ETHERNET_01) { + if (cfg->ethernet.flags & ETHERNET_SETTINGS2_FLAG_AUTO_NEG) { + return ETH_LINK_MODE_AUTO_NEGOTIATION; + } + + bool fullDuplex = (cfg->ethernet.flags & ETHERNET_SETTINGS2_FLAG_FULL_DUPLEX) != 0; + + switch (cfg->ethernet.link_speed) { + case 0: + return fullDuplex ? ETH_LINK_MODE_10MBPS_FULLDUPLEX + : ETH_LINK_MODE_10MBPS_HALFDUPLEX; + case 1: + return fullDuplex ? ETH_LINK_MODE_100MBPS_FULLDUPLEX + : ETH_LINK_MODE_100MBPS_HALFDUPLEX; + case 2: + return fullDuplex ? ETH_LINK_MODE_1GBPS_FULLDUPLEX + : ETH_LINK_MODE_1GBPS_HALFDUPLEX; + default: + report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error); + return std::nullopt; + } + + } else if (net.getNetID() == Network::NetID::AE_01) { + const AE_SETTINGS* ae = &cfg->ae_01; + + // Check auto-negotiate + if (ae->link_spd == 3 || (cfg->ethT1.flags & ETHERNET_SETTINGS2_FLAG_AUTO_NEG)) { + return ETH_LINK_MODE_AUTO_NEGOTIATION; + } + + // T1 is always full-duplex + switch (ae->link_spd) { + case 1: // 100 Mbps + return ETH_LINK_MODE_100MBPS_FULLDUPLEX; + case 2: // 1000 Mbps + return ETH_LINK_MODE_1GBPS_FULLDUPLEX; + default: + report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error); + return std::nullopt; + } + + } else if (net.getNetID() >= Network::NetID::AE_02 && net.getNetID() <= Network::NetID::AE_07) { + // 10BASE-T1S ports - half-duplex only + return ETH_LINK_MODE_10MBPS_HALFDUPLEX; + + } else { + report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error); + return std::nullopt; + } + } + private: const ETHERNET10T1S_SETTINGS* getT1SSettingsFor(Network net) const { auto cfg = getStructurePointer(); if(cfg == nullptr) return nullptr; - + switch(net.getNetID()) { case Network::NetID::AE_02: return &(cfg->t1s1); case Network::NetID::AE_03: return &(cfg->t1s2); @@ -243,7 +555,7 @@ private: auto cfg = getMutableStructurePointer(); if(cfg == nullptr) return nullptr; - + switch(net.getNetID()) { case Network::NetID::AE_02: return &(cfg->t1s1); case Network::NetID::AE_03: return &(cfg->t1s2); diff --git a/include/icsneo/device/tree/radepsilon/radepsilonsettings.h b/include/icsneo/device/tree/radepsilon/radepsilonsettings.h index dc564c5..c9c9bee 100644 --- a/include/icsneo/device/tree/radepsilon/radepsilonsettings.h +++ b/include/icsneo/device/tree/radepsilon/radepsilonsettings.h @@ -168,7 +168,7 @@ public: return true; } - bool setPhySpeed(uint8_t index, EthLinkSpeed speed) override { + bool setPhySpeed(uint8_t index, EthPhyLinkMode mode) override { if (index > RADEPSILON_MAX_PHY) { report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error); return false; @@ -178,19 +178,30 @@ public: return false; } EpsilonPhySpeed epsilonSpeed; - switch (speed) { + switch (mode) { + case ETH_LINK_MODE_AUTO_NEGOTIATION: + // Auto-negotiate - default to 1G base speed + epsilonSpeed = EpsilonPhySpeed::Speed1000; + break; + case ETH_LINK_MODE_100MBPS_FULLDUPLEX: + epsilonSpeed = EpsilonPhySpeed::Speed100; + break; + case ETH_LINK_MODE_1GBPS_FULLDUPLEX: + epsilonSpeed = EpsilonPhySpeed::Speed1000; + break; + case ETH_LINK_MODE_10GBPS_FULLDUPLEX: + epsilonSpeed = EpsilonPhySpeed::Speed10000; + break; + // Reject half-duplex modes - automotive T1 is full-duplex only + case ETH_LINK_MODE_10MBPS_HALFDUPLEX: + case ETH_LINK_MODE_10MBPS_FULLDUPLEX: + case ETH_LINK_MODE_100MBPS_HALFDUPLEX: + case ETH_LINK_MODE_1GBPS_HALFDUPLEX: + case ETH_LINK_MODE_2_5GBPS_FULLDUPLEX: + case ETH_LINK_MODE_5GBPS_FULLDUPLEX: default: report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error); return false; - case ETH_SPEED_100: - epsilonSpeed = EpsilonPhySpeed::Speed100; - break; - case ETH_SPEED_1000: - epsilonSpeed = EpsilonPhySpeed::Speed1000; - break; - case ETH_SPEED_10000: - epsilonSpeed = EpsilonPhySpeed::Speed10000; - break; } cfg->switchSettings.speed[index] = static_cast(epsilonSpeed); return true; @@ -235,7 +246,7 @@ public: return std::make_optional(static_cast(cfg->switchSettings.enablePhy[index])); } - std::optional getPhySpeed(uint8_t index) override { + std::optional getPhySpeed(uint8_t index) override { if (index > RADEPSILON_MAX_PHY) { report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error); return std::nullopt; @@ -244,22 +255,18 @@ public: if (cfg == nullptr) { return std::nullopt; } - EthLinkSpeed speed; + // Automotive Ethernet T1 is always full-duplex switch (static_cast(cfg->switchSettings.speed[index])) { + case EpsilonPhySpeed::Speed100: + return ETH_LINK_MODE_100MBPS_FULLDUPLEX; + case EpsilonPhySpeed::Speed1000: + return ETH_LINK_MODE_1GBPS_FULLDUPLEX; + case EpsilonPhySpeed::Speed10000: + return ETH_LINK_MODE_10GBPS_FULLDUPLEX; default: report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error); return std::nullopt; - case EpsilonPhySpeed::Speed100: - speed = ETH_SPEED_100; - break; - case EpsilonPhySpeed::Speed1000: - speed = ETH_SPEED_1000; - break; - case EpsilonPhySpeed::Speed10000: - speed = ETH_SPEED_10000; - break; } - return std::make_optional(speed); } private: