# Copyright 2017-2018, 2024-2025 NXP
# SPDX-License-Identifier: BSD-3-Clause

# -*- coding: utf-8 -*-
"""
    Implementation of Flash Programmer info command

Copyright 2015 Freescale Semiconductor, Inc.

SPDX-License-Identifier: BSD-3-Clause

"""

import gdb   # @UnresolvedImport  # pylint: disable=F0401
import argparse
import string

from flash.gdbcommands.base_command import CwFlashBase
from flash.gdbcommands.cmd_name import CMD_CW_FLASH_INFO

from flash.scripts.utils import size_to_human_readable
from flash.scripts.utils import string_to_size
from flash.scripts.utils import string_to_offset
from flash.scripts.utils import get_soc_ctx_from_current
from flash.scripts.remote import execute_remote

###################################################################
######### flash programmer info command
###################################################################
class CwFlashInfo(CwFlashBase):
    """
usage: [-h] [-d]

S32DS Flash Programming info command.

optional arguments:
  -h, --help  show this help message and exit
  -d, --devices list of registered devicesf
    """

    def __init__(self, hse_limits, is_MRAM, is_crc_implemented):
        """
            Register new command with GDB
            Add a parameter parser with only one parameter used to select
            current device
        """
        super(CwFlashInfo, self).__init__(CMD_CW_FLASH_INFO,
        gdb.COMMAND_USER, gdb.COMPLETE_COMMAND)
        parser = argparse.ArgumentParser(description='S32DS \
                                         Flash Programming info command.')
        parser.add_argument('-d', '--devices',
                            action="store_true",
                            help = 'list registered devices')
        self._parser = parser

        self.HSE_limits = hse_limits
        self.is_MRAM = is_MRAM
        self.is_crc_implemented = is_crc_implemented

    def execute(self, args, from_tty):
        """
            Execute command called with args parameters
            Build command string in the form of a monitor command
            and call internal gdb execution.
        """

        if args.devices:
            self._list_all_registered_devices(from_tty)
        else:
            self._print_info_for_current_device(from_tty)

    def _list_all_registered_devices(self, from_tty):
        # get soc context first
        cmd_string = 'mon ctx get current'
        result = execute_remote(cmd_string, from_tty, to_string = True)
        soc_ctx = '.'
        if result:
            result = result.rstrip('\n')
            soc_ctx = get_soc_ctx_from_current(result)
        cmd_string = 'mon ctx find %s | has prop type = flash' % soc_ctx

        #execute command
        found_devs = execute_remote(cmd_string, from_tty, to_string = True)
        gdb.write('%s\n' % found_devs)

    def _print_info_for_current_device(self, from_tty):
        cmd_string = 'mon flash current'
        current_flash = execute_remote(cmd_string, from_tty, to_string = True, \
            no_wait = True)
        current_flash = current_flash.rstrip('\n')

        if 'no device selected' in current_flash:
            gdb.write('%s\n' % current_flash)
            return
        cmd_string = 'mon ctx get current'
        current_ctx = execute_remote(cmd_string, from_tty, to_string = True)
        if not current_ctx:
            gdb.write('no context selected\n')
            return

        current_ctx = current_ctx.rstrip('\n')
        cmd_string = 'mon ctx id %s:%s info' % (current_ctx, current_flash)
        ctxs = current_ctx.split(':')
        if len(ctxs) >= 3:
            device = ':%s:%s:%s' % (ctxs[1], ctxs[2], current_flash)
            cmd_string = 'mon ctx id %s info' % device
        result = execute_remote(cmd_string, from_tty, to_string = True)
        prop_bag = self._strToPropertyBag(result)
        self._pretty_print(prop_bag)

    def _strToPropertyBag(self, strProp):
        prop_bag = {}
        prop_list = strProp.split('\n')
        for prop in prop_list:
            prop = prop.replace(' ', '')
            name_value = prop.split(':')
            if len(name_value) == 2:
            #guard against inconsistency from gta side
                if name_value[1].startswith('0x') or \
                   not all(c in string.hexdigits for c in name_value[1]):
                    prop_bag[name_value[0]] = name_value[1]
                else:
                    prop_bag[name_value[0]] = ''.join(['0x', name_value[1]])
        return prop_bag

    def _pretty_print(self, data):
        if(self.is_MRAM):
            gdb.write('--------------------------\n')
            value = data['name']
            gdb.write('part: %s \n' % value)
            value = data['address']
            gdb.write('base address: 0x%x \n' % string_to_offset(value))
            gdb.write('--- Code MRAM Info ---\n')
            value = data['program_flash_address']
            gdb.write('code MRAM start address offset: 0x%x \n' % string_to_offset(value))
            value = data['size']
            gdb.write('code MRAM size: 0x%x (%s) \n' % (string_to_size(value), \
                size_to_human_readable(string_to_size(value))))
            f_sector_size = int(data['data_sect_size'],0)
            f_data_sectors = int(data['data_sectors'],0)
            gdb.write('--- Data MRAM Info ---\n')
            value = data['data_flash_address']
            gdb.write('data MRAM start address offset: 0x%x \n' % string_to_offset(value))
            value = hex(f_sector_size * f_data_sectors)
            gdb.write('data MRAM size: 0x%x (%s) \n' % (string_to_size(value), \
                size_to_human_readable(string_to_size(value))))    
            gdb.write('--------------------------\n')
            value = data['max_byte_buffer']
            gdb.write('Packet Size: %x bytes\n' % string_to_size(value))
            gdb.write('CRC verify implemented: %s \n' % self.is_crc_implemented)
            value = data['features']
            gdb.write('features: %s \n' % value)
            gdb.write('--------------------------\n')
            return
        if(data['data_flash_address'] == "0xdeadbeef"):
            value = data['name']
            gdb.write('part: %s \n' % value)
            value = data['address']
            gdb.write('base address: 0x%x \n' % string_to_offset(value))
            value = data['size']
            gdb.write('size: 0x%x (%s) \n' % (string_to_size(value), \
                size_to_human_readable(string_to_size(value))))
            value = data['sector']
            gdb.write('sectors: %d \n' % string_to_size(value))
            value = data['sector_size']
            gdb.write('sector size: 0x%x (%s) \n' % (string_to_size(value), \
                size_to_human_readable(string_to_size(value))))
            value = data['geometry']
            gdb.write('geometry: %s \n' % value)
            value = data['max_byte_buffer']
            gdb.write('Packet Size: %x bytes\n' % string_to_size(value))
            gdb.write('CRC verify implemented: %s \n' % self.is_crc_implemented)
            value = data['features']
            gdb.write('features: %s \n' % value)
        else: # Display data and program flash info
            gdb.write('--------------------------\n')
            value = data['name']
            gdb.write('part: %s \n' % value)
            value = data['address']
            gdb.write('base address: 0x%x \n' % string_to_offset(value))
            gdb.write('--- Program Flash Info ---\n')
            value = data['program_flash_address']
            gdb.write('program flash start address offset: 0x%x \n' % string_to_offset(value))
            value = data['size']
            gdb.write('program flash size: 0x%x (%s) \n' % (string_to_size(value), \
                size_to_human_readable(string_to_size(value))))
            value = data['sector']
            gdb.write('program flash sectors: %d \n' % string_to_size(value))
            value = data['sector_size']
            gdb.write('program flash sector size: 0x%x (%s) \n' % (string_to_size(value), \
                size_to_human_readable(string_to_size(value))))
            f_sector_size = int(data['data_sect_size'],0)
            f_data_sectors = int(data['data_sectors'],0)
            gdb.write('--- Data Flash Info ---\n')
            value = data['data_flash_address']
            gdb.write('data flash start address offset: 0x%x \n' % string_to_offset(value))
            value = hex(f_sector_size * f_data_sectors)
            gdb.write('data flash size: 0x%x (%s) \n' % (string_to_size(value), \
                size_to_human_readable(string_to_size(value))))    

            value = data['data_sectors']
            gdb.write('data flash sectors: %d \n' % string_to_size(value))
            value = data['data_sect_size']
            gdb.write('data flash sector size: 0x%x (%s) \n' % (string_to_size(value), \
                size_to_human_readable(string_to_size(value))))
            gdb.write('--------------------------\n')
            value = data['geometry']
            gdb.write('geometry: %s \n' % value)
            value = data['max_byte_buffer']
            gdb.write('Packet Size: %x bytes\n' % string_to_size(value))
            gdb.write('CRC verify implemented: %s \n' % self.is_crc_implemented)
            value = data['features']
            gdb.write('features: %s \n' % value)
            gdb.write('--------------------------\n')
            if(self.HSE_limits != None):
                try:
                    HSE_areas = self.HSE_limits.get_info()
                except:
                    return
                value = HSE_areas[0]
                gdb.write('Restricted Zone Detected.\nMemory Layout: %s \n' % value)
                for i in range(1,len(HSE_areas), 2):
                    gdb.write('Restricted memory: %s --- %s\n' % (HSE_areas[i], HSE_areas[i+1]))
                gdb.write('--------------------------\n')

    def show_progress_bar(self):
        pass

    def end_progress_bar(self):
        pass

def create_command(hse_limits, is_MRAM, is_crc_implemented):
    """
        Instantiate flash programmer info command
    """
    CwFlashInfo(hse_limits, is_MRAM, is_crc_implemented)
