/*
 * AXCCommRingBufFreeRTOS.cpp
 */

#include "AXCCommRingBufFreeRTOS.hpp"
#include "FreeRTOS.h"
#include "event_groups.h"

enum DSP_REGS {	// baba 以前のデータシート取得後検討
  r_DSP_CTL             = 0x00,
  r_DSP_ACT             = 0x04,
  r_DSP_PSTATUS         = 0x08,
  r_DSP_STAT_VECTOR_SEL = 0x0c,
  r_DSP_SYSROM_ADDR     = 0x10,
  r_DSP_SYSRAM_ADDR     = 0x14,
  r_HOST_INT_MASK       = 0x18,
  r_HOST_INT_STATUS     = 0x1c,
  r_HOST_INT_UNMASK     = 0x20,
  r_HOST_INT_RAW        = 0x24,
  r_HOST_RES_ID_REQ     = 0x28,
  r_HOST_RES_ARG00      = 0x2c,
  r_HOST_RES_ARG01      = 0x30,
  r_HOST_RES_ARG02      = 0x34,
  r_HOST_RES_ARG03      = 0x38,
  r_DSP_INT_MASK        = 0x3c,
  r_DSP_INT_STATUS      = 0x40,
  r_DSP_INT_UNMASK      = 0x44,
  r_DSP_INT_RAW         = 0x48,
  r_DSP_COM_ID_REQ      = 0x4c,
  r_DSP_COM_ARG00       = 0x50,
  r_DSP_COM_ARG01       = 0x54,
  r_DSP_COM_ARG02       = 0x58,
  r_DSP_COM_ARG03       = 0x5c,
};

enum AUDIO_DSP_INT {	// baba 以前のデータシート取得後検討
  AUDIO_DSP_INT_SIO2            = (1 << 15),
  AUDIO_DSP_INT_SIO1            = (1 << 14),
  AUDIO_DSP_INT_SIO0            = (1 << 13),
  AUDIO_DSP_INT_I2C1            = (1 << 12),
  AUDIO_DSP_INT_I2C0            = (1 << 11),
  AUDIO_DSP_INT_APKT            = (1 << 10),
  AUDIO_DSP_INT_ISP_DMAR        = (1 << 9),
  AUDIO_DSP_INT_ISP_DMAW        = (1 << 8),
  AUDIO_DSP_INT_ISP_SCL         = (1 << 7),
  AUDIO_DSP_INT_ISP_RPU         = (1 << 6),
  AUDIO_DSP_INT_IMAGEIF_DMAR    = (1 << 5),
  AUDIO_DSP_INT_IMAGEIF_DMAW    = (1 << 4),
  AUDIO_DSP_INT_IMAGEIF_MIX     = (1 << 3),
  AUDIO_DSP_INT_IMAGEIF_SPU     = (1 << 2),
  AUDIO_DSP_INT_IMAGEIF_ISI     = (1 << 1),
  AUDIO_DSP_INT_HOST            = (1 << 0),
  AUDIO_DSP_INT_ALL             = (0xffff)
};

AXCCommRingBufFreeRTOS::AXCCommRingBufFreeRTOS(
  char* buf,
  int size,
  volatile int* rp,
  volatile int* wp,
  UINT32_t dspRegBase)
  : AXCRingBuf(buf, size),
    m_dspRegBase(dspRegBase) {

  m_offsetP[RINGBUF_READ] = rp;
  m_offsetP[RINGBUF_WRITE] = wp;
}

AXCCommRingBufFreeRTOS::ringBufStatus AXCCommRingBufFreeRTOS::init() {
  if (AXCRingBuf::init() != RINGBUF_SUCCESS) return RINGBUF_ERROR;

  for (int i=0; i<RINGBUF_RW_NUM; i++) {
    ringBufRW rw = (ringBufRW)i;
    *m_offsetP[rw] = 0;
  }
  return RINGBUF_SUCCESS;
}

int AXCCommRingBufFreeRTOS::getOffset(ringBufRW rw) {
#ifdef XTENSA_CACHE_FLUSH
  xtensa_cache_flush((unsigned)m_offsetP[rw]);
#endif
  return *m_offsetP[rw];
}

void AXCCommRingBufFreeRTOS::setOffset(ringBufRW rw, int v) {
#ifndef BB_TMP_PASS		// レジスタ操作関数と考えられるが不明のためコンパイル用に除去
  drvXInt_unsetMask(AUDIO_DSP_INT_HOST);	// baba 以前のデータシート取得後検討
#endif
  *m_offsetP[rw] = v;
#ifndef BB_TMP_PASS		// レジスタ操作関数と考えられるが不明のためコンパイル用に除去
  drvXInt_setMask(AUDIO_DSP_INT_HOST);		// baba 以前のデータシート取得後検討
#endif
}

AXCCommRingBufFreeRTOS::ringBufStatus AXCCommRingBufFreeRTOS::waitFor(ringBufRW rw) {
  switch (rw) {
  case RINGBUF_WRITE:
		EventBits_t flgptn;	
#ifdef BB_TMP_PASS	// axc_comm_flg_log_wはレジスタ？か不明のためコンパイル用に仮実装しておく
		flgptn = xEventGroupWaitBits((EventGroupHandle_t)axc_comm_flg_log_w, 1, pdTRUE, pdFALSE, portMAX_DELAY);	// baba 以前のデータシート取得後検討
#else
		flgptn = xEventGroupWaitBits(axc_comm_flg_log_w, 1, pdTRUE, pdFALSE, portMAX_DELAY);	// baba 以前のデータシート取得後検討
#endif
		if ((flgptn & 1) != 1) return RINGBUF_ERROR;
    break;    
  case RINGBUF_READ:
  default:
    break;
  }
  return RINGBUF_SUCCESS;
}

AXCCommRingBufFreeRTOS::ringBufStatus  AXCCommRingBufFreeRTOS::signalTo(ringBufRW rw) {
  switch (rw) {
  case RINGBUF_READ:
    raiseIntr();
    break;
  case RINGBUF_WRITE:
  default:
		EventBits_t flgptn;
#ifdef BB_TMP_PASS	// axc_comm_flg_log_wはレジスタ？か不明のためコンパイル用に仮実装しておく
		(void)xEventGroupSetBits((EventGroupHandle_t)axc_comm_flg_log_w, 1);	/* 戻り値は別タスク再度クリアされるため確認しない */
#else
		(void)xEventGroupSetBits(axc_comm_flg_log_w, 1);	// baba 以前のデータシート取得後検討
#endif

    break;
  }
  return RINGBUF_SUCCESS;
}

void AXCCommRingBufFreeRTOS::raiseIntr() {
  while (readReg(r_HOST_RES_ID_REQ) & 1) {
      /* busy wait */
  }
  writeReg(r_HOST_RES_ID_REQ, 1);
} 

UINT32_t AXCCommRingBufFreeRTOS::readReg(int offset)
{ 
#ifdef XTENSA_CACHE_FLUSH
  xtensa_cache_flush(m_dspRegBase + offset);	// baba 以前のデータシート取得後検討
#endif
  return *(volatile UINT32_t *)(m_dspRegBase + offset);
}

void AXCCommRingBufFreeRTOS::writeReg(int offset, UINT32_t v)
{ 
  *(volatile UINT32_t *)(m_dspRegBase + offset) = v;
}
