/* USER CODE BEGIN Header */
/**
 ******************************************************************************
 * @file           : main.c
 * @brief          : Main program body
 ******************************************************************************
 ** This notice applies to any and all portions of this file
 * that are not between comment pairs USER CODE BEGIN and
 * USER CODE END. Other portions of this file, whether 
 * inserted by the user or by software development tools
 * are owned by their respective copyright owners.
 *
 * COPYRIGHT(c) 2019 STMicroelectronics
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *   1. Redistributions of source code must retain the above copyright notice,
 *      this list of conditions and the following disclaimer.
 *   2. Redistributions in binary form must reproduce the above copyright notice,
 *      this list of conditions and the following disclaimer in the documentation
 *      and/or other materials provided with the distribution.
 *   3. Neither the name of STMicroelectronics nor the names of its contributors
 *      may be used to endorse or promote products derived from this software
 *      without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 ******************************************************************************
 */
/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include <stdint.h>
#include "crypto_aead.h"
#include "api.h"

#define DEBUG 
#define MAX_LEN 1400

#ifdef DEBUG
  #include "SEGGER_RTT.h"
  #include "SEGGER_RTT_Conf.h"
  #define dbg_printf(...) SEGGER_RTT_printf(0, __VA_ARGS__)
#endif

unsigned char c[MAX_LEN];
unsigned long long clen = 0;
unsigned char m[MAX_LEN];
unsigned long long mlen = 0;
unsigned char ad[MAX_LEN];
unsigned long long adlen = 0;
unsigned char text[2] = "OK";

unsigned char nsec[CRYPTO_NSECBYTES];
const unsigned long long nslen = CRYPTO_NSECBYTES;
unsigned char npub[CRYPTO_NPUBBYTES];
const unsigned long long nplen = CRYPTO_NPUBBYTES;
unsigned char k[CRYPTO_KEYBYTES];
const unsigned long long klen = CRYPTO_KEYBYTES;

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART1_UART_Init(void);
static void read_variable_serial(unsigned char action);
static void write_variable_serial(unsigned char target[], uint32_t len);

static void read_serial(void *dst, unsigned int len) {
	unsigned char *buf = dst;
  #ifdef DEBUG
  dbg_printf("Reading %d serial bytes\n", len);
  #endif
	for (int i = 0; i < len; i++) {
		while (!LL_USART_IsActiveFlag_RXNE(USART1));
		buf[i] = LL_USART_ReceiveData8(USART1);
	}
  #ifdef DEBUG
  dbg_printf("done.\n", len);
  #endif
}

static void write_serial(const void *src, unsigned int len) {
	const unsigned char *buf = src;
	for (int i = 0; i < len; i++) {
    #ifdef DEBUG
    dbg_printf("Write to serial: %02x\n", buf[i]);
    #endif
    while (!(LL_USART_IsActiveFlag_TXE(USART1)));
		LL_USART_TransmitData8(USART1, buf[i]);
    #ifdef DEBUG
    dbg_printf("Done writing!\n");
    #endif
	}
}

static void read_variable_serial(unsigned char action) {
	uint32_t len;
  #ifdef DEBUG
  dbg_printf("Let's read our variable: %c\n", action);
  #endif
  read_serial(&len, sizeof(len));
  #ifdef DEBUG
  dbg_printf("with length %lu \n", len);
  #endif 
  switch(action) {
		case 'k':
			while (len != CRYPTO_KEYBYTES);
			read_serial(k, len);
			break;
		case 'p':
			if (len != CRYPTO_NPUBBYTES) { 
        #ifdef DEBUG 
        dbg_printf("Assert failed %d != %d\n", len, CRYPTO_NPUBBYTES);
        #endif
        for(;;); 
      }
			read_serial(npub, len);
			break;
		case 's':
			while (len != CRYPTO_NSECBYTES);
			read_serial(nsec, len);
			break;
		case 'a':
			while (len > MAX_LEN);
			adlen = len;
			read_serial(ad, len);
			break;
		case 'm':
			while (len > MAX_LEN);
			mlen = len;
			read_serial(m, len);
			break;
		case 'c':
			while (len > MAX_LEN);
			clen = len;
			read_serial(c, len);
			break;
		default: 
			for (;;);
	}
}

static void write_variable_serial(unsigned char target[], uint32_t len) {
	write_serial(&len, sizeof(len));
	write_serial(target, len);
}


int main(void)
{
	/* USER CODE BEGIN 1 */

	/* USER CODE END 1 */

	/* MCU Configuration--------------------------------------------------------*/

	/* Reset of all peripherals, Initializes the Flash interface and the Systick. */


	LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_AFIO);
	LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_PWR);

	NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);

	/* System interrupt init*/

	/**NOJTAG: JTAG-DP Disabled and SW-DP Enabled 
	*/
	LL_GPIO_AF_Remap_SWJ_NOJTAG();

	/* USER CODE BEGIN Init */

	/* USER CODE END Init */

	/* Configure the system clock */
	SystemClock_Config();

	/* USER CODE BEGIN SysInit */
  SEGGER_RTT_Init();
	/* USER CODE END SysInit */

	/* Initialize all configured peripherals */
	MX_GPIO_Init();
	MX_USART1_UART_Init();
	/* USER CODE BEGIN 2 */

	/* USER CODE END 2 */

	/* Infinite loop */
	/* USER CODE BEGIN WHILE */
	unsigned char rcv;
	int res;

	while (1) {
		read_serial(&rcv, 1);
    #ifdef DEBUG
    dbg_printf("Received action: %c\n", rcv);
    #endif
    switch (rcv) {
			case 'c': 
			case 'm': 
			case 'a': 
			case 'k': 
			case 's': 
			case 'p':
				read_variable_serial(rcv);
				break;

			case 'C': write_variable_serial(c, clen); break;
			case 'M': write_variable_serial(m, mlen); break;
			case 'A': write_variable_serial(ad, adlen); break;
			case 'K': write_variable_serial(k, klen); break;
			case 'S': write_variable_serial(nsec, nslen); break;
			case 'P': write_variable_serial(npub, nplen); break;

			case 'e':
        #ifdef DEBUG
        dbg_printf("m: "); for (int i = 0; i < mlen; i++) dbg_printf("%02x", m[i]); dbg_printf("\n");
        dbg_printf("a: "); for (int i = 0; i < adlen; i++) dbg_printf("%02x", ad[i]); dbg_printf("\n");
        dbg_printf("p: "); for (int i = 0; i < nplen; i++) dbg_printf("%02x", npub[i]); dbg_printf("\n");
        dbg_printf("k: "); for (int i = 0; i < klen; i++) dbg_printf("%02x", k[i]); dbg_printf("\n");
        #endif
        LL_GPIO_TogglePin(GPIOB, LL_GPIO_PIN_12);
        res = crypto_aead_encrypt(c, &clen, m, mlen, ad, adlen, nsec, npub, k);
        LL_GPIO_TogglePin(GPIOB, LL_GPIO_PIN_12);
				break;
      
      case 'd':
        #ifdef DEBUG
        dbg_printf("m: "); for (int i = 0; i < mlen; i++) dbg_printf("%02x", m[i]); dbg_printf("\n");
        dbg_printf("a: "); for (int i = 0; i < adlen; i++) dbg_printf("%02x", ad[i]); dbg_printf("\n");
        dbg_printf("p: "); for (int i = 0; i < nplen; i++) dbg_printf("%02x", npub[i]); dbg_printf("\n");
        dbg_printf("k: "); for (int i = 0; i < klen; i++) dbg_printf("%02x", k[i]); dbg_printf("\n");
        #endif

        LL_GPIO_TogglePin(GPIOB, LL_GPIO_PIN_12);
        res = crypto_aead_decrypt(m, &mlen, nsec, c, clen, ad, adlen, npub, k);
        LL_GPIO_TogglePin(GPIOB, LL_GPIO_PIN_12);
        break;

      default:
        continue;

		}
		/* USER CODE END WHILE */
	}
}

/**
 * @brief System Clock Configuration
 * @retval None
 */
void SystemClock_Config(void)
{
	LL_FLASH_SetLatency(LL_FLASH_LATENCY_1);

	if(LL_FLASH_GetLatency() != LL_FLASH_LATENCY_1)
	{
		Error_Handler();  
	}
	LL_RCC_HSI_SetCalibTrimming(16);
	LL_RCC_HSI_Enable();

	/* Wait till HSI is ready */
	while(LL_RCC_HSI_IsReady() != 1)
	{

	}
	LL_RCC_PLL_ConfigDomain_SYS(LL_RCC_PLLSOURCE_HSI_DIV_2, LL_RCC_PLL_MUL_12);
	LL_RCC_PLL_Enable();

	/* Wait till PLL is ready */
	while(LL_RCC_PLL_IsReady() != 1)
	{

	}
	LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1);
	LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_2);
	LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_1);
	LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL);

	/* Wait till System clock is ready */
	while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL)
	{

	}
	LL_Init1msTick(48000000);
	LL_SYSTICK_SetClkSource(LL_SYSTICK_CLKSOURCE_HCLK);
	LL_SetSystemCoreClock(48000000);
}

/**
 * @brief USART1 Initialization Function
 * @param None
 * @retval None
 */
static void MX_USART1_UART_Init(void)
{

	/* USER CODE BEGIN USART1_Init 0 */

	/* USER CODE END USART1_Init 0 */

	LL_USART_InitTypeDef USART_InitStruct = {0};

	LL_GPIO_InitTypeDef GPIO_InitStruct = {0};

	/* Peripheral clock enable */
	LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_USART1);

	LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOA);
	/**USART1 GPIO Configuration  
	  PA9   ------> USART1_TX
	  PA10   ------> USART1_RX 
	  */
	GPIO_InitStruct.Pin = LL_GPIO_PIN_9;
	GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
	GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH;
	GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
	LL_GPIO_Init(GPIOA, &GPIO_InitStruct);

	GPIO_InitStruct.Pin = LL_GPIO_PIN_10;
	GPIO_InitStruct.Mode = LL_GPIO_MODE_FLOATING;
	LL_GPIO_Init(GPIOA, &GPIO_InitStruct);

	/* USER CODE BEGIN USART1_Init 1 */

	/* USER CODE END USART1_Init 1 */
	USART_InitStruct.BaudRate = 115200;
	USART_InitStruct.DataWidth = LL_USART_DATAWIDTH_8B;
	USART_InitStruct.StopBits = LL_USART_STOPBITS_1;
	USART_InitStruct.Parity = LL_USART_PARITY_NONE;
	USART_InitStruct.TransferDirection = LL_USART_DIRECTION_TX_RX;
	USART_InitStruct.HardwareFlowControl = LL_USART_HWCONTROL_NONE;
	LL_USART_Init(USART1, &USART_InitStruct);
	LL_USART_ConfigAsyncMode(USART1);
	LL_USART_Enable(USART1);
	/* USER CODE BEGIN USART1_Init 2 */

	/* USER CODE END USART1_Init 2 */

}

/**
 * @brief GPIO Initialization Function
 * @param None
 * @retval None
 */
static void MX_GPIO_Init(void)
{
	LL_GPIO_InitTypeDef GPIO_InitStruct = {0};

	/* GPIO Ports Clock Enable */
	LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOC);
	LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOD);
	LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOA);
	LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOB);

	/**/
	LL_GPIO_ResetOutputPin(GPIOB, LL_GPIO_PIN_12);

	/**/
	GPIO_InitStruct.Pin = LL_GPIO_PIN_13|LL_GPIO_PIN_14|LL_GPIO_PIN_15;
	GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG;
	LL_GPIO_Init(GPIOC, &GPIO_InitStruct);

	/**/
	GPIO_InitStruct.Pin = LL_GPIO_PIN_0|LL_GPIO_PIN_1;
	GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG;
	LL_GPIO_Init(GPIOD, &GPIO_InitStruct);

	/**/
	GPIO_InitStruct.Pin = LL_GPIO_PIN_0|LL_GPIO_PIN_1|LL_GPIO_PIN_2|LL_GPIO_PIN_3 
		|LL_GPIO_PIN_4|LL_GPIO_PIN_5|LL_GPIO_PIN_6|LL_GPIO_PIN_7 
		|LL_GPIO_PIN_8|LL_GPIO_PIN_11|LL_GPIO_PIN_12|LL_GPIO_PIN_15;
	GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG;
	LL_GPIO_Init(GPIOA, &GPIO_InitStruct);

	/**/
	GPIO_InitStruct.Pin = LL_GPIO_PIN_0|LL_GPIO_PIN_1|LL_GPIO_PIN_2|LL_GPIO_PIN_10 
		|LL_GPIO_PIN_11|LL_GPIO_PIN_13|LL_GPIO_PIN_14|LL_GPIO_PIN_15 
		|LL_GPIO_PIN_3|LL_GPIO_PIN_4|LL_GPIO_PIN_5|LL_GPIO_PIN_6 
		|LL_GPIO_PIN_7|LL_GPIO_PIN_8|LL_GPIO_PIN_9;
	GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG;
	LL_GPIO_Init(GPIOB, &GPIO_InitStruct);

	/**/
	GPIO_InitStruct.Pin = LL_GPIO_PIN_12;
	GPIO_InitStruct.Mode = LL_GPIO_MODE_OUTPUT;
	GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
	GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
	LL_GPIO_Init(GPIOB, &GPIO_InitStruct);

	/**/
	LL_GPIO_AF_EnableRemap_PD01();

}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
 * @brief  This function is executed in case of error occurrence.
 * @retval None
 */
void Error_Handler(void)
{
	/* USER CODE BEGIN Error_Handler_Debug */
	/* User can add his own implementation to report the HAL error return state */

	/* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
 * @brief  Reports the name of the source file and the source line number
 *         where the assert_param error has occurred.
 * @param  file: pointer to the source file name
 * @param  line: assert_param error line source number
 * @retval None
 */
void assert_failed(uint8_t *file, uint32_t line)
{ 
	/* USER CODE BEGIN 6 */
	/* User can add his own implementation to report the file name and line number,
tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
	/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
