Skip to content

Commit a95d29e

Browse files
MFD-7556: Added functionality
feature: Adding get_phy_info functionality under mfd_network_adapter\network_interface\feature\utils\windows.py
1 parent aa5c916 commit a95d29e

File tree

1 file changed

+78
-0
lines changed
  • mfd_network_adapter/network_interface/feature/utils

1 file changed

+78
-0
lines changed

mfd_network_adapter/network_interface/feature/utils/windows.py

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,3 +95,81 @@ def get_interface_index(self) -> str:
9595
f"(Get-NetAdapter '{self._interface().name}').InterfaceIndex", expected_return_codes={0}
9696
)
9797
return result.stdout.strip()
98+
99+
def get_phy_info(self, adapter_interface_description: str = None) -> Dict:
100+
"""
101+
Get PHY information and check auto-negotiation bits using WMI.
102+
103+
:param adapter_interface_description: Optional specific adapter description to match
104+
:return: Dictionary containing PHY information and auto-negotiation status
105+
:raises: UtilsException if PHY info command execution failed
106+
"""
107+
cmd = (
108+
'gwmi -namespace "root\\WMI" IntlLan_GetPhyInfo -property InstanceName,PhyInfo | '
109+
'Format-Table InstanceName, @{n="PhyInfo";e={($_ | select -expand PhyInfo) -join ","}} -auto'
110+
)
111+
result = self._connection.execute_powershell(cmd, custom_exception=UtilsException)
112+
phy_data = {}
113+
phy_info_found = auto_neg_bits_detected = False
114+
115+
# Only process if we have output
116+
if result.stdout:
117+
lines = [
118+
line.strip()
119+
for line in result.stdout.splitlines()
120+
if line.strip() and not any(x in line for x in ['InstanceName', 'PhyInfo', '----'])
121+
]
122+
123+
# Normalize adapter name (strip "for ..." and trailing #N)
124+
base_name = None
125+
if adapter_interface_description:
126+
base_name = adapter_interface_description.split(' for ')[0].strip()
127+
base_name = re.sub(r'\s+#\d+$', '', base_name).strip().lower()
128+
129+
matching_line = None
130+
if base_name:
131+
for line in lines:
132+
# Extract full InstanceName part (everything before two or more spaces)
133+
instance_match = re.match(r'^(.*?)\s{2,}', line)
134+
if not instance_match:
135+
continue
136+
instance_name = instance_match.group(1).strip()
137+
normalized_name = re.sub(r'\s+#\d+$', '', instance_name, flags=re.IGNORECASE).strip().lower()
138+
139+
# Match exact normalized name
140+
if normalized_name == base_name:
141+
matching_line = line
142+
break
143+
144+
# Fallback if no exact match, use first line
145+
if not matching_line and lines:
146+
matching_line = lines[0]
147+
148+
if matching_line and ',' in matching_line:
149+
# Extract the comma-separated PHY values (rightmost part)
150+
phy_info_str = matching_line.split(None, 1)[-1]
151+
if ',' in phy_info_str:
152+
phy_values = phy_info_str.split(',')
153+
phy_data = {'raw_values': phy_values}
154+
155+
# Extract third value (auto-negotiation bits live here)
156+
if len(phy_values) >= 3:
157+
try:
158+
third_value = int(phy_values[2].strip())
159+
auto_neg_bits = {f'bit_{bit}': bool(third_value & (1 << bit)) for bit in [0, 1]}
160+
phy_data.update({
161+
'third_value_decimal': third_value,
162+
'third_value_binary': bin(third_value)[2:],
163+
'auto_neg_bits': auto_neg_bits
164+
})
165+
phy_info_found = True
166+
auto_neg_bits_detected = any(auto_neg_bits.values())
167+
except ValueError as e:
168+
phy_data['parse_error'] = str(e)
169+
170+
return {
171+
'phy_info_found': phy_info_found,
172+
'auto_neg_bits_detected': auto_neg_bits_detected,
173+
'phy_data': phy_data,
174+
'raw_output': result.stdout or ''
175+
}

0 commit comments

Comments
 (0)