
#include "uart_IO.h"

int String_HexToVal_Multi(const char* str, u8* hex, u16 hex_max)
{
  int num;
  u16 idx = 0;
  u8  tmp = 0;
  u8  high_nibble = 1;

  if( str == NULL || hex == NULL || hex_max == 0 ) 
  {
    xil_printf("[E] We received something from UART but lost at converting stage(Pointer Problem?)\r\n");
    return -1;
  }

  for( u16 i = 0; str[i] != '\0' && str[i] != '\r' && str[i] != '\n'; i++ )
  {
    char c = str[i];

    // Skip whitespace (spaces, tabs)
    if( c == ' ' || c == '\t' ) continue;

    // Convert hex char to nibble
    if( c >= '0' && c <= '9' ) num = c - '0';
    else if( c >= 'A' && c <= 'F' ) num = 10 + c - 'A';
    else if( c >= 'a' && c <= 'f' ) num = 10 + c - 'a';
    else
    {
      xil_printf("[E] Invalid hex '%c' at pos %d\r\n", c, i);
      return -2;
    }

    if( high_nibble )
    {
      tmp = (u8)(num << 4);
      high_nibble = 0;
    }
    else
    {
      tmp |= (u8)num;

      if( idx >= hex_max )
      {
        xil_printf("[E] Output buffer overflow\r\n");
        return -3;
      }

      hex[idx++] = tmp;
      high_nibble = 1;
    }
  }

  // Check for incomplete final byte (odd number of hex chars)
  if( high_nibble == 0 )
  {
    xil_printf("[E] Odd-length hex string, last byte incomplete\r\n");
    return -4;  // Incomplete byte is an error
  }

  if( idx == 0 ) return 0;
  return (int)idx;
}


int Console_In( char* str, int max_len )
{
  static char pending = 0;  // Hold char after \r when not followed by \n
                            // Persistent across calls for proper \r\n handling
  int i = 0;
  char c = pending;
  pending = 0;  // Clear pending for this call
  
  if( str == NULL || max_len < 2 ) return -1;
  
  for( ; ; i++ )
  {
    // If we have a pending character, use it first
    if( c == 0 )
    {
      // Bounds check FIRST, BEFORE writing
      if( i >= max_len - 1 )
      {
        str[i] = '\0';
        xil_printf("[E] UART Input buffer overflow!\r\n");
        return -1;  /* Buffer overflow */
      }
      
      c = (char)inbyte();
    }
    
    // Handle line endings
    if( c == '\r' )
    {
      // Consume potential \n after \r (Windows line ending)
      char next = (char)inbyte();
      if( next == '\n' )
      {
        // \r\n - consume both
        str[i] = '\0';
        pending = 0;
        return i;
      }
      else
      {
        // Just \r - the next byte is not \n
        // Store it for next call (it might be the start of the next command)
        pending = next;
        str[i] = '\0';
        return i;
      }
    }
    else if( c == '\n' )
    {
      // Unix line ending
      str[i] = '\0';
      pending = 0;
      return i;
    }
    else
    {
      str[i] = c;
      c = 0;  // Clear so we read next character
    }
  }
}

int UART_RecvInstr(u8* recvbuffer)
{
  char cin[4096] = {0};
  int len = 0;

	int inCount = 0;
	inCount = Console_In( cin, 4096 );
	xil_printf("[I] Console_InByte: %d\r\n", inCount);
	len = String_HexToVal_Multi( cin, recvbuffer, HEX_MAX_LEN );
	if( len <= 0 ) return 0;  /* 0 = no input, <0 = parse error */

	// Validate command length
	if( len < CMD_LEN_MIN )
	{
	  xil_printf("[E] Cmd too short: %d < %d\r\n", len, CMD_LEN_MIN);
	  return -1;
	}

	if( len > CMD_LEN_MAX )
	{
	  xil_printf("[E] Cmd too long: %d > %d\r\n", len, CMD_LEN_MAX);
	  return -2;
	}
	xil_printf("[D] HexToVal:  " );
	for( int i=0; i<len; i++ ) xil_printf("  %02x", recvbuffer[i] );
	xil_printf("\r\n");
	xil_printf("[D] Total Intake %d bytes\r\n",len);
  return len;
}
