/*****************************************************************************
* File Name          : htk_cli.c
* Author             : Crystal
* Version            : V1.0.0.0
* Date               : 11/Feb/2020
* Description        : This file can be modified for using with any project.
******************************************************************************/

#include "htk_cli.h"
#include "htk_spi.h"

void htk_SPI_writeSingleRegister(uint8_t address, uint8_t data);
void htk_SPI_readSingleRegister(uint8_t address, uint8_t *data);

/**
 *  Definition of HTK shell commands
 *  For example 4 commands
 *  - help:  for list command
 *  - read:  read data from a given address
 *  - write: write data to a given address
 *  - info:  for example of shell
 */
shell_cmds htk_shell_cmds =
{
  4,
  {
    { "help",
	  "List available commands",
	  shell_command_help },

	{ "info",
	  "Print out device informations",
	  shell_command_info },

	{ "read",
	  "Read data at a given address",
	  shell_command_read },

	{ "write",
	  "Write data at a given address",
	  shell_command_write },

  }
};


/**
 *  Write a callback handler
 *  must be in following format
 *  int (*func)(shell_cmd_args *args);
 */

/**
 *  INFO command for example using shell
 *
 */
int shell_command_info(shell_cmd_args * args)
{
	htk_UART_Transmit((uint8_t*)"\r\nINFO:STM32F103T8"
			"\r\nSupported: BC45 RefA FESCO module"
			"\r\nOK\r\n", 59);

  return 0;
}

/**
 *  HELP command for list available commands
 *  > help
 *  > CMD: help,  DESC: List available commands
 *  > CMD: read,  DESC: Read data at a given address
 *  > CMD: write, DESC: Write data at a given address
 *  > OK
 *  >
 */
int shell_command_help(shell_cmd_args * args)
{
  uint8_t i;
  uint8_t tmpLen = 0;

	for(i=0; i<htk_shell_cmds.count; i++) 
	{
		htk_UART_Transmit( (uint8_t *)"\r\nCMD: ", 7);
		// Print out Command
		tmpLen = shell_str_len((char *)htk_shell_cmds.cmds[i].cmd);
		htk_UART_Transmit( (uint8_t *)htk_shell_cmds.cmds[i].cmd, tmpLen);

		if(tmpLen == 4) 
		{
			htk_UART_Transmit( (uint8_t *)",  DESC: ", 9);
		}
		else if(tmpLen ==5)
		{
			htk_UART_Transmit( (uint8_t*)", DESC: ", 8);
		}
		else if(tmpLen == 6)
		{
			htk_UART_Transmit((uint8_t *)",DESC: ", 7);
		}
		else
		{
			htk_UART_Transmit((uint8_t *)",    DESC: ", 11);
		}
		// Print out Description
		tmpLen = shell_str_len((char *)htk_shell_cmds.cmds[i].desc);
		htk_UART_Transmit((uint8_t *)htk_shell_cmds.cmds[i].desc, tmpLen);
	}

	htk_UART_Transmit((uint8_t *)"\r\nOK\r\n", 6);

	return 0;
}

/**
 *  READ command for read data at a given address
 *
 *  > read -h
 *  > Usage: -read <address in hex>
 * 	>		 -read <page number> <address in hex>
 *  > NOTE: If you don't specify page number. It 
 *  		will read data at a given address on
 * 			page 0.
 *  > OK
 *
 *  > read 1A
 *  > ADDR[HEX]: 1A, VAL[HEX]: 08
 *  > OK
 */
int shell_command_read(shell_cmd_args * args)
{
  uint8_t tmpData;
  uint8_t tmpLen;
  uint8_t rdAddress;
  //uint8_t wrAddress;
  //uint8_t wrData;
  uint8_t tmpBuffer[3];
  uint8_t status = ERROR;
  //uint8_t i = 0;


	// check arguments
	if((args->count > 1)||(args->count == 0))
	{
		htk_UART_Transmit((uint8_t *)"\r\nInvalid parameter"
						"\r\nFAIL\r\n", 27);
	}
	else
	{
		tmpLen = shell_str_len(args->args[0].val);
		// The argument is help option
		if(shell_str_cmp(args->args[0].val, "-h", tmpLen, 2) == 0)
		{
			htk_UART_Transmit(
					(uint8_t *)"\r\nUsage: -read <address in hex>"
					"\r\n"
					"\r\nEx > read 1A"
					"\r\n     ADDR[HEX]: 1A, VAL[HEX]: 08"
					"\r\n     OK\r\n", 92
					);
		}
		// The argument is a register address
		else
		{
			// Convert Address
			status = customParseHEX((uint8_t *)args->args[0].val, tmpLen, &rdAddress);
			if(status == 0x00)
			{
				//Read a data from a given address
				htk_SPI_readSingleRegister(rdAddress, &tmpData);

				htk_UART_Transmit((uint8_t *)"\r\nADDR[HEX]: ", 13);
				dataToHex(&tmpBuffer[0], rdAddress);
				htk_UART_Transmit((uint8_t *)tmpBuffer, 2);
				dataToHex(&tmpBuffer[0], tmpData);
				htk_UART_Transmit((uint8_t *)", VAL[HEX]:", 11);
				htk_UART_Transmit((uint8_t *)tmpBuffer, 2);
				htk_UART_Transmit((uint8_t *)"\r\nOK\r\n", 6);
			}
			else
			{
				htk_UART_Transmit(
						(uint8_t *)"\r\nError: Invalid address"
						"\r\nFAIL\r\n", 32
						);
			}
		}
	}

	return 0;
}


/**
 *  WRITE command for write data at a given address
 *
 *  > write -h
 *  > Usage: -write <address in hex> <value in hex>
 *  > OK
 * 
 *  > write 1A 10
 *  > ADDR[HEX] 1A, WR[HEX] 10
 *  > OK
 *
 */
int shell_command_write(shell_cmd_args * args)
{
  uint8_t tmpLen;
  uint8_t wrAddress;
  uint8_t wrValue;
  uint8_t tmpBuffer[3];
  //uint8_t i = 0;
  uint8_t status = ERROR;

	// check arguments
	if((args->count > 2)||(args->count == 0))
	{
		htk_UART_Transmit(
				(uint8_t *)"\r\nInvalid parameter"
				"\r\nFAIL\r\n", 27);
	}
	// Check the arguments is help option or not.
	else if(args->count == 1)
	{
		tmpLen = shell_str_len(args->args[0].val);
		if(shell_str_cmp(args->args[0].val, "-h", tmpLen, 2) == 0)
		{
			htk_UART_Transmit(
			(uint8_t *)"\r\nUsage: -write <address in hex> <value in hex>"
			"\r\n"
			"\r\nEx > write 1A 10"
			"\r\n     ADDR[HEX] 1A, WR[HEX] 10"
			"\r\n     OK\r\n", 109
			);
		}
		else
		{
			htk_UART_Transmit(
			(uint8_t *)"\r\nInvalid parameter"
			"\r\nFAIL\r\n", 27);
		}
	}
	//There are two arguments via an address and value.
	else
	{
		tmpLen = shell_str_len(args->args[0].val);
		// Convert Address
		status = customParseHEX((uint8_t *)args->args[0].val, tmpLen, &wrAddress);
		if(status == 0x00)
		{
			//Convert Value
			status = customParseHEX((uint8_t *)args->args[1].val, tmpLen, &wrValue);
			if(status == 0x00)
			{
				htk_SPI_writeSingleRegister(wrAddress, wrValue);
				htk_UART_Transmit((uint8_t *)"\r\nADDR[HEX]: ", 13);
				dataToHex(&tmpBuffer[0], wrAddress);
				htk_UART_Transmit((uint8_t *)tmpBuffer, 2);
				htk_UART_Transmit((uint8_t *)", WR[HEX]:", 10);
				dataToHex(&tmpBuffer[0], wrValue);
				htk_UART_Transmit((uint8_t *)tmpBuffer, 2);
				htk_UART_Transmit((uint8_t *)"\r\nOK\r\n", 6);
			}
			else
			{
				htk_UART_Transmit(
				(uint8_t *)"\r\nInvalid value"
				"\r\nFAIL\r\n", 23
				);
			}
		}
		else
		{
			htk_UART_Transmit(
			(uint8_t *)"\r\nInvalid address"
			"\r\nFAIL\r\n", 25
			);
		}
	}
	return 0;
}


/**
 *  shell command processing
 *
 */
uint8_t htk_shellProcess(uint8_t * commandLine)
{
  uint16_t status;
  /* Modify for use with setup mode of BC45*/
  status = shell_process_cmds(&htk_shell_cmds, (char *)commandLine);
  switch (status)
  {
    case SHELL_PROCESS_ERR_CMD_UNKN:
    	htk_UART_Transmit((uint8_t *)"\r\nERROR: Unknown command\r\n", 26);
    	break;
    case SHELL_PROCESS_ERR_ARGS_LEN:
    	htk_UART_Transmit((uint8_t *)"\r\nERROR: Argument length\r\n", 26);
    	break;
    case SHELL_PROCESS_ERR_ARGS_MAX:
    	htk_UART_Transmit((uint8_t *)"\r\nERROR: Too many arguments\r\n", 29);
    	break;
    default: // OK
    	break;
  }
  return status;
}

/**
 *  shell command prompt
 *
 */
uint8_t htk_commandPrompt(uint8_t * pBuffer, uint8_t * pBufferLen,
		                      uint8_t * prompt,  uint8_t promptLen)
{
  static uint8_t startPrompt = 0;
  static uint8_t * pData;
  uint8_t tmpData;
  static uint8_t dataCounter = 0;

  if(startPrompt == 0)
  {
    startPrompt = 1;
    pData = pBuffer;
    * pData = '\0';
    dataCounter = 0;
    htk_UART_Transmit((uint8_t *)prompt, promptLen);
  }
  // Create pBuffer from rxFIFO
  while(rxFIFO.entries > 0)
  {
    // get data from rxFIFO
    htk_ringBufferRead(&rxFIFO, &tmpData);
		switch(tmpData)
		{
			case '\r': // 0x0D Enter
				startPrompt = 0;
				* pBufferLen = dataCounter;
				return (uint8_t)shell_str_len((char *)pBuffer);
			//break;
			case 0x7F: // delete (127)
				if(pData > pBuffer)
				{
					* (--pData) = '\0';
					dataCounter--;
					htk_UART_Transmit(&tmpData, 1);
				}
			break;
			default:
				if((tmpData >= ' ')&&(tmpData < 127))
				{
					* pData++ = tmpData;
					* pData = '\0';
					dataCounter++;
					htk_UART_Transmit(&tmpData, 1);
				}
			break;
		}
  }
  return 0;
}

