/* * ESPRSSIF MIT License * * Copyright (c) 2015 * * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, * it is free of charge, to any person obtaining a copy of this software and associated * documentation files (the "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the Software is furnished * to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all copies or * substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include "freertos/FreeRTOS.h" #include "soc/gpio_sig_map.h" #include "freertos/task.h" #include "AP80/Ap80xx.h" #include "driver/gpio.h" #include "driver/spi.h" #include "esp_timer.h" #include "Utility.h" #include "string.h" #include "crc.h" // Define the SPI port #define AUDIO_IFACE_PORT SPI_NUM_SPI2 #define TX_SPI_BUF_LEN (2*1024) #define RX_SPI_BUF_LEN (1024) #define RX_SPI_LEN (1024) #define DECODETYPELEN (4) #define RESENDCOUNT (2) #define AP80GPIOINITNUM (19) #define SPIM_STREAM_CONTROL_GET_STATUS() (gpio_get_level(GPIO_NUM_22)) #define divDBG(level,fmt, ...) do { \ if(level > 3){ \ printf("[DECODE](%d) ", __LINE__); \ printf(fmt, ##__VA_ARGS__); \ printf("\n"); \ } \ } while(0) #define divByteS(level,indata,len) do { \ if(level > 3){ \ printfByteS(indata, len); \ } \ } while(0) uint8_t SPIM_SEND_BUFFER[sizeof(EAUCmdContext) + EAU_SYNC_WORD_LENGTH + EAU_SEND_DATA_LENGTH + EAU_CRC_VALUE_LENGTH]; uint8_t SPIM_RECV_BUFFFR_ALL[sizeof(EAUCmdContext) + EAU_SYNC_WORD_LENGTH + EAU_SEND_DATA_LENGTH + EAU_CRC_VALUE_LENGTH]; uint8_t SPIM_RECV_BUFFER[RX_SPI_LEN]; EAUCmdContext *CommandContext = (EAUCmdContext *)SPIM_SEND_BUFFER; EAUCmdResponseContext *ResponseContext = (EAUCmdResponseContext *)SPIM_SEND_BUFFER; static bool spiRecv(uint8_t *RecvData, uint16_t Recvlen); static void uint8ChangeFormat(uint32_t *inData, uint8_t *outData, uint16_t len); static void uint32ChangeFormat(uint8_t *inData, uint32_t *outData, uint16_t len); static uint8_t sendData(SSPP_CMD CMD, uint16_t value, uint8_t *sendData, uint16_t sendLen,uint8_t *receiveData, uint16_t *receiveLen); static uint32_t g_waitTime = 20000; static bool g_noResponse = false; uint8_t g_enableDma = 0; //The default is not able to DMA static xSemaphoreHandle ap80_mutex_sendData; #ifdef AP80XXENABLEDMA static spi_dma_attr_t spiDmaAp80xxTxObj; static spi_dma_attr_t spiDmaAp80xxRxObj; #endif static os_timer_t timer; static bool divTimeOut = false; xQueueHandle apQueRecv = NULL; xQueueHandle apQueSend = NULL; xQueueHandle apFlowControl = NULL; static void timerOut() { divTimeOut = true; } #ifdef AP80XXENABLEDMA uint32_t sendcount0 = 0; uint32_t sendcount1 = 0; uint32_t recvCount = 0; //#include "freertos/portmacro.h" static void spiDmaAp80xxIsr(void *para) { uint32_t regvalue; uint32_t statusW, statusR; char pQueSend = 0x55; portBASE_TYPE xHigherPriorityTaskWoken; regvalue = spi_int_status_get(SPI_NUM_SPI2); spi_int_clear(SPI_NUM_SPI2); if (regvalue & SPI_INT_SRC_WR_BUF_DONE) { divDBG(2, "SPI2_SLV_WR_BUF_DONE\n\r"); } else if (regvalue & SPI_INT_SRC_RD_BUF_DONE) { divDBG(2, "SPI2_SLV_RD_BUF_DONE\n\r"); } else if (regvalue & SPI_INT_SRC_RD_STA_DONE) { statusR = READ_PERI_REG(SPI_RD_STATUS_REG(SPI_NUM_SPI2)); statusW = READ_PERI_REG(SPI_SLV_WR_STATUS_REG(SPI_NUM_SPI2)); divDBG(2, "statusR %x statusW %x\n\r", statusR, statusW); } else if (regvalue & SPI_INT_SRC_WR_STA_DONE) { statusR = READ_PERI_REG(SPI_RD_STATUS_REG(SPI_NUM_SPI2)); statusW = READ_PERI_REG(SPI_SLV_WR_STATUS_REG(SPI_NUM_SPI2)); divDBG(2, "statusR %x statusW %x\n\r", statusR, statusW); } else if ((regvalue & SPI_INT_SRC_TRANS_DONE) && ((regvalue & 0xf) == 0)) { divDBG(2, "send SPI2_TRANS_DONE %d", sendcount0++); } uint32_t spi2DmaIntStatus = spi_dma_int_status_get(SPI_NUM_SPI2); spi_dma_int_clear(SPI_NUM_SPI2); if (SPI_INT_SRC_ONE_BUF_SEND_DONE == (spi2DmaIntStatus & SPI_INT_SRC_ONE_BUF_SEND_DONE)) { if(xQueueSendFromISR(apQueSend, &pQueSend, &xHigherPriorityTaskWoken) == pdPASS) { //portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); } //ets_printf("TX SPI2\n"); } if (SPI_INT_SRC_ONE_BUF_RECV_DONE == (spi2DmaIntStatus & SPI_INT_SRC_ONE_BUF_RECV_DONE)) { if(xQueueSendFromISR(apQueRecv, &pQueSend, &xHigherPriorityTaskWoken) == pdPASS) { //portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); } //ets_printf("RX SPI2\n"); } divDBG(2, "SPI2_INT_DONE"); } static int32_t user_spi_dma_memcpy(spi_dma_attr_t *obj, void *src, uint32_t total, uint32_t *copied, uint32_t len) { if ((NULL == obj) || (NULL == src)) { return -1; } uint32_t *bufAddress = NULL; uint8_t *srcDat = (uint8_t*)src; switch (obj->dir) { case SPI_DMA_DIR_OUT: { if (0 == *copied) { divDBG(2, "len=%d, buflen=%d\r\n", len, obj->buf->len); if (len <= obj->buf->len) { dma_buf_len_set(obj->buf, obj->buf->ping, len); memcpy(obj->buf->ping->buffer_addr, srcDat, len); *copied = len; } else { dma_buf_len_set(obj->buf, obj->buf->ping, obj->buf->len); memcpy(obj->buf->ping->buffer_addr, srcDat, obj->buf->len); srcDat += obj->buf->len; if (len < (obj->buf->len * 2)) { dma_buf_len_set(obj->buf, obj->buf->pong, (len - obj->buf->len)); memcpy(obj->buf->pong->buffer_addr, srcDat, (len - obj->buf->len)); *copied = len; } else { dma_buf_len_set(obj->buf, obj->buf->pong, obj->buf->len); memcpy(obj->buf->pong->buffer_addr, srcDat, (obj->buf->len)); *copied = obj->buf->len * 2; } } } else { if ((spi_dma_status_get(obj)) == obj->buf->ping->buffer_addr) { uint32_t remdLen = total - *copied; if (remdLen < (obj->buf->len + total % obj->buf->len)) { dma_buf_len_set(obj->buf, obj->buf->ping, remdLen); memcpy(obj->buf->ping->buffer_addr, srcDat, remdLen); *copied += remdLen; } else { memcpy(obj->buf->ping->buffer_addr, srcDat, obj->buf->len); *copied += obj->buf->len; } printf("Pi%d,remdLen%d,sent%d\r\n", len, remdLen, *copied); } else if ((spi_dma_status_get(obj)) == obj->buf->pong->buffer_addr) { uint32_t remdLen = total - *copied; if (remdLen < (obj->buf->len + total % obj->buf->len)) { dma_buf_len_set(obj->buf, obj->buf->pong, remdLen); memcpy(obj->buf->pong->buffer_addr, srcDat, remdLen); *copied += remdLen; } else { memcpy(obj->buf->pong->buffer_addr, srcDat, obj->buf->len); *copied += obj->buf->len; } divDBG(2, "Po%d,remdLen%d,sent%d\r\n", len, remdLen, *copied); } } break; } case SPI_DMA_DIR_IN: { if ((spi_dma_status_get(obj)) == obj->buf->ping->buffer_addr) { bufAddress = obj->buf->ping->buffer_addr; if (len < obj->buf->len) { dma_buf_len_set(obj->buf, obj->buf->ping, len); } } else if ((spi_dma_status_get(obj)) == obj->buf->pong->buffer_addr) { bufAddress = obj->buf->pong->buffer_addr; if (len < obj->buf->len) { dma_buf_len_set(obj->buf, obj->buf->pong, len); } } else { bufAddress = obj->buf->ping->buffer_addr; dma_buf_len_set(obj->buf, obj->buf->ping, len); if (obj->buf_size < len) { dma_buf_len_set(obj->buf, obj->buf->pong, (len - obj->buf_size)); } } if (bufAddress) { memcpy(src, bufAddress, obj->buf_size); } break; } default: len = 0; break; } return len; } #endif /** * For receiving data buf, format processing */ static void uint32ChangeFormat(uint8_t *inData, uint32_t *outData, uint16_t len) { uint8_t i, j; if (len == 0) { return; } for (i = 0; i < len / sizeof(uint32_t); i++) { outData[i] = (uint32_t) (inData[4 * i + 0] << 0) | (inData[4 * i + 1] << 8) | (inData[4 * i + 2] << 16) | (inData[4 * i + 3] << 24); } for (j = 0; j < (len % 4); j++) { outData[i] |= (inData[4 * i + j] << (8 * j)); } } /** * For receiving data buf, format processing */ static void uint8ChangeFormat(uint32_t *inData, uint8_t *outData, uint16_t len) { uint8_t i, j; if (len == 0) { return; } for (i = 0; i < (len / sizeof(uint32_t)); i++) { outData[4 * i + 0] = inData[i] >> 0; outData[4 * i + 1] = inData[i] >> 8; outData[4 * i + 2] = inData[i] >> 16; outData[4 * i + 3] = inData[i] >> 24; } for (j = 0; j < (len % 4); j++) { outData[4 * i + j] = (uint8_t)(inData[i] >> (8 * j)); } } static bool FindSpiStreamDataSyncWord() { uint32_t SyncWord; uint32_t Cnt = 0; uint8_t *p = (uint8_t *)&SyncWord; while (1) { SyncWord = 0; if (spiRecv(p, 1)) { if (p[0] == EAU_SYNC_BYTE) { return false; } } if (Cnt++ > 100) { return false; } } } /** * To send data by way of SPI */ static bool spiSend(uint8_t *sendData, uint16_t len) { uint32_t data[16] = { 0 }; spi_data_t pDat; if (len > 64) return false; pDat.cmd_len = 0; pDat.addr_len = 0; pDat.tx_data_len = len; pDat.tx_data = data; uint32ChangeFormat((uint8_t *)sendData, data, pDat.tx_data_len); spi_master_send_data(AUDIO_IFACE_PORT, &pDat); return true; } /** * Receiving data by way of SPI */ static bool spiRecv(uint8_t *recvData, uint16_t len) { uint32_t data[16] = { 0 }; spi_data_t pDat; if (len > 64) return false; pDat.cmd_len = 0; pDat.addr_len = 0; pDat.rx_data_len = len; pDat.rx_data = data; spi_master_recv_data(AUDIO_IFACE_PORT, &pDat); uint8ChangeFormat(data, recvData, len); return true; } #ifdef AP80XXENABLEDMA /** * Send data by way of SPI(Dma) */ static bool spiDmaSend(uint8_t *sendData, uint16_t sendLen) { uint32_t sendlen = 0x00; char pQueSend = 0x00; uint8_t *pSendRd = sendData; if (sendLen > TX_SPI_BUF_LEN) return false; spi_dma_rest(&spiDmaAp80xxTxObj); user_spi_dma_memcpy(&spiDmaAp80xxTxObj, pSendRd, sendLen, &sendlen, sendLen); xQueueReset(apQueSend); spi_dma_start(&spiDmaAp80xxTxObj, sendLen); if(xQueueReceive(apQueSend, &pQueSend, 150 / portTICK_RATE_MS) == pdFALSE) { return false; } return true; } /** * Receiving data by way of SPI(Dma) */ static bool spiDmaRecv(uint8_t *recvData, uint16_t recvlen) { uint8_t *recvDataPtr = recvData; uint16_t wantedRecvLen = recvlen; uint32_t sendlen = 0x00; char pQueRecv = 0x00; if (wantedRecvLen > RX_SPI_BUF_LEN) return false; wantedRecvLen = wantedRecvLen; //printf("start recv\n"); //spi_dma_int_clear(SPI_NUM_SPI2); xQueueReset(apQueRecv); spi_dma_rest(&spiDmaAp80xxTxObj); spiDmaAp80xxRxObj.dir = SPI_DMA_DIR_IN; spi_dma_dest_add_set(&spiDmaAp80xxRxObj); spi_dma_start(&spiDmaAp80xxRxObj, wantedRecvLen); if(xQueueReceive(apQueRecv, &pQueRecv, 200 / portTICK_RATE_MS) == pdFALSE) { //printf("recv time out\n"); return false; } user_spi_dma_memcpy(&spiDmaAp80xxRxObj, recvDataPtr, wantedRecvLen, &sendlen, wantedRecvLen); return true; } #endif typedef void (*xt_handler)(void *); static void ap_intr_callback(void *arg) { //printf("in gpio_intr\n"); portBASE_TYPE xHigherPriorityTaskWoken; char pQueSend = 0x55; uint32_t gpio_intr_status = READ_PERI_REG(GPIO_STATUS_REG); SET_PERI_REG_MASK(GPIO_STATUS_W1TC_REG, 1 << GPIO_NUM_22); if(xQueueSendFromISR(apFlowControl, &pQueSend, &xHigherPriorityTaskWoken) == pdPASS) { ; } } static void gpio_intr_init(uint8_t gpio_num) { gpio_config_t gpio_test; memset(&gpio_test,0,sizeof(gpio_test)); gpio_test.pin_bit_mask=(uint64_t)((uint64_t)(1)<= EAU_SEND_DATA_LENGTH - EAU_SEND_FARMA_LENGTH) { result = ERROR_PARAMETER; goto error; } } do { divDBG(2, "send data stup 01 %d",system_get_time()); //1. Send EAU_CMD_DATA command CommandContext->SyncWord = EAU_SYNC_BYTE; CommandContext->Command = CMD; if(CMD == EAU_CMD_VOL_SET) { CommandContext->Content = value; } else { CommandContext->Content = sendDataLen; } CommandContext->CrcValue = GetCRC16NBS((uint8_t *)CommandContext, sizeof(EAUCmdContext) - EAU_CRC_VALUE_LENGTH); if(protocolMode & BIT1) { *sendDataFramePtr = EAU_SYNC_BYTE; MEMCPY(sendDataFramePtr + EAU_SYNC_WORD_LENGTH, sendData, sendDataLen); uint16_t crc = GetCRC16NBS(sendDataFramePtr + 1, CommandContext->Content); sendDataFramePtr[sendDataLen + EAU_SYNC_WORD_LENGTH + 0] = (uint8_t) crc; sendDataFramePtr[sendDataLen + EAU_SYNC_WORD_LENGTH + 1] = crc >> 8; sendRemLen = sizeof(EAUCmdContext) + EAU_SYNC_WORD_LENGTH + sendDataLen + EAU_CRC_VALUE_LENGTH; } else { sendRemLen = sizeof(EAUCmdContext); } #ifdef AP80DEBUG if((*sendData == 0xE7) && (*(sendData + 1) == 0x04)) { //printfByteS(debugData, sendRemLen); //printf("%x%x%x%x",SPIM_SEND_BUFFER[sendRemLen - 1],SPIM_SEND_BUFFER[sendRemLen - 2],SPIM_SEND_BUFFER[sendRemLen - 3],SPIM_SEND_BUFFER[sendRemLen - 4]); } #endif #if AP80XXENABLEINT == 0 os_timer_arm(&timer, 1000, false); while (SPIM_STREAM_CONTROL_GET_STATUS()) { if(divTimeOut) { result = ERROR_DEVICE_TIME_OUT; divDBG(4, "send data stup 04 %d",system_get_time()); goto error; } }; #else if(receivePulse(5000)) { result = ERROR_DEVICE_TIME_OUT; divDBG(4, "Hardware decoder busy %d",SPIM_STREAM_CONTROL_GET_STATUS()); goto error; } #endif divDBG(2, "stup 02 %d",system_get_time()); if (!spiDmaSend((uint8_t *) SPIM_SEND_BUFFER, (uint16_t) sendRemLen)) { divDBG(4, "send data time out (no dma int)"); goto error; } divDBG(2, "stup 04 %d %x %x",system_get_time(),(uint32_t)spiDmaAp80xxTxObj.buf->ping->buffer_addr,(uint32_t)spiDmaAp80xxTxObj.buf->pong->buffer_addr); //divDBG(4, "stup 04 %d %x %x",system_get_time(),(uint32_t)spiDmaAp80xxTxObj.buf->ping->buffer_addr,(uint32_t)spiDmaAp80xxTxObj.buf->pong->buffer_addr); memset(spiDmaAp80xxTxObj.buf->ping->buffer_addr, 0, TX_SPI_BUF_LEN); memset(spiDmaAp80xxTxObj.buf->pong->buffer_addr, 0, TX_SPI_BUF_LEN); memset(spiDmaAp80xxRxObj.buf->ping->buffer_addr, 0, RX_SPI_LEN); memset(spiDmaAp80xxRxObj.buf->pong->buffer_addr, 0, RX_SPI_LEN); //if(g_noResponse) { result = OK_RESPONSE; reSendCnt--; goto error; } #if AP80XXENABLEINT == 1 if(receivePulse(1000)) { result = ERROR_TIME_OUT; divDBG(4, "Hardware decoder no response"); goto error; } #endif //3. Receive response uint8_t *pRecvRd = SPIM_RECV_BUFFER; uint8_t *pRecvAllData = SPIM_RECV_BUFFFR_ALL; uint32_t recvCount = 0; uint8_t packetResponse = 0; uint16_t packetDataLen = 0; uint16_t recvBufValidLen = 0; ptr = (uint8_t *)&ResponseContext->SyncWord; cnt = 0; flag = false; do { //vTaskDelay(1 / portTICK_PERIOD_MS); spiDmaRecv(pRecvRd, RX_SPI_LEN); divByteS(2, pRecvRd, RX_SPI_LEN); for(int i = 0; i < RX_SPI_LEN; i++) { if(pRecvRd[i] == EAU_SYNC_BYTE) { memcpy(pRecvAllData, pRecvRd + i,RX_SPI_LEN - i); recvBufValidLen += (RX_SPI_LEN - i); divDBG(2, "decode recv response is 0:"); if(i >= RX_SPI_LEN - sizeof(EAUCmdContext)) { divDBG(2, "recv heard len is %d", i); spiDmaRecv(pRecvRd, RX_SPI_LEN); memcpy(pRecvAllData + RX_SPI_LEN - i, pRecvRd,RX_SPI_LEN); recvBufValidLen += RX_SPI_LEN; } ResponseContext = (EAUCmdResponseContext *) pRecvAllData; packetResponse = ResponseContext->Response & 0x000F; packetDataLen = (uint16_t) (ResponseContext->Response >> 0x04); divByteS(2, pRecvAllData, 0x10); while(packetDataLen > recvBufValidLen) { divDBG(2, "recv heard len is %d %d", i, recvBufValidLen); divByteS(2, pRecvAllData, 0x10); spiDmaRecv(pRecvRd, RX_SPI_LEN); memcpy(pRecvAllData + recvBufValidLen, pRecvRd,RX_SPI_LEN); recvBufValidLen += RX_SPI_LEN; } divDBG(2, "decode recv response is: %d", recvBufValidLen); divByteS(2, pRecvAllData, 0x60); flag = true; goto tag; } } if(++recvCount > 1000) { divDBG(4, "decode recv response time out"); break; } }while(1); #ifdef AP80DEBUG if(!flag) { divDBG(4, "send error01 %x",debugCRC); printfByteS(debugData, 0x200); divDBG(4, "send error02"); printfByteS(sendData, 0x80); divDBG(4, "1 recv heard is %x %x %x %x recvCount %d", sendData[0], sendData[1], sendData[2], sendData[3],recvCount); } #endif tag: if(flag) { if (ResponseContext->Command == CMD) { ptr = (uint8_t *)&ResponseContext->SyncWord; //divDBG(4, "recv heard is %x %x %x %x recvCount %d", ptr[0], ptr[1], ptr[2], ptr[3],recvCount); divDBG(2, "response = %d dataLen = %d recvCount = %d",packetResponse,packetDataLen,recvCount); if(packetResponse == EAU_CMD_RESP_OKSEND || packetResponse == EAU_CMD_RESP_OKCMD) { result = OK_RESPONSE; if(packetDataLen > 0 && (protocolMode & BIT0)) { uint16_t localCrc = 0x00; uint16_t recvCrc = 0x00; ptr = pRecvAllData + sizeof(EAUCmdContext) + EAU_SYNC_WORD_LENGTH; localCrc = GetCRC16NBS(ptr, packetDataLen); recvCrc = *(uint16_t*)(ptr + packetDataLen); if(localCrc == recvCrc) { if(*receiveLen != 0 && *receiveLen < packetDataLen) { result = ERROR_PARAMETER; goto reSend; } memcpy(receiveData, ptr, packetDataLen); *receiveLen = packetDataLen; divDBG(2, "recv ok packetDataLen is %d %d", *receiveLen,packetDataLen); } else { result = ERROR_CRC; divDBG(4, "[ERROR] recv CRC error localCrc %X recvCrc %X", localCrc, recvCrc); divByteS(2, ptr, packetDataLen); goto reSend; } } } else if (packetResponse == EAU_CMD_RESP_NEXTSEND) { result = ERROR_STREAM_FULL; } else if (packetResponse == EAU_CMD_RESP_RESEND) { result = ERROR_CRC; } else if(packetResponse == EAU_CMD_RESP_ERCMD) { result = ERROR_OTHER; } else if(packetResponse == EAU_CMD_RESP_STATEERROR) { result = ERROR_START; } else { divDBG(4, "response = %d dataLen = %d",packetResponse,packetDataLen); result = ERROR_RESPONSE; } if (packetResponse == EAU_CMD_RESP_INITERROR) { result = ERROR_INIT; goto reSend; } } else { divDBG(4, "cmd = %x response = %x dataLen = %x",ResponseContext->Command,packetResponse,packetDataLen); divByteS(2, pRecvAllData, 64); result = ERROR_CMD; } } reSend: { ; } } while ((--reSendCnt >= 0) && (result != OK_RESPONSE)); error: os_timer_disarm(&timer); if(reSendCnt != RESENDCOUNT - 1 && reSendCnt != RESENDCOUNT) divDBG(4, "SPI resend %d %d",reSendCnt,sendLen); sys_mutex_unlock(&ap80_mutex_sendData); return result; #else sys_mutex_lock(&ap80_mutex_sendData); EAUCmdContext *CommandContext = (EAUCmdContext *)SPIM_SEND_BUFFER; EAUCmdResponseContext *ResponseContext = (EAUCmdResponseContext *)SPIM_SEND_BUFFER; uint8_t *sendDataFramePtr = (uint8_t *) &SPIM_SEND_BUFFER[sizeof(EAUCmdContext)]; uint8_t *ptr = NULL; uint8_t result = 1; uint16_t sendDataLen = sendLen; uint32_t cnt = 0; bool flag = false; uint16_t timeOut = g_waitTime; int8_t reSendCnt = RESENDCOUNT; int16_t sendRemLen = 0; uint16_t pos = 0; uint8_t protocolMode = 0; divTimeOut = false; if(sendData == NULL && sendLen == 0 && receiveData == NULL) { protocolMode = 0; } else if(sendData != NULL && sendLen != 0 && receiveData == NULL) { protocolMode = 2; } else if(sendData == NULL && sendLen == 0 && receiveData != NULL) { protocolMode = 1; } else if(sendData != NULL && sendLen != 0 && receiveData != NULL) { protocolMode = 3; } else { result = ERROR_PROMODE; goto error; } if(protocolMode & BIT1) { if (sendLen >= EAU_SEND_DATA_LENGTH - EAU_SEND_FARMA_LENGTH) { result = ERROR_PARAMETER; goto error; } } do { //1. Send EAU_CMD_DATA command CommandContext->SyncWord = EAU_SYNC_BYTE; CommandContext->Command = CMD; if(CMD == EAU_CMD_VOL_SET) { CommandContext->Content = value; } else { CommandContext->Content = sendDataLen; } CommandContext->CrcValue = GetCRC16NBS((uint8_t *)CommandContext, sizeof(EAUCmdContext) - EAU_CRC_VALUE_LENGTH); pos = 0; if(protocolMode & BIT1) { *sendDataFramePtr = EAU_SYNC_BYTE; MEMCPY(sendDataFramePtr + EAU_SYNC_WORD_LENGTH, sendData, sendDataLen); uint16_t crc = GetCRC16NBS(sendDataFramePtr + 1, CommandContext->Content); sendDataFramePtr[sendDataLen + EAU_SYNC_WORD_LENGTH + 0] = (uint8_t) crc; sendDataFramePtr[sendDataLen + EAU_SYNC_WORD_LENGTH + 1] = crc >> 8; sendRemLen = sizeof(EAUCmdContext) + EAU_SYNC_WORD_LENGTH + sendDataLen + EAU_CRC_VALUE_LENGTH; } else { sendRemLen = sizeof(EAUCmdContext); } os_timer_arm(&timer, 500, false); while (SPIM_STREAM_CONTROL_GET_STATUS()) { if(divTimeOut) { result = ERROR_DEVICE_TIME_OUT; goto error; } }; divDBG(2, "stup 02"); if(g_noResponse) { result = OK_RESPONSE; reSendCnt--; goto error; } do { if(sendRemLen >= EAU_SEND_FARMA_LENGTH) { spiSend(SPIM_SEND_BUFFER + pos, EAU_SEND_FARMA_LENGTH); pos += EAU_SEND_FARMA_LENGTH; } else { spiSend(SPIM_SEND_BUFFER + pos, sendRemLen); break; } sendRemLen -= EAU_SEND_FARMA_LENGTH; } while(sendRemLen >= 0); divDBG(2, "stup 03"); //3. Receive response ptr = (uint8_t *)&ResponseContext->SyncWord; cnt = 0; flag = false; while (1) { spiRecv(ptr, 1); if (ptr[0] == EAU_SYNC_BYTE) { spiRecv((uint8_t *)&ResponseContext->Command, (sizeof(EAUCmdContext) - EAU_SYNC_WORD_LENGTH)); divDBG(2, "Command:%02x Response:%04x\n",ResponseContext->Command,ResponseContext->Response); if(ResponseContext->Command == CMD) { flag = true; break; } } if (cnt++ > timeOut) { divDBG(2, "Cnt %08x",cnt); result = ERROR_TIME_OUT; break; } } if (flag) { if (ResponseContext->Command == CMD) { uint8_t response = ResponseContext->Response & 0x00FF; uint8_t dataLen = ResponseContext->Response >> 0x08; divDBG(1, "response = %d dataLen = %d",response,dataLen); if(response == EAU_CMD_RESP_OKSEND || response == EAU_CMD_RESP_OKCMD) { result = OK_RESPONSE; if(dataLen > 0 && (protocolMode & BIT0)) { uint8_t recvLen = 0x00; uint16_t LocalCrc = 0x00; uint16_t recvCrc = 0x00; uint8_t recvCrcLen = 0x00; if(FindSpiStreamDataSyncWord()) { uint8_t *RecvBuff = (uint8_t*)ResponseContext; int16_t recvRemLen = dataLen; pos = 0; do { if(recvRemLen >= EAU_SEND_FARMA_LENGTH) { spiRecv(RecvBuff + pos, EAU_RECV_FARMA_LENGTH); pos += EAU_SEND_FARMA_LENGTH; } else { spiRecv(RecvBuff + pos, recvRemLen); break; } recvRemLen -= EAU_SEND_FARMA_LENGTH; }while(recvRemLen >= 0); spiRecv((uint8_t *) &recvCrc, EAU_CRC_VALUE_LENGTH); LocalCrc = GetCRC16NBS(RecvBuff, dataLen); if(LocalCrc == recvCrc) { if(*receiveLen != 0 && *receiveLen < dataLen) { result = ERROR_PARAMETER; goto error; } memcpy(receiveData, RecvBuff, dataLen); *receiveLen = dataLen; } else { result = ERROR_CRC; goto error; } } } } else if (response == EAU_CMD_RESP_NEXTSEND) { result = ERROR_STREAM_FULL; } else if (response == EAU_CMD_RESP_RESEND) { result = ERROR_CRC; } else if(response == EAU_CMD_RESP_ERCMD) { result = ERROR_OTHER; } else if(response == EAU_CMD_RESP_STATEERROR) { result = ERROR_START; } else { result = ERROR_RESPONSE; } if (response == EAU_CMD_RESP_INITERROR) { result = ERROR_INIT; goto error; } } else { result = ERROR_CMD; } } else { result = ERROR_TIME_OUT; } } while ((--reSendCnt >= 0) && (result != 0)); error: os_timer_disarm(&timer); if(reSendCnt != RESENDCOUNT - 1) divDBG(4, "SPI resend %d %d",reSendCnt,sendLen); sys_mutex_unlock(&ap80_mutex_sendData); return result; #endif } /** * Audio playback start */ uint8_t apPlayStart(const char *parameter, uint8_t len, DecoderType decType) { uint8_t data[64]; if(len > 60) return ERROR_PARAMETER; memcpy(data + DECODETYPELEN, parameter, len); *(uint32_t*) data = decType; return sendData(EAU_CMD_START, 0, data, len + DECODETYPELEN,NULL, 0); } /** * Send the data */ uint8_t apSendData(uint8_t *sendBuf, uint16_t sendLen) { apSetResponse(false); uint8_t ret = sendData(EAU_CMD_DATA, 0, sendBuf, sendLen , NULL, NULL); apSetResponse(true); return ret; } /** * Set audio volume */ uint8_t apVolSet(uint16_t vol) { // Vol range: 0~32 uint16_t apVol = vol; return sendData(EAU_CMD_VOL_SET, apVol, NULL, 0,NULL, 0); } /** * Set audio volume mute */ uint8_t apVolMuteEnable(void) { return sendData(EAU_CMD_MUTE, 0, NULL, 0,NULL, 0); } /** * Set audio volume unmute */ uint8_t apVolMuteDisable(void) { return sendData(EAU_CMD_UNMUTE, 0, NULL, 0,NULL, 0); } /** * Pause audio decode */ uint8_t apPlayPause(void) { return sendData(EAU_CMD_PAUSE, 0, NULL, 0,NULL, 0); } /** * Resume audio decode */ uint8_t apPlayResume(void) { return sendData(EAU_CMD_RESUME, 0, NULL, 0,NULL, 0); } /** * Stop audio decode */ uint8_t apPlayStop(void) { return sendData(EAU_CMD_STOP, 0, NULL, 0,NULL, 0); } /** * get song file info */ uint8_t apGetInfo(SongInformation *songInfo) { uint8_t result = 0; uint16_t revLen = 0; uint8_t recvbuf[SPIDATABUFMAXLEN]; result = sendData(EAU_CMD_INFO_GET, 0, NULL, 0, recvbuf, &revLen); if(result == OK_RESPONSE) MEMCPY((uint8_t *) songInfo, recvbuf, revLen); return result; } /** * rest decode time */ uint8_t apRestDecodeTime(void) { return sendData(EAU_CMD_TIME_REST, 0, NULL, 0,NULL, 0); } /** * get decode time */ uint8_t apGetDecodeTime(DecodeTime *time) { uint8_t result = 1; uint16_t revLen = sizeof(DecodeTime); uint8_t recvbuf[sizeof(DecodeTime)]; result = sendData(EAU_CMD_TIME_GET, 0, NULL, 0, recvbuf, &revLen); if(result == OK_RESPONSE) MEMCPY((uint8_t *) time, recvbuf, revLen); return result; } /** * To set the current mode for encode */ uint8_t apSetEncodeMode(void) { return sendData(EAU_CMD_ENCODE_MODE, 0, NULL, 0, NULL, NULL); } /** * To set the current mode for decode */ uint8_t apSetDecodeMode(void) { return sendData(EAU_CMD_DECODE_MODE, 0, NULL, 0, NULL, NULL); } /** * Read the data from mic */ uint8_t apMicReadData(uint8_t *readData, uint16_t *readLen) { uint8_t result = 0; uint16_t revLen = 0; result = sendData(EAU_CMD_READ_DATA, 0, NULL, 0 , readData, &revLen); if(result == OK_RESPONSE) { *readLen = revLen; } return result; } /** * Lin Switch */ uint8_t apLinSwitch(void) { return sendData(EAU_CMD_LIN_SWITCH, 0, NULL, 0, NULL, NULL); } /** * Mic Switch */ uint8_t apMicSwitch(void) { return sendData(EAU_CMD_MIC_SWITCH, 0, NULL, 0, NULL, NULL); } /** * start encode */ uint8_t apEncodeStart(void) { return sendData(EAU_CMD_ENCODE_START, 0, NULL, 0, NULL, NULL); } /** * set encode info such as num_channels bitrate */ uint8_t apSetEncodeInfo(setEnccodeInfo *encodeInfo) { if(encodeInfo == NULL) return ERROR_OTHER; return sendData(EAU_CMD_INFO_SET, 0, (uint8_t *)encodeInfo, sizeof(setEnccodeInfo), NULL, NULL); } /** * set decode info such as num_channels bitrate */ uint8_t apSetDecodeInfo(setDecodeInfo *decodeInfo) { if(decodeInfo == NULL) return ERROR_OTHER; return sendData(EAU_CMD_INFO_SET, 0, (uint8_t *)decodeInfo, sizeof(setDecodeInfo), NULL, NULL); } /** * The wait time setup command sent */ uint8_t apSetWaitTime(uint32_t waitTime) { if(waitTime < 1000) return ERROR_PARAMETER; g_waitTime = waitTime; return OK_RESPONSE; } void apSetResponse(bool responseEnable) { g_noResponse = !responseEnable; }