|
|
@@ -0,0 +1,255 @@
|
|
|
+#include "user.h"
|
|
|
+
|
|
|
+enum
|
|
|
+{
|
|
|
+ AUDIO_STATE_IDLE,
|
|
|
+ AUDIO_STATE_NEED_DATA,
|
|
|
+ AUDIO_STATE_WAIT_PAUSE,
|
|
|
+ AUDIO_STATE_PAUSE,
|
|
|
+};
|
|
|
+
|
|
|
+typedef struct
|
|
|
+{
|
|
|
+ llist_head Node;
|
|
|
+ PV_Union uPV;
|
|
|
+ uint32_t Len;
|
|
|
+}Audio_DataBlockStruct;
|
|
|
+
|
|
|
+typedef struct
|
|
|
+{
|
|
|
+ uint32_t DACOutRMode;
|
|
|
+ uint8_t DACBit;
|
|
|
+}Audio_CtrlStruct;
|
|
|
+
|
|
|
+static Audio_CtrlStruct prvAudio;
|
|
|
+
|
|
|
+static int32_t prvAudio_DACCB(void *pData, void *pParam)
|
|
|
+{
|
|
|
+ Audio_StreamStruct *pStream = (Audio_StreamStruct *)pParam;
|
|
|
+ Audio_DataBlockStruct *OldBlock, *NewBlock;
|
|
|
+ OldBlock = (Audio_DataBlockStruct *)pStream->DataHead.next;
|
|
|
+ llist_del(&OldBlock->Node);
|
|
|
+
|
|
|
+
|
|
|
+ if (!llist_empty(&pStream->DataHead) && !pStream->IsPause)
|
|
|
+ {
|
|
|
+ NewBlock = (Audio_DataBlockStruct *)pStream->DataHead.next;
|
|
|
+ DAC_Send(pStream->BusID, NewBlock->uPV.pu16, NewBlock->Len, prvAudio_DACCB, pParam);
|
|
|
+ pStream->IsHardwareRun = 1;
|
|
|
+ }
|
|
|
+ free(OldBlock->uPV.pu8);
|
|
|
+ free(OldBlock);
|
|
|
+ if (!pStream->IsPause)
|
|
|
+ {
|
|
|
+ pStream->CB(pStream, NULL);
|
|
|
+ }
|
|
|
+ if (llist_empty(&pStream->DataHead))
|
|
|
+ {
|
|
|
+ pStream->IsHardwareRun = 0;
|
|
|
+ pStream->CB(pStream, INVALID_HANDLE_VALUE);
|
|
|
+ }
|
|
|
+ else if (!pStream->IsPause)
|
|
|
+ {
|
|
|
+ if (!pStream->IsHardwareRun)
|
|
|
+ {
|
|
|
+ NewBlock = (Audio_DataBlockStruct *)pStream->DataHead.next;
|
|
|
+ DAC_Send(pStream->BusID, NewBlock->uPV.pu16, NewBlock->Len, prvAudio_DACCB, pParam);
|
|
|
+ pStream->IsHardwareRun = 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ pStream->IsHardwareRun = 0;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+void Audio_GlobalInit(void)
|
|
|
+{
|
|
|
+ prvAudio.DACOutRMode = 1;
|
|
|
+ prvAudio.DACBit = 10;
|
|
|
+}
|
|
|
+
|
|
|
+int32_t Audio_StartRaw(Audio_StreamStruct *pStream)
|
|
|
+{
|
|
|
+ INIT_LLIST_HEAD(&pStream->DataHead);
|
|
|
+ if (pStream->BitDepth > 16) return -ERROR_PARAM_INVALID;
|
|
|
+ if (pStream->BitDepth < 8) return -ERROR_PARAM_INVALID;
|
|
|
+ switch(pStream->Format)
|
|
|
+ {
|
|
|
+ case AUSTREAM_FORMAT_PCM:
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ return -ERROR_PARAM_INVALID;
|
|
|
+ }
|
|
|
+ switch(pStream->BusType)
|
|
|
+ {
|
|
|
+ case AUSTREAM_BUS_DAC:
|
|
|
+ GPIO_Iomux(GPIOC_00, 2);
|
|
|
+ GPIO_PullConfig(GPIOC_00, 0, 0);
|
|
|
+ DAC_ForceStop(pStream->BusID);
|
|
|
+ DAC_DMAInit(0, DAC_TX_DMA_STREAM);
|
|
|
+ DAC_Setup(pStream->BusID, pStream->SampleRate, prvAudio.DACOutRMode);
|
|
|
+ pStream->IsHardwareRun = 0;
|
|
|
+ pStream->IsPause = 0;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ return -ERROR_PARAM_INVALID;
|
|
|
+ }
|
|
|
+ return ERROR_NONE;
|
|
|
+}
|
|
|
+
|
|
|
+static int32_t prvAudio_RunDAC(Audio_StreamStruct *pStream)
|
|
|
+{
|
|
|
+ Audio_DataBlockStruct *Block = (Audio_DataBlockStruct *)pStream->DataHead.next;
|
|
|
+ if (llist_empty(&pStream->DataHead))
|
|
|
+ {
|
|
|
+ pStream->CB(pStream, NULL);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ Block = (Audio_DataBlockStruct *)pStream->DataHead.next;
|
|
|
+ DAC_Send(pStream->BusID, Block->uPV.pu16, Block->Len, prvAudio_DACCB, pStream);
|
|
|
+ pStream->IsHardwareRun = 1;
|
|
|
+ }
|
|
|
+ return ERROR_NONE;
|
|
|
+}
|
|
|
+
|
|
|
+static int32_t prvAudio_WriteDACRaw(Audio_StreamStruct *pStream, uint8_t *pByteData, uint32_t ByteLen)
|
|
|
+{
|
|
|
+ uint32_t i;
|
|
|
+ uint32_t DiffBit;
|
|
|
+ Audio_DataBlockStruct *Block = zalloc(sizeof(Audio_DataBlockStruct));
|
|
|
+ if (pStream->BitDepth > 8)
|
|
|
+ {
|
|
|
+ Block->uPV.pu8 = malloc(ByteLen);
|
|
|
+ if (!Block->uPV.pu8)
|
|
|
+ {
|
|
|
+ free(Block);
|
|
|
+ DBG("no mem!");
|
|
|
+ return -ERROR_NO_MEMORY;
|
|
|
+ }
|
|
|
+ memcpy(Block->uPV.pu8, pByteData, ByteLen);
|
|
|
+ Block->Len = ByteLen >> 1;
|
|
|
+ if (pStream->IsDataSigned)
|
|
|
+ {
|
|
|
+ for(i = 0; i < Block->Len; i++)
|
|
|
+ {
|
|
|
+ Block->uPV.pu16[i] += 0x8000;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (pStream->BitDepth >= prvAudio.DACBit)
|
|
|
+ {
|
|
|
+ DiffBit = pStream->BitDepth - prvAudio.DACBit;
|
|
|
+ for(i = 0; i < Block->Len; i++)
|
|
|
+ {
|
|
|
+ Block->uPV.pu16[i] = Block->uPV.pu16[i] >> DiffBit;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ DiffBit = prvAudio.DACBit - pStream->BitDepth;
|
|
|
+ for(i = 0; i < Block->Len; i++)
|
|
|
+ {
|
|
|
+ Block->uPV.pu16[i] = Block->uPV.pu16[i] << DiffBit;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ Block->uPV.pu8 = malloc(ByteLen * 2);
|
|
|
+ if (!Block->uPV.pu8)
|
|
|
+ {
|
|
|
+ free(Block);
|
|
|
+ DBG("no mem!");
|
|
|
+ return -ERROR_NO_MEMORY;
|
|
|
+ }
|
|
|
+ Block->Len = ByteLen;
|
|
|
+ DiffBit = prvAudio.DACBit - 8;
|
|
|
+ if (pStream->IsDataSigned)
|
|
|
+ {
|
|
|
+ for(i = 0; i < Block->Len; i++)
|
|
|
+ {
|
|
|
+ Block->uPV.pu16[i] = ((pByteData[i] + 0x80) & 0x00ff);
|
|
|
+ Block->uPV.pu16[i] <<= DiffBit;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ for(i = 0; i < Block->Len; i++)
|
|
|
+ {
|
|
|
+ Block->uPV.pu16[i] = pByteData[i];
|
|
|
+ Block->uPV.pu16[i] <<= DiffBit;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ uint32_t Critical;
|
|
|
+ Critical = OS_EnterCritical();
|
|
|
+ llist_add_tail(&Block->Node, &pStream->DataHead);
|
|
|
+ OS_ExitCritical(Critical);
|
|
|
+ if (!pStream->IsHardwareRun)
|
|
|
+ {
|
|
|
+ return prvAudio_RunDAC(pStream);
|
|
|
+ }
|
|
|
+ return ERROR_NONE;
|
|
|
+}
|
|
|
+
|
|
|
+int32_t Audio_WriteRaw(Audio_StreamStruct *pStream, uint8_t *pByteData, uint32_t ByteLen)
|
|
|
+{
|
|
|
+ switch(pStream->BusType)
|
|
|
+ {
|
|
|
+ case AUSTREAM_BUS_DAC:
|
|
|
+ return prvAudio_WriteDACRaw(pStream, pByteData, ByteLen);
|
|
|
+ default:
|
|
|
+ return -ERROR_PARAM_INVALID;
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+static int32_t prvAudio_DeleteData(void *pData, void *pParam)
|
|
|
+{
|
|
|
+ Buffer_Struct *UriBuf = (Buffer_Struct *)pParam;
|
|
|
+ Audio_DataBlockStruct *Block = (Audio_DataBlockStruct *)pData;
|
|
|
+ free(Block->uPV.p);
|
|
|
+ return LIST_DEL;
|
|
|
+}
|
|
|
+
|
|
|
+void Audio_Stop(Audio_StreamStruct *pStream)
|
|
|
+{
|
|
|
+ switch(pStream->BusType)
|
|
|
+ {
|
|
|
+ case AUSTREAM_BUS_DAC:
|
|
|
+ DAC_ForceStop(pStream->BusID);
|
|
|
+ llist_traversal(&pStream->DataHead, prvAudio_DeleteData, NULL);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ return;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void Audio_Pause(Audio_StreamStruct *pStream)
|
|
|
+{
|
|
|
+ pStream->IsPause = 1;
|
|
|
+}
|
|
|
+
|
|
|
+void Audio_Resume(Audio_StreamStruct *pStream)
|
|
|
+{
|
|
|
+ pStream->IsPause = 0;
|
|
|
+ if (!pStream->IsHardwareRun)
|
|
|
+ {
|
|
|
+ switch(pStream->BusType)
|
|
|
+ {
|
|
|
+ case AUSTREAM_BUS_DAC:
|
|
|
+ prvAudio_RunDAC(pStream);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+#ifdef __BUILD_APP__
|
|
|
+INIT_DRV_EXPORT(Audio_GlobalInit, "0");
|
|
|
+#endif
|