# Copyright 2019 The ChromiumOS Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

import logging
import six

from autotest_lib.client.common_lib import error
from autotest_lib.client.common_lib.cros import cr50_utils
from autotest_lib.server.cros.faft.cr50_test import Cr50Test


class firmware_Cr50PartialBoardId(Cr50Test):
    """Verify cr50 partial board id.


    Verify the board id flags can be set alone and the brand can be set later.
    """
    version = 1

    # Brand used for testing. It doesn't matter what this is.
    DEFAULT_BRAND = 'ZZAF'

    ALLOW_FLAGS = 0x3f80
    OTHER_FLAGS = 0x7f7f

    SUCCESS = ''
    ERR_ALREADY_SET = 'Error 7 while setting board id'
    ERR_BID_MISMATCH = 'Error 5 while setting board id'


    def initialize(self, host, cmdline_args, full_args, bid=''):
        """Generate the test flags and verify the device setup."""
        if host.servo.main_device_is_ccd():
            raise error.TestNAError('Use a flex cable instead of CCD cable.')

        # Restore the original image, rlz code, and board id during cleanup.
        super(firmware_Cr50PartialBoardId, self).initialize(
            host, cmdline_args, full_args, restore_cr50_image=True,
            restore_cr50_board_id=True)
        running_ver = self.get_saved_cr50_original_version()
        logging.info('Cr50 Version: %s', running_ver)
        bid = running_ver[2]
        brand = self.get_device_brand()
        self.test_brand = brand if brand else self.DEFAULT_BRAND
        logging.info('Test Brand: %r', self.test_brand)
        self.image_flags = int(bid.rsplit(':', 1)[-1], 16) if bid else 0
        # The image may have non-zero flags. Use test flags as close to the
        # allowed flags as possible, but make sure they can be used with
        # the running image.
        self.test_flags = self.ALLOW_FLAGS | self.image_flags
        self.other_flags = self.OTHER_FLAGS | self.image_flags


    def eraseflashinfo(self):
        """Eraseflashinfo if the board id is set."""
        if cr50_utils.GetChipBoardId(self.host) == cr50_utils.ERASED_CHIP_BID:
            return
        # Erase the board id so we can change it.
        self.eraseflashinfo_and_restore_image()


    def set_bid_with_dbg_image(self, bid):
        """Use the console command on the DBG image to set the board id."""
        self.eraseflashinfo_and_restore_image(self.get_saved_dbg_image_path())
        self.gsc.set_board_id(int(bid[0], 16), bid[2])
        self.cr50_update(self.get_saved_cr50_original_path(), rollback=True)


    @staticmethod
    def get_bid_str(bid):
        """Returns a string representation of the board id tuple."""
        bid_str_fields = []
        for field in bid:
            if isinstance(field, six.string_types):
                bid_str_fields.append(field)
            elif isinstance(field, int):
                bid_str_fields.append(hex(field))
            else:
                bid_str_fields.append(str(field))
        return ':'.join(bid_str_fields)


    def set_board_id_check_response(self, set_bid, expected_bid, expected_msg):
        """Try to set the board id and verify the response.

        @param set_bid: a tuple of the board id to set (brand, brand_inv,
                        flags). brand_inv is ignored, but it's included to be
                        consistent with expected_bid. The flags should be an
                        integer.
        @param expected_bid: a tuple of the board id cr50 should have (brand,
                             brand_inv, flags). brand_inv is ignored if it's
                             None. The flags should be an integer.
        @param expected_msg: The expected response from setting the board id
                             with gsctool.
        @raises TestFail if the cr50 board id doesn't match expected_bid or
                the gsctool doesn't contain expected_msg.
        """
        logging.info('Set BID %s.', self.get_bid_str(set_bid))
        logging.info('Expect BID %s (%s)', self.get_bid_str(expected_bid),
                     expected_msg)
        board_id_arg = '%s:0x%08x' % (set_bid[0], set_bid[2])

        result = cr50_utils.GSCTool(self.host, ['-a', '-i', board_id_arg],
                                    ignore_status=True)

        stderr = result.stderr.strip()
        result_msg = stderr if stderr else result.stdout.strip()
        logging.info('Response: BID %s %s', board_id_arg,
                     ('(%s)' % result_msg) if result_msg else '')
        if expected_msg and expected_msg not in result_msg:
            err = ('Unexpected response setting %r (%d): got %r expected %r' %
                   (board_id_arg, result.exit_status, result_msg,
                    expected_msg))
            raise error.TestFail(err)
        cr50_utils.CheckChipBoardId(self.host, expected_bid[0], expected_bid[2],
                                    board_id_inv=expected_bid[1])


    def run_once(self):
        """Verify partial board id"""
        self.eraseflashinfo()
        # Basic check. Setting board id fails if it's already been fully set.
        bid = (self.test_brand, None, self.test_flags)
        self.set_board_id_check_response(bid, bid, self.SUCCESS)
        self.set_board_id_check_response(bid, bid, self.ERR_ALREADY_SET)

        self.eraseflashinfo()
        # No special behavior for flags that are 0xffffffff. The flags cannot
        # be changed if the board id is set even if the flags are 0xffffffff.
        original_bid = (self.test_brand, None, cr50_utils.ERASED_BID_INT)
        second_bid = (self.test_brand, None, self.test_flags)
        self.set_board_id_check_response(original_bid, original_bid,
                                         self.SUCCESS)
        self.set_board_id_check_response(second_bid, original_bid,
                                         self.ERR_ALREADY_SET)

        self.eraseflashinfo()
        # Flags can be set if board_id_type and board_id_type_inv are 0xffffffff
        partial_bid = (cr50_utils.ERASED_BID_STR, None, self.test_flags)
        stored_partial_bid = (cr50_utils.ERASED_BID_STR,
                              cr50_utils.ERASED_BID_STR, self.test_flags)
        self.set_board_id_check_response(partial_bid, stored_partial_bid,
                                         self.SUCCESS)
        set_brand = (self.test_brand, None, self.other_flags)
        updated_brand_bid = (self.test_brand, None, self.test_flags)
        self.set_board_id_check_response(set_brand, updated_brand_bid,
                                         self.SUCCESS)

        # Setting the board id type to 0xffffffff on the console will set the
        # type to 0xffffffff and type_inv to 0. This isn't considered a partial
        # board id. Setting the board id a second time will fail.
        bid = (cr50_utils.ERASED_BID_STR, '00000000', self.test_flags)
        new_bid = (self.test_brand, None, self.other_flags)
        self.set_bid_with_dbg_image(bid)
        self.set_board_id_check_response(new_bid, bid, self.ERR_ALREADY_SET)
        if not self.image_flags:
            logging.info('Image is not board id locked. Done')
            return

        self.eraseflashinfo()
        # Plain whitelabel flags will run on any board id locked image.
        bid = (cr50_utils.ERASED_BID_STR, None, self.ALLOW_FLAGS)
        self.set_board_id_check_response(bid, cr50_utils.ERASED_CHIP_BID,
                                         self.ERR_BID_MISMATCH)
        # Previous board id was rejected. The board id can still be set.
        basic_bid = (self.test_brand, None, self.image_flags)
        self.set_board_id_check_response(basic_bid, basic_bid, self.SUCCESS)
