/* USER CODE BEGIN Header */
/**
 ******************************************************************************
 * @file    app_azure_rtos.c
 * @author  MCD Application Team
 * @brief   app_azure_rtos application implementation file
 ******************************************************************************
 * @attention
 *
 * Copyright (c) 2020-2021 STMicroelectronics.
 * All rights reserved.
 *
 * This software is licensed under terms that can be found in the LICENSE file
 * in the root directory of this software component.
 * If no LICENSE file comes with this software, it is provided AS-IS.
 *
 ******************************************************************************
 */
/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/

#include "app_azure_rtos.h"
#include "leds.h"
#include "stm32h7xx.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "app.h"
#include "main.h"
#include "ui.h"
#include "vehicle.h"

#include "app_touchgfx.h"
#include "tx_api.h"
#include "tx_port.h"

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
#if (USE_STATIC_ALLOCATION == 1)
/* USER CODE BEGIN TX_Pool_Buffer */
/* USER CODE END TX_Pool_Buffer */
#if defined(__ICCARM__)
#pragma data_alignment = 4
#endif
__ALIGN_BEGIN static UCHAR
    tx_byte_pool_buffer[TX_APP_MEM_POOL_SIZE] __ALIGN_END;
static TX_BYTE_POOL tx_app_byte_pool;

#endif

/* USER CODE BEGIN PV */
TX_THREAD app_thread;
TX_THREAD ui_thread;
TX_THREAD vehicle_thread;
TX_THREAD led_thread;
TX_QUEUE gui_button_queue;
TX_EVENT_FLAGS_GROUP gui_update_events;
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/**
 * @brief  Define the initial system.
 * @param  first_unused_memory : Pointer to the first unused memory
 * @retval None
 */
VOID tx_application_define(VOID *first_unused_memory) {
  /* USER CODE BEGIN  tx_application_define_1*/

  /* USER CODE END  tx_application_define_1 */
#if (USE_STATIC_ALLOCATION == 1)
  UINT status = TX_SUCCESS;
  VOID *memory_ptr;

  if (tx_byte_pool_create(&tx_app_byte_pool, "Tx App memory pool",
                          tx_byte_pool_buffer,
                          TX_APP_MEM_POOL_SIZE) != TX_SUCCESS) {
    /* USER CODE BEGIN TX_Byte_Pool_Error */

    /* USER CODE END TX_Byte_Pool_Error */
  } else {
    /* USER CODE BEGIN TX_Byte_Pool_Success */

    /* USER CODE END TX_Byte_Pool_Success */

    memory_ptr = (VOID *)&tx_app_byte_pool;
    status = App_ThreadX_Init(memory_ptr);
    if (status != TX_SUCCESS) {
      /* USER CODE BEGIN  App_ThreadX_Init_Error */
      while (1) {
      }
      /* USER CODE END  App_ThreadX_Init_Error */
    }

    /* USER CODE BEGIN  App_ThreadX_Init_Success */

    /* USER CODE END  App_ThreadX_Init_Success */
  }

#else
  /*
   * Using dynamic memory allocation requires to apply some changes to the
   linker file.
   * ThreadX needs to pass a pointer to the first free memory location in RAM to
   the tx_application_define() function,
   * using the "first_unused_memory" argument.
   * This require changes in the linker files to expose this memory location.
   * For EWARM add the following section into the .icf file:
       place in RAM_region    { last section FREE_MEM };
   * For MDK-ARM
       - either define the RW_IRAM1 region in the ".sct" file
       - or modify the line below in "tx_initialize_low_level.S to match the
   memory region being used LDR r1, =|Image$$RW_IRAM1$$ZI$$Limit|

   * For STM32CubeIDE add the following section into the .ld file:
       ._threadx_heap :
         {
            . = ALIGN(8);
            __RAM_segment_used_end__ = .;
            . = . + 64K;
            . = ALIGN(8);
          } >RAM_D1 AT> RAM_D1
      * The simplest way to provide memory for ThreadX is to define a new
   section, see ._threadx_heap above.
      * In the example above the ThreadX heap size is set to 64KBytes.
      * The ._threadx_heap must be located between the .bss and the
   ._user_heap_stack sections in the linker script.
      * Caution: Make sure that ThreadX does not need more than the provided
   heap memory (64KBytes in this example).
      * Read more in STM32CubeIDE User Guide, chapter: "Linker script".

   * The "tx_initialize_low_level.S" should be also modified to enable the
   "USE_DYNAMIC_MEMORY_ALLOCATION" flag.
   */

  /* USER CODE BEGIN DYNAMIC_MEM_ALLOC */
  void *mem = first_unused_memory;

  void *app_thread_stack = mem;
  mem += THREAD_STACK_SIZE;
  if (tx_thread_create(&app_thread, "Main Thread", app_thread_entry, 0,
                       app_thread_stack, THREAD_STACK_SIZE, THREAD_PRIO_APP,
                       THREAD_PRIO_APP, TX_NO_TIME_SLICE,
                       TX_AUTO_START) != TX_SUCCESS) {
    Error_Handler();
  }

  void *ui_queue_start = mem;
  ULONG ui_queue_msg_size = sizeof(ButtonMessage) / sizeof(ULONG);
  if (sizeof(ButtonMessage) % sizeof(ULONG) != 0) {
    ui_queue_msg_size++;
  }
  mem += UI_QUEUE_SIZE * ui_queue_msg_size;
  if (tx_queue_create(&gui_button_queue, "UI Queue", ui_queue_msg_size,
                      ui_queue_start,
                      UI_QUEUE_SIZE * ui_queue_msg_size) != TX_SUCCESS) {
    Error_Handler();
  }

  void *ui_thread_stack = mem;
  mem += THREAD_STACK_SIZE;
  if (tx_thread_create(&ui_thread, "UI Thread", ui_thread_entry, 0,
                       ui_thread_stack, THREAD_STACK_SIZE, THREAD_PRIO_UI,
                       THREAD_PRIO_UI, TX_NO_TIME_SLICE,
                       TX_AUTO_START) != TX_SUCCESS) {
    Error_Handler();
  }

  if (tx_event_flags_create(&gui_update_events, "GUI Update Events") !=
      TX_SUCCESS) {
    Error_Handler();
  }
  void *vehicle_thread_stack = mem;
  mem += THREAD_STACK_SIZE;
  ULONG hfdcan_addr = (ULONG)&hfdcan1;
  if (tx_thread_create(&vehicle_thread, "Vehicle Thread", vehicle_thread_entry,
                       hfdcan_addr, vehicle_thread_stack, THREAD_STACK_SIZE,
                       THREAD_PRIO_VEHICLE, THREAD_PRIO_VEHICLE, 0,
                       TX_AUTO_START) != TX_SUCCESS) {
    Error_Handler();
  }

  void *led_thread_stack = mem;
  mem += THREAD_STACK_SIZE;
  void *led_child_thread_stack = mem;
  mem += THREAD_STACK_SIZE;
  if (tx_thread_create(&led_thread, "LED Thread", led_thread_entry,
                       (ULONG)led_child_thread_stack, led_thread_stack,
                       THREAD_STACK_SIZE, THREAD_PRIO_LED, THREAD_PRIO_LED, 0,
                       TX_AUTO_START) != TX_SUCCESS) {
    Error_Handler();
  }

  if (MX_TouchGFX_Init(mem) != TX_SUCCESS) {
    Error_Handler();
  }
  // TODO: Use TOUCHGFX_BYTE_POOL_SIZE? This is only defined in app_touchgfx.c
  mem += 4096;
  /* USER CODE END DYNAMIC_MEM_ALLOC */
#endif
}