/*
 * *****************************************************************************
 * MIT License
 * 
 * Copyright (C) 2025 Ji Youzhou. or its affiliates.  All Rights Reserved.
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 ***********************************************************************************/

#include "shell.h"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>   // 放文件顶部

#include "hal_data.h"

extern Shell shell;          
#define shell_printf(fmt, ...) \
        shellPrint(&shell, fmt, ##__VA_ARGS__)

static uint32_t cpu_mhz = 90;   /* 根据实际主频修改 */

__STATIC_INLINE uint64_t shell_get_ts_ns(void)
{
	static uint32_t cyc = 0;
	if(cyc > DWT->CYCCNT)      // 溢出
	{
    	return ((uint64_t)((uint64_t)0xffffffff + (uint64_t)DWT->CYCCNT) * 1000) / cpu_mhz;/* ns = cycle * (1000/MHz) */
	}
    cyc = DWT->CYCCNT;              /* 原子读 32-bit */
    return ((uint64_t)cyc * 1000) / cpu_mhz;/* ns = cycle * (1000/MHz) */
}  

int cmd_rd(uint8_t argc, char **argv)
{
	uintptr_t addr;
	uint32_t size = 1;
	uint8_t *p;
	uint32_t i, j;

	if (argc < 2) {
		shell_printf("Usage: rd <addr hex> [size dec, default 1]\r\n");
		shell_printf("Example: rd 0x58b053f79c50 16\r\n");
		return -1;
	}

	if (sscanf(argv[1], "%" SCNxPTR , &addr) != 1) {
		shell_printf("Invalid address format\r\n");
		return -1;
	}

	if (argc > 2) {
		if (sscanf(argv[2], "%d", &size) != 1) {
			printf("Invalid size format\r\n");
			return -1;
		}
	}

	shell_printf("start address: %p\r\n", addr);

	p = (uint8_t *)addr;
	for (i = 0; i < size; i += 16) {
		shell_printf("%08lx: ", i);
		for (j = 0; j < 16 && (i + j) < size; j++) {
			shell_printf("%02x ", p[i + j]);
			if (j == 7)
				shell_printf(" "); // 添加空格分隔
		}

		while (j < 16) {
			shell_printf("   ");
			if (j == 7)
				shell_printf(" ");
			j++;
		}

		shell_printf(" |");

		for (j = 0; j < 16 && (i + j) < size; j++) {
			if (p[i + j] >= 32 && p[i + j] <= 126) {
				shell_printf("%c", p[i + j]);
			} else {
				shell_printf(".");
			}
		}

		shell_printf("|\r\n");
	}

	return 0;
}
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN), rd, cmd_rd, test);

int cmd_wr(uint8_t argc, char **argv)
{
	uintptr_t addr;
	uint32_t value;
	uint8_t *p;
	int size = 4;

	if (argc < 3) {
		shell_printf("Usage: wr <addr hex> <value hex> [b|w|l]\r\n");
		shell_printf("  b: byte (1 byte)\r\n");
		shell_printf("  w: word (2 bytes)\r\n");
		shell_printf("  l: long (4 bytes, default)\r\n");
		return -1;
	}

	if (sscanf(argv[1], "%" SCNxPTR, &addr) != 1) {
		shell_printf("Invalid address format\r\n");
		return -1;
	}

	if (sscanf(argv[2], "%" SCNxPTR, &value) != 1) {
		shell_printf("Invalid value format\r\n");
		return -1;
	}

	if (argc > 3) {
		switch (argv[3][0]) {
			case 'b': size = 1; break;
			case 'w': size = 2; break;
			case 'l': size = 4; break;
			default: shell_printf("Invalid size format, use b/w/l\r\n"); return -1;
		}
	}

	p = (uint8_t *)addr;

	switch (size) {
		case 1:
			*p = (uint8_t)value;
			shell_printf("Wrote 0x%02x to 0x%08x\r\n", value, addr);
			break;
		case 2:
			*(uint16_t *)p = (uint16_t)value;
			shell_printf("Wrote 0x%04x to 0x%08x\r\n", value, addr);
			break;
		case 4:
			*(uint32_t *)p = value;
			shell_printf("Wrote 0x%08x to 0x%08x\r\n", value, addr);
			break;
	}

	return 0;
}
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN), wr, cmd_wr, test);

int cmd_hex2dec(uint8_t argc, char **argv)
{
	uint32_t value;

	if (argc < 2) {
		shell_printf("Usage: hex2dec <hex>\r\n");
		return -1;
	}

	if (sscanf(argv[1], "%" SCNxPTR, &value) != 1) {
		shell_printf("Invalid hex format\r\n");
		return -1;
	}

	shell_printf("0x%x = %u\r\n", value, value);
	return 0;
}
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN), hex2dec, cmd_hex2dec, test);


int cmd_time(uint8_t argc, char **argv)
{
	uint64_t start_time;
	uint64_t end_time;
	int ret;

	if (argc < 2) {
		shell_printf("Usage: time <command>\r\n");
		return -1;
	}

	ShellCommand *command = shellSeekCommand(&shell,
                                                 argv[1],
                                                 shell.commandList.base,
                                                 0);

	if (!command)
    {
		shell_printf("Unknown command: %s\r\n", argv[1]);
        return 0;
    }

	if (command->data.cmd.function) {
		start_time = shell_get_ts_ns();
		ret = command->data.cmd.function(argc - 1, argv + 1);
		end_time = shell_get_ts_ns();
	} else {
		shell_printf("Command %s has no function\r\n", command->data.cmd.name);
		return -1;
	}

	shell_printf("------------------------------------------------------\r\n");
	shell_printf("start time: %" PRIu64 " ns\r\n", start_time);
	shell_printf("end time: %" PRIu64 " ns\r\n", end_time);
	shell_printf("time consumption %" PRIu64 " ns.\r\n",  end_time - start_time);

	return 0;
}

SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN), timecal, cmd_time, test);
/******************* (C) COPYRIGHT 2025  *********************************/