/*
 * AXCMutexFreeRTOS.cpp
 */

#include <string.h>
#include <errno.h>

#include "AXCMutexFreeRTOS.hpp"
#include "AXCStdioFreeRTOS.hpp"

AXCMutexFreeRTOS::AXCMutexFreeRTOS()
    : m_isInited(false) {
	m_mutex = NULL;
}

AXCMutexFreeRTOS::~AXCMutexFreeRTOS() {
  if ( m_isInited ) {
		if (m_mutex != NULL) {
			vSemaphoreDelete(m_mutex);
			m_mutex = NULL;
		}
  }
}

AXCMutexFreeRTOS::mutexStatus AXCMutexFreeRTOS::init() {
  mutexStatus stat = MUTEX_ERROR;

  /* Check initialzed */
  if ( true == m_isInited ) {
    goto err;
  }

  /* Create mutex */
	m_mutex = xSemaphoreCreateMutex();
#ifdef USE_FRTOSDEBUG
  {
    AXCStdioFreeRTOS stdio;
    std::cout << "### mutex id = " << m_mutex << axstdio::endl;
    stdio.flush();
  }
#endif /* USE_FRTOSDEBUG */
	if (m_mutex == NULL) {
		goto err;
	}

  m_isInited = true;

  return MUTEX_SUCCESS;

  err:
#ifdef USE_FRTOSDEBUG
  {
    AXCStdioFreeRTOS stdio;
    std::cout << "### mutex cre err = " << m_mutex << axstdio::endl;
    stdio.flush();
  }
#endif /* USE_FRTOSDEBUG */
  return stat;
}

AXCMutexFreeRTOS::mutexStatus AXCMutexFreeRTOS::lock() {
  mutexStatus stat = MUTEX_ERROR;
	portBASE_TYPE	ercd = pdFALSE;

  /* Check initialized */
  if ( false == m_isInited ) {
    stat = MUTEX_ERROR_NOINIT;
    goto err;
  }

  /* Lock mutex forever */
	ercd = xSemaphoreTake(m_mutex, portMAX_DELAY);
	if (ercd == pdFALSE) {
		goto err;
	}
	
  return MUTEX_SUCCESS;

  err:
#ifdef USE_FRTOSDEBUG
  {
    AXCStdioFreeRTOS stdio;
    std::cout << "### mutex loc err = " << ercd << axstdio::endl;
    stdio.flush();
  }
#endif /* USE_FRTOSDEBUG */
  return stat;

}

AXCMutexFreeRTOS::mutexStatus AXCMutexFreeRTOS::trylock() {
  mutexStatus stat = MUTEX_ERROR;
	portBASE_TYPE	ercd = pdFALSE;

  /* Check initialized */
  if ( false == m_isInited ) {
    stat = MUTEX_ERROR_NOINIT;
    goto err;
  }

  /* Lock mutex without waiting */
	ercd = xSemaphoreTake(m_mutex, (portTickType)0);
  switch (ercd) {
		case pdTRUE:
			goto end;
		case pdFALSE:
      stat = MUTEX_ERROR_BUSY;
			goto err;
		default:
			goto err;
	}

  end:

  return MUTEX_SUCCESS;

  err:
#ifdef USE_FRTOSDEBUG
  {
    AXCStdioFreeRTOS stdio;
    std::cout << "### mutex tloc err = " << ercd << axstdio::endl;
    stdio.flush();
  }
#endif /* USE_FRTOSDEBUG */
  return stat;
}

AXCMutexFreeRTOS::mutexStatus AXCMutexFreeRTOS::unlock() {
  mutexStatus stat = MUTEX_ERROR;
	portBASE_TYPE	ercd = pdFALSE;

  /* Check initialized */
  if ( false == m_isInited ) {
    stat = MUTEX_ERROR_NOINIT;
    goto err;
  }

  /* Unlock mutex */
	ercd = xSemaphoreGive(m_mutex);
	if (ercd == pdFALSE) {
		goto err;
	}

  return MUTEX_SUCCESS;

  err:
#ifdef USE_FRTOSDEBUG
  {
    AXCStdioFreeRTOS stdio;
    std::cout << "### mutex unl err = " << ercd << axstdio::endl;
    stdio.flush();
  }
#endif /* USE_FRTOSDEBUG */
  return stat;
}
