/*
 * AXCTaskFreeRTOS.cpp
 */
#include "AXCTaskFreeRTOS.hpp"
#include "AXCStdioFreeRTOS.hpp"
#include "FreeRTOS.h"

AXCTaskFreeRTOS::AXCTaskFreeRTOS(AXCConditionVariableFreeRTOS* cond, bool gtest)
  : m_func(NULL),
    m_param(NULL),
    m_tskId(0),
    m_isCreated(false),
    m_Cond(cond),
    m_Name(""),
    m_gtest(gtest) {
}

AXCTaskFreeRTOS::~AXCTaskFreeRTOS() {
  if(m_Cond){
    m_Cond->signal();
  }
  delete m_Cond;
  m_Cond = NULL;

  if(m_tskId > 0){
		vTaskDelete(m_tskId);
  }
}

AXCTaskFreeRTOS::taskStatus AXCTaskFreeRTOS::create(
    const std::string& name, taskPriority priority, size_t stackSize,
    void *(*start_routine)(void *), void *arg) {
	portBASE_TYPE err;
  int val;
  taskStatus stat = TASK_ERROR;

  if (m_isCreated) {
    goto err;
  }

  if(m_gtest == false){
    if(m_Cond == NULL){
      m_Cond = new (std::nothrow) AXCConditionVariableFreeRTOS();
    }
  }
  if(NULL == m_Cond) {
    goto err;
  }

  val = m_Cond->init();

  if(AXCConditionVariable::COND_SUCCESS != val) {
    goto err_destroy;
  }
	
  m_func = *start_routine;
	m_param = arg;
  m_Name  = name;
	/* スケジューラが動作している場合は本関数により自動的にタスクは開始されます。※注：現状のヒープメモリは32bit単位のため以前の環境（8bit単位）に有っているサイズ（stackSize）を1/4する	*/
	err = xTaskCreate(AXCTaskFreeRTOS::SubFunc, (const portCHAR*)m_Name.c_str(), stackSize >> 2, this, (taskMaxPriority - priority + 1), &m_tskId);
#ifdef USE_FRTOSDEBUG
  {
    AXCStdioFreeRTOS stdio;
    std::cout << "### task = " << m_tskId << ": " << m_Name << 
    "(" << ctsk.itskpri << ":" << stackSize << ")" << axstdio::endl;
    stdio.flush();
  }
#endif /* USE_FRTOSDEBUG */
  if (err != pdPASS) {
    goto err_destroy;
  }
 
  m_isCreated = true;
  return TASK_SUCCESS;

  err_destroy:

  delete m_Cond;
  m_Cond = NULL;

  err:

  return stat;
}

void AXCTaskFreeRTOS::SubFunc( void* exinf )
{
  AXCTaskFreeRTOS *obj = reinterpret_cast<AXCTaskFreeRTOS*>(exinf);
  obj->m_func(obj->m_param);
  //@UTIGN exitSelf
}

AXCTaskFreeRTOS::taskStatus AXCTaskFreeRTOS::cancel() {
  if (false == m_isCreated) {
    return TASK_ERROR_NOCREATE;
  }

  return TASK_SUCCESS;
}

AXCTaskFreeRTOS::taskStatus AXCTaskFreeRTOS::join() {
  taskStatus stat = TASK_ERROR;
  int val;

  if (false == m_isCreated) {
    return TASK_ERROR_NOCREATE;
  }

  val = m_Cond->wait();

  if(AXCConditionVariable::COND_SUCCESS != val) {
    goto err;
  }

  return TASK_SUCCESS;

  err:

  return stat;
}

void AXCTaskFreeRTOS::exitSelf() {
  if (false == m_isCreated) {
    return;
  }

  m_Cond->signal();

#ifdef USE_FRTOSDEBUG
  {
    AXCStdioFreeRTOS stdio;
    std::cout << "### task exd" << axstdio::endl;
    stdio.flush();
  }
#endif /* USE_FRTOSDEBUG */
	/* FreeRTOSにはTaskをTerminate（強制終了）する機能は存在しないためdeleteする。 */
	vTaskDelete(m_tskId);
}

