#!/usr/bin/env python3
# Copyright (c) 2007-2011 Arista Networks, Inc.  All rights reserved.
# Arista Networks, Inc. Confidential and Proprietary.

# pylint: disable=consider-using-f-string

import Tac

from PowerDiagLib import OptionParser
from PowerDiagLib import exitWithError, hwPowerSupplySlotConfig
from PyClient import PyClient

parser = OptionParser()
parser.add_option( "", "--powerSupply", action="store",
                   help="The power supply to test " )
( options, args ) = parser.parse_args()

if args:
   parser.error( "unexpected arguments" )
if not options.powerSupply:
   parser.error( "you must specify a power supply to test" )

sysdbRoot = PyClient( options.sysname, "Sysdb" ).agentRoot()

# Mount the hardware power supply slot state
powerSupplyConfig = hwPowerSupplySlotConfig( sysdbRoot )

import SmbusClient # pylint: disable=wrong-import-position
SmbusClient.setup( options.sysname, "IpmiFruIdpromRegTest" )

supplyConfig = powerSupplyConfig.slotConfig.get( options.powerSupply )
if not supplyConfig:
   exitWithError( "Could not find supply %s" % options.powerSupply )

print( "ipmiFruIdpromRegTest: checking the idprom contents" )

aham = supplyConfig.powerSupplyBaseAhamDesc.aham
idPromOffset = SmbusClient.ahamAddress( accelId=0, busId=0, addrSize='addrSize1',
                                        deviceId=0x50, offset=0 )

idPromBuf = SmbusClient.newBuf( 256 )
req = aham.newRequest
req.nextOp = Tac.Value( "Hardware::AhamRequest::OpDesc",
                        op="read", addr=idPromOffset, data=idPromBuf.address,
                        count=256, elementSize=1, accessSize=1 )
req.state = 'started'

Tac.waitFor( lambda: req.status != 'inProgress',
             description='dump of the idprom to complete',
             timeout=90 )

if req.status != 'succeeded':
   exitWithError( "Failed to read the power supply idprom. "
                  "Is it properly inserted?" )

# Check the various checksums in the idprom

def computeChecksum( idpromStr ):
   checksum = 0
   for i in idpromStr:
      checksum += ord( i )
   if checksum > 0x100:
      checksum = checksum & 0xff
   if checksum == 0:
      # Special case - in cpp, the return value of ( 0x100 - 0x00 )
      # would be case to a U8 of 0x00, but we don't have that luxury
      # in python...
      return checksum
   return 0x100 - checksum

print( "Checking the common header area" )

idPromBufStr = idPromBuf.str

commonHeader = idPromBufStr[ 0x0 : 0x07 ]
actualCommonHeaderChecksum = computeChecksum( commonHeader )
commonHeaderChecksum = ord( idPromBufStr[ 0x07 ] )
if actualCommonHeaderChecksum != commonHeaderChecksum:
   exitWithError( "Common header area checksum of the idprom is incorrect. " \
                  "Corrupted idprom?" )

productInfoOffset = ord( commonHeader[ 0x04 ] ) * 8
multiRecordOffset = ord( commonHeader[ 0x05 ] ) * 8

print( "Checking the product info area" )

productInfoArea = idPromBufStr[ productInfoOffset : multiRecordOffset - 1 ]
productInfoChecksum = ord( idPromBufStr[ multiRecordOffset - 1 ] )
actualProductInfoChecksum = computeChecksum( productInfoArea )
if actualProductInfoChecksum != productInfoChecksum:
   exitWithError( "Product info area checksum of the idprom is incorrect. " \
                  "Corrupted idprom?" )


print( "Checking the multi-record area" )
 
def checkRecord( recordStart, recordName ):
   recordHeader = idPromBufStr[ recordStart : recordStart + 4 ]
   actualRecordHeaderChecksum = computeChecksum( recordHeader )
   recordHeaderChecksum = ord( idPromBufStr[ recordStart + 4 ] )
   if actualRecordHeaderChecksum != recordHeaderChecksum:
      exitWithError( "%s record header checksum in the idprom is incorrect. " \
                     "Corrupted idprom?" % recordName )

   recordLength = ord( idPromBufStr[ recordStart + 2 ] )
   recordEnd = recordStart + 5 + recordLength

   record = idPromBufStr[ recordStart + 5 : recordEnd ]
   actualRecordChecksum = computeChecksum( record )
   recordChecksum = ord( idPromBufStr[ recordStart + 3 ] )
   if actualRecordChecksum != recordChecksum:
      exitWithError( "%s record checksum in the idprom is incorrect. " \
                     "Corrupted idprom?" % recordName )
   return recordEnd

idToRecordType = { 0x00 : "PowerSupply",
                   0x01 : "DC Output",
                   0x02 : "DC Load",
                   0xC0 : "PSMI" }

curOffset = multiRecordOffset
while True:
   recordType = idToRecordType.get( curOffset, None )
   if recordType is None:
      break
   curOffset = checkRecord( curOffset, recordType )
      
print( "ipmiFruIdpromRegTest: power supply", options.powerSupply, "passed!" )
