/**
 * @file   Utility.c
 * @author StepTechnica
 * @date   Nov 16 2022
 * 
 * @brief Evaluation Board 用ソースファイル「ユーティリティ」
 * 
 * @copyright (C) 2022- StepTechnica Co.,Ltd.
 * 
 * このソフトウェアは、コピー利用、配布、変更の追加、変更を加えたもの再配布、商用利用、有料販売など、どなたも自由にお使いいただくことができます。
 * このソフトウェアには保証はついていません。
 * このソフトウェアを利用したことで問題が起きた際に、ソフトウェアの製作者は一切の責任を負いません。
 * 
 */

/* -----------------------------------------------------------------------------
 * #include
 */

#include "Utility.h"
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "stm32f4xx_hal.h"

extern TIM_HandleTypeDef htim1;


/**
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 * @brief： 指定された時間待つ。
 * 
 * @note： 
 * 
 * @param  uint16_t us ： 待つ時間 [μsec]
 * @retval none
 * 
 */
void delay_us(uint16_t us)
{
	// set the counter value a 0
	__HAL_TIM_SET_COUNTER(&htim1,0);
	// wait for the counter to reach the us input in the parameter
	while (__HAL_TIM_GET_COUNTER(&htim1) < us) {}
}

/**
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 * @brief： 64ビットの整数を、16桁になるよう0パディングした文字列に変換する
 * 
 * @note： 
 * 
 * @param  char* dest ： 文字列格納先
 * @param  uint64_t val ： 64ビットの整数
 * @retval none
 * 
 */
void Uint64ToHexStr(char* dest, uint64_t val)
{
	int i;
	for (i = 0; i < 8; i++)
	{
		int shift = ((8 - i - 1) * 8);
		uint64_t mask = (uint64_t)0xFF << shift;
		uint16_t output = (uint16_t)((val & mask) >> shift);
		sprintf(dest, "%02X", output);
		dest += 2;
	}
}

/**
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 * @brief： 2byte単位のスワップを行う
 * 
 * @note： 
 * 
 * @param  uint16_t* d ： 対象データ格納先
 * @retval none
 * 
 */
void SwapWord(uint16_t* d)
{
	uint16_t swap = (*d & 0xFF00) >> 8;
	swap |= (*d & 0x00FF) << 8;
	*d = swap;
}

/**
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 * @brief： 4byte単位のスワップを行う
 * 
 * @note： 
 * 
 * @param  uint32_t* d ： 対象データ格納先
 * @retval none
 * 
 */
void SwapLong(uint32_t* d)
{
	uint32_t swap = (*d & 0xFF000000) >> 24;
	swap |= (*d & 0x00FF0000) >> 8;
	swap |= (*d & 0x0000FF00) << 8;
	swap |= (*d & 0x000000FF) << 24;
	*d = swap;
}

/**
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 * @brief： 8byte単位のスワップを行う
 * 
 * @note： 
 * 
 * @param  uint64_t* d ： 対象データ格納先
 * @retval none
 * 
 */
void SwapLongLong(uint64_t* d)
{
	uint64_t swap = (*d & 0xFF00000000000000) >> 56;
	swap |= (*d & 0x00FF000000000000) >> 40;
	swap |= (*d & 0x0000FF0000000000) >> 24;
	swap |= (*d & 0x000000FF00000000) >> 8;
	swap |= (*d & 0x00000000FF000000) << 8;
	swap |= (*d & 0x0000000000FF0000) << 24;
	swap |= (*d & 0x000000000000FF00) << 40;
	swap |= (*d & 0x00000000000000FF) << 56;
	*d = swap;
}

/**
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 * @brief： 文字列中の小文字を大文字に変換する
 * 
 * @note： 
 * 
 * @param  char* str ： 変換対象文字列
 * @param  int maxLen： 変換するバイト数のリミット
 * @retval none
 * 
 */
void StrToUpper(char* str, int maxLen)
{
    char *p;
	int i = 0;
    for (p = str; *p != '\0' && i < maxLen; p++)
	{
        *p = toupper(*p);
	}
}

/**
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 * @brief： 16進文字列の変換
 *
 * @note： 文字列を16進数として変換した値を返す
 *
 * @param  char* hexstring  : 対象の文字列
 * @param  short format     : 書式
 * @retval unsigned short convert = 変換された値
 *                                < 0 = 解釈エラー
 *
 */
short getHexStrings(char* hexstring, short format)
{
	char buf[32];	// 32
	unsigned long convert;
	unsigned long dwLength;
	unsigned long dwIndex;

	strcpy(buf, hexstring);
	dwLength = strlen(buf);
	if(4 < dwLength) {
		// print_string("unrecognized hex-strings.\n");
		return(-1);
	}

	//// 文字種
	for(dwIndex=0; 0 != buf[dwIndex]; dwIndex++) {
		if( ((0x30 <= buf[dwIndex]) && (buf[dwIndex] <= 0x39))	// '0'-'9'
		||  ((0x41 <= buf[dwIndex]) && (buf[dwIndex] <= 0x46))	// 'A'-'F'
		||  ((0x61 <= buf[dwIndex]) && (buf[dwIndex] <= 0x66))	// 'a'-'f'
		) {
			// OK
		} else {
			// NG
			// print_string("illegal character in hex-strings.\n");
			return(-2);
		}
	}

	// convert
	strToBin(buf, &convert);

	//// アドレス
	if(convert % format) {
		// print_string("not match byte order.\n");
		return(-3);
	}

	return((short)convert);
}

/**
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 * @brief： 16進文字列の変換
 *
 * @note： 文字列を数値に変換する
 *
 * @param  char* com  : 対象の文字列
 * @param  unsigned short* a  : 変換後の値を返すバッファ
 * @retval 0   = 正常終了
 *         < 0 = 16進数文字ではない
 *
 */
short strToBin(char* com, unsigned long* a)
{
	int 	i;

	*a = 0;

	// check character
	for (i=0; 0 != com[i]; i++) {
		if( ((0x30 <= com[i]) && (com[i] <= 0x39))	// '0'-'9'
		||  ((0x41 <= com[i]) && (com[i] <= 0x46))	// 'A'-'F'
		||  ((0x61 <= com[i]) && (com[i] <= 0x66))	// 'a'-'f'
		) {
			// OK
		} else {
			// NG
			return(-1);
		}
	}

	// convert
	while (*com != 0) {
        if ((*com >= '0') && (*com <= '9')) {
            *a = (*a * 0x10) + (*com - (char)'0');
        }
        else if ((*com >= 'a') && (*com <= 'z')) {
            *a = (*a * 0x10) + (*com - 'a' + 0x0a);
        }
        else if ((*com >= 'A') && (*com <= 'Z')) {
            *a = (*a * 0x10) + (*com - 'A' + 0x0a);
        }

        com++;
    }

	return(0);
}


/**
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 * @brief： トークン切り出し
 *
 * @note： 文字列からトークン切り出す
 *
 * @param  unsigned char *str : 対象の文字列
 * @param  char *argv[]  : 切り出したトークンを格納するバッファ
 * @retval 0 = トークンなし もしくは 8個以上の場合
 *         n = 切り出したトークンの数
 *
 */
long divideToken(unsigned char *str, char *argv[])
{
	long    n ;
	char    *token ;


	// バックアップ
	token = (char *)str ;

	while ( *str != '\0' ) {

		if ( (*str >= 'a') && (*str <= 'z') ) {
			// 文字列中の文字をすべて大文字化
			*str -= 'a' - 'A';
		} else if ( *str == ';' ) {
			// セミコロン以降はコメントとみなす
			*str = '\0';
			break;
		}
		str++;
	}

	// リストア
	str = (unsigned char *)token;
	n = 0;
	while ((token = strtok((char *)str, " ")) != NULL) {
		// トークンの分解
		argv[n] = (char *)token;
		n++;
		str = NULL;
		if ( n > 8 ) {
			// Too Many Argment
//			printf( "Too Many Argment.\n" );
			return 0 ;
		}
	}

	return( n );
}

