From 49076a99ac675582783a8d56b4e51468df07831d Mon Sep 17 00:00:00 2001 From: vdahiya12 <67608553+vdahiya12@users.noreply.github.com> Date: Fri, 22 Jan 2021 10:29:58 -0800 Subject: [PATCH] [sonic_y_cable] Add support for measuring BER and EYE scan and running Loopback, PRBS modes on the Y cable (#158) * [sonic_y_cable] Add support for measuring BER and EYE scan with Loopback, PRBS and Mission modes. What is the motivation for this PR? To add the necessary support for measuring BER and EYE scan, and run PRBS/Loopback modes on the Y cable How did you do it? Added the changes in sonic-platform-common module in the y_cable.py file How did you verify/test it? opened a python shell and ran the API's manually and test verified the values are correct. Signed-off-by: vaibhav-dahiya --- sonic_y_cable/y_cable.py | 634 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 616 insertions(+), 18 deletions(-) diff --git a/sonic_y_cable/y_cable.py b/sonic_y_cable/y_cable.py index 95b11a59925f..7d557fecd50f 100644 --- a/sonic_y_cable/y_cable.py +++ b/sonic_y_cable/y_cable.py @@ -5,12 +5,15 @@ # API's for Y cable functionality in SONiC try: + import math import struct - from sonic_py_common import logger + from ctypes import c_int8 + import sonic_platform.platform + from sonic_py_common import logger except ImportError as e: # When build python3 xcvrd, it tries to do basic check which will import this file. However, - # not all platform supports python3 API now, so it could cause an issue when importing + # not all platform supports python3 API now, so it could cause an issue when importing # sonic_platform.platform. We skip the ImportError here. This is safe because: # 1. If any python package is not available, there will be exception when use it # 2. Vendors know their platform API version, they are responsible to use correct python @@ -20,14 +23,57 @@ # definitions of the offset with width accommodated for values # of MUX register specs of upper page 0x04 starting at 640 # info eeprom for Y Cable -Y_CABLE_IDENTFIER_LOWER_PAGE = 0 -Y_CABLE_IDENTFIER_UPPER_PAGE = 128 -Y_CABLE_DETERMINE_CABLE_READ_SIDE = 640 -Y_CABLE_CHECK_LINK_ACTIVE = 641 -Y_CABLE_SWITCH_MUX_DIRECTION = 642 -Y_CABLE_MUX_DIRECTION = 644 -Y_CABLE_ACTIVE_TOR_INDICATOR = 645 -Y_CABLE_MANUAL_SWITCH_COUNT = 669 +OFFSET_IDENTFIER_LOWER_PAGE = 0 +OFFSET_IDENTFIER_UPPER_PAGE = 128 +OFFSET_DETERMINE_CABLE_READ_SIDE = 640 +OFFSET_CHECK_LINK_ACTIVE = 641 +OFFSET_SWITCH_MUX_DIRECTION = 642 +OFFSET_MUX_DIRECTION = 644 +OFFSET_ACTIVE_TOR_INDICATOR = 645 +OFFSET_MANUAL_SWITCH_COUNT = 669 +OFFSET_CONFIGURE_PRBS_TYPE = 768 +OFFSET_ENABLE_PRBS = 769 +OFFSET_INITIATE_BER_MEASUREMENT = 770 +OFFSET_TARGET = 794 +OFFSET_ENABLE_LOOPBACK = 793 +OFFSET_LANE_1_BER_RESULT = 771 +OFFSET_MAX_LANES = 2 +OFFSET_INITIATE_EYE_MEASUREMENT = 784 +OFFSET_LANE_1_EYE_RESULT = 785 +OFFSET_PN_NUMBER = 168 +OFFSET_VENDOR_NAME = 148 +OFFSET_MANUAL_SWITCH_COUNT = 653 +OFFSET_AUTO_SWITCH_COUNT = 657 +OFFSET_NIC_CURSOR_VALUES = 661 +OFFSET_TOR1_CURSOR_VALUES = 681 +OFFSET_TOR2_CURSOR_VALUES = 701 +OFFSET_NIC_LANE_ACTIVE = 721 + +# definitions of targets for getting the cursor +# equalization parameters from the register spec +# the name of the target denotes which side cursor +# values will be retreived + +TARGET_NIC = 0 +TARGET_TOR1 = 1 +TARGET_TOR2 = 2 + +# definitions of targets for getting the EYE/BER +# and initiating PRBS/Loopback on the Y cable +# the name of the target denotes which side values +# will be retreived/initiated + +EYE_PRBS_TARGET_LOCAL = 0 +EYE_PRBS_TARGET_TOR1 = 1 +EYE_PRBS_TARGET_TOR2 = 2 +EYE_PRBS_TARGET_NIC = 3 + +# definitions of switch counter types +# to be entered by the user in get_switch_count api +# for retreiving the counter values + +SWITCH_COUNT_MANUAL = "manual" +SWITCH_COUNT_AUTO = "auto" SYSLOG_IDENTIFIER = "sonic_y_cable" @@ -44,6 +90,24 @@ helper_logger.log_warning("Failed to load chassis due to {}".format(repr(e))) +def y_cable_validate_read_data(result, size, physical_port, message): + + if result is not None: + if isinstance(result, bytearray): + if len(result) != size: + LOG_MESSAGE_TEMPLATE = "Error: for checking mux_cable {}, eeprom read returned a size {} not equal to 1 for port {}" + helper_logger.log_error(LOG_MESSAGE_TEMPLATE.format(message, len(result), physical_port)) + return -1 + else: + LOG_MESSAGE_TEMPLATE = "Error: for checking mux_cable {}, eeprom read returned an instance value of type {} which is not a bytearray for port {}" + helper_logger.log_error(LOG_MESSAGE_TEMPLATE.format(message, type(result), physical_port)) + return -1 + else: + LOG_MESSAGE_TEMPLATE = "Error: for checking mux_cable {}, eeprom read returned a None value for port {} which is not expected" + helper_logger.log_error(LOG_MESSAGE_TEMPLATE.format(message, physical_port)) + return -1 + + def hook_y_cable_simulator(target): """Decorator to add hook for calling y_cable_simulator_client. @@ -94,7 +158,7 @@ def toggle_mux_to_torA(physical_port): """ buffer = bytearray([2]) - curr_offset = Y_CABLE_SWITCH_MUX_DIRECTION + curr_offset = OFFSET_SWITCH_MUX_DIRECTION if platform_chassis is not None: result = platform_chassis.get_sfp( @@ -132,7 +196,7 @@ def toggle_mux_to_torB(physical_port): """ buffer = bytearray([3]) - curr_offset = Y_CABLE_SWITCH_MUX_DIRECTION + curr_offset = OFFSET_SWITCH_MUX_DIRECTION if platform_chassis is not None: result = platform_chassis.get_sfp( @@ -170,7 +234,7 @@ def check_read_side(physical_port): , -1 if reading the Y cable API fails. """ - curr_offset = Y_CABLE_DETERMINE_CABLE_READ_SIDE + curr_offset = OFFSET_DETERMINE_CABLE_READ_SIDE if platform_chassis is not None: result = platform_chassis.get_sfp( @@ -235,7 +299,7 @@ def check_mux_direction(physical_port): , -1 if checking which side mux is pointing to API fails. """ - curr_offset = Y_CABLE_MUX_DIRECTION + curr_offset = OFFSET_MUX_DIRECTION if platform_chassis is not None: result = platform_chassis.get_sfp( @@ -299,7 +363,7 @@ def check_active_linked_tor_side(physical_port): , -1 if checking which side linked for routing API fails. """ - curr_offset = Y_CABLE_ACTIVE_TOR_INDICATOR + curr_offset = OFFSET_ACTIVE_TOR_INDICATOR if platform_chassis is not None: result = platform_chassis.get_sfp( @@ -364,7 +428,7 @@ def check_if_link_is_active_for_NIC(physical_port): a boolean, true if the link is active , false if the link is not active """ - curr_offset = Y_CABLE_CHECK_LINK_ACTIVE + curr_offset = OFFSET_CHECK_LINK_ACTIVE if platform_chassis is not None: result = platform_chassis.get_sfp( @@ -420,7 +484,7 @@ def check_if_link_is_active_for_torA(physical_port): , false if the link is not active """ - curr_offset = Y_CABLE_CHECK_LINK_ACTIVE + curr_offset = OFFSET_CHECK_LINK_ACTIVE if platform_chassis is not None: result = platform_chassis.get_sfp( @@ -476,7 +540,7 @@ def check_if_link_is_active_for_torB(physical_port): , false if the link is not active """ - curr_offset = Y_CABLE_CHECK_LINK_ACTIVE + curr_offset = OFFSET_CHECK_LINK_ACTIVE if platform_chassis is not None: result = platform_chassis.get_sfp( @@ -507,3 +571,537 @@ def check_if_link_is_active_for_torB(physical_port): return True else: return False + + +@hook_y_cable_simulator +def enable_prbs_mode(physical_port, target, mode_value, lane_map): + """ + This API specifically configures and enables the PRBS mode/type depending upon the mode_value the user provides. + The mode_value configures the PRBS Type for generation and BER sensing on a per side basis. + Each side can only R/W its own value. 0x00 = PRBS 9, 0x01 = PRBS 15, 0x02 = PRBS 23, 0x03 = PRBS 31, 0x04-0xFF reserved. + Target is an integer for selecting which end of the Y cable we want to run PRBS on. + LaneMap specifies the lane configuration to run the PRBS on. + + + Register Specification of upper page 0x5 at offset 128, 129 is documented below + + Byte offset bits Name Description + 128 7-0 Reserved PRBS Type for generation and BER sensing on a per side basis. + Each side can only R/W its own value. + 0x00 = PRBS 9, 0x01 = PRBS 15, 0x02 = PRBS 23, 0x03 = PRBS 31, 0x04-0xFF reserved + + 129 7-4 Reserved + 3 Lane 4 enable "Enable PRBS generation on target lane 0b1 : + Enable, 0b0 disable If any lanes are enabled, + then that side of cable is removed fro mission mode and no longer passing valid traffic." + 2 Lane 3 enable + 1 Lane 2 enable + 0 Lane 1 enable + + Args: + physical_port: + an Integer, the actual physical port connected to a Y cable + target: + an Integer, the target on which to enable the PRBS + EYE_PRBS_TARGET_LOCAL -> local side, + EYE_PRBS_TARGET_TOR1 -> TOR 1 + EYE_PRBS_TARGET_TOR2 -> TOR 2 + EYE_PRBS_TARGET_NIC -> NIC + mode_value: + an Integer, the mode/type for configuring the PRBS mode. + 0x00 = PRBS 9, 0x01 = PRBS 15, 0x02 = PRBS 23, 0x03 = PRBS 31 + lane_map: + an Integer, representing the lane_map to be run PRBS on + 0bit for lane 0, 1bit for lane1 and so on. + for example 3 -> 0b'0011 , means running on lane0 and lane1 + + Returns: + a boolean, true if the enable is successful + , false if the enable failed + """ + + buffer = bytearray([target]) + curr_offset = OFFSET_TARGET + + if platform_chassis is not None: + result = platform_chassis.get_sfp( + physical_port).write_eeprom(curr_offset, 1, buffer) + if result is False: + return result + buffer = bytearray([mode_value]) + curr_offset = OFFSET_CONFIGURE_PRBS_TYPE + result = platform_chassis.get_sfp( + physical_port).write_eeprom(curr_offset, 1, buffer) + if result is False: + return result + buffer = bytearray([lane_map]) + curr_offset = OFFSET_ENABLE_PRBS + result = platform_chassis.get_sfp( + physical_port).write_eeprom(curr_offset, 1, buffer) + + else: + helper_logger.log_error("platform_chassis is not loaded, failed to configure the PRBS type") + return -1 + + return result + + +@hook_y_cable_simulator +def disable_prbs_mode(physical_port, target): + """ + This API specifically disables the PRBS mode on the physcial port. + + Register Specification of upper page 0x5 at offset 129 is documented below + + Byte offset bits Name Description + 129 7-4 Reserved + 3 Lane 4 enable "Enable PRBS generation on target lane 0b1 : + Enable, 0b0 disable If any lanes are enabled, + then that side of cable is removed fro mission mode and no longer passing valid traffic." + 2 Lane 3 enable + 1 Lane 2 enable + 0 Lane 1 enable + + Args: + physical_port: + an Integer, the actual physical port connected to a Y cable + target: + an Integer, the target on which to enable the PRBS + EYE_PRBS_TARGET_LOCAL -> local side, + EYE_PRBS_TARGET_TOR1 -> TOR 1 + EYE_PRBS_TARGET_TOR2 -> TOR 2 + EYE_PRBS_TARGET_NIC -> NIC + + Returns: + a boolean, true if the disable is successful + , false if the disable failed + """ + + buffer = bytearray([target]) + curr_offset = OFFSET_TARGET + + if platform_chassis is not None: + result = platform_chassis.get_sfp( + physical_port).write_eeprom(curr_offset, 1, buffer) + if result is False: + return result + buffer = bytearray([0]) + curr_offset = OFFSET_ENABLE_PRBS + result = platform_chassis.get_sfp( + physical_port).write_eeprom(curr_offset, 1, buffer) + + else: + helper_logger.log_error("platform_chassis is not loaded, failed to configure the PRBS type") + return -1 + + return result + + +@hook_y_cable_simulator +def enable_loopback_mode(physical_port, target, lane_map): + """ + This API specifically configures and enables the Loopback mode on the port user provides. + Target is an integer for selecting which end of the Y cable we want to run loopback on. + LaneMap specifies the lane configuration to run the loopback on. + + + Register Specification of upper page 0x5 at offset 153 is documented below + + Byte offset bits Name Description + 153 7-4 Reserved + 3 Lane 4 enable "Enable loopback generation on target lane 0b1 : + Enable, 0b0 disable.The cable supports 3 modes of operation : mission mode; PRBS mode or loopback mode. + Enabling loopback on any lane of any sides puts cable in loopback mode and disables PRBS. + 2 Lane 3 enable + 1 Lane 2 enable + 0 Lane 1 enable + + Args: + physical_port: + an Integer, the actual physical port connected to a Y cable + target: + an Integer, the target on which to enable the PRBS + EYE_PRBS_TARGET_LOCAL -> local side, + EYE_PRBS_TARGET_TOR1 -> TOR 1 + EYE_PRBS_TARGET_TOR2 -> TOR 2 + EYE_PRBS_TARGET_NIC -> NIC + lane_map: + an Integer, representing the lane_map to be run PRBS on + 0bit for lane 0, 1bit for lane1 and so on. + for example 3 -> 0b'0011 , means running on lane0 and lane1 + + Returns: + a boolean, true if the enable is successful + , false if the enable failed + """ + + buffer = bytearray([target]) + curr_offset = OFFSET_TARGET + + if platform_chassis is not None: + result = platform_chassis.get_sfp( + physical_port).write_eeprom(curr_offset, 1, buffer) + if result is False: + return result + buffer = bytearray([lane_map]) + curr_offset = OFFSET_ENABLE_LOOPBACK + result = platform_chassis.get_sfp( + physical_port).write_eeprom(curr_offset, 1, buffer) + + else: + helper_logger.log_error("platform_chassis is not loaded, failed to configure the PRBS type") + return -1 + + return result + + +@hook_y_cable_simulator +def disable_loopback_mode(physical_port, target): + """ + This API specifically disables the Loopback mode on the port user provides. + Target is an integer for selecting which end of the Y cable we want to run loopback on. + + + Register Specification of upper page 0x5 at offset 153 is documented below + + Byte offset bits Name Description + 153 7-4 Reserved + 3 Lane 4 enable "Enable loopback generation on target lane 0b1 : + Enable, 0b0 disable.The cable supports 3 modes of operation : + mission mode; PRBS mode or loopback mode. + Enabling loopback on any lane of any sides puts cable in loopback mode and disables PRBS. + 2 Lane 3 enable + 1 Lane 2 enable + 0 Lane 1 enable + + Args: + physical_port: + an Integer, the actual physical port connected to a Y cable + target: + an Integer, the target on which to enable the PRBS + EYE_PRBS_TARGET_LOCAL -> local side, + EYE_PRBS_TARGET_TOR1 -> TOR 1 + EYE_PRBS_TARGET_TOR2 -> TOR 2 + EYE_PRBS_TARGET_NIC -> NIC + + Returns: + a boolean, true if the disable is successful + , false if the disable failed + """ + + buffer = bytearray([target]) + curr_offset = OFFSET_TARGET + + if platform_chassis is not None: + result = platform_chassis.get_sfp( + physical_port).write_eeprom(curr_offset, 1, buffer) + if result is False: + return result + buffer = bytearray([0]) + curr_offset = OFFSET_ENABLE_LOOPBACK + result = platform_chassis.get_sfp( + physical_port).write_eeprom(curr_offset, 1, buffer) + + else: + helper_logger.log_error("platform_chassis is not loaded, failed to configure the PRBS type") + return -1 + + return result + + +@hook_y_cable_simulator +def get_ber_info(physical_port, target): + """ + This API specifically returns the BER (Bit error rate) value for a specfic port. + The target could be local side, TOR1, TOR2, NIC etc. + + + Register Specification of upper page 0x5 at offset 130 is documented below + + Byte offset bits Name Description + 130 1-0 Initiate BER Measurement "Write 0x00 - initiate gated BER measurement on target side with PRBS traffic + Write 0x01-0xFF - reserved + Read 0x00 - BER Gate in process + Read 0x01 - BER Gate complete, valid values in Lane BER registers + NB this command is only valid when PRBS has been enabled on at least one lane + The cable supports 3 modes of operation : mission mode; PRBS mode or loopback mode. + Enabling PRBS on any lane of any sides puts cable in PRBS mode and disables loopback and mission mode." + + Args: + physical_port: + an Integer, the actual physical port connected to a Y cable + target: + an Integer, the target on which to enable the PRBS + EYE_PRBS_TARGET_LOCAL -> local side, + EYE_PRBS_TARGET_TOR1 -> TOR 1 + EYE_PRBS_TARGET_TOR2 -> TOR 2 + EYE_PRBS_TARGET_NIC -> NIC + Returns: + a list, with BER values of lane 0 and lane 1 with corresponding index + """ + + buffer = bytearray([target]) + curr_offset = OFFSET_TARGET + + ber_result = [] + + if platform_chassis is not None: + result = platform_chassis.get_sfp( + physical_port).write_eeprom(curr_offset, 1, buffer) + if result is False: + return result + buffer = bytearray([0]) + curr_offset = OFFSET_INITIATE_BER_MEASUREMENT + result = platform_chassis.get_sfp( + physical_port).write_eeprom(curr_offset, 1, buffer) + if result is False: + return result + while(True): + done = platform_chassis.get_sfp(physical_port).read_eeprom(curr_offset, 1) + y_cable_validate_read_data(done, 1, physical_port, "BER data ready to read") + if done[0] == 1: + break + + idx = 0 + maxLane = 2 + curr_offset = OFFSET_LANE_1_BER_RESULT + for lane in range(maxLane): + msb_result = platform_chassis.get_sfp(physical_port).read_eeprom(curr_offset+idx, 1) + y_cable_validate_read_data(msb_result, 1, physical_port, "BER data msb result") + lsb_result = platform_chassis.get_sfp(physical_port).read_eeprom(curr_offset+1+idx, 1) + y_cable_validate_read_data(lsb_result, 1, physical_port, "BER data lsb result") + lane_result = msb_result[0] * math.pow(10, (lsb_result[0]-24)) + ber_result.append(lane_result) + idx += 2 + + else: + helper_logger.log_error("platform_chassis is not loaded, failed to configure the PRBS type") + return -1 + + return ber_result + + +@hook_y_cable_simulator +def get_eye_info(physical_port, target): + """ + This API specifically returns the EYE height value for a specfic port. + The target could be local side, TOR1, TOR2, NIC etc. + + + Register Specification of upper page 0x5 at offset 144 is documented below + + Byte offset bits Name Description + 144 1-0 Initiate EYE Measurement "Write 0x00 - initiate gated eye height measurement on target side with any traffic (PRBS or mission mode) + Write 0x01-0xFF - reserved + Read 0x00 - Eye Height Measurement in process + Read 0x01 - Eye Height Gate complete, valid values in Eye Height Registers + NB this command can be issued whenever the side is linked, this does not interrupt mission mode traffic" R/W + + Args: + physical_port: + an Integer, the actual physical port connected to a Y cable + target: + an Integer, the target on which to enable the PRBS + EYE_PRBS_TARGET_LOCAL -> local side, + EYE_PRBS_TARGET_TOR1 -> TOR 1 + EYE_PRBS_TARGET_TOR2 -> TOR 2 + EYE_PRBS_TARGET_NIC -> NIC + Returns: + a list, with EYE values of lane 0 and lane 1 with corresponding index + """ + + buffer = bytearray([target]) + curr_offset = OFFSET_TARGET + + eye_result = [] + + if platform_chassis is not None: + result = platform_chassis.get_sfp( + physical_port).write_eeprom(curr_offset, 1, buffer) + if result is False: + return result + buffer = bytearray([0]) + curr_offset = OFFSET_INITIATE_EYE_MEASUREMENT + result = platform_chassis.get_sfp( + physical_port).write_eeprom(curr_offset, 1, buffer) + if result is False: + return result + + while(True): + done = platform_chassis.get_sfp(physical_port).read_eeprom(curr_offset, 1) + y_cable_validate_read_data(done, 1, physical_port, "EYE data ready to read") + if done[0] == 1: + break + + idx = 0 + maxLane = 2 + for lane in range(maxLane): + curr_offset = OFFSET_LANE_1_EYE_RESULT + msb_result = platform_chassis.get_sfp(physical_port).read_eeprom(curr_offset+idx, 1) + y_cable_validate_read_data(msb_result, 1, physical_port, "EYE data msb result") + lsb_result = platform_chassis.get_sfp(physical_port).read_eeprom(curr_offset+1+idx, 1) + y_cable_validate_read_data(lsb_result, 1, physical_port, "EYE data lsb result") + lane_result = (msb_result[0] << 8 | lsb_result[0]) + eye_result.append(lane_result) + idx += 2 + + else: + helper_logger.log_error("platform_chassis is not loaded, failed to configure the PRBS type") + return -1 + + return eye_result + + +@hook_y_cable_simulator +def get_pn_number_and_vendor_name(physical_port): + """ + This API specifically returns the pn number and vendor name for a specfic port. + + Args: + physical_port: + an Integer, the actual physical port connected to a Y cable + Returns: + a tuple, with pn_number and vendor name + """ + + curr_offset = OFFSET_PN_NUMBER + + if platform_chassis is not None: + pn_result = platform_chassis.get_sfp(physical_port).read_eeprom(curr_offset, 15) + y_cable_validate_read_data(pn_result, 1, physical_port, "PN number") + curr_offset = OFFSET_VENDOR_NAME + vendor_name = platform_chassis.get_sfp(physical_port).read_eeprom(curr_offset, 15) + y_cable_validate_read_data(vendor_name, 15, physical_port, "vendor name") + + else: + helper_logger.log_error("platform_chassis is not loaded, failed to get pin results") + return -1 + + return pn_result, vendor_name + + +@hook_y_cable_simulator +def get_switch_count(physical_port, count_type): + """ + This API specifically returns the switch count to change the Active TOR which has + been done manually by the user. + + Args: + physical_port: + an Integer, the actual physical port connected to a Y cable + count_type: + a string, for getting the count type + "manual" -> manual switch count + "auto" -> automatic switch count + Returns: + an integer, the number of times manually the Y-cable has been switched + """ + + if count_type == SWITCH_COUNT_MANUAL: + curr_offset = OFFSET_MANUAL_SWITCH_COUNT + elif count_type == SWITCH_COUNT_AUTO: + curr_offset = OFFSET_AUTO_SWITCH_COUNT + else: + helper_logger.log_error("not a valid count_type, failed to get switch count") + return -1 + + count = 0 + + if platform_chassis is not None: + msb_result = platform_chassis.get_sfp(physical_port).read_eeprom(curr_offset, 1) + y_cable_validate_read_data(msb_result, 1, physical_port, "{} switch count msb result".format(count_type)) + msb_result_1 = platform_chassis.get_sfp(physical_port).read_eeprom(curr_offset + 1, 1) + y_cable_validate_read_data(msb_result_1, 1, physical_port, "{} switch count msb result 1".format(count_type)) + msb_result_2 = platform_chassis.get_sfp(physical_port).read_eeprom(curr_offset + 2, 1) + y_cable_validate_read_data(msb_result_2, 1, physical_port, "{} switch count msb result 2".format(count_type)) + lsb_result = platform_chassis.get_sfp(physical_port).read_eeprom(curr_offset+3, 1) + y_cable_validate_read_data(lsb_result, 1, physical_port, "{} switch count lsb result".format(count_type)) + count = (msb_result[0] << 24 | msb_result_1[0] << 16 | msb_result_2[0] << 8 | lsb_result[0]) + + else: + helper_logger.log_error("platform_chassis is not loaded, failed to get manual switch count") + return -1 + + return count + + +@hook_y_cable_simulator +def get_target_cursor_values(physical_port, lane, target): + """ + This API specifically returns the cursor equalization parameters for a target(NIC, TOR1, TOR2). + This includes pre one, pre two , main, post one, post two cursor values + + Args: + physical_port: + an Integer, the actual physical port connected to a Y cable + lane: + an Integer, the lane on which to collect the cursor values + 1 -> lane 1, + 2 -> lane 2 + 3 -> lane 3 + 4 -> lane 4 + target: + an Integer, the actual target to get the cursor values on + TARGET_NIC -> NIC, + TARGET_TOR1-> TOR1, + TARGET_TOR2 -> TOR2 + Returns: + an list, with pre one, pre two , main, post one, post two cursor values in the order + """ + + curr_offset = OFFSET_NIC_CURSOR_VALUES + + result = [] + + if platform_chassis is not None: + pre1 = platform_chassis.get_sfp(physical_port).read_eeprom(curr_offset + (target)*20 + (lane-1)*5, 1) + y_cable_validate_read_data(pre1, 1, physical_port, "target cursor result") + result.append(c_int8(pre1[0]).value) + pre2 = platform_chassis.get_sfp(physical_port).read_eeprom(curr_offset + (target)*20 + (lane-1)*5 + 1, 1) + y_cable_validate_read_data(pre2, 1, physical_port, "target cursor result") + result.append(c_int8(pre2[0]).value) + main = platform_chassis.get_sfp(physical_port).read_eeprom(curr_offset + (target)*20 + (lane-1)*5 + 2, 1) + y_cable_validate_read_data(main, 1, physical_port, "target cursor result") + result.append(c_int8(main[0]).value) + post1 = platform_chassis.get_sfp(physical_port).read_eeprom(curr_offset + (target)*20 + (lane-1)*5 + 3, 1) + y_cable_validate_read_data(post1, 1, physical_port, "target cursor result") + result.append(c_int8(post1[0]).value) + post2 = platform_chassis.get_sfp(physical_port).read_eeprom(curr_offset + (target)*20 + (lane-1)*5 + 4, 1) + y_cable_validate_read_data(post2, 1, physical_port, "target cursor result") + result.append(c_int8(post2[0]).value) + + else: + helper_logger.log_error("platform_chassis is not loaded, failed to get target cursor values") + return -1 + + return result + + +@hook_y_cable_simulator +def check_if_nic_lanes_active(physical_port): + """ + This API specifically returns the byte value which denotes which nic lanes + are detected and active + + Args: + physical_port: + an Integer, the actual physical port connected to a Y cable + Returns: + an integer, with lower 4 bits representing which lanes are active from 1, 2, 3, 4 + in that order. + """ + + curr_offset = OFFSET_NIC_LANE_ACTIVE + + result = None + + if platform_chassis is not None: + res = platform_chassis.get_sfp(physical_port).read_eeprom(curr_offset, 1) + y_cable_validate_read_data(res, 1, physical_port, "nic lanes active") + result = res[0] + + else: + helper_logger.log_error("platform_chassis is not loaded, failed to get NIC lanes active") + return -1 + + return result