# Copyright 2019 The Chromium OS Authors. All rights reserved.
# 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."""
        # 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)
        if self.servo.main_device_is_ccd():
            raise error.TestNAError('Use a flex cable instead of CCD cable.')

        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.cr50.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)
