component/bt: A2DP code original in example project moved to component/bt directory;
1. move btif and A2DP source code from project directory to bluetooth directory; 2. some updates of audio source code;
This commit is contained in:
parent
6163d214b3
commit
0ad3017df7
132 changed files with 222955 additions and 39 deletions
|
@ -29,4 +29,5 @@ typedef enum {
|
|||
esp_err_t esp_bt_gap_set_scan_mode(bt_scan_mode_t mode);
|
||||
|
||||
esp_err_t esp_bt_gap_set_device_name(const char *name);
|
||||
|
||||
#endif /* __ESP_GAP_BT_API_H__ */
|
||||
|
|
0
examples/09_a2dp/components/bluedroid_demos/btif/include/btif_api.h → components/bt/bluedroid/btif/include/btif_api.h
Executable file → Normal file
0
examples/09_a2dp/components/bluedroid_demos/btif/include/btif_api.h → components/bt/bluedroid/btif/include/btif_api.h
Executable file → Normal file
0
examples/09_a2dp/components/bluedroid_demos/btif/include/btif_av.h → components/bt/bluedroid/btif/include/btif_av.h
Executable file → Normal file
0
examples/09_a2dp/components/bluedroid_demos/btif/include/btif_av.h → components/bt/bluedroid/btif/include/btif_av.h
Executable file → Normal file
0
examples/09_a2dp/components/bluedroid_demos/btif/include/btif_dm.h → components/bt/bluedroid/btif/include/btif_dm.h
Executable file → Normal file
0
examples/09_a2dp/components/bluedroid_demos/btif/include/btif_dm.h → components/bt/bluedroid/btif/include/btif_dm.h
Executable file → Normal file
0
examples/09_a2dp/components/bluedroid_demos/btif/include/stack_manager.h → components/bt/bluedroid/btif/include/stack_manager.h
Executable file → Normal file
0
examples/09_a2dp/components/bluedroid_demos/btif/include/stack_manager.h → components/bt/bluedroid/btif/include/stack_manager.h
Executable file → Normal file
|
@ -10,6 +10,7 @@ COMPONENT_ADD_INCLUDEDIRS := bluedroid/bta/include \
|
|||
bluedroid/hci/include \
|
||||
bluedroid/osi/include \
|
||||
bluedroid/utils/include \
|
||||
bluedroid/embdrv/sbc/decoder/include \
|
||||
bluedroid/btc/core/include \
|
||||
bluedroid/btc/profile/esp/blufi/include \
|
||||
bluedroid/btc/profile/esp/include \
|
||||
|
@ -18,6 +19,7 @@ COMPONENT_ADD_INCLUDEDIRS := bluedroid/bta/include \
|
|||
bluedroid/btc/profile/std/sdp/include \
|
||||
bluedroid/btc/profile/std/include \
|
||||
bluedroid/btc/include \
|
||||
bluedroid/btif/include \
|
||||
bluedroid/stack/btm/include \
|
||||
bluedroid/stack/btu/include \
|
||||
bluedroid/stack/gap/include \
|
||||
|
@ -59,6 +61,7 @@ COMPONENT_SRCDIRS := bluedroid/bta/dm \
|
|||
bluedroid/hci \
|
||||
bluedroid/main \
|
||||
bluedroid/osi \
|
||||
bluedroid/embdrv/sbc/decoder/srce \
|
||||
bluedroid/btc/core \
|
||||
bluedroid/btc/profile/esp/blufi \
|
||||
bluedroid/btc/profile/std/gap \
|
||||
|
|
1
examples/09_a2dp/components/EspAudio/.gitignore
vendored
Normal file
1
examples/09_a2dp/components/EspAudio/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
*.o
|
30
examples/09_a2dp/components/EspAudio/Kconfig
Normal file
30
examples/09_a2dp/components/EspAudio/Kconfig
Normal file
|
@ -0,0 +1,30 @@
|
|||
menu "EspAudio"
|
||||
|
||||
config AUDIO_PLAYER_EN
|
||||
bool "Enable ESP player"
|
||||
default y
|
||||
config AUDIO_RECORDER_EN
|
||||
bool "Enable ESP recorder"
|
||||
default y
|
||||
config AUDIO_LOG_ERROR_EN
|
||||
bool "Enable Audio error message"
|
||||
default y
|
||||
help
|
||||
Disable it will redurce error information and run faster
|
||||
config AUDIO_LOG_WARN_EN
|
||||
bool "Enable Audio warning message"
|
||||
default y
|
||||
help
|
||||
Disable it will redurce warning information and run faster
|
||||
config AUDIO_LOG_INFO_EN
|
||||
bool "Enable Audio normal message"
|
||||
default y
|
||||
help
|
||||
Disable it will redurce normal information and run faster
|
||||
config AUDIO_LOG_DEBUG_EN
|
||||
bool "Enable Audio debug message"
|
||||
default n
|
||||
help
|
||||
Disable it will redurce debug information and run faster
|
||||
|
||||
endmenu
|
4
examples/09_a2dp/components/EspAudio/README.md
Normal file
4
examples/09_a2dp/components/EspAudio/README.md
Normal file
|
@ -0,0 +1,4 @@
|
|||
#This is Espressif Audio Platform
|
||||
|
||||
# Setting Up ESP-IDF
|
||||
|
17
examples/09_a2dp/components/EspAudio/component.mk
Normal file
17
examples/09_a2dp/components/EspAudio/component.mk
Normal file
|
@ -0,0 +1,17 @@
|
|||
#
|
||||
# Component Makefile
|
||||
#
|
||||
# This Makefile should, at the very least, just include $(SDK_PATH)/Makefile. By default,
|
||||
# this will take the sources in the src/ directory, compile them and link them into
|
||||
# lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable,
|
||||
# please read the SDK documents if you need to do this.
|
||||
#
|
||||
COMPONENT_ADD_INCLUDEDIRS := include player/inc recorder/inc \
|
||||
../media_hal/include \
|
||||
../misc/include
|
||||
|
||||
COMPONENT_SRCDIRS := player recorder
|
||||
|
||||
include $(IDF_PATH)/make/component_common.mk
|
||||
|
||||
|
146
examples/09_a2dp/components/EspAudio/include/EspAudio.h
Normal file
146
examples/09_a2dp/components/EspAudio/include/EspAudio.h
Normal file
|
@ -0,0 +1,146 @@
|
|||
// Copyright 2010-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef ESP_AUDIO
|
||||
#define ESP_AUDIO
|
||||
#include "esp_types.h"
|
||||
#include "EspAudioCom.h"
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Maximum size of the URI, including null character.
|
||||
*/
|
||||
//#define MAX_URI_SIZE 1024
|
||||
|
||||
/*
|
||||
* Defines various states that the ESP player can be.
|
||||
*/
|
||||
enum EspAudioState
|
||||
{
|
||||
AUDIOSTATE_UNINITIALIZED = 0, /* player is not initialized */
|
||||
AUDIOSTATE_IDLE, /* player is idle */
|
||||
AUDIOSTATE_STOPPED, /* player is stopled */
|
||||
AUDIOSTATE_TRANSIT, /* player is busy in a transition */
|
||||
AUDIOSTATE_PLAYING, /* player is currently playing */
|
||||
AUDIOSTATE_PAUSED, /* player is in the paused state for playback */
|
||||
AUDIOSTATE_ENDED, /* player finished decoding player, without user request. */
|
||||
AUDIOSTATE_ERROR, /* player was given a URI that could not be played */
|
||||
|
||||
AUDIOSTATE_UNKNOWN /* unknown playstate */
|
||||
};
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
InputSrcType_NetSpec = 0, ///< Specify audio file from internet.
|
||||
InputSrcType_NetLiving = 1, ///< Living audio stream from internet,e.g.m3u8
|
||||
InputSrcType_LocalFile = 2, ///< Local file which store in the SD card
|
||||
InputSrcType_Stream = 3, ///< Only audio stream,e.g.PCM
|
||||
InputSrcType_Max
|
||||
} InputSrcType;
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
EspAudioErr_NoErr =0, ///< No error
|
||||
EspAudioErr_InvalidPara, ///< Invalid parameters
|
||||
EspAudioErr_NoMem, ///< Malloc failed
|
||||
EspAudioErr_HardwareErr, ///< Hardware error
|
||||
EspAudioErr_OutOfRange, ///< length of URI is too long.
|
||||
EspAudioErr_NotSupport, ///< Not support the
|
||||
|
||||
} EspAudioErr;
|
||||
|
||||
|
||||
/*
|
||||
* Initializes the ESP player library.
|
||||
*/
|
||||
void EspAudio_Init(void);
|
||||
|
||||
/*
|
||||
* Cleans up the ESP player library.
|
||||
*/
|
||||
void EspAudio_UnInit(void);
|
||||
|
||||
/*
|
||||
* Play, stop, pause the streaming and output of player
|
||||
* EspAudio_Init must be called before these methods work.
|
||||
*/
|
||||
int EspAudio_SetupStream(const char* URI, InputSrcType UriType);
|
||||
/*
|
||||
* Call this method to transition to playing state.
|
||||
*
|
||||
* Returns nonzero if an error occurred.
|
||||
*/
|
||||
int EspAudio_Play(void);
|
||||
|
||||
/*
|
||||
* Call this method to stop playing ESP player.
|
||||
*
|
||||
* Returns nonzero if an error occurred.
|
||||
*/
|
||||
int EspAudio_Stop(void);
|
||||
|
||||
/*
|
||||
* Call this method to pause the playing ESP player.
|
||||
*
|
||||
* Returns nonzero if an error occurred.
|
||||
*/
|
||||
int EspAudio_Pause(void);
|
||||
|
||||
/*
|
||||
* Returns the playstate of the ESP player library.
|
||||
* Returns MEDIA_UNKNOWN if the stream could not be found.
|
||||
*/
|
||||
enum EspAudioState EspAudio_GetPlayState(void);
|
||||
|
||||
/*
|
||||
* Get the player volume level . Volume level is from 0 to 100.
|
||||
* Returns a negative value if the stream could not be found or the value is unknown.
|
||||
*/
|
||||
int EspAudio_GetVolume(int *level);
|
||||
|
||||
/*
|
||||
* Set the player volume level . Volume level is from 0 to 100.
|
||||
* Returns a negative value if the stream could not be found or the value is unknown.
|
||||
*/
|
||||
int EspAudio_SetVolume(int level);
|
||||
|
||||
/*
|
||||
* Call this method to configrate stream information.
|
||||
*
|
||||
* Returns nonzero if an error occurred.
|
||||
*/
|
||||
EspAudioErr EspAudioPlayerStreamCfg(uint32_t rate, uint32_t channel,uint32_t bitLen);
|
||||
|
||||
/*
|
||||
* Call this method to flush stream data to driver.
|
||||
*
|
||||
* Returns nonzero if an error occurred.
|
||||
*
|
||||
* Note:Timeout portMAX_DELAY-block; others,unblock.
|
||||
*/
|
||||
EspAudioErr EspAudioPlayerStreamWrite(uint8_t *inData, uint32_t inSize, uint32_t timeout);
|
||||
|
||||
/*
|
||||
* Call this method to stop once stream write.
|
||||
*
|
||||
* Returns nonzero if an error occurred.
|
||||
*
|
||||
*/
|
||||
EspAudioErr EspAudioPlayerStreamWriteEnd(void);
|
||||
|
||||
|
||||
#endif
|
78
examples/09_a2dp/components/EspAudio/include/EspAudioCom.h
Normal file
78
examples/09_a2dp/components/EspAudio/include/EspAudioCom.h
Normal file
|
@ -0,0 +1,78 @@
|
|||
// Copyright 2010-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef _ESPAUDIOCOM_H
|
||||
#define _ESPAUDIOCOM_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "audio_log.h"
|
||||
#include "EspAudioCom.h"
|
||||
|
||||
#define ESP_AUDIO_RELEASE_MAJOR (0000)
|
||||
#define ESP_AUDIO_RELEASE_MINOR (52)
|
||||
#define ESP_AUDIO_RELEASE_VER "0.52"
|
||||
|
||||
// Specified audio buffer address
|
||||
#define AUDIO_BUFFER_ADDR (0x3f800000) // For external RAM
|
||||
|
||||
// Specified aduio buffer size
|
||||
#ifdef AUDIO_BUFFER_ADDR
|
||||
#define AUDIO_BUFFER_SIZE (1024*1024)
|
||||
#else
|
||||
#define AUDIO_BUFFER_SIZE (25000)
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t type;
|
||||
char str[1024];
|
||||
} UrlInfo;
|
||||
|
||||
|
||||
typedef enum {
|
||||
StreamType_Opus,
|
||||
StreamType_Pcm, // it will be support
|
||||
StreamType_Max,
|
||||
} StreamType;
|
||||
|
||||
|
||||
typedef enum {
|
||||
StreamSampleRate_8k = 8000,
|
||||
StreamSampleRate_16k = 16000, // This is support
|
||||
StreamSampleRate_22K = 22050,
|
||||
StreamSampleRate_32K = 32000,
|
||||
StreamSampleRate_44k = 44100,
|
||||
StreamSampleRate_48k = 48000,
|
||||
StreamSampleRate_Max,
|
||||
} StreamSampleRate;
|
||||
|
||||
|
||||
typedef enum {
|
||||
StreamBitLen_8BIT = 8,
|
||||
StreamBitLen_16BIT = 16,
|
||||
StreamBitLen_24BIT = 24,
|
||||
StreamBitLen_32BIT = 32,
|
||||
StreamBitLen_Max,
|
||||
} StreamBitLen;
|
||||
|
||||
|
||||
typedef enum {
|
||||
StreamChannel_One, // it will be support
|
||||
StreamChannel_Two,
|
||||
StreamChannel_Max,
|
||||
} StreamChannel;
|
||||
|
||||
#endif /* _ESPAUDIOCOM_H */
|
|
@ -0,0 +1,70 @@
|
|||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef __ESPAUDIORECORDER_H__
|
||||
#define __ESPAUDIORECORDER_H__
|
||||
#include "esp_types.h"
|
||||
#include "EspAudio.h"
|
||||
|
||||
|
||||
//Type Definitions
|
||||
typedef void (*Callback_RecordData)(void *recBuf, uint32_t *recLen);
|
||||
|
||||
typedef enum {
|
||||
RecorderState_Unknown = 0,
|
||||
RecorderState_Init,
|
||||
RecorderState_Stoped,
|
||||
RecorderState_Recording,
|
||||
RecorderState_Paused,
|
||||
} RecorderState;
|
||||
|
||||
typedef enum {
|
||||
EncodeType_Opus = 1,
|
||||
EncodeType_Pcm,
|
||||
EncodeType_Max,
|
||||
} EncodeType;
|
||||
|
||||
|
||||
typedef enum {
|
||||
RecorderSampleRate_8k = 8000, // it will be support
|
||||
RecorderSampleRate_16k = 16000,
|
||||
RecorderSampleRate_Max,
|
||||
} RecorderSampleRate;
|
||||
|
||||
|
||||
typedef enum {
|
||||
RecorderChannel_One = 1,
|
||||
RecorderChannel_Two, // it will be support
|
||||
RecorderChannel_Max,
|
||||
} RecorderChannel;
|
||||
|
||||
|
||||
typedef struct {
|
||||
RecorderSampleRate rate;
|
||||
RecorderChannel channel;
|
||||
EncodeType encodeType;
|
||||
Callback_RecordData func;
|
||||
} RecorderAttr;
|
||||
|
||||
|
||||
EspAudioErr EspAudioRecorderStart(RecorderAttr *recorderAttr);
|
||||
EspAudioErr EspAudioRecorderStop(void);
|
||||
EspAudioErr EspAudioRecorderPause(void);
|
||||
EspAudioErr EspAudioRecorderResume(void);
|
||||
EspAudioErr EspAudioRecorderStateGet(RecorderState *state);
|
||||
EspAudioErr EspAudioRecorderInit(void);
|
||||
EspAudioErr EspAudioRecorderUninit(void);
|
||||
|
||||
|
||||
#endif //__ESPAUDIORECORDER_H__
|
855
examples/09_a2dp/components/EspAudio/player/DownloadTask.c
Normal file
855
examples/09_a2dp/components/EspAudio/player/DownloadTask.c
Normal file
|
@ -0,0 +1,855 @@
|
|||
#include <string.h>
|
||||
#include "esp_types.h"
|
||||
#include "stdlib.h"
|
||||
#include "stdio.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/queue.h"
|
||||
|
||||
#include "lwip/sockets.h"
|
||||
#include "lwip/err.h"
|
||||
#include "lwip/dns.h"
|
||||
#include "lwip/netdb.h"
|
||||
#include "lwip/sys.h"
|
||||
#include "errno.h"
|
||||
#include "audio_log.h"
|
||||
#include "inc/DownloadTask.h"
|
||||
#include "inc/M3u8.h"
|
||||
#include "EspAudioCom.h"
|
||||
#include "EspAudio.h"
|
||||
|
||||
#include "inc/MediaDecoderTask.h"
|
||||
#include "Storage.h"
|
||||
#include "MediaHal.h"
|
||||
#include "Utility.h"
|
||||
|
||||
#define PRIO_DOWNLOAD 19
|
||||
#define DEFAULT_AAC_SEQ 0xFFFFFFFF
|
||||
#define REQUEST_BUF_LEN 1024
|
||||
#define RECV_BUF_LEN 1500
|
||||
|
||||
|
||||
#if 1
|
||||
#define DEBUGHTTP printf
|
||||
#else
|
||||
#define DEBUGHTTP
|
||||
#endif
|
||||
|
||||
|
||||
uint32_t fileTaskState = 0;
|
||||
uint32_t m3u8TaskState = 0;
|
||||
void m3u8DownloadTask(void *pvParameters);
|
||||
void fileDownloadTask(void *pvParameters);
|
||||
|
||||
typedef struct {
|
||||
int status; // 1:downloading; 2:finished
|
||||
char *reqBuf;
|
||||
char *recvBuf;
|
||||
int blockQuit;
|
||||
int receivedSize;
|
||||
uint32_t remaindSize;
|
||||
uint32_t downloadedSize;
|
||||
uint32_t contentTotalSize;
|
||||
UriSrcAttr uri;
|
||||
} HttpObj;
|
||||
|
||||
|
||||
typedef struct {
|
||||
TaskState state;
|
||||
pthread_t thread;
|
||||
int threadQuit;
|
||||
} DownloadInstance;
|
||||
|
||||
|
||||
static HttpObj localHttp;
|
||||
//static mutex_t downloadMutex;
|
||||
static UrlInfo actLiveUrl;
|
||||
|
||||
DownloadInstance dlInstance = { 0 };
|
||||
|
||||
typedef void (*Callback_Recv)(HttpObj *obj);
|
||||
|
||||
int checkIsReqOk(char *buf)
|
||||
{
|
||||
char *l = strstr(buf, "HTTP/1.1 2");
|
||||
if (NULL == l) {
|
||||
l = strstr(buf, "HTTP/1.0 2");
|
||||
if (NULL == l) {
|
||||
l = strstr(buf, "HTTP/1.0 3");
|
||||
if (NULL == l) {
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int getLocation (const char *buf, char* dest)
|
||||
{
|
||||
// Location: http://119.90.25.49/live.xmcdn.com/192.168.3.134/live/38/24/161118_174054_588.aac
|
||||
char *l = strstr(buf, "Location:");
|
||||
if (NULL == l) {
|
||||
LOGE("Can't find Location:%s", buf);
|
||||
return -1;
|
||||
}
|
||||
l += 10;
|
||||
int i1 = 0;
|
||||
if (l != NULL) {
|
||||
while (*l != '\r') {
|
||||
dest[i1++] = *(l++);
|
||||
if (i1 > ESP_URI_LEN) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LOGE("Can't find Location:%s", buf);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int getFileLength(char *buf)
|
||||
{
|
||||
char *l = strstr(buf, "Content-Length:");
|
||||
if (NULL == l) {
|
||||
LOGE("Can't find length:%s", buf);
|
||||
return 0;
|
||||
}
|
||||
l += 16;
|
||||
char len[32] = {0};
|
||||
int i1 = 0;
|
||||
if (l != NULL) {
|
||||
while (*l != '\r') {
|
||||
len[i1++] = *(l++);
|
||||
}
|
||||
} else {
|
||||
LOGE("Can't find length:%s", buf);
|
||||
return 0;
|
||||
}
|
||||
return atoi(len);
|
||||
|
||||
}
|
||||
|
||||
|
||||
void ReqHead(char* outReqBuf, const char *url, char* host)
|
||||
{
|
||||
LOGD("http HEAD requst\r\n");
|
||||
sprintf(outReqBuf, "HEAD %s HTTP/1.1\r\n"
|
||||
"Accept:*/*\r\n"
|
||||
"User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.80 Safari/537.36\r\n"
|
||||
"Host: %s\r\n"
|
||||
"Connection:Keep-Alive\r\n"
|
||||
"Cache-Control: no-cache\r\n"
|
||||
"\r\n\r\n", url, host);
|
||||
DEBUGHTTP(outReqBuf);
|
||||
}
|
||||
|
||||
|
||||
void ReqGetM3u8(char* outReqBuf, const char *url, char* host)
|
||||
{
|
||||
LOGD("http GET requst:");
|
||||
if ((NULL == url) || (NULL == host)) {
|
||||
LOGE("NULL = url or NULL = host");
|
||||
return;
|
||||
}
|
||||
sprintf(outReqBuf, "GET %s HTTP/1.1\r\n"
|
||||
"Accept:*/*\r\n"
|
||||
"User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.80 Safari/537.36\r\n"
|
||||
"Host: %s\r\n"
|
||||
"Connection: Close\r\n" // Keep-Alive
|
||||
"Cache-Control: no-cache\r\n"
|
||||
"\r\n\r\n", url, host);
|
||||
DEBUGHTTP(outReqBuf);
|
||||
}
|
||||
|
||||
|
||||
void ReqDataPre(char* outReqBuf, const char *url, char* host, uint32_t startLen, uint32_t endLen)
|
||||
{
|
||||
if (0 != endLen) {
|
||||
sprintf(outReqBuf, "GET %s HTTP/1.1\r\n"
|
||||
"Accept:*/*\r\n"
|
||||
"User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.80 Safari/537.36\r\n"
|
||||
"Host: %s\r\n"
|
||||
"Proxy-Connection: Keep-Alive\r\n"
|
||||
"Cache-Control: no-cache\r\n"
|
||||
"Range: bytes=%d-%d\r\n\r\n", url, host, startLen, endLen - 1);
|
||||
} else {
|
||||
sprintf(outReqBuf, "GET %s HTTP/1.1\r\n"
|
||||
"Accept:*/*\r\n"
|
||||
"User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.80 Safari/537.36\r\n"
|
||||
"Host: %s\r\n"
|
||||
"Proxy-Connection: Keep-Alive\r\n"
|
||||
"Cache-Control: no-cache\r\n\r\n", url, host);
|
||||
}
|
||||
|
||||
LOGD("http GET requst-%d:", strlen(outReqBuf));
|
||||
//DEBUGHTTP(outReqBuf);
|
||||
}
|
||||
|
||||
int getIpForHost(const char *host, struct sockaddr_in *ip)
|
||||
{
|
||||
struct hostent *he;
|
||||
struct in_addr **addr_list;
|
||||
char str[200] ;
|
||||
|
||||
he = gethostbyname(host);
|
||||
if (he == NULL) return 0;
|
||||
addr_list = (struct in_addr **)he->h_addr_list;
|
||||
if (addr_list[0] == NULL) return 0;
|
||||
ip->sin_family = AF_INET;
|
||||
memcpy(&ip->sin_addr, addr_list[0], sizeof(ip->sin_addr));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int splitHostUrl(const char* url, char* host, uint16_t *port, char **path)
|
||||
{
|
||||
if ((NULL == url) || (NULL == host)) {
|
||||
LOGE("ERR:url=NULL or Host=NULL\n");
|
||||
return -1;
|
||||
}
|
||||
char* temp1;
|
||||
char* source = (char*)url;
|
||||
char portBuf[10] = {0};
|
||||
while (url) {
|
||||
source = strstr(source, "//");
|
||||
if (url == NULL) {
|
||||
LOGE("ERR:strchr=NULL\n");
|
||||
return -1;
|
||||
}
|
||||
source += 2;
|
||||
temp1 = strchr(source, ':');
|
||||
if (temp1 != NULL) {
|
||||
// try to find '/'
|
||||
strncpy(host, source, temp1 - source);
|
||||
temp1 += 1;
|
||||
source = strchr(source, '/');
|
||||
if (source == NULL) {
|
||||
LOGE("ERR:strchr=NULL\n");
|
||||
return 0;
|
||||
}
|
||||
strncpy(portBuf, temp1, source - temp1);
|
||||
*port = strtoul(portBuf, 0, 10);
|
||||
*path = source;
|
||||
LOGD("\nUsed Host[%s] Port[%d],Path:%s\n", host, *port, *path);
|
||||
} else {
|
||||
// try to find port
|
||||
temp1 = strchr(source, '/');
|
||||
if (temp1 == NULL) {
|
||||
LOGE("ERR:strchr=NULL\n");
|
||||
return -1;
|
||||
}
|
||||
strncpy(host, source, temp1 - source);
|
||||
*port = 80;
|
||||
*path = temp1;
|
||||
LOGD("\nUsed Host[%s] Port[%d],Path:%s\n", host, *port, *path);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int connectToServer(const char* actUrl, const char* hostName, uint16_t port, int timeOut)
|
||||
{
|
||||
struct sockaddr_in remote_ip;
|
||||
int sock = -1;
|
||||
int nNetTimeout = timeOut; // socket timeout 1 Sec
|
||||
int retryCnt = 3;
|
||||
while (retryCnt--) {
|
||||
bzero(&remote_ip, sizeof(struct sockaddr_in));
|
||||
if (1 != inet_aton(hostName, &remote_ip.sin_addr)) {
|
||||
if (!getIpForHost(hostName, &remote_ip)) {
|
||||
vTaskDelay(1000 / portTICK_RATE_MS);
|
||||
LOGE("getIpForHost failed");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
remote_ip.sin_family = AF_INET;
|
||||
int sock = socket(PF_INET, SOCK_STREAM, 0);
|
||||
if (sock == -1) {
|
||||
LOGE("socket failed errno=%d", errno);
|
||||
continue;
|
||||
}
|
||||
// setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&nNetTimeout, sizeof(int));
|
||||
struct timeval tv_out;
|
||||
tv_out.tv_sec = 20; //Wait 20 seconds.
|
||||
tv_out.tv_usec = 0;
|
||||
setsockopt(sock,SOL_SOCKET,SO_RCVTIMEO,&tv_out, sizeof(tv_out));
|
||||
|
||||
remote_ip.sin_port = htons(port);
|
||||
LOGD("[sock=%d],connecting to server IP:%s,Port:%d...",
|
||||
sock, ipaddr_ntoa((const ip_addr_t*)&remote_ip.sin_addr.s_addr), port);
|
||||
if (connect(sock, (struct sockaddr *)(&remote_ip), sizeof(struct sockaddr)) != 0) {
|
||||
close(sock);
|
||||
LOGE("Conn err.\n");
|
||||
vTaskDelay(1000 / portTICK_RATE_MS);
|
||||
continue;
|
||||
}
|
||||
return sock;
|
||||
}
|
||||
LOGE("Lost host,connect and getIpForHost timeout");
|
||||
return -2;
|
||||
}
|
||||
|
||||
void resetDownloadAttr(char *src, uint32_t *type)
|
||||
{
|
||||
localHttp.status = 0;
|
||||
if (localHttp.blockQuit < 0) {
|
||||
localHttp.blockQuit = 0;
|
||||
}
|
||||
localHttp.receivedSize = 0;
|
||||
localHttp.remaindSize = 0;
|
||||
localHttp.downloadedSize = 0;
|
||||
localHttp.uri.srcType = *type;
|
||||
localHttp.contentTotalSize = 0;
|
||||
memset(localHttp.uri.str, 0, ESP_URI_LEN);
|
||||
strncpy(localHttp.uri.str, src, strlen(src));
|
||||
}
|
||||
|
||||
void OnFileDataCB(HttpObj *obj)
|
||||
{
|
||||
int ret;
|
||||
|
||||
do {
|
||||
ret = audioBufWrite(obj->reqBuf, obj->receivedSize, 100);
|
||||
if (ret) {
|
||||
obj->remaindSize -= obj->receivedSize;
|
||||
obj->downloadedSize += obj->receivedSize;
|
||||
// uint32_t rd, wr;
|
||||
// audioBufPosGet(&rd, &wr);
|
||||
// LOGD("rd:%x,wr:%x,downloaded=%d, remaind=%d, total=%d, recvSize=%d",
|
||||
// rd,wr,obj->downloadedSize, obj->remaindSize, obj->contentTotalSize, obj->receivedSize);
|
||||
break;
|
||||
} else {
|
||||
LOGE("audioBufWrite failed ret=%d. rcev=%d,remaind=%d, d=%d", ret,
|
||||
obj->receivedSize, obj->remaindSize, obj->downloadedSize);
|
||||
break;
|
||||
}
|
||||
} while (0 == obj->blockQuit);
|
||||
}
|
||||
|
||||
void OnM3u8DataCB(HttpObj *obj)
|
||||
{
|
||||
obj->remaindSize -= obj->receivedSize;
|
||||
obj->downloadedSize += obj->receivedSize;
|
||||
// LOGD(":\n%s", obj->reqBuf);
|
||||
}
|
||||
|
||||
char *GetValidUrl(M3u8Info *pActM3u8, M3u8Seq *actSeq)
|
||||
{
|
||||
char *retUrl = NULL;
|
||||
if ((NULL == actSeq)
|
||||
|| (NULL == pActM3u8)) {
|
||||
LOGE("pActM3u8 or actSeq is NULL");
|
||||
return retUrl;
|
||||
}
|
||||
int validM3u8 = -1;
|
||||
for (uint8_t i = 0; i < 3; i++) {
|
||||
// LOGD("M3u8 AAC URL,%dth,%s\n", i, pActM3u8->segList[i].url);
|
||||
if ((actSeq->sub == DEFAULT_AAC_SEQ)
|
||||
|| (1 == m3u8CheckValid(&pActM3u8->segList[i].seq, (const M3u8Seq*)actSeq))) {
|
||||
validM3u8 = 1;
|
||||
retUrl = pActM3u8->segList[i].url;
|
||||
memcpy(actSeq, &pActM3u8->segList[i].seq, sizeof(pActM3u8->segList[i].seq));
|
||||
pActM3u8->segList[i].seq.sub = 0;
|
||||
LOGD("Get one valid AAC URL,%dth,seq=%x,%s\n", i, actSeq->sub, retUrl);
|
||||
if ((0 == actSeq->sub)
|
||||
|| (retUrl[0] == '\0')) {
|
||||
retUrl = NULL;
|
||||
}
|
||||
return retUrl;
|
||||
} else {
|
||||
// LOGD("Get one valid AAC URL,%dth,seq=%x,%s\n", i, pActM3u8->segList[i].seq.sub, pActM3u8->segList[i].url);
|
||||
pActM3u8->segList[i].seq.sub = 0;
|
||||
}
|
||||
}
|
||||
if (validM3u8 != 1) {
|
||||
LOGD("Can not found valid aac url, curtAacSeq=%x", actSeq->sub);
|
||||
}
|
||||
return retUrl;
|
||||
|
||||
}
|
||||
|
||||
int httpDownloading(HttpObj *obj, Callback_Recv recvCB)
|
||||
{
|
||||
if ((NULL == obj)
|
||||
|| (NULL == obj->uri.str)
|
||||
|| (NULL == obj->reqBuf)
|
||||
|| (NULL == obj->recvBuf)
|
||||
|| (0 == strlen(obj->uri.str))) {
|
||||
LOGE("Pointer is NULL,obj:%x,URL:%x reqbuf:%x recvBuf:%x,len:%d,blockQuit:%d",
|
||||
obj, obj->uri.str, obj->reqBuf, obj->recvBuf, strlen(obj->uri.str), obj->blockQuit);
|
||||
return -1;
|
||||
}
|
||||
char hostName[32] = { 0 };
|
||||
int actSocket = -1;
|
||||
uint32_t contrlDat = 0;
|
||||
uint8_t modifyProFlag = 0;
|
||||
int cnt = 0;
|
||||
int n = 0;
|
||||
LOGD("\n>>>>>Downloading start:%s,0x%x,remaind=%d,downloaded=%d,total=%d,fill=%d",
|
||||
obj->uri.str, obj->uri.str, obj->remaindSize, obj->downloadedSize, obj->contentTotalSize, audioBufFillGet());
|
||||
obj->status = 1;
|
||||
uint16_t ipPort = 80;
|
||||
char *uriPath = NULL;
|
||||
do {
|
||||
// Here will check exit event;
|
||||
|
||||
Retry: LOGD("retry new url size=%d", obj->remaindSize);
|
||||
memset(hostName, 0, sizeof(hostName));
|
||||
if (0 != splitHostUrl(obj->uri.str, hostName, &ipPort, &uriPath)) {
|
||||
LOGE("splitHostUrl failed:%s", obj->uri.str);
|
||||
continue;
|
||||
}
|
||||
LOGD("Hostname:%s", hostName);
|
||||
if ((actSocket = connectToServer((const char*)obj->uri.str, hostName, ipPort, 10000)) >= 0) {
|
||||
char * datPos = NULL;
|
||||
bzero(obj->reqBuf, REQUEST_BUF_LEN);
|
||||
ReqDataPre(obj->reqBuf, uriPath, hostName, obj->downloadedSize, obj->contentTotalSize);
|
||||
LOGD("Hostname:%s++++++++", hostName);
|
||||
write(actSocket, obj->reqBuf, strlen(obj->reqBuf));
|
||||
LOGD("Hostname:%s--------", hostName);
|
||||
bzero(obj->recvBuf, RECV_BUF_LEN);
|
||||
datPos = NULL;
|
||||
cnt = 0;
|
||||
do {
|
||||
bzero(obj->reqBuf, REQUEST_BUF_LEN);
|
||||
n = read(actSocket, obj->reqBuf, REQUEST_BUF_LEN);
|
||||
if ((n > 0) && (cnt <= RECV_BUF_LEN)) {
|
||||
// DEBUGHTTP("Head is: %s", obj->reqBuf);
|
||||
memcpy(obj->recvBuf + cnt, obj->reqBuf, n);
|
||||
datPos = strstr(obj->recvBuf, "\r\n""""\r\n");
|
||||
if (datPos) {
|
||||
//DEBUGHTTP("Find CRLF CRLF ok");
|
||||
// LOGD("Head is: %s", obj->recvBuf);
|
||||
} else {
|
||||
LOGE("Find CRLF CRLF failed,wait more data");
|
||||
}
|
||||
}
|
||||
cnt += n;
|
||||
} while ((datPos == NULL) && (n > 0) && (cnt < RECV_BUF_LEN));
|
||||
if (n < 0) {
|
||||
close(actSocket);
|
||||
continue;
|
||||
}
|
||||
if (NULL == datPos) {
|
||||
// datPos == strstr(obj->recvBuf, "\r\n""""\r\n");
|
||||
LOGD("Head is: %s", obj->recvBuf);
|
||||
|
||||
if (NULL == datPos) {
|
||||
close(actSocket);
|
||||
LOGE("Can't Find CRLF CRLF,it's bad response,try again");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
int ret = checkIsReqOk(obj->recvBuf);
|
||||
if (ret < 0) {
|
||||
close(actSocket);
|
||||
LOGE("Recv a bad resp:%s", obj->recvBuf);
|
||||
continue;
|
||||
} else if (ret == 1) {
|
||||
close(actSocket);
|
||||
LOGW("Recv a 3xx resp:%s", obj->recvBuf);
|
||||
memset(obj->uri.str, 0, ESP_URI_LEN);
|
||||
if (getLocation((const char*)obj->recvBuf, obj->uri.str) < 0) {
|
||||
LOGE("Find 3xx URL error");
|
||||
} else {
|
||||
LOGW("Recv a 3xx resp:%s", obj->uri.str);
|
||||
}
|
||||
goto Retry;
|
||||
}
|
||||
if (0 == obj->contentTotalSize) obj->contentTotalSize = getFileLength(obj->recvBuf);
|
||||
datPos += 4;
|
||||
cnt = cnt - (datPos - obj->recvBuf);
|
||||
if (0 == obj->remaindSize) {
|
||||
obj->remaindSize = obj->contentTotalSize;
|
||||
}
|
||||
// Save the tail data
|
||||
bzero(obj->reqBuf, REQUEST_BUF_LEN);
|
||||
memcpy(obj->reqBuf, datPos, cnt);
|
||||
|
||||
LOGD("downloaded=%d, remaind=%d, total=%d, cnt=%d",
|
||||
obj->downloadedSize, obj->remaindSize, obj->contentTotalSize, cnt);
|
||||
int writeComplete = 0;
|
||||
do {
|
||||
if (writeComplete) {
|
||||
bzero(obj->reqBuf, REQUEST_BUF_LEN);
|
||||
n = read(actSocket, obj->reqBuf, REQUEST_BUF_LEN);
|
||||
cnt = n;
|
||||
// DEBUGHTTP("recv,cnt:%d\n", cnt);
|
||||
}
|
||||
if (n > 0) {
|
||||
if (cnt > 0) {
|
||||
obj->receivedSize = cnt;
|
||||
recvCB(obj);
|
||||
}
|
||||
cnt = 0;
|
||||
writeComplete = 1;
|
||||
}
|
||||
} while ((n > 0) && (obj->remaindSize > 0) && (0 == obj->blockQuit));
|
||||
close(actSocket);
|
||||
LOGD("Sock[%d] has closed,n=%d,blockQuit=%d", actSocket, n, obj->blockQuit);
|
||||
} else {
|
||||
LOGE("Connect is error.");
|
||||
}
|
||||
LOGD("Connect closed,file size remaind=%d", obj->remaindSize);
|
||||
|
||||
} while ((obj->remaindSize != 0) && (0 == obj->blockQuit));
|
||||
if (0 == obj->remaindSize) {
|
||||
obj->status = 2;
|
||||
} else {
|
||||
obj->status = 3;
|
||||
}
|
||||
LOGD("\n<<<<<Downloading finish:%s,remaind=%d,downloaded=%d,total=%d fill=%d status=%d\n",
|
||||
obj->uri.str, obj->remaindSize, obj->downloadedSize, obj->contentTotalSize,
|
||||
audioBufFillGet(), obj->status);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void fileDownloadTask(void *pvParameters)
|
||||
{
|
||||
int n, cnt;
|
||||
DownloadInstance *downloadObj = (DownloadInstance *)pvParameters;
|
||||
LOGI("%s is running.%x %x", __func__, pvParameters, downloadObj->threadQuit);
|
||||
|
||||
/////////////////////////////
|
||||
M3u8Seq runningAacSeq = {0, 0, DEFAULT_AAC_SEQ};
|
||||
M3u8Info *pUsingM3u8 = NULL;
|
||||
uint32_t mediaSeq = DEFAULT_AAC_SEQ;
|
||||
|
||||
downloadObj->threadQuit = 0;
|
||||
while (downloadObj->threadQuit == 0) {
|
||||
switch (downloadObj->state) {
|
||||
case TaskState_Ready:
|
||||
if ((NULL == actLiveUrl.str)
|
||||
|| (actLiveUrl.str[0] == '\0')
|
||||
|| (NULL == localHttp.uri.str )) {
|
||||
downloadObj->state = TaskState_Idle;
|
||||
vTaskDelay(200 / portTICK_RATE_MS);
|
||||
LOGI("Downloading URL is NULL,downloading task paused");
|
||||
break;
|
||||
} else {
|
||||
LOGI("Download task is ready.%s type:%d", actLiveUrl.str, actLiveUrl.type);
|
||||
}
|
||||
if (InputSrcType_NetSpec == actLiveUrl.type) {
|
||||
resetDownloadAttr(actLiveUrl.str, &actLiveUrl.type);
|
||||
downloadObj->state = TaskState_Running;
|
||||
audioBufWrRest();
|
||||
} else if (InputSrcType_NetLiving == actLiveUrl.type) {
|
||||
resetDownloadAttr(actLiveUrl.str, &actLiveUrl.type);
|
||||
|
||||
audioBufWrRest();
|
||||
mediaSeq = DEFAULT_AAC_SEQ;
|
||||
downloadObj->state = TaskState_Running;
|
||||
runningAacSeq.sub = DEFAULT_AAC_SEQ;
|
||||
if (pUsingM3u8) {
|
||||
free(pUsingM3u8);
|
||||
pUsingM3u8 = NULL;
|
||||
}
|
||||
pUsingM3u8 = calloc(1, sizeof(M3u8Info));
|
||||
if (pUsingM3u8 == NULL) {
|
||||
LOGE("recvBuf malloc error");
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
LOGE("Http uri.srcType is not supported[%d]", localHttp.uri.srcType);
|
||||
downloadObj->state = TaskState_Idle;
|
||||
vTaskDelay(200 / portTICK_RATE_MS);
|
||||
}
|
||||
break;
|
||||
case TaskState_Pause:
|
||||
LOGI("TaskState_Pause,Total=%d, downloaded=%d,remaind=%d", localHttp.contentTotalSize,
|
||||
localHttp.downloadedSize,
|
||||
localHttp.remaindSize);
|
||||
downloadObj->state = TaskState_Idle;
|
||||
break;
|
||||
case TaskState_Resume:
|
||||
downloadObj->state = TaskState_Running;
|
||||
LOGI("TaskState_Resume,Total=%d, downloaded=%d,remaind=%d", localHttp.contentTotalSize,
|
||||
localHttp.downloadedSize,
|
||||
localHttp.remaindSize);
|
||||
break;
|
||||
case TaskState_Running:
|
||||
if (InputSrcType_NetSpec == localHttp.uri.srcType) {
|
||||
LOGI("Excute URL:%s", localHttp.uri.str);
|
||||
httpDownloading(&localHttp, OnFileDataCB);
|
||||
if (2 == localHttp.status) {
|
||||
downloadObj->state = TaskState_Idle;
|
||||
LOGI("Excute URL over, task will be idle.remind[%d]", localHttp.remaindSize);
|
||||
}
|
||||
} else if (InputSrcType_NetLiving == localHttp.uri.srcType) {
|
||||
resetDownloadAttr(actLiveUrl.str, &actLiveUrl.type);
|
||||
memset(localHttp.recvBuf, 0, RECV_BUF_LEN);
|
||||
memset(localHttp.reqBuf, 0, REQUEST_BUF_LEN);
|
||||
|
||||
LOGD("Excute URL:%s, actLiveUrl.str=%x", localHttp.uri.str, actLiveUrl.str);
|
||||
httpDownloading(&localHttp, OnM3u8DataCB);
|
||||
|
||||
M3u8Info *pActM3u8 = m3u8Parser(localHttp.reqBuf, pUsingM3u8);
|
||||
if (NULL == pActM3u8) {
|
||||
LOGE("Parser m3u8 is error");
|
||||
vTaskDelay(1000 / portTICK_RATE_MS);
|
||||
break;
|
||||
}
|
||||
if ((pActM3u8->mediaSeq <= mediaSeq) && (mediaSeq != DEFAULT_AAC_SEQ)) {
|
||||
LOGD("mediaSeq has not update,used=%d,new=%d", mediaSeq, pActM3u8->mediaSeq);
|
||||
vTaskDelay(1000 / portTICK_RATE_MS);
|
||||
break;
|
||||
}
|
||||
char *validUrl = GetValidUrl(pActM3u8, &runningAacSeq);
|
||||
|
||||
LOGD("AAC URL,runningAacSeq:%x,%x,%x\n",
|
||||
runningAacSeq.sub, runningAacSeq.main, runningAacSeq.date);
|
||||
if (NULL == validUrl) {
|
||||
vTaskDelay(100 / portTICK_RATE_MS);
|
||||
LOGE("uri.str is NULL,state=%d", downloadObj->state);
|
||||
break;
|
||||
}
|
||||
DecoderObj decoder;
|
||||
mediaDecoderTaskInfoGet(&decoder);
|
||||
decoder.musicType = checkMediaType(validUrl);
|
||||
if (decoder.musicType >= EspAudioMeidaType_M3u) {
|
||||
LOGE("%s,Music type[%d] is error", validUrl, decoder.musicType);
|
||||
vTaskDelay(100 / portTICK_RATE_MS);
|
||||
break;
|
||||
} else {
|
||||
mediaDecoderTaskInfoSet(&decoder);
|
||||
}
|
||||
do {
|
||||
resetDownloadAttr(validUrl, &actLiveUrl.type);
|
||||
memset(localHttp.recvBuf, 0, RECV_BUF_LEN);
|
||||
memset(localHttp.reqBuf, 0, REQUEST_BUF_LEN);
|
||||
|
||||
httpDownloading(&localHttp, OnFileDataCB);
|
||||
validUrl = GetValidUrl(pActM3u8, &runningAacSeq);
|
||||
|
||||
LOGD("AAC URL,runningAacSeq:%x,%x,%x\n", runningAacSeq.sub, runningAacSeq.main, runningAacSeq.date);
|
||||
if (NULL == validUrl) {
|
||||
LOGD("uri.str is NULL,state=%d", downloadObj->state);
|
||||
break;
|
||||
}
|
||||
} while (validUrl != NULL);
|
||||
mediaSeq = pActM3u8->mediaSeq;
|
||||
} else {
|
||||
LOGE("Http uri.srcType is not supported[%d]", localHttp.uri.srcType);
|
||||
downloadObj->state = TaskState_Idle;
|
||||
vTaskDelay(200 / portTICK_RATE_MS);
|
||||
}
|
||||
|
||||
break;
|
||||
case TaskState_Stoped:
|
||||
downloadObj->state = TaskState_Idle;
|
||||
break;
|
||||
case TaskState_Idle:
|
||||
default:
|
||||
vTaskDelay(250 / portTICK_RATE_MS);
|
||||
// LOGD("blockQuit[%d] state[%d]", localHttp.blockQuit, downloadObj->state);
|
||||
break;
|
||||
}
|
||||
}
|
||||
downloadObj->threadQuit = -1;
|
||||
downloadObj->thread = NULL;
|
||||
downloadObj->state = TaskState_Stoped;
|
||||
if (pUsingM3u8) {
|
||||
free(pUsingM3u8);
|
||||
pUsingM3u8 = NULL;
|
||||
}
|
||||
LOGD("%s is ended...", __func__);
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
TaskState downloadTaskStateGet()
|
||||
{
|
||||
return dlInstance.state;
|
||||
}
|
||||
|
||||
int downloadTaskHTTPStateGet()
|
||||
{
|
||||
return localHttp.status;
|
||||
}
|
||||
|
||||
void downloadTaskDownloadSizeSet(int *size)
|
||||
{
|
||||
if (NULL == size) {
|
||||
LOGE("Invalid para");
|
||||
return ;
|
||||
}
|
||||
// localHttp.blockQuit = 1;
|
||||
localHttp.downloadedSize = *size;
|
||||
downloadTaskResume();
|
||||
}
|
||||
|
||||
void downloadTaskContentSizeGet(uint32_t *size)
|
||||
{
|
||||
if (NULL == size) {
|
||||
LOGE("Invalid para");
|
||||
return ;
|
||||
}
|
||||
*size = localHttp.contentTotalSize;
|
||||
}
|
||||
|
||||
void downloadTaskInfoSet(UriSrcAttr *uri)
|
||||
{
|
||||
if (NULL == uri) {
|
||||
LOGE("Invalid para");
|
||||
return ;
|
||||
}
|
||||
actLiveUrl.type = uri->srcType;
|
||||
memset(actLiveUrl.str, 0 , ESP_URI_LEN);
|
||||
strncpy(actLiveUrl.str, uri->str, strlen(uri->str));
|
||||
localHttp.blockQuit = 0;
|
||||
LOGD("Set url ok:%s", actLiveUrl.str);
|
||||
}
|
||||
|
||||
void downloadTaskPause()
|
||||
{
|
||||
if (0 == dlInstance.thread) {
|
||||
dlInstance.state = TaskState_Unknown;
|
||||
LOGE("dlInstance.thread is NULL");
|
||||
return;
|
||||
}
|
||||
if (TaskState_Running == dlInstance.state) {
|
||||
localHttp.blockQuit = -1;
|
||||
}
|
||||
dlInstance.state = TaskState_Pause;
|
||||
|
||||
LOGD("download task state=%d", dlInstance.state);
|
||||
}
|
||||
|
||||
void downloadTaskResume()
|
||||
{
|
||||
if (0 == dlInstance.thread) {
|
||||
dlInstance.state = TaskState_Unknown;
|
||||
LOGE("dlInstance.thread is NULL");
|
||||
return;
|
||||
}
|
||||
if (TaskState_Pause == dlInstance.state) {
|
||||
localHttp.blockQuit = 0;
|
||||
}
|
||||
dlInstance.state = TaskState_Resume;
|
||||
LOGD("download task state=%d", dlInstance.state);
|
||||
}
|
||||
|
||||
void downloadTaskCreate(int taskType)
|
||||
{
|
||||
if (localHttp.reqBuf) {
|
||||
free(localHttp.reqBuf);
|
||||
}
|
||||
if (localHttp.recvBuf) {
|
||||
free(localHttp.recvBuf);
|
||||
}
|
||||
if (localHttp.uri.str) {
|
||||
free(localHttp.uri.str);
|
||||
}
|
||||
localHttp.reqBuf = calloc(1, REQUEST_BUF_LEN);
|
||||
if (NULL == localHttp.reqBuf) {
|
||||
LOGE("reqBuf malloc error");
|
||||
return;
|
||||
}
|
||||
localHttp.recvBuf = calloc(1, RECV_BUF_LEN);
|
||||
if (NULL == localHttp.recvBuf) {
|
||||
LOGE("recvBuf malloc error");
|
||||
free(localHttp.reqBuf);
|
||||
return;
|
||||
}
|
||||
localHttp.uri.str = calloc(1, ESP_URI_LEN);
|
||||
if (NULL == localHttp.uri.str) {
|
||||
LOGE("uri.str malloc error");
|
||||
free(localHttp.reqBuf);
|
||||
free(localHttp.recvBuf);
|
||||
return;
|
||||
}
|
||||
// mutex_init(&downloadMutex);
|
||||
// configASSERT(downloadMutex);
|
||||
xTaskCreate(fileDownloadTask, "fileDownloadTask", (6 * 1024), &dlInstance, PRIO_DOWNLOAD, &dlInstance.thread);
|
||||
configASSERT(dlInstance.thread);
|
||||
LOGD("download task state=%d", dlInstance.state);
|
||||
}
|
||||
|
||||
int downloadTaskStart()
|
||||
{
|
||||
if (0 == dlInstance.thread) {
|
||||
dlInstance.state = TaskState_Unknown;
|
||||
LOGE("dlInstance.thread is NULL");
|
||||
return -1;
|
||||
}
|
||||
if ((actLiveUrl.str == NULL)
|
||||
|| (actLiveUrl.str[0] == '\0')) {
|
||||
dlInstance.state = TaskState_Idle;
|
||||
LOGE("uri.str task is NULL");
|
||||
return -1;
|
||||
}
|
||||
dlInstance.state = TaskState_Ready;
|
||||
LOGD("download task state=%d, %s, %d", dlInstance.state, actLiveUrl.str, localHttp.blockQuit);
|
||||
audioBufWrRest();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void downloadTaskStop(void *que)
|
||||
{
|
||||
if (0 == dlInstance.thread) {
|
||||
dlInstance.state = TaskState_Unknown;
|
||||
LOGE("dlInstance.thread is NULL");
|
||||
return;
|
||||
}
|
||||
if (dlInstance.state == TaskState_Unknown) {
|
||||
LOGW("dlInstance.state is TaskState_Unknown");
|
||||
return;
|
||||
}
|
||||
localHttp.blockQuit = 1;
|
||||
dlInstance.state = TaskState_Stoped;
|
||||
configASSERT(que);
|
||||
xQueueSend(que, &localHttp.blockQuit, 0);
|
||||
|
||||
LOGD("download task +++++ blockQuit=%d, state=%d", localHttp.blockQuit, dlInstance.state);
|
||||
while ((TaskState_Finished != dlInstance.state)
|
||||
&& (TaskState_Idle != dlInstance.state)) {
|
||||
if ((TaskState_Idle == dlInstance.state)) {
|
||||
localHttp.blockQuit = 0;
|
||||
break;
|
||||
}
|
||||
vTaskDelay(10 / portTICK_RATE_MS);
|
||||
}
|
||||
audioBufWrRest();
|
||||
xQueueReset(que);
|
||||
LOGD("download task ------ blockQuit=%d, state=%d", localHttp.blockQuit, dlInstance.state);
|
||||
}
|
||||
|
||||
void downloadTaskDestroy()
|
||||
{
|
||||
if (0 == dlInstance.thread) {
|
||||
dlInstance.state = TaskState_Unknown;
|
||||
LOGE("dlInstance.thread is NULL");
|
||||
return;
|
||||
}
|
||||
|
||||
LOGD("download task +++++ blockQuit=%d, state=%d", localHttp.blockQuit, dlInstance.state);
|
||||
if (0 == dlInstance.threadQuit) {
|
||||
localHttp.blockQuit = 1;
|
||||
dlInstance.threadQuit = 1;
|
||||
dlInstance.state = TaskState_Stoped;
|
||||
while (1) {
|
||||
if ((dlInstance.threadQuit == -1)) {
|
||||
localHttp.blockQuit = 0;
|
||||
break;
|
||||
}
|
||||
vTaskDelay(200 / portTICK_RATE_MS);
|
||||
}
|
||||
}
|
||||
if (localHttp.reqBuf) free(localHttp.reqBuf);
|
||||
if (localHttp.recvBuf) free(localHttp.recvBuf);
|
||||
if (localHttp.uri.str) free(localHttp.uri.str);
|
||||
|
||||
memset(&localHttp, 0, sizeof(localHttp));
|
||||
localHttp.reqBuf = NULL;
|
||||
localHttp.recvBuf = NULL;
|
||||
localHttp.uri.str = NULL;
|
||||
dlInstance.state = TaskState_Unknown;
|
||||
dlInstance.thread = NULL;
|
||||
// mutex_destroy(&downloadMutex);
|
||||
// downloadMutex = NULL;
|
||||
LOGD("download task ------ blockQuit=%d, state=%d", localHttp.blockQuit, dlInstance.state);
|
||||
}
|
||||
|
1113
examples/09_a2dp/components/EspAudio/player/EspAudio.c
Normal file
1113
examples/09_a2dp/components/EspAudio/player/EspAudio.c
Normal file
File diff suppressed because it is too large
Load diff
318
examples/09_a2dp/components/EspAudio/player/M3u8.c
Normal file
318
examples/09_a2dp/components/EspAudio/player/M3u8.c
Normal file
|
@ -0,0 +1,318 @@
|
|||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "inc/M3u8.h"
|
||||
|
||||
static int read_line_from_m3u8_info(char *m3u8_info, char *line_buffer, int buffer_size);
|
||||
static int m3u8_info_eof();
|
||||
static int parseSegFromUrl(M3u8Segment* tsp);
|
||||
static char * strdupmy(const char *s);
|
||||
unsigned int length;
|
||||
unsigned int offset;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
char* trim_str(char *str)
|
||||
{
|
||||
char* tmp = str;
|
||||
|
||||
while (*str++ != '\r') {
|
||||
if (*str == '\0' || *str == '\n') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
*str = '\0';
|
||||
return tmp;
|
||||
}
|
||||
|
||||
// Must to be free memory
|
||||
static char * strdupmy(const char *s)
|
||||
{
|
||||
size_t len = strlen(s) + 1;
|
||||
void *new = malloc(len);
|
||||
if (new == NULL)
|
||||
return NULL;
|
||||
return (char *)memcpy(new, s, len);
|
||||
}
|
||||
|
||||
char* split_url(char* url, char* seg_path, char* seg_name)
|
||||
{
|
||||
char* temp1;
|
||||
char rateStr[10] = {0};
|
||||
int len = strlen(url);
|
||||
while (url) {
|
||||
temp1 = strrchr(url, '/');
|
||||
if (temp1 == NULL) {
|
||||
printf("ERR:strrchr=NULL,%s,%d\n", __FUNCTION__, __LINE__);
|
||||
return NULL;
|
||||
}
|
||||
temp1 += 1;
|
||||
strncpy(seg_path, url, temp1 - url);
|
||||
strncpy(seg_name, temp1, len - (temp1 - url));
|
||||
return seg_path;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int is_blank(char *str)
|
||||
{
|
||||
if (0 == strlen(str))
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int read_line_from_m3u8_info(char *m3u8_info, char *line_buffer, int buffer_size)
|
||||
{
|
||||
int start;
|
||||
int end = -1;
|
||||
char cur_char = '\0';
|
||||
int copy_size;
|
||||
|
||||
start = offset;
|
||||
while (offset < length) {
|
||||
cur_char = m3u8_info[offset];
|
||||
if (cur_char == '\r' || cur_char == '\n') {
|
||||
end = offset;
|
||||
offset++;
|
||||
break;
|
||||
}
|
||||
offset++;
|
||||
}
|
||||
if (end == -1) {
|
||||
end = length;
|
||||
}
|
||||
if (cur_char == '\r') {
|
||||
offset++;
|
||||
}
|
||||
memset(line_buffer, 0, buffer_size);
|
||||
copy_size = end - start;
|
||||
if (copy_size > buffer_size - 1) {
|
||||
copy_size = buffer_size - 1;
|
||||
}
|
||||
strncpy(line_buffer, m3u8_info + start, copy_size);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int m3u8_info_eof()
|
||||
{
|
||||
if (offset >= length) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int parseSegFromUrl(M3u8Segment* tsp)
|
||||
{
|
||||
int len = strlen(tsp->url);
|
||||
int ret = -1;
|
||||
char *segment_path = (char*)malloc(len);
|
||||
char *segment_name = (char*)malloc(len);
|
||||
if ((segment_path == NULL) | (segment_name == NULL)) {
|
||||
goto SAVEEXIT;
|
||||
}
|
||||
memset(segment_path, 0, len);
|
||||
memset(segment_name, 0, len);
|
||||
split_url(tsp->url, segment_path, segment_name);
|
||||
//http://live.xmcdn.com/192.168.3.134/live/12/24/160411_000003_15f9.ts
|
||||
//http://live.xmcdn.com/192.168.3.134/live/75/24/160413_082919_12b0.aac
|
||||
char* temp1 = strchr(segment_name, '.');
|
||||
char* temp2 = strrchr(segment_name, '_');
|
||||
if ((temp1 == NULL) | (temp2 == NULL)) {
|
||||
printf("ERR:strrchr=NULL,%s,%d\n", __FUNCTION__, __LINE__);
|
||||
goto SAVEEXIT;
|
||||
}
|
||||
*temp1 = '\0';
|
||||
temp1++;
|
||||
if (strncmp(temp1, "aac", 3) == 0) {
|
||||
tsp->fmt = AUDIOFMT_AAC;
|
||||
} else if (strncmp(temp1, "ts", 3) == 0) {
|
||||
tsp->fmt = AUDIOFMT_TS;
|
||||
} else {
|
||||
tsp->fmt = AUDIOFMT_UNKNOWN;
|
||||
}
|
||||
///subSeq
|
||||
temp2++;
|
||||
tsp->seq.sub = strtoul(temp2, 0, 16);
|
||||
////mainSeq
|
||||
temp2--;
|
||||
*temp2 = '\0';
|
||||
temp1 = strrchr(segment_name, '_');
|
||||
if (temp1 == NULL) {
|
||||
printf("ERR:strrchr=NULL,%s,%d\n", __FUNCTION__, __LINE__);
|
||||
goto SAVEEXIT;
|
||||
}
|
||||
temp1++;
|
||||
tsp->seq.main = strtoul(temp1, 0, 16);
|
||||
///
|
||||
temp2 = strchr(segment_name, '_');
|
||||
if (temp2 == NULL) {
|
||||
printf("ERR:strchr=NULL,%s,%d\n", __FUNCTION__, __LINE__);
|
||||
goto SAVEEXIT;
|
||||
}
|
||||
*temp2 = '\0';
|
||||
tsp->seq.date = strtoul(segment_name, 0, 16);
|
||||
|
||||
temp1 = strrchr(segment_path, '/');
|
||||
if (temp1 == NULL) {
|
||||
printf("ERR:strrchr=NULL,%s,%d\n", __FUNCTION__, __LINE__);
|
||||
goto SAVEEXIT;
|
||||
}
|
||||
*temp1 = '\0';
|
||||
temp1 = strrchr(segment_path, '/');
|
||||
if (temp1 == NULL) {
|
||||
printf("ERR:strrchr=NULL,%s,%d\n", __FUNCTION__, __LINE__);
|
||||
goto SAVEEXIT;
|
||||
}
|
||||
temp1++;
|
||||
tsp->rate = atoi(temp1);
|
||||
ret = 0;
|
||||
SAVEEXIT:
|
||||
if (segment_path) {
|
||||
free(segment_path);
|
||||
}
|
||||
if (segment_name) {
|
||||
free(segment_name);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#define ONE_LINE_SIZE 1024
|
||||
M3u8Info *m3u8Parser(char *m3u8Str, M3u8Info* m3u8)
|
||||
{
|
||||
int has_segment = 0;
|
||||
if (NULL == m3u8) {
|
||||
printf("malloc for M3u8Info failed.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *line = malloc(ONE_LINE_SIZE);
|
||||
if (NULL == line) {
|
||||
printf("zalloc for line failed.");
|
||||
return NULL;
|
||||
}
|
||||
memset(line, 0, ONE_LINE_SIZE);
|
||||
memset(m3u8, 0, sizeof(M3u8Info));
|
||||
length = strlen(m3u8Str);
|
||||
offset = 0;
|
||||
|
||||
while (!m3u8_info_eof()) {
|
||||
int result = 0;
|
||||
char *str = NULL;
|
||||
if (m3u8->segCount >= MAX_SEGMENT_COUNT) {
|
||||
printf("segCount >= MAX_SEGMENT_COUNT[%d].", MAX_SEGMENT_COUNT);
|
||||
break;
|
||||
}
|
||||
result = read_line_from_m3u8_info(m3u8Str, line, ONE_LINE_SIZE);
|
||||
if (!result) {
|
||||
printf("ERR:read line error from m3u8 info.");
|
||||
if (line) free(line);
|
||||
return NULL;
|
||||
}
|
||||
if (is_blank(line)) {
|
||||
continue;
|
||||
}
|
||||
str = trim_str(line);
|
||||
if (has_segment) {
|
||||
int size = strlen(str) + 1;
|
||||
m3u8->segList[m3u8->segCount].seq.sub = m3u8->mediaSeq + m3u8->segCount;
|
||||
// m3u8->segList[m3u8->segCount - 1].url = (char *)malloc(size);
|
||||
memset(m3u8->segList[m3u8->segCount].url, 0, size);
|
||||
strcpy(m3u8->segList[m3u8->segCount].url, str);
|
||||
parseSegFromUrl(&m3u8->segList[m3u8->segCount]);
|
||||
has_segment = 0;
|
||||
m3u8->segCount++;
|
||||
} else {
|
||||
if (0 == strncmp(str, "#EXTM3U", strlen("#EXTM3U"))) {
|
||||
|
||||
} else if (0 == strncmp(str, "#EXT-X-VERSION:", strlen("#EXT-X-VERSION:"))) {
|
||||
|
||||
} else if (0 == strncmp(str, "#EXT-X-ALLOW-CACHE:", strlen("#EXT-X-ALLOW-CACHE:"))) {
|
||||
|
||||
} else if (0 == strncmp(str, "#EXT-X-TARGETDURATION:", strlen("#EXT-X-TARGETDURATION:"))) {
|
||||
char *str_duration = str + strlen("#EXT-X-TARGETDURATION:");
|
||||
m3u8->targetDuration = atoi(trim_str(str_duration));
|
||||
// printf("Get the TARGETDURATION=%d\n", m3u8->targetDuration);
|
||||
} else if (0 == strncmp(str, "#EXT-X-MEDIA-SEQUENCE:", strlen("#EXT-X-MEDIA-SEQUENCE:"))) {
|
||||
char *str_sequence = str + strlen("#EXT-X-MEDIA-SEQUENCE:");
|
||||
m3u8->mediaSeq = atol(trim_str(str_sequence));
|
||||
// printf("Get the MEDIA-SEQUENCE=%d\n", m3u8->mediaSeq);
|
||||
} else if (0 == strncmp(str, "#EXTINF:", strlen("#EXTINF:"))) {
|
||||
char *str_segment_duration = NULL;
|
||||
int i = 0;
|
||||
has_segment = 1;
|
||||
str_segment_duration = str + strlen("#EXTINF:");
|
||||
while (str_segment_duration[i] != 0) {
|
||||
if ((str_segment_duration[i] < '0') || (str_segment_duration[i] > '9')) {
|
||||
str_segment_duration[i] = 0;
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
m3u8->segList[m3u8->segCount].duration = atoi(str_segment_duration);
|
||||
} else if (0 == strncmp(str, "#EXT-X-DISCONTINUITY", strlen("#EXT-X-DISCONTINUITY"))) {
|
||||
|
||||
} else if (0 == strncmp(str, "#EXT-X-ENDLIST", strlen("#EXT-X-ENDLIST"))) {
|
||||
|
||||
} else {
|
||||
printf("unknown line: %s.", str);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (line) free(line);
|
||||
return m3u8;
|
||||
}
|
||||
|
||||
uint8_t m3u8CheckValid(const M3u8Seq* new, const M3u8Seq* pre)
|
||||
{
|
||||
if (pre->date < new->date) {
|
||||
return 1;
|
||||
} else if (pre->date == new->date) {
|
||||
if (pre->main < new->main) {
|
||||
return 1;
|
||||
} else if (pre->main == new->main) {
|
||||
if ((pre->sub & 0x0000FFFF) < (new->sub & 0x0000FFFF)) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void m3u8Destroy(M3u8Info *m3u8)
|
||||
{
|
||||
int i = 0;
|
||||
if (m3u8 == NULL) {
|
||||
return;
|
||||
}
|
||||
free(m3u8);
|
||||
}
|
||||
|
||||
int m3u8_test(char* pStr)
|
||||
{
|
||||
//char *m3u8Str = "#EXTM3U\n"
|
||||
// "#EXT-X-TARGETDURATION:8\n"
|
||||
// "#EXT-X-MEDIA-SEQUENCE:92595\n"
|
||||
// "#EXTINF:8,\n"
|
||||
// "20121120T182851-04-92595.ts\n"
|
||||
// "#EXTINF:8,\n"
|
||||
// "20121120T182851-04-92596.ts\n"
|
||||
// "#EXTINF:8,\n"
|
||||
// "20121120T182851-04-92597.ts\n"
|
||||
// "#EXTINF:8,\n"
|
||||
// "20121120T182851-04-92598.ts\n";
|
||||
|
||||
|
||||
for (int i = 0; i < 10000; i++) {
|
||||
// M3u8Info *m3u8 = m3u8Parser(pStr, m3u8);
|
||||
// m3u8Destroy(m3u8);
|
||||
}
|
||||
return 1;
|
||||
}
|
370
examples/09_a2dp/components/EspAudio/player/MediaDecoderTask.c
Normal file
370
examples/09_a2dp/components/EspAudio/player/MediaDecoderTask.c
Normal file
|
@ -0,0 +1,370 @@
|
|||
#include <string.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/queue.h"
|
||||
|
||||
#include "esp_types.h"
|
||||
#include "stdlib.h"
|
||||
#include "stdio.h"
|
||||
#include "audio_log.h"
|
||||
|
||||
#include "inc/DecoderCom.h"
|
||||
#include "EspAudioCom.h"
|
||||
#include "Storage.h"
|
||||
#include "Utility.h"
|
||||
#include "inc/MediaDecoderTask.h"
|
||||
|
||||
|
||||
#define DECODER_TSK_PRIO 8
|
||||
#define DATA_PKG_SIZE (512*2)
|
||||
|
||||
#if 0
|
||||
#define DEBUGPLY printf
|
||||
#else
|
||||
#define DEBUGPLY
|
||||
#endif
|
||||
|
||||
static xQueueHandle rdQue;
|
||||
|
||||
void mediaDecoderTask(void *pvParameters);
|
||||
|
||||
typedef struct {
|
||||
TaskState state;
|
||||
pthread_t thread;
|
||||
int threadQuit;
|
||||
TaskState lastState;
|
||||
DecoderObj player;
|
||||
} MediaPlayerInstance;
|
||||
extern uint32_t rdpos;
|
||||
extern uint32_t wrpos;
|
||||
|
||||
|
||||
MediaPlayerInstance decoderInstance = { 0 };
|
||||
static StreamInfo streamInfo;
|
||||
|
||||
typedef void (*mediaTaskCallback)(uint32_t *state);
|
||||
static mediaTaskCallback stateCB;
|
||||
|
||||
|
||||
void mediaDecoderTask(void *pvParameters)
|
||||
{
|
||||
MediaPlayerInstance *MPI = (MediaPlayerInstance *)pvParameters;
|
||||
LOGI("%s is running.%x %x", __func__, pvParameters, MPI->threadQuit);
|
||||
|
||||
/////////////////////////////
|
||||
MPI->threadQuit = 0;
|
||||
int newPos = 0;
|
||||
uint32_t wrPos, rdPos;
|
||||
int isLoopNum = 0;
|
||||
int readSize = DATA_PKG_SIZE;
|
||||
int writeDataFinished = 0;
|
||||
while (MPI->threadQuit == 0) {
|
||||
switch (MPI->state) {
|
||||
case TaskState_Ready:
|
||||
if (MPI->player.musicType == EspAudioMeidaType_Unknown) {
|
||||
vTaskDelay(100);
|
||||
continue;
|
||||
}
|
||||
LOGD("MPI is here,rate=%d,channel=%d,bitLen=%x",
|
||||
streamInfo.rate,
|
||||
streamInfo.ch,
|
||||
streamInfo.bitLen);
|
||||
MusicInfo setInfo;
|
||||
setInfo.num_channels = streamInfo.ch;
|
||||
setInfo.sampling_rate = streamInfo.rate;
|
||||
mediaHalModeSet(MediaMode_Decode, &setInfo);
|
||||
mediaHalPlay(MPI->player.musicType);
|
||||
audioBufPosGet(&rdPos, &wrPos);
|
||||
if ((InputSrcType_NetSpec == MPI->player.srcType)
|
||||
|| (InputSrcType_LocalFile == MPI->player.srcType)
|
||||
|| ((InputSrcType_Stream == MPI->player.srcType) && (MPI->player.totalByteLength != 0))) {
|
||||
if ((MPI->player.totalByteLength - MPI->player.bytePosition) < DATA_PKG_SIZE) {
|
||||
readSize = MPI->player.totalByteLength - MPI->player.bytePosition;
|
||||
} else {
|
||||
readSize = DATA_PKG_SIZE;
|
||||
}
|
||||
} else {
|
||||
readSize = DATA_PKG_SIZE;
|
||||
}
|
||||
LOGD("rdPos=%x,wrPos=%x,readSize=%d, type=%d\r\n", rdPos, wrPos, readSize, MPI->player.srcType);
|
||||
MPI->state = TaskState_Running;
|
||||
writeDataFinished = 0;
|
||||
isLoopNum = 0;
|
||||
|
||||
MPI->lastState = TaskState_Ready;
|
||||
break;
|
||||
case TaskState_Pause:
|
||||
mediaHalPause();
|
||||
LOGI("Pause playing music....");
|
||||
MPI->state = TaskState_Idle;
|
||||
MPI->lastState = TaskState_Pause;
|
||||
break;
|
||||
case TaskState_Resume:
|
||||
mediaHalPlay(MPI->player.musicType);
|
||||
MPI->state = TaskState_Running;
|
||||
MPI->lastState = TaskState_Resume;
|
||||
LOGI("Resume playing music....");
|
||||
break;
|
||||
case TaskState_Running: {
|
||||
if (1 == writeDataFinished) {
|
||||
MusicInfo info;
|
||||
mediaHalMusicInfoGet(&info);
|
||||
if (1 == info.bufEmpty) {
|
||||
MPI->state = TaskState_Stoped;
|
||||
LOGI("Set state TaskState_Stoped");
|
||||
} else {
|
||||
LOGI("Waiting for decoder empty...");
|
||||
}
|
||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||
break;
|
||||
}
|
||||
int res = audioBufRead(MPI->player.dat, readSize, 100);
|
||||
if (res == 0) {
|
||||
MPI->state = TaskState_Stoped;
|
||||
LOGD("audio buffer read quit");
|
||||
break;
|
||||
}
|
||||
MediaErr ret = mediaHalDataWrite((uint8_t*)MPI->player.dat, readSize);
|
||||
if (ret == MediaErr_NoError) {
|
||||
MPI->player.bytePosition += readSize;
|
||||
if ((InputSrcType_NetSpec == MPI->player.srcType)
|
||||
|| (InputSrcType_LocalFile == MPI->player.srcType)
|
||||
|| ((InputSrcType_Stream == MPI->player.srcType) && (MPI->player.totalByteLength != 0))) {
|
||||
newPos = MPI->player.bytePosition + DATA_PKG_SIZE;
|
||||
if (MPI->player.totalByteLength <= newPos) {
|
||||
writeDataFinished = 1;
|
||||
readSize = MPI->player.totalByteLength - MPI->player.bytePosition;
|
||||
|
||||
MPI->player.bytePosition = MPI->player.totalByteLength;
|
||||
LOGD("Last byte Pos=%d total=%d", MPI->player.bytePosition, MPI->player.totalByteLength);
|
||||
break;
|
||||
} else {
|
||||
readSize = DATA_PKG_SIZE;
|
||||
}
|
||||
}
|
||||
} else if (MediaErr_CodecError == ret) {
|
||||
uint32_t rdPOS, wrPOS;
|
||||
audioBufPosGet(&rdPOS, &wrPOS);
|
||||
LOGI("ap8048 init failed ret=%x.Try again.rdPOS=%x,wrPOS=%x", ret, rdPOS, wrPOS);
|
||||
audioBufRdPosSet(&rdPos);
|
||||
mediaHalStop();
|
||||
MPI->state = TaskState_Ready;
|
||||
} else {
|
||||
LOGE("ap8048 ret error[%x]", ret);
|
||||
}
|
||||
MPI->lastState = TaskState_Running;
|
||||
}
|
||||
|
||||
break;
|
||||
case TaskState_Stoped: {
|
||||
mediaHalStop();
|
||||
newPos = 0;
|
||||
if (MPI->player.bytePosition == MPI->player.totalByteLength) {
|
||||
MPI->state = TaskState_Finished;
|
||||
MPI->player.bytePosition = 0;
|
||||
MPI->player.totalByteLength = 0;
|
||||
} else {
|
||||
MPI->state = TaskState_Idle;
|
||||
}
|
||||
LOGI("Stop playing music....state[%d]", MPI->state);
|
||||
MPI->lastState = TaskState_Stoped;
|
||||
if (stateCB) stateCB(&MPI->state);
|
||||
break;
|
||||
}
|
||||
case TaskState_Finished:
|
||||
case TaskState_Idle:
|
||||
default:
|
||||
vTaskDelay(300 / portTICK_PERIOD_MS);
|
||||
// LOGD("MPI->state[%d]", MPI->state);
|
||||
break;
|
||||
}
|
||||
}
|
||||
MPI->threadQuit = -1;
|
||||
MPI->thread = NULL;
|
||||
MPI->state = TaskState_Unknown;
|
||||
MPI->lastState = TaskState_Unknown;
|
||||
|
||||
LOGD("%s is ended...", __func__);
|
||||
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
void mediaDecoderTaskCb(void *func)
|
||||
{
|
||||
stateCB = func;
|
||||
}
|
||||
TaskState mediaDecoderTaskStateGet()
|
||||
{
|
||||
return decoderInstance.lastState;
|
||||
}
|
||||
|
||||
void mediaDecoderTaskInfoGet(DecoderObj *obj)
|
||||
{
|
||||
if (NULL == obj) {
|
||||
LOGE("Invalid para");
|
||||
return ;
|
||||
}
|
||||
memcpy(obj, &decoderInstance.player, sizeof(*obj));
|
||||
}
|
||||
|
||||
void mediaDecoderStreamInfoSet(StreamInfo *info)
|
||||
{
|
||||
if (NULL == info) {
|
||||
LOGE("Invalid para");
|
||||
return ;
|
||||
}
|
||||
memcpy(&streamInfo, info, sizeof(streamInfo));
|
||||
decoderInstance.player.totalByteLength = 0;
|
||||
LOGD("Set Stream info ok,rate=%d,channel=%d,bitLen=%x",
|
||||
streamInfo.rate,
|
||||
streamInfo.ch,
|
||||
streamInfo.bitLen);
|
||||
}
|
||||
|
||||
void mediaDecoderStreamSizeUpdate(uint32_t *size)
|
||||
{
|
||||
if (NULL == *size) {
|
||||
LOGE("Invalid para");
|
||||
return ;
|
||||
}
|
||||
decoderInstance.player.totalByteLength = *size;
|
||||
LOGD("Stream total size=%d", decoderInstance.player.totalByteLength);
|
||||
}
|
||||
|
||||
|
||||
void mediaDecoderTaskInfoSet(DecoderObj *obj)
|
||||
{
|
||||
if (NULL == obj) {
|
||||
LOGE("Invalid para");
|
||||
return ;
|
||||
}
|
||||
memcpy(&decoderInstance.player, obj, sizeof(*obj));
|
||||
|
||||
LOGD("Set DecoderObj ok,total=%d,type=%d,dat=%x music=%d",
|
||||
decoderInstance.player.totalByteLength,
|
||||
decoderInstance.player.srcType,
|
||||
decoderInstance.player.dat,
|
||||
decoderInstance.player.musicType);
|
||||
}
|
||||
|
||||
void mediaDecoderTaskPause()
|
||||
{
|
||||
if (0 == decoderInstance.thread) {
|
||||
decoderInstance.state = TaskState_Unknown;
|
||||
LOGE("decoderInstance.thread is NULL");
|
||||
return;
|
||||
}
|
||||
if (TaskState_Running == decoderInstance.state) {
|
||||
decoderInstance.state = TaskState_Pause;
|
||||
}
|
||||
LOGD("Task state=%d", decoderInstance.state);
|
||||
}
|
||||
|
||||
void mediaDecoderTaskResume()
|
||||
{
|
||||
if (0 == decoderInstance.thread) {
|
||||
decoderInstance.state = TaskState_Unknown;
|
||||
LOGE("decoderInstance.thread is NULL");
|
||||
return;
|
||||
}
|
||||
decoderInstance.state = TaskState_Resume;
|
||||
LOGD("Task state=%d", decoderInstance.state);
|
||||
}
|
||||
|
||||
void mediaDecoderTaskCreate()
|
||||
{
|
||||
if (NULL != decoderInstance.player.dat) {
|
||||
free(decoderInstance.player.dat);
|
||||
}
|
||||
memset(&decoderInstance, 0, sizeof(decoderInstance));
|
||||
memset(&streamInfo, 0, sizeof(streamInfo));
|
||||
decoderInstance.player.dat = calloc(1, DATA_PKG_SIZE);
|
||||
if (NULL == decoderInstance.player.dat) {
|
||||
LOGE("decoderInstance.player.dat malloc error");
|
||||
return;
|
||||
}
|
||||
xTaskCreate(mediaDecoderTask, "mediaDecoderTask", (5 * 1024), &decoderInstance, DECODER_TSK_PRIO, &decoderInstance.thread);
|
||||
configASSERT(decoderInstance.thread);
|
||||
LOGD("Task state=%d,dat:%x", decoderInstance.state, decoderInstance.player.dat);
|
||||
rdQue = xQueueCreate(2, 1);
|
||||
configASSERT(rdQue);
|
||||
audioBufRdQuitCfg(rdQue);
|
||||
}
|
||||
|
||||
|
||||
int mediaDecoderTaskStart()
|
||||
{
|
||||
if (0 == decoderInstance.thread) {
|
||||
decoderInstance.state = TaskState_Unknown;
|
||||
LOGE("decoderInstance.thread is NULL");
|
||||
return -1;
|
||||
}
|
||||
if ((decoderInstance.player.srcType == InputSrcType_NetSpec)
|
||||
|| (decoderInstance.player.srcType == InputSrcType_LocalFile)) {
|
||||
if (decoderInstance.player.totalByteLength == 0) {
|
||||
LOGE("Player parameter is not ready");
|
||||
decoderInstance.state = TaskState_Idle;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
decoderInstance.state = TaskState_Ready;
|
||||
LOGD("Task state=%d", decoderInstance.state);
|
||||
audioBufRdRest();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mediaDecoderTaskStop()
|
||||
{
|
||||
if (0 == decoderInstance.thread) {
|
||||
decoderInstance.state = TaskState_Unknown;
|
||||
LOGE("decoderInstance.thread is NULL");
|
||||
return;
|
||||
}
|
||||
if ((decoderInstance.lastState == TaskState_Unknown)
|
||||
|| (decoderInstance.lastState == TaskState_Stoped)) {
|
||||
LOGW("dlInstance.state is [%d]", decoderInstance.state);
|
||||
return;
|
||||
}
|
||||
decoderInstance.state = TaskState_Stoped;
|
||||
configASSERT(rdQue);
|
||||
xQueueSend(rdQue, &decoderInstance.state, 0);
|
||||
LOGD("Task state=%d", decoderInstance.state);
|
||||
while ((TaskState_Finished != decoderInstance.state)
|
||||
&& (TaskState_Idle != decoderInstance.state)) {
|
||||
if ((TaskState_Idle == decoderInstance.state)) {
|
||||
break;
|
||||
}
|
||||
vTaskDelay(10 / portTICK_RATE_MS);
|
||||
}
|
||||
audioBufRdRest();
|
||||
int flag;
|
||||
xQueueReceive(rdQue, &flag, 0);
|
||||
LOGD("Task state=%d", decoderInstance.state);
|
||||
}
|
||||
|
||||
void mediaDecoderTaskDestroy()
|
||||
{
|
||||
if (0 == decoderInstance.threadQuit) {
|
||||
decoderInstance.state = TaskState_Stoped;
|
||||
decoderInstance.threadQuit = 1;
|
||||
while (1) {
|
||||
if ((decoderInstance.threadQuit == -1)) {
|
||||
break;
|
||||
}
|
||||
vTaskDelay(100 / portTICK_RATE_MS);
|
||||
}
|
||||
}
|
||||
|
||||
if (NULL != decoderInstance.player.dat) {
|
||||
free(decoderInstance.player.dat);
|
||||
}
|
||||
memset(&decoderInstance.player, 0, sizeof(decoderInstance.player));
|
||||
memset(&streamInfo, 0, sizeof(streamInfo));
|
||||
decoderInstance.player.dat = NULL;
|
||||
decoderInstance.state = TaskState_Unknown;
|
||||
vQueueDelete(rdQue);
|
||||
rdQue = NULL;
|
||||
LOGD("Task state=%d", decoderInstance.state);
|
||||
}
|
42
examples/09_a2dp/components/EspAudio/player/inc/DecoderCom.h
Normal file
42
examples/09_a2dp/components/EspAudio/player/inc/DecoderCom.h
Normal file
|
@ -0,0 +1,42 @@
|
|||
/*****************************************************************************
|
||||
*
|
||||
* File Name : wm_http_client.h
|
||||
*
|
||||
* Description: Http client header file.
|
||||
*
|
||||
* Copyright (c) 2014 Winner Microelectronics Co., Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author : wanghf
|
||||
*
|
||||
* Date : 2014-6-6
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __DECODER_COM_H__
|
||||
#define __DECODER_COM_H__
|
||||
#include "esp_types.h"
|
||||
|
||||
|
||||
|
||||
// HTTP Type Definitions
|
||||
|
||||
//#define pthread_t sys_thread_t
|
||||
|
||||
|
||||
typedef enum {
|
||||
TaskState_Unknown = 0,
|
||||
TaskState_Idle = 1, // running state
|
||||
TaskState_Running = 2,
|
||||
TaskState_Stoped = 3,
|
||||
TaskState_Finished = 4,
|
||||
|
||||
TaskState_Ready = 10, //control state
|
||||
TaskState_Resume = 11,
|
||||
TaskState_Pause = 12,
|
||||
|
||||
} TaskState;
|
||||
|
||||
|
||||
|
||||
|
||||
#endif //__DECODER_COM_H__
|
|
@ -0,0 +1,46 @@
|
|||
/*****************************************************************************
|
||||
*
|
||||
* File Name : wm_http_client.h
|
||||
*
|
||||
* Description: Http client header file.
|
||||
*
|
||||
* Copyright (c) 2014 Winner Microelectronics Co., Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author : wanghf
|
||||
*
|
||||
* Date : 2014-6-6
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef HTTP_CLIENT_H
|
||||
#define HTTP_CLIENT_H
|
||||
#include "esp_types.h"
|
||||
#include "lwip/sys.h"
|
||||
#include "DecoderCom.h"
|
||||
|
||||
#define ESP_URI_LEN 1024
|
||||
|
||||
typedef struct {
|
||||
char *str;
|
||||
int srcType; // 0:specific net audio; 1:m3u8 files; 2:audio data files
|
||||
// int setStartBytePos;
|
||||
} UriSrcAttr;
|
||||
|
||||
TaskState downloadTaskStateGet();
|
||||
|
||||
void downloadTaskContentSizeGet(uint32_t *size);
|
||||
|
||||
void downloadTaskInfoSet(UriSrcAttr *obj);
|
||||
int downloadTaskHTTPStateGet();
|
||||
|
||||
void downloadTaskPause();
|
||||
|
||||
void downloadTaskResume();
|
||||
|
||||
int downloadTaskStart();
|
||||
void downloadTaskStop();
|
||||
|
||||
void downloadTaskCreate(int taskType);
|
||||
void downloadTaskDestroy();
|
||||
|
||||
#endif //
|
79
examples/09_a2dp/components/EspAudio/player/inc/M3u8.h
Normal file
79
examples/09_a2dp/components/EspAudio/player/inc/M3u8.h
Normal file
|
@ -0,0 +1,79 @@
|
|||
#ifndef _M3U8_H_
|
||||
#define _M3U8_H_
|
||||
#include "esp_types.h"
|
||||
|
||||
#define MAX_SEGMENT_COUNT 3
|
||||
|
||||
|
||||
//
|
||||
typedef enum {
|
||||
AUDIOFMT_UNKNOWN = 0,
|
||||
AUDIOFMT_AAC = 1,
|
||||
AUDIOFMT_TS = 2,
|
||||
} AUDIOFMT;
|
||||
|
||||
typedef struct {
|
||||
size_t date;
|
||||
size_t main;
|
||||
size_t sub;
|
||||
} M3u8Seq;
|
||||
//
|
||||
typedef struct {
|
||||
int duration;
|
||||
int rate;
|
||||
AUDIOFMT fmt;
|
||||
char url[128];
|
||||
char name[256];
|
||||
M3u8Seq seq;
|
||||
} M3u8Segment;
|
||||
|
||||
//
|
||||
typedef struct _M3u8Info {
|
||||
int targetDuration;
|
||||
size_t mediaSeq;
|
||||
int segCount;
|
||||
M3u8Segment segList[MAX_SEGMENT_COUNT];
|
||||
} M3u8Info;
|
||||
|
||||
|
||||
typedef struct _audioUrlObj {
|
||||
AUDIOFMT fmt;
|
||||
uint32_t uflag; // 0-empty;1-ready;2-using;3-used;
|
||||
uint32_t idx; // stream sequence
|
||||
// uint32_t totalTime; // time of music,live:0
|
||||
char *url;
|
||||
char *radioName;
|
||||
char *musicName;
|
||||
struct _audioUrlObj *next;
|
||||
} audioUrlObj;
|
||||
|
||||
|
||||
uint8_t m3u8CheckValid(const M3u8Seq* new, const M3u8Seq* pre);
|
||||
|
||||
|
||||
/**
|
||||
* [m3u8_parser Parser the m3u8 string]
|
||||
* @param m3u8_string [To be parser string]
|
||||
* @return [m3u8 object, NULL->failed]
|
||||
*/
|
||||
M3u8Info *m3u8Parser(char *m3u8Str, M3u8Info* m3u8);
|
||||
|
||||
/**
|
||||
* [m3u8_destroy Destroy the m3u8 struct]
|
||||
* @param m3u8 [m3u8 struct]
|
||||
*/
|
||||
void m3u8Destroy(M3u8Info *m3u8);
|
||||
|
||||
/**
|
||||
* [m3u8_save description]
|
||||
* @param m3u8 [m3u8 struct]
|
||||
* @param m3u8_path [file path]
|
||||
* @param ts_segment_url_prefix [prefix will be fill]
|
||||
* @return [0->failed;1->successed]
|
||||
*/
|
||||
//int m3u8_save(M3u8Info *m3u8, char *m3u8_path, char *ts_segment_url_prefix);
|
||||
|
||||
|
||||
int m3u8_test(char* pStr);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,66 @@
|
|||
/*****************************************************************************
|
||||
*
|
||||
* File Name : wm_http_client.h
|
||||
*
|
||||
* Description: Http client header file.
|
||||
*
|
||||
* Copyright (c) 2014 Winner Microelectronics Co., Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author : wanghf
|
||||
*
|
||||
* Date : 2014-6-6
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __PLAYERTASK_H__
|
||||
#define __PLAYERTASK_H__
|
||||
#include "esp_types.h"
|
||||
#include "EspAudioCom.h"
|
||||
#include "EspAudio.h"
|
||||
#include "lwip/sys.h"
|
||||
#include "MediaHal.h"
|
||||
|
||||
//Type Definitions
|
||||
|
||||
typedef struct {
|
||||
char *dat;
|
||||
InputSrcType srcType;
|
||||
EspAudioMeidaType musicType;
|
||||
uint32_t totalByteLength;
|
||||
uint32_t bytePosition;
|
||||
int codecVer;
|
||||
int codecType; // 0:hardware; 1:software
|
||||
} DecoderObj;
|
||||
|
||||
typedef struct {
|
||||
uint32_t rate;
|
||||
uint32_t ch;
|
||||
uint32_t bitLen;
|
||||
uint32_t size; // 0xFFFFFFFF stream length is infinite
|
||||
} StreamInfo;
|
||||
|
||||
TaskState mediaDecoderTaskStateGet();
|
||||
void mediaDecoderStreamInfoSet(StreamInfo *info);
|
||||
|
||||
void mediaDecoderTaskInfoGet(DecoderObj *obj);
|
||||
void mediaDecoderTaskInfoSet(DecoderObj *obj);
|
||||
void mediaDecoderTaskPause();
|
||||
void mediaDecoderTaskResume();
|
||||
|
||||
int mediaDecoderTaskStart();
|
||||
void mediaDecoderTaskStop();
|
||||
|
||||
void mediaDecoderTaskCreate();
|
||||
void mediaDecoderTaskDestroy();
|
||||
|
||||
void mediaDecoderVolSet();
|
||||
void mediaDecoderVolGet();
|
||||
void mediaDecoderMusicInfoGet();
|
||||
void mediaDecoderDecodeTimeGet();
|
||||
void mediaDecoderModeSet();
|
||||
void mediaDecoderStreamSizeUpdate(uint32_t *size);
|
||||
void mediaDecoderTaskCb(void *func);
|
||||
|
||||
|
||||
|
||||
#endif //__PLAYERTASK_H__
|
300
examples/09_a2dp/components/EspAudio/recorder/EspAudioRecorder.c
Normal file
300
examples/09_a2dp/components/EspAudio/recorder/EspAudioRecorder.c
Normal file
|
@ -0,0 +1,300 @@
|
|||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <string.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/queue.h"
|
||||
|
||||
#include "stdlib.h"
|
||||
#include "stdio.h"
|
||||
#include "DecoderCom.h"
|
||||
#include "EspAudioCom.h"
|
||||
#include "MediaHal.h"
|
||||
#include "EspAudioRecorder.h"
|
||||
#include "Ap80xx.h"
|
||||
|
||||
#define RECORD_TSK_PRIO 6
|
||||
#define RECORDER_PKG_SIZE 1024
|
||||
|
||||
typedef enum {
|
||||
RecorderEventType_Unknown,
|
||||
RecorderEventType_Start,
|
||||
RecorderEventType_Stop,
|
||||
RecorderEventType_Pause,
|
||||
RecorderEventType_Resume,
|
||||
RecorderEventType_Quit,
|
||||
} RecorderEventType;
|
||||
|
||||
typedef struct {
|
||||
RecorderEventType type;
|
||||
void *value;
|
||||
} RecorderEventInfo;
|
||||
|
||||
static xTaskHandle recorderThread;
|
||||
static xQueueHandle recorderEventQue;
|
||||
static RecorderState recTaskState;
|
||||
static MusicInfo streamInfo;
|
||||
|
||||
void MediaEncoderTask(void *pvParameters)
|
||||
{
|
||||
LOGI("%s is running.%x %x", __func__);
|
||||
/////////////////////////////
|
||||
RecorderEventInfo eventInfo ;
|
||||
static RecorderAttr s_attr;
|
||||
static int recordStartFlag = 0;
|
||||
eventInfo.type = RecorderEventType_Unknown;
|
||||
eventInfo.value = NULL;
|
||||
uint8_t *recvData = malloc(RECORDER_PKG_SIZE);
|
||||
if (NULL == recvData) {
|
||||
LOGE("malloc failed");
|
||||
return ;
|
||||
}
|
||||
memset(recvData, 0, RECORDER_PKG_SIZE);
|
||||
|
||||
while (1) {
|
||||
if (xQueueReceive(recorderEventQue, &eventInfo, 10)) {
|
||||
switch (eventInfo.type) {
|
||||
case RecorderEventType_Start: {
|
||||
MediaState mediaState;
|
||||
mediaHalStatusGet(&mediaState);
|
||||
LOGD("Start recording ...%d", mediaState);
|
||||
if (MediaState_Initialized > mediaState) {
|
||||
mediaHalInit();
|
||||
LOGD("Need to init codec driver...[%d]", mediaState);
|
||||
}
|
||||
if (eventInfo.value) {
|
||||
memcpy(&s_attr, eventInfo.value, sizeof(s_attr));
|
||||
free(eventInfo.value);
|
||||
eventInfo.value = NULL;
|
||||
LOGI("recv:channel=%d, rate=%d, encodeType=%d, func=%p",
|
||||
s_attr.channel, s_attr.rate, s_attr.encodeType, s_attr.func);
|
||||
streamInfo.sampling_rate =s_attr.rate;
|
||||
streamInfo.num_channels = s_attr.channel;
|
||||
streamInfo.stream_type = s_attr.encodeType;
|
||||
|
||||
mediaHalModeSet(MediaMode_Encode, &streamInfo);
|
||||
recordStartFlag = 1;
|
||||
recTaskState = RecorderState_Recording;
|
||||
LOGI("Start recording ....");
|
||||
} else {
|
||||
LOGE("eventInfo.value = NULL");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RecorderEventType_Pause: {
|
||||
if (RecorderState_Recording == recTaskState) {
|
||||
recordStartFlag = 0;
|
||||
recTaskState = RecorderState_Paused;
|
||||
LOGI("Pause recording");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RecorderEventType_Resume: {
|
||||
if (RecorderState_Paused == recTaskState) {
|
||||
recordStartFlag = 1;
|
||||
recTaskState = RecorderState_Recording;
|
||||
LOGI("Resume recording");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RecorderEventType_Stop: {
|
||||
recordStartFlag = 0;
|
||||
recTaskState = RecorderState_Stoped;
|
||||
|
||||
apSetDecodeMode();
|
||||
memset(&streamInfo, 0, sizeof(streamInfo));
|
||||
LOGI("Stop recording");
|
||||
break;
|
||||
}
|
||||
case RecorderEventType_Quit: {
|
||||
recordStartFlag = 0;
|
||||
recTaskState = RecorderState_Unknown;
|
||||
LOGI("MediaEncoderTask will be quit");
|
||||
goto encoderTaskQuit;
|
||||
}
|
||||
default:
|
||||
vTaskDelay(250 / portTICK_RATE_MS);
|
||||
LOGE("Event type does not support[%d]", eventInfo.type);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// LOGD("stack left %d byte\n", uxTaskGetStackHighWaterMark(NULL));
|
||||
if (recordStartFlag) {
|
||||
int len = 0;
|
||||
int ret = mediaHalDataRead(recvData, &len);
|
||||
if ((ret != 0) || (len == 1)) {
|
||||
LOGE("mediaHalDataRead failed,ret=%d len=%d", ret, len);
|
||||
continue;
|
||||
} else {
|
||||
// LOGD("mediaHalDataRead ok,ret=%d len=%d", ret, len);
|
||||
if (len>0) {
|
||||
s_attr.func(recvData, (uint32_t*)&len);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
encoderTaskQuit:
|
||||
free(recvData);
|
||||
recvData = NULL;
|
||||
configASSERT(recorderEventQue);
|
||||
vQueueDelete(recorderEventQue);
|
||||
recorderEventQue = NULL;
|
||||
recorderThread = NULL;
|
||||
LOGI("%s is ended...", __func__);
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
EspAudioErr EspAudioRecorderStateGet(RecorderState *state)
|
||||
{
|
||||
if (NULL == state) {
|
||||
LOGE("Invalid para,%p", state);
|
||||
return EspAudioErr_InvalidPara;
|
||||
}
|
||||
*state = recTaskState;
|
||||
|
||||
return EspAudioErr_NoErr;
|
||||
}
|
||||
|
||||
EspAudioErr EspAudioRecorderInit(void)
|
||||
{
|
||||
if (NULL == recorderThread) {
|
||||
xTaskCreate(MediaEncoderTask, "MediaEncoderTask", (5*1024), NULL, RECORD_TSK_PRIO, &recorderThread);
|
||||
configASSERT(recorderThread);
|
||||
}
|
||||
if (NULL == recorderEventQue) {
|
||||
recorderEventQue = xQueueCreate(4, sizeof(RecorderEventInfo));
|
||||
configASSERT(recorderEventQue);
|
||||
}
|
||||
|
||||
LOGD("recorder has been created, %p,%p", recorderThread, recorderEventQue);
|
||||
recTaskState = RecorderState_Init;
|
||||
return EspAudioErr_NoErr;
|
||||
}
|
||||
|
||||
EspAudioErr EspAudioRecorderStart(RecorderAttr *recorderAttr)
|
||||
{
|
||||
if ((NULL == recorderAttr)
|
||||
|| (NULL == recorderThread)
|
||||
|| (NULL == recorderEventQue)) {
|
||||
LOGE("Invalid para, %p,%p,%p", recorderAttr, recorderThread, recorderEventQue);
|
||||
return EspAudioErr_InvalidPara;
|
||||
}
|
||||
if (NULL == recorderAttr->func) {
|
||||
LOGE("Invalid para, %p", recorderAttr->func);
|
||||
return EspAudioErr_InvalidPara;
|
||||
}
|
||||
RecorderAttr *attr = malloc(sizeof(RecorderAttr));
|
||||
if (NULL == attr) {
|
||||
LOGE("Malloc failed");
|
||||
return EspAudioErr_NoMem;
|
||||
}
|
||||
attr->channel = recorderAttr->channel;
|
||||
attr->rate = recorderAttr->rate;
|
||||
attr->encodeType = recorderAttr->encodeType;
|
||||
attr->func = recorderAttr->func;
|
||||
|
||||
RecorderEventInfo eventInfo ;
|
||||
eventInfo.type = RecorderEventType_Start;
|
||||
eventInfo.value = attr;
|
||||
LOGD("channel=%d, rate=%d, encodeType=%d, func=%p",
|
||||
attr->channel, attr->rate, attr->encodeType, attr->func);
|
||||
configASSERT(recorderEventQue);
|
||||
if (pdTRUE != xQueueSend(recorderEventQue, &eventInfo, 0)) {
|
||||
LOGE("EspAudioRecorderStart, queue send failed");
|
||||
} else {
|
||||
LOGD("EspAudioRecorderStart, send sucessed");
|
||||
}
|
||||
return EspAudioErr_NoErr;
|
||||
}
|
||||
|
||||
EspAudioErr EspAudioRecorderPause(void)
|
||||
{
|
||||
if ((NULL == recorderThread)
|
||||
|| (NULL == recorderEventQue)) {
|
||||
LOGE("Invalid para, %p,%p", recorderThread, recorderEventQue);
|
||||
return EspAudioErr_InvalidPara;
|
||||
}
|
||||
RecorderEventInfo eventInfo ;
|
||||
eventInfo.type = RecorderEventType_Pause;
|
||||
eventInfo.value = NULL;
|
||||
configASSERT(recorderEventQue);
|
||||
if (pdTRUE != xQueueSend(recorderEventQue, &eventInfo, 0)) {
|
||||
LOGE("RecorderEventType_Pause, queue send failed");
|
||||
} else {
|
||||
LOGD("RecorderEventType_Pause, send sucessed");
|
||||
}
|
||||
return EspAudioErr_NoErr;
|
||||
}
|
||||
|
||||
EspAudioErr EspAudioRecorderResume(void)
|
||||
{
|
||||
if ((NULL == recorderThread)
|
||||
|| (NULL == recorderEventQue)) {
|
||||
LOGE("Invalid para, %p,%p", recorderThread, recorderEventQue);
|
||||
return EspAudioErr_InvalidPara;
|
||||
}
|
||||
RecorderEventInfo eventInfo ;
|
||||
eventInfo.type = RecorderEventType_Resume;
|
||||
eventInfo.value = NULL;
|
||||
configASSERT(recorderEventQue);
|
||||
if (pdTRUE != xQueueSend(recorderEventQue, &eventInfo, 0)) {
|
||||
LOGE("RecorderEventType_Resume, queue send failed");
|
||||
} else {
|
||||
LOGD("RecorderEventType_Resume, send sucessed");
|
||||
}
|
||||
return EspAudioErr_NoErr;
|
||||
|
||||
}
|
||||
|
||||
EspAudioErr EspAudioRecorderStop(void)
|
||||
{
|
||||
if ((NULL == recorderThread)
|
||||
|| (NULL == recorderEventQue)) {
|
||||
LOGE("Invalid para, %p,%p", recorderThread, recorderEventQue);
|
||||
return EspAudioErr_InvalidPara;
|
||||
}
|
||||
RecorderEventInfo eventInfo ;
|
||||
eventInfo.type = RecorderEventType_Stop;
|
||||
eventInfo.value = NULL;
|
||||
configASSERT(recorderEventQue);
|
||||
if (pdTRUE != xQueueSend(recorderEventQue, &eventInfo, 0)) {
|
||||
LOGE("RecorderEventType_Stop, queue send failed");
|
||||
} else {
|
||||
LOGD("RecorderEventType_Stop, send sucessed");
|
||||
}
|
||||
return EspAudioErr_NoErr;
|
||||
}
|
||||
|
||||
EspAudioErr EspAudioRecorderUninit(void)
|
||||
{
|
||||
if ((NULL == recorderThread)
|
||||
|| (NULL == recorderEventQue)) {
|
||||
LOGE("recorderThread=%p, recorderEventQue=%p", recorderThread, recorderEventQue);
|
||||
return EspAudioErr_InvalidPara;
|
||||
}
|
||||
RecorderEventInfo eventInfo ;
|
||||
eventInfo.type = RecorderEventType_Quit;
|
||||
eventInfo.value = NULL;
|
||||
configASSERT(recorderEventQue);
|
||||
if (pdTRUE != xQueueSend(recorderEventQue, &eventInfo, 0)) {
|
||||
LOGE("RecorderEventType_Quit, queue send failed");
|
||||
} else {
|
||||
LOGD("RecorderEventType_Quit, send sucessed");
|
||||
}
|
||||
return EspAudioErr_NoErr;
|
||||
}
|
1301
examples/09_a2dp/components/MediaHal/AP80/Ap80xx.c
Normal file
1301
examples/09_a2dp/components/MediaHal/AP80/Ap80xx.c
Normal file
File diff suppressed because it is too large
Load diff
53
examples/09_a2dp/components/MediaHal/AP80/crc.c
Normal file
53
examples/09_a2dp/components/MediaHal/AP80/crc.c
Normal file
|
@ -0,0 +1,53 @@
|
|||
#include <stdint.h>
|
||||
|
||||
static const uint16_t gCRC16TableNBS[256] =
|
||||
{
|
||||
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
|
||||
0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
|
||||
0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
|
||||
0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
|
||||
0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
|
||||
0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
|
||||
0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
|
||||
0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
|
||||
0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
|
||||
0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
|
||||
0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
|
||||
0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
|
||||
0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
|
||||
0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
|
||||
0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
|
||||
0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
|
||||
0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
|
||||
0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
|
||||
0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
|
||||
0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
|
||||
0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
|
||||
0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
|
||||
0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
|
||||
0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
|
||||
0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
|
||||
0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
|
||||
0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
|
||||
0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
|
||||
0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
|
||||
0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
|
||||
0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
|
||||
0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
|
||||
};
|
||||
|
||||
uint16_t GetCRC16NBS(uint8_t* data, uint32_t length)
|
||||
{
|
||||
uint16_t crc = 0;
|
||||
uint8_t temp;
|
||||
|
||||
while(length--)
|
||||
{
|
||||
temp = (unsigned char)(crc >> 8); // get high byte
|
||||
crc <<= 8; // get low byte
|
||||
crc ^= gCRC16TableNBS[*data ^ temp];
|
||||
data++;
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
387
examples/09_a2dp/components/MediaHal/Driver/dma.c
Normal file
387
examples/09_a2dp/components/MediaHal/Driver/dma.c
Normal file
|
@ -0,0 +1,387 @@
|
|||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "dma.h"
|
||||
#include "rom/ets_sys.h"
|
||||
#include "string.h"
|
||||
#include "stdlib.h"
|
||||
|
||||
#define QUEUE_BLOCK_LENGTH (4096L)
|
||||
|
||||
|
||||
#define DMA_DBG_WARING_ENABLE (0)
|
||||
#define DMA_DBG_ERROR_ENABLE (0)
|
||||
#define DMA_INFO_ENABLE (0)
|
||||
#define DMA_DBG_ENABLE (0)
|
||||
|
||||
//DBG INFOR
|
||||
#if DMA_DBG_ENABLE
|
||||
#define DMA_DBG(format,...) do{\
|
||||
ets_printf("[dbg][%s#%u]",__FUNCTION__,__LINE__);\
|
||||
ets_printf(format,##__VA_ARGS__);\
|
||||
}while(0)
|
||||
#else
|
||||
#define DMA_DBG(...)
|
||||
#endif
|
||||
#if DMA_INFO_ENABLE
|
||||
#define DMA_INFO(format,...) do{\
|
||||
ets_printf("[info][%s#%u]",__FUNCTION__,__LINE__);\
|
||||
ets_printf(format,##__VA_ARGS__);\
|
||||
}while(0)
|
||||
#else
|
||||
#define DMA_INFO(...)
|
||||
#endif
|
||||
|
||||
#if DMA_DBG_WARNING_ENABLE
|
||||
#define DMA_WARNING(format,...) do{\
|
||||
ets_printf("[waring][%s#%u]",__FUNCTION__,__LINE__);\
|
||||
ets_printf(format,##__VA_ARGS__);\
|
||||
}while(0)
|
||||
#else
|
||||
#define DMA_WARNING(...)
|
||||
#endif
|
||||
#if DMA_DBG_ERROR_ENABLE
|
||||
#define DMA_ERROR(format,...) do{\
|
||||
ets_printf("[error][%s#%u]",__FUNCTION__,__LINE__);\
|
||||
ets_printf(format,##__VA_ARGS__);\
|
||||
}while(0)
|
||||
#else
|
||||
#define DMA_ERROR(...)
|
||||
#endif
|
||||
|
||||
void dma_show_queue(ping_pong_buf_t *pcfg)
|
||||
{
|
||||
uint32_t i;
|
||||
DMA_INFO("obj=%x \r\n", pcfg);
|
||||
DMA_INFO("ping bck que=%x buf=%x,next_link_ptr=%x\r\n", pcfg->ping->backup_queue, pcfg->ping->buffer_addr, pcfg->ping->backup_queue.next_link_ptr);
|
||||
DMA_INFO("ping first_que=%x, %08x, buf=%x\r\n", pcfg->ping->first_queue,*pcfg->ping->first_queue, pcfg->ping->buffer_addr);
|
||||
DMA_INFO("ping last_que=%x, %08x, buf=%x\r\n", pcfg->ping->last_queue, *pcfg->ping->last_queue, pcfg->ping->buffer_addr);
|
||||
|
||||
DMA_INFO("pong bck que=%x buf=%x,next_link_ptr=%x\r\n", pcfg->pong->backup_queue, pcfg->pong->buffer_addr, pcfg->pong->backup_queue.next_link_ptr);
|
||||
DMA_INFO("pong first_que=%x, %08x, buf=%x\r\n", pcfg->pong->first_queue, *pcfg->pong->first_queue, pcfg->pong->buffer_addr);
|
||||
DMA_INFO("pong last_que=%x, %08x, buf=%x\r\n", pcfg->pong->last_queue, *pcfg->pong->last_queue, pcfg->pong->buffer_addr);
|
||||
|
||||
dma_queue_t *addr = (dma_queue_t*)pcfg->ping->first_queue;
|
||||
dma_queue_t *addr1 = (dma_queue_t*)pcfg->pong->first_queue;
|
||||
for (i = 0; i < pcfg->queue_cnt; ++i) {
|
||||
DMA_INFO("ping queue%d buf:%08x,len=%d,size=%d,cur_link:%08x,next_link:%08x\r\n", i,
|
||||
addr->buf_ptr,addr->data_length, addr->block_size, addr, addr->next_link_ptr);
|
||||
addr = (dma_queue_t*)addr->next_link_ptr;
|
||||
}
|
||||
for (i = 0; i < pcfg->queue_cnt; ++i) {
|
||||
DMA_INFO("pong queue%d buf:%08x,len=%d,size=%d,cur_link:%08x,next_link:%08x\r\n", i,
|
||||
addr1->buf_ptr,addr1->data_length, addr1->block_size, addr1, addr1->next_link_ptr);
|
||||
addr1 = (dma_queue_t*)addr1->next_link_ptr;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Fill a link
|
||||
*
|
||||
*/
|
||||
static void fill_one_link(uint8_t own, uint8_t eof, uint8_t sub_sof, uint16_t size, uint16_t length,
|
||||
uint32_t *buf_ptr, dma_queue_t *nxt_ptr, dma_queue_t *i2s_queue)
|
||||
{
|
||||
i2s_queue->owner = own;
|
||||
i2s_queue->eof = eof;
|
||||
i2s_queue->sub_sof = sub_sof;
|
||||
i2s_queue->data_length = 0x0FFF & length;
|
||||
i2s_queue->block_size = size ;
|
||||
i2s_queue->buf_ptr = (uint32_t)buf_ptr;
|
||||
i2s_queue->next_link_ptr = (uint32_t)nxt_ptr;
|
||||
i2s_queue->unused = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Fill the queue
|
||||
*
|
||||
*/
|
||||
static int dma_queue_fill(uint32_t cnt, uint32_t len, ping_pong_buf_t *cfg)
|
||||
{
|
||||
if (0 == cnt) {
|
||||
return -1;
|
||||
}
|
||||
// ping queue list
|
||||
dma_queue_t *pingAry[cnt];
|
||||
// pong queue list
|
||||
dma_queue_t *pongAry[cnt];
|
||||
uint32_t i, j;
|
||||
memset(&pingAry, 0, sizeof(pingAry));
|
||||
memset(&pongAry, 0, sizeof(pongAry));
|
||||
cnt = 1;
|
||||
for (i = 0; i < cnt; ++i) {
|
||||
pingAry[i] = (dma_queue_t*)malloc(sizeof(dma_queue_t));
|
||||
if (pingAry[i] == NULL) {
|
||||
for (j = 0; j < i; ++j) {
|
||||
free(pingAry[j]);
|
||||
pingAry[j] = NULL;
|
||||
}
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < cnt; ++i) {
|
||||
pongAry[i] = (dma_queue_t*)malloc(sizeof(dma_queue_t));
|
||||
if (NULL == pongAry[i]) {
|
||||
for (j = 0; j < cnt; ++j) {
|
||||
free(pingAry[j]);
|
||||
pingAry[j] = NULL;
|
||||
}
|
||||
for (j = 0; j < i; ++j) {
|
||||
free(pongAry[j]);
|
||||
pongAry[j] = NULL;
|
||||
}
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
|
||||
cfg->ping->first_queue = pingAry[0];
|
||||
cfg->pong->first_queue = pongAry[0];
|
||||
if (1 == cnt) {
|
||||
cfg->ping->last_queue = pingAry[0];
|
||||
cfg->pong->last_queue = pongAry[0];
|
||||
} else {
|
||||
cfg->ping->last_queue = pingAry[cnt - 1];
|
||||
cfg->pong->last_queue = pongAry[cnt - 1];
|
||||
}
|
||||
uint32_t remainSize = len;
|
||||
uint32_t bufSize = QUEUE_BLOCK_LENGTH;
|
||||
for (i = 0; i < cnt; ++i) {
|
||||
if (1 == cnt) {
|
||||
// Queue list include only one link, and set up eof bit.
|
||||
if (QUEUE_BLOCK_LENGTH == len) {
|
||||
bufSize = len - 1;
|
||||
} else {
|
||||
bufSize = len;
|
||||
}
|
||||
fill_one_link(1, 1, 0, bufSize, bufSize, cfg->ping->buffer_addr, pongAry[i], pingAry[i]);
|
||||
fill_one_link(1, 1, 0, bufSize, bufSize, cfg->pong->buffer_addr, pingAry[i], pongAry[i]);
|
||||
} else {
|
||||
if (i == (cnt - 1)) {
|
||||
// ping/pong queue list last link connect to the pong/ping first link, and set up eof bit.
|
||||
bufSize = remainSize;
|
||||
fill_one_link(1, 1, 0, bufSize, bufSize, cfg->ping->buffer_addr + ((QUEUE_BLOCK_LENGTH / sizeof(uint32_t)) * i),
|
||||
pongAry[0], pingAry[i]);
|
||||
fill_one_link(1, 1, 0, bufSize, bufSize, cfg->pong->buffer_addr + ((QUEUE_BLOCK_LENGTH / sizeof(uint32_t)) * i),
|
||||
pingAry[0], pongAry[i]);
|
||||
} else {
|
||||
// Conncet the next link.
|
||||
fill_one_link(1, 0, 0, bufSize - 1, bufSize - 1, cfg->ping->buffer_addr + ((QUEUE_BLOCK_LENGTH / sizeof(uint32_t)) * i), pingAry[i + 1], pingAry[i]);
|
||||
fill_one_link(1, 0, 0, bufSize - 1, bufSize - 1, cfg->pong->buffer_addr + ((QUEUE_BLOCK_LENGTH / sizeof(uint32_t)) * i), pongAry[i + 1], pongAry[i]);
|
||||
}
|
||||
}
|
||||
remainSize -= bufSize;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Create a ping-pong buffer object used by DMA.
|
||||
*
|
||||
*/
|
||||
ping_pong_buf_t* dma_buf_create(uint32_t bufLen)
|
||||
{
|
||||
if (0 == bufLen) {
|
||||
return NULL;
|
||||
}
|
||||
uint32_t i, j;
|
||||
uint32_t queue_cnt ;
|
||||
uint8_t * pBuf = NULL;
|
||||
i = bufLen / QUEUE_BLOCK_LENGTH;
|
||||
j = bufLen % QUEUE_BLOCK_LENGTH;
|
||||
if (0 == j) {
|
||||
queue_cnt = i;
|
||||
} else {
|
||||
queue_cnt = i + 1;
|
||||
}
|
||||
DMA_INFO("\r\nbufLen=%d queue_cnt=%d\r\n", bufLen, queue_cnt);
|
||||
|
||||
ping_pong_buf_t* pcfg;
|
||||
pcfg = (ping_pong_buf_t*)malloc(sizeof(ping_pong_buf_t));
|
||||
if (NULL == pcfg) {
|
||||
return NULL;
|
||||
}
|
||||
pBuf = ((uint8_t*)malloc(bufLen * 2)); // buflen is number of bytes buffer.malloc ping and pong buffer.
|
||||
pcfg->ping = (dma_element_t*)malloc(sizeof(dma_element_t));
|
||||
pcfg->pong = (dma_element_t*)malloc(sizeof(dma_element_t));
|
||||
if ((NULL == pBuf)
|
||||
|| (NULL == pcfg->pong)
|
||||
|| (NULL == pcfg->ping)) {
|
||||
free(pBuf);
|
||||
pBuf = NULL;
|
||||
free(pcfg->pong);
|
||||
pcfg->pong = NULL;
|
||||
free(pcfg->ping);
|
||||
pcfg->ping = NULL;
|
||||
free(pcfg);
|
||||
pcfg = NULL;
|
||||
DMA_INFO("Malloc ping->buffer_addr failed");
|
||||
return NULL;
|
||||
}
|
||||
memset(pBuf, 0, (bufLen * 2));
|
||||
memset(pcfg->ping, 0, sizeof(dma_element_t));
|
||||
memset(pcfg->pong, 0, sizeof(dma_element_t));
|
||||
pcfg->ping->buffer_addr = (uint32_t*)pBuf;
|
||||
pcfg->pong->buffer_addr = (uint32_t*)(pBuf + bufLen);
|
||||
pcfg->queue_cnt = queue_cnt; // Number of queue
|
||||
if (dma_queue_fill(queue_cnt, bufLen, pcfg) < 0) {
|
||||
free(pcfg->ping->buffer_addr);
|
||||
pcfg->ping->buffer_addr = NULL;
|
||||
free(pcfg->pong->buffer_addr);
|
||||
pcfg->pong->buffer_addr = NULL;
|
||||
free(pBuf);
|
||||
pBuf = NULL;
|
||||
free(pcfg->pong);
|
||||
pcfg->pong = NULL;
|
||||
free(pcfg->ping);
|
||||
pcfg->ping = NULL;
|
||||
free(pcfg);
|
||||
pcfg = NULL;
|
||||
return NULL;
|
||||
}
|
||||
pcfg->len = bufLen; // Buffer length
|
||||
dma_show_queue(pcfg);
|
||||
return pcfg;
|
||||
}
|
||||
static esp_err_t dma_queue_reset(int32_t que_size, dma_element_t *obj)
|
||||
{
|
||||
if (NULL == obj) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
// No need reset;
|
||||
if (0 == obj->backup_queue.next_link_ptr) {
|
||||
return ESP_OK;
|
||||
}
|
||||
dma_queue_t *dmaQueCur = obj->first_queue;
|
||||
dma_queue_t *dmaQueNext = NULL;
|
||||
if (que_size > 1) {
|
||||
while (dmaQueNext != obj->first_queue) {
|
||||
dmaQueNext = (dma_queue_t*)dmaQueCur->next_link_ptr;
|
||||
if ((dma_queue_t*)obj->backup_queue.next_link_ptr == dmaQueNext) {
|
||||
DMA_INFO("find next_link_ptr=%x \r\n", dmaQueNext);
|
||||
break;
|
||||
}
|
||||
dmaQueCur = dmaQueNext;
|
||||
}
|
||||
}
|
||||
memcpy(dmaQueCur, &obj->backup_queue, sizeof(obj->backup_queue));
|
||||
memset(&obj->backup_queue, 0, sizeof(obj->backup_queue));
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reset the dma buffer length.
|
||||
*
|
||||
*/
|
||||
esp_err_t dma_buf_len_reset(ping_pong_buf_t *obj)
|
||||
{
|
||||
if (NULL == obj) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
dma_queue_t *dmaQueCur = obj->ping->first_queue;
|
||||
dma_queue_t *dmaQueNext = NULL;
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
DMA_INFO("next_link_ptr=%x lenght=%d\r\n", obj->ping->backup_queue.next_link_ptr, obj->ping->first_queue->data_length);
|
||||
|
||||
obj->ping->first_queue->owner = 1;
|
||||
obj->ping->last_queue->owner = 1;
|
||||
obj->pong->first_queue->owner = 1;
|
||||
obj->pong->last_queue->owner = 1;
|
||||
|
||||
obj->pong->first_queue->data_length = 32;
|
||||
obj->pong->last_queue->data_length = 32;
|
||||
obj->ping->first_queue->data_length = 32;
|
||||
obj->ping->last_queue->data_length = 32;
|
||||
|
||||
ret = dma_queue_reset(obj->queue_cnt, obj->ping);
|
||||
ret += dma_queue_reset(obj->queue_cnt, obj->pong);
|
||||
|
||||
//dma_show_queue(obj);
|
||||
DMA_INFO("[%s # %u lenght=%d]\r\n",__FUNCTION__,__LINE__, obj->ping->first_queue->data_length);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the buffer length before the start.
|
||||
*
|
||||
*/
|
||||
esp_err_t dma_buf_len_set(ping_pong_buf_t *obj, dma_element_t *element, uint32_t len)
|
||||
{
|
||||
if (NULL == obj) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
if (len < obj->len) {
|
||||
int i, k, cnt;
|
||||
i = len / QUEUE_BLOCK_LENGTH;
|
||||
k = len % QUEUE_BLOCK_LENGTH;
|
||||
if (0 == k) {
|
||||
cnt = i;
|
||||
} else {
|
||||
cnt = i + 1;
|
||||
}
|
||||
dma_queue_t *dmaQueCur = element->first_queue;
|
||||
dma_queue_t *dmaQueNext = NULL;
|
||||
while (--cnt) {
|
||||
dmaQueNext = (dma_queue_t*)dmaQueCur->next_link_ptr;
|
||||
dmaQueCur = dmaQueNext;
|
||||
}
|
||||
memcpy(&element->backup_queue, (dma_queue_t*)dmaQueCur, sizeof(element->backup_queue));
|
||||
|
||||
dmaQueCur->next_link_ptr = 0;
|
||||
dmaQueCur->data_length = k;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Destroy the ping-pong buffer instance.
|
||||
*
|
||||
*/
|
||||
void dma_buf_destroy(ping_pong_buf_t *obj)
|
||||
{
|
||||
ping_pong_buf_t *temp = obj;
|
||||
dma_show_queue(temp);
|
||||
if (NULL != temp) {
|
||||
// Free the link list
|
||||
uint32_t i = 0;
|
||||
dma_queue_t *curtCfg = temp->ping->first_queue;
|
||||
dma_queue_t *nextCfg = NULL;
|
||||
for (i = 0; i < temp->queue_cnt; ++i) {
|
||||
nextCfg = (dma_queue_t*)curtCfg->next_link_ptr;
|
||||
free(curtCfg);
|
||||
curtCfg = NULL;
|
||||
curtCfg = nextCfg;
|
||||
}
|
||||
curtCfg = temp->pong->first_queue;
|
||||
nextCfg = NULL;
|
||||
for (i = 0; i < temp->queue_cnt; ++i) {
|
||||
nextCfg = (dma_queue_t*)curtCfg->next_link_ptr;
|
||||
free(curtCfg);
|
||||
curtCfg = NULL;
|
||||
curtCfg = nextCfg;
|
||||
}
|
||||
// Free the buffer
|
||||
free(temp->ping->buffer_addr);
|
||||
temp->ping->buffer_addr = NULL;
|
||||
free(temp->ping);
|
||||
temp->ping = NULL;
|
||||
free(temp->pong);
|
||||
temp->pong = NULL;
|
||||
free(temp);
|
||||
temp = NULL;
|
||||
}
|
||||
}
|
350
examples/09_a2dp/components/MediaHal/Driver/i2c_soft.c
Normal file
350
examples/09_a2dp/components/MediaHal/Driver/i2c_soft.c
Normal file
|
@ -0,0 +1,350 @@
|
|||
/*
|
||||
* ESPRSSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2015 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP32 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 "rom/ets_sys.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "i2c_soft.h"
|
||||
|
||||
static uint8_t m_nLastSDA;
|
||||
static uint8_t m_nLastSCL;
|
||||
|
||||
/******************************************************************************
|
||||
* FunctionName : i2c_master_setDC
|
||||
* Description : Internal used function -
|
||||
* set i2c SDA and SCL bit value for half clk cycle
|
||||
* Parameters : uint8_t SDA
|
||||
* uint8_t SCL
|
||||
* Returns : NONE
|
||||
*******************************************************************************/
|
||||
static void i2c_master_setDC(uint8_t SDA, uint8_t SCL)
|
||||
{
|
||||
SDA &= 0x01;
|
||||
SCL &= 0x01;
|
||||
m_nLastSDA = SDA;
|
||||
m_nLastSCL = SCL;
|
||||
//ETS_INTR_LOCK();
|
||||
if ((0 == SDA) && (0 == SCL)) {
|
||||
I2C_MASTER_SDA_LOW_SCL_LOW();
|
||||
} else if ((0 == SDA) && (1 == SCL)) {
|
||||
I2C_MASTER_SDA_LOW_SCL_HIGH();
|
||||
} else if ((1 == SDA) && (0 == SCL)) {
|
||||
I2C_MASTER_SDA_HIGH_SCL_LOW();
|
||||
} else {
|
||||
I2C_MASTER_SDA_HIGH_SCL_HIGH();
|
||||
}
|
||||
//ETS_INTR_UNLOCK();
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* FunctionName : i2c_master_getDC
|
||||
* Description : Internal used function -
|
||||
* get i2c SDA bit value
|
||||
* Parameters : NONE
|
||||
* Returns : uint8_t - SDA bit value
|
||||
*******************************************************************************/
|
||||
static uint8_t i2c_master_getDC(void)
|
||||
{
|
||||
uint8_t sda_out;
|
||||
//ETS_INTR_LOCK();
|
||||
//sda_out = GPIO_INPUT_GET(GPIO_ID_PIN(I2C_MASTER_SDA_GPIO));
|
||||
sda_out = gpio_get_level(GPIO_ID_PIN(I2C_MASTER_SDA_GPIO));
|
||||
//ETS_INTR_UNLOCK();
|
||||
return sda_out;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* FunctionName : i2c_master_init
|
||||
* Description : initilize I2C bus to enable i2c operations
|
||||
* Parameters : NONE
|
||||
* Returns : NONE
|
||||
*******************************************************************************/
|
||||
void i2c_master_init(void)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
i2c_master_setDC(1, 0);
|
||||
i2c_master_wait(5);
|
||||
|
||||
// when SCL = 0, toggle SDA to clear up
|
||||
i2c_master_setDC(0, 0) ;
|
||||
i2c_master_wait(5);
|
||||
i2c_master_setDC(1, 0) ;
|
||||
i2c_master_wait(5);
|
||||
|
||||
// set data_cnt to max value
|
||||
for (i = 0; i < 28; i++) {
|
||||
i2c_master_setDC(1, 0);
|
||||
i2c_master_wait(5); // sda 1, scl 0
|
||||
i2c_master_setDC(1, 1);
|
||||
i2c_master_wait(5); // sda 1, scl 1
|
||||
}
|
||||
|
||||
// reset all
|
||||
i2c_master_stop();
|
||||
//return;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* FunctionName : i2c_master_gpio_init
|
||||
* Description : config SDA and SCL gpio to open-drain output mode,
|
||||
* mux and gpio num defined in i2c_master.h
|
||||
* Parameters : NONE
|
||||
* Returns : NONE
|
||||
*******************************************************************************/
|
||||
void i2c_master_gpio_init(void)
|
||||
{
|
||||
|
||||
gpio_config_t io_config;
|
||||
io_config.pin_bit_mask= (I2C_MASTER_SDA_PIN) | (I2C_MASTER_SCL_PIN);
|
||||
io_config.mode= GPIO_MODE_INPUT_OUTPUT_OD;
|
||||
io_config.pull_up_en= GPIO_PULLUP_ENABLE;
|
||||
io_config.pull_down_en= GPIO_PULLDOWN_DISABLE;
|
||||
io_config.intr_type = GPIO_PIN_INTR_DISABLE;
|
||||
|
||||
gpio_config(&io_config);
|
||||
#if 0
|
||||
io_config.gpio_intry_type_sel = GPIO_PIN_INTR_DISABLE;
|
||||
io_config.gpio_mode_sel = GPIO_MODE_OUTPUT_OD;
|
||||
io_config.gpio_pin_sel = I2C_MASTER_SCL_PIN;
|
||||
io_config.gpio_pulldown_sel = GPIO_PULLDOWN_DISABLE;
|
||||
io_config.gpio_pullup_sel = GPIO_PULLUP_ENABLE;
|
||||
|
||||
gpio_config(&io_config);
|
||||
#endif
|
||||
#if 0
|
||||
ETS_INTR_UNLOCK();
|
||||
// Set to GPIO function
|
||||
PIN_FUNC_SELECT(I2C_MASTER_SDA_MUX, I2C_MASTER_SDA_FUNC);
|
||||
PIN_FUNC_SELECT(I2C_MASTER_SCL_MUX, I2C_MASTER_SCL_FUNC);
|
||||
// Enable input
|
||||
SET_PERI_REG_MASK(I2C_MASTER_SDA_MUX, FUN_IE);
|
||||
|
||||
GPIO_REG_WRITE(GPIO_PIN_ADDR(I2C_MASTER_SDA_GPIO),
|
||||
GPIO_REG_READ(GPIO_PIN_ADDR(I2C_MASTER_SDA_GPIO)) | GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_ENABLE)); //open drain;
|
||||
GPIO_REG_WRITE(GPIO_ENABLE, GPIO_REG_READ(GPIO_ENABLE) | (1 << I2C_MASTER_SDA_GPIO));
|
||||
|
||||
GPIO_REG_WRITE(GPIO_PIN_ADDR(I2C_MASTER_SCL_GPIO),
|
||||
GPIO_PIN_ADDR(I2C_MASTER_SCL_GPIO) | GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_ENABLE)); //open drain;
|
||||
GPIO_REG_WRITE(GPIO_ENABLE, GPIO_REG_READ(GPIO_ENABLE) | (1 << I2C_MASTER_SCL_GPIO));
|
||||
I2C_MASTER_SDA_HIGH_SCL_HIGH();
|
||||
PIN_PULLUP_EN(I2C_MASTER_SDA_MUX);
|
||||
PIN_PULLUP_EN(I2C_MASTER_SCL_MUX);
|
||||
ETS_INTR_UNLOCK();
|
||||
#endif
|
||||
|
||||
i2c_master_init();
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* FunctionName : i2c_master_start
|
||||
* Description : set i2c to send state
|
||||
* Parameters : NONE
|
||||
* Returns : NONE
|
||||
*******************************************************************************/
|
||||
void i2c_master_start(void)
|
||||
{
|
||||
// ETS_INTR_UNLOCK();
|
||||
i2c_master_setDC(1, m_nLastSCL);
|
||||
i2c_master_wait(5);
|
||||
i2c_master_setDC(1, 1);
|
||||
i2c_master_wait(5); // sda 1, scl 1
|
||||
i2c_master_setDC(0, 1);
|
||||
i2c_master_wait(5); // sda 0, scl 1
|
||||
// ETS_INTR_UNLOCK();
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* FunctionName : i2c_master_stop
|
||||
* Description : set i2c to stop sending state
|
||||
* Parameters : NONE
|
||||
* Returns : NONE
|
||||
*******************************************************************************/
|
||||
void i2c_master_stop(void)
|
||||
{
|
||||
// ETS_INTR_UNLOCK();
|
||||
i2c_master_wait(5);
|
||||
|
||||
i2c_master_setDC(0, m_nLastSCL);
|
||||
i2c_master_wait(5); // sda 0
|
||||
i2c_master_setDC(0, 1);
|
||||
i2c_master_wait(5); // sda 0, scl 1
|
||||
i2c_master_setDC(1, 1);
|
||||
i2c_master_wait(5); // sda 1, scl 1
|
||||
// ETS_INTR_UNLOCK();
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* FunctionName : i2c_master_setAck
|
||||
* Description : set ack to i2c bus as level value
|
||||
* Parameters : uint8_t level - 0 or 1
|
||||
* Returns : NONE
|
||||
*******************************************************************************/
|
||||
void i2c_master_setAck(uint8_t level)
|
||||
{
|
||||
// ETS_INTR_UNLOCK();
|
||||
|
||||
i2c_master_setDC(m_nLastSDA, 0);
|
||||
i2c_master_wait(5);
|
||||
i2c_master_setDC(level, 0);
|
||||
i2c_master_wait(5); // sda level, scl 0
|
||||
i2c_master_setDC(level, 1);
|
||||
i2c_master_wait(8); // sda level, scl 1
|
||||
i2c_master_setDC(level, 0);
|
||||
i2c_master_wait(5); // sda level, scl 0
|
||||
i2c_master_setDC(1, 0);
|
||||
i2c_master_wait(5);
|
||||
// ETS_INTR_UNLOCK();
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* FunctionName : i2c_master_getAck
|
||||
* Description : confirm if peer send ack
|
||||
* Parameters : NONE
|
||||
* Returns : uint8_t - ack value, 0 or 1
|
||||
*******************************************************************************/
|
||||
uint8_t i2c_master_getAck(void)
|
||||
{
|
||||
uint8_t retVal;
|
||||
// ETS_INTR_UNLOCK();
|
||||
i2c_master_setDC(m_nLastSDA, 0);
|
||||
i2c_master_wait(5);
|
||||
i2c_master_setDC(1, 0);
|
||||
i2c_master_wait(5);
|
||||
i2c_master_setDC(1, 1);
|
||||
i2c_master_wait(5);
|
||||
|
||||
retVal = i2c_master_getDC();
|
||||
i2c_master_wait(5);
|
||||
i2c_master_setDC(1, 0);
|
||||
i2c_master_wait(5);
|
||||
// ETS_INTR_UNLOCK();
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* FunctionName : i2c_master_checkAck
|
||||
* Description : get dev response
|
||||
* Parameters : NONE
|
||||
* Returns : true : get ack ; false : get nack
|
||||
*******************************************************************************/
|
||||
bool i2c_master_checkAck(void)
|
||||
{
|
||||
if(i2c_master_getAck()){
|
||||
return false;
|
||||
}else{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* FunctionName : i2c_master_send_ack
|
||||
* Description : response ack
|
||||
* Parameters : NONE
|
||||
* Returns : NONE
|
||||
*******************************************************************************/
|
||||
void i2c_master_send_ack(void)
|
||||
{
|
||||
i2c_master_setAck(0x0);
|
||||
}
|
||||
/******************************************************************************
|
||||
* FunctionName : i2c_master_send_nack
|
||||
* Description : response nack
|
||||
* Parameters : NONE
|
||||
* Returns : NONE
|
||||
*******************************************************************************/
|
||||
void i2c_master_send_nack(void)
|
||||
{
|
||||
i2c_master_setAck(0x1);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* FunctionName : i2c_master_readByte
|
||||
* Description : read Byte from i2c bus
|
||||
* Parameters : NONE
|
||||
* Returns : uint8_t - readed value
|
||||
*******************************************************************************/
|
||||
uint8_t i2c_master_readByte(void)
|
||||
{
|
||||
uint8_t retVal = 0;
|
||||
uint8_t k, i;
|
||||
// ETS_INTR_UNLOCK();
|
||||
i2c_master_wait(5);
|
||||
i2c_master_setDC(m_nLastSDA, 0);
|
||||
i2c_master_wait(5); // sda 1, scl 0
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
i2c_master_wait(5);
|
||||
i2c_master_setDC(1, 0);
|
||||
i2c_master_wait(5); // sda 1, scl 0
|
||||
i2c_master_setDC(1, 1);
|
||||
i2c_master_wait(5); // sda 1, scl 1
|
||||
|
||||
k = i2c_master_getDC();
|
||||
i2c_master_wait(5);
|
||||
|
||||
if (i == 7) {
|
||||
i2c_master_wait(3); ////
|
||||
}
|
||||
|
||||
k <<= (7 - i);
|
||||
retVal |= k;
|
||||
}
|
||||
|
||||
i2c_master_setDC(1, 0);
|
||||
i2c_master_wait(5); // sda 1, scl 0
|
||||
// ETS_INTR_UNLOCK();
|
||||
return retVal;
|
||||
}
|
||||
#define DBG_TONY ets_printf
|
||||
/******************************************************************************
|
||||
* FunctionName : i2c_master_writeByte
|
||||
* Description : write wrdata value(one byte) into i2c
|
||||
* Parameters : uint8_t wrdata - write value
|
||||
* Returns : NONE
|
||||
*******************************************************************************/
|
||||
void i2c_master_writeByte(uint8_t wrdata)
|
||||
{
|
||||
uint8_t dat;
|
||||
int8_t i;
|
||||
|
||||
i2c_master_wait(5);
|
||||
i2c_master_setDC(m_nLastSDA, 0);
|
||||
i2c_master_wait(5);
|
||||
|
||||
for (i = 7; i >= 0; i--) {
|
||||
dat = wrdata >> i;
|
||||
i2c_master_setDC(dat, 0);
|
||||
i2c_master_wait(5);
|
||||
i2c_master_setDC(dat, 1);
|
||||
i2c_master_wait(5);
|
||||
|
||||
if (i == 0) {
|
||||
i2c_master_wait(3); ////
|
||||
}
|
||||
|
||||
i2c_master_setDC(dat, 0);
|
||||
i2c_master_wait(5);
|
||||
}
|
||||
|
||||
}
|
615
examples/09_a2dp/components/MediaHal/Driver/i2s.c
Normal file
615
examples/09_a2dp/components/MediaHal/Driver/i2s.c
Normal file
|
@ -0,0 +1,615 @@
|
|||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "i2s.h"
|
||||
#include <string.h>
|
||||
#include "rom/ets_sys.h"
|
||||
#include "esp_intr.h"
|
||||
#include "soc/gpio_reg.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "stdio.h"
|
||||
|
||||
|
||||
#define I2S_BASE_CLK (80000000L)
|
||||
#define ABS(x) (((x)>0)?(x):(-(x)))
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Make sure all of the definitions in this header have a C binding.
|
||||
//
|
||||
//*****************************************************************************
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Set the interrupt function.
|
||||
*
|
||||
*/
|
||||
static void i2s_intr_func_set(void * isr, i2s_num_t i2sNum)
|
||||
{
|
||||
if (I2S_NUM_I2S0 == i2sNum) {
|
||||
intr_matrix_set(0, ETS_I2S0_INTR_SOURCE, ETS_I2S0_INUM);
|
||||
ESP_I2S0_INTR_ATTACH(isr, NULL);
|
||||
// enable intr in cpu
|
||||
ESP_I2S0_INTR_ENABLE();
|
||||
} else if (I2S_NUM_I2S1 == i2sNum) {
|
||||
intr_matrix_set(0, ETS_I2S1_INTR_SOURCE, ETS_I2S1_INUM);
|
||||
ESP_I2S1_INTR_ATTACH(isr, NULL);
|
||||
// enable intr in cpu
|
||||
ESP_I2S1_INTR_ENABLE();
|
||||
} else {
|
||||
// To do nothing
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get I2S ping buffer address.
|
||||
*
|
||||
*/
|
||||
uint32_t* i2s_dma_ping_buf_get(i2s_dma_attr_t *obj)
|
||||
{
|
||||
if (NULL == obj) {
|
||||
return NULL;
|
||||
}
|
||||
return obj->buf->ping->buffer_addr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get I2S pong buffer address.
|
||||
*
|
||||
*/
|
||||
uint32_t* i2s_dma_pong_buf_get(i2s_dma_attr_t *obj)
|
||||
{
|
||||
if (NULL == obj) {
|
||||
return NULL;
|
||||
}
|
||||
return obj->buf->pong->buffer_addr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get not working ping-pong buffer address.
|
||||
*
|
||||
*/
|
||||
uint32_t* i2s_dma_status_get(i2s_num_t i2sNum, i2s_dma_attr_t *obj)
|
||||
{
|
||||
if ((NULL == obj)
|
||||
|| (i2sNum > I2S_NUM_MAX)) {
|
||||
return NULL;
|
||||
}
|
||||
if ((I2S_MODE_MASTER_RX == obj->mode)
|
||||
|| (I2S_MODE_SLAVE_RX == obj->mode)) {
|
||||
// Data stream receive
|
||||
if (READ_PERI_REG(I2S_IN_EOF_DES_ADDR_REG(i2sNum)) == ((uint32_t)obj->buf->ping->last_queue)) {
|
||||
return obj->buf->ping->buffer_addr;
|
||||
} else if (READ_PERI_REG(I2S_IN_EOF_DES_ADDR_REG(i2sNum)) == ((uint32_t)obj->buf->pong->last_queue)) {
|
||||
return obj->buf->pong->buffer_addr;
|
||||
}
|
||||
} else if ((I2S_MODE_MASTER_TX == obj->mode)
|
||||
|| (I2S_MODE_SLAVE_TX == obj->mode)) {
|
||||
// Data stream send
|
||||
if (READ_PERI_REG(I2S_OUT_EOF_DES_ADDR_REG(i2sNum)) == ((uint32_t)obj->buf->ping->last_queue)) {
|
||||
return obj->buf->ping->buffer_addr;
|
||||
} else if (READ_PERI_REG(I2S_OUT_EOF_DES_ADDR_REG(i2sNum)) == ((uint32_t)obj->buf->pong->last_queue)) {
|
||||
return obj->buf->pong->buffer_addr;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the Ping-Pong buffer to the destination
|
||||
*
|
||||
*/
|
||||
void i2s_dma_dest_add_set(i2s_num_t i2sNum, i2s_dma_attr_t *obj)
|
||||
{
|
||||
if ((NULL == obj)
|
||||
|| (i2sNum > I2S_NUM_MAX)) {
|
||||
return;
|
||||
}
|
||||
if ((I2S_MODE_MASTER_RX == obj->mode)
|
||||
|| (I2S_MODE_SLAVE_RX == obj->mode)) {
|
||||
SET_PERI_REG_BITS(I2S_IN_LINK_REG(i2sNum), I2S_INLINK_ADDR, ((uint32_t)(obj->buf->ping->first_queue)), I2S_INLINK_ADDR_S);
|
||||
} else if ((I2S_MODE_MASTER_TX == obj->mode)
|
||||
|| (I2S_MODE_SLAVE_TX == obj->mode)) {
|
||||
SET_PERI_REG_BITS(I2S_OUT_LINK_REG(i2sNum), I2S_OUTLINK_ADDR, ((uint32_t)(obj->buf->ping->first_queue)), I2S_OUTLINK_ADDR_S);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialize DMA and create a I2S DMA instance
|
||||
*
|
||||
*/
|
||||
int i2s_dma_init(i2s_num_t i2sNum, i2s_dma_attr_t *obj, void *isr)
|
||||
{
|
||||
if ((NULL == obj)
|
||||
|| (i2sNum > I2S_NUM_MAX)) {
|
||||
return -1;
|
||||
}
|
||||
obj->buf = dma_buf_create(obj->buf_size);
|
||||
if (NULL == obj->buf) {
|
||||
return -2;
|
||||
}
|
||||
if ((I2S_MODE_MASTER_TX == obj->mode)
|
||||
|| (I2S_MODE_SLAVE_TX == obj->mode)) {
|
||||
//Reset DMA
|
||||
SET_PERI_REG_MASK(I2S_LC_CONF_REG(i2sNum), I2S_OUT_RST);
|
||||
CLEAR_PERI_REG_MASK(I2S_LC_CONF_REG(i2sNum), I2S_OUT_RST);
|
||||
// enable send intr
|
||||
i2s_int_enable(i2sNum, I2S_INT_SRC_ONE_BUF_SEND_DONE);
|
||||
} else if ((I2S_MODE_MASTER_RX == obj->mode)
|
||||
|| (I2S_MODE_SLAVE_RX == obj->mode)) {
|
||||
//Reset DMA
|
||||
SET_PERI_REG_MASK(I2S_LC_CONF_REG(i2sNum), I2S_IN_RST);
|
||||
CLEAR_PERI_REG_MASK(I2S_LC_CONF_REG(i2sNum), I2S_IN_RST);
|
||||
SET_PERI_REG_BITS(I2S_RXEOF_NUM_REG(i2sNum), I2S_RX_EOF_NUM, (obj->buf_size / 4), I2S_RX_EOF_NUM_S);
|
||||
// enable receive intr
|
||||
i2s_int_enable(i2sNum, I2S_INT_SRC_ONE_BUF_RECV_DONE /*| I2sIntSrc_RxHalfFull |I2sIntSrc_RxFull*/);
|
||||
}
|
||||
|
||||
//Enable and configure DMA
|
||||
SET_PERI_REG_MASK(I2S_LC_CONF_REG(i2sNum), I2S_CHECK_OWNER | I2S_OUT_EOF_MODE |
|
||||
I2S_OUT_LOOP_TEST | I2S_IN_LOOP_TEST);
|
||||
i2s_intr_func_set(isr, i2sNum);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Destroy the I2S DMA instance
|
||||
*
|
||||
*/
|
||||
esp_err_t i2s_dma_uninit(i2s_dma_attr_t *obj)
|
||||
{
|
||||
if (NULL == obj) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
dma_buf_destroy(obj->buf);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable the I2S DMA work mode.
|
||||
*
|
||||
*/
|
||||
void i2s_dma_enable(i2s_num_t i2sNum, i2s_mode_t mode)
|
||||
{
|
||||
if (i2sNum > I2S_NUM_MAX) {
|
||||
return;
|
||||
}
|
||||
if ((I2S_MODE_MASTER_RX == mode)
|
||||
|| (I2S_MODE_SLAVE_RX == mode)) {
|
||||
SET_PERI_REG_MASK(I2S_IN_LINK_REG(i2sNum), I2S_INLINK_START);
|
||||
} else if ((I2S_MODE_MASTER_TX == mode)
|
||||
|| (I2S_MODE_SLAVE_TX == mode)) {
|
||||
SET_PERI_REG_MASK(I2S_OUT_LINK_REG(i2sNum), I2S_OUTLINK_START);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable the I2S DMA work mode.
|
||||
*
|
||||
*/
|
||||
void i2s_dma_disable(i2s_num_t i2sNum, i2s_mode_t mode)
|
||||
{
|
||||
if (i2sNum > I2S_NUM_MAX) {
|
||||
return;
|
||||
}
|
||||
if ((I2S_MODE_MASTER_RX == mode)
|
||||
|| (I2S_MODE_SLAVE_RX == mode)) {
|
||||
SET_PERI_REG_MASK(I2S_IN_LINK_REG(i2sNum), I2S_INLINK_STOP);
|
||||
} else if ((I2S_MODE_MASTER_TX == mode)
|
||||
|| (I2S_MODE_SLAVE_TX == mode)) {
|
||||
SET_PERI_REG_MASK(I2S_OUT_LINK_REG(i2sNum), I2S_OUTLINK_STOP);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the I2S sample rate, in HZ
|
||||
*
|
||||
*/
|
||||
void i2s_clk_set(int rate, int bits)
|
||||
{
|
||||
uint32_t i2sNum = 0 ;
|
||||
int bckdiv, factor = 32;
|
||||
int clkmInteger, clkmDecimals;
|
||||
float denom = (float)1 / 16;
|
||||
// BCLK = Fs * bits * 2;
|
||||
// MCLK = factor * BCLK; m = 2;
|
||||
// clkm = 160MHz / MCLK;
|
||||
ets_printf("rate=%d, bits=%d \r\n", rate, bits);
|
||||
float clkmdiv = (float)I2S_BASE_CLK / (rate * factor * bits * 2);
|
||||
ets_printf("clkmdiv=%f\r\n", clkmdiv);
|
||||
if (clkmdiv > 256) {
|
||||
factor++;
|
||||
clkmdiv = (float)I2S_BASE_CLK / (rate * factor * bits * 2);
|
||||
}
|
||||
ets_printf("clkmdiv=%f\r\n", clkmdiv);
|
||||
clkmInteger = clkmdiv;
|
||||
ets_printf("clkmInteger=%d\r\n", clkmInteger);
|
||||
clkmDecimals = (clkmdiv - clkmInteger) / denom;
|
||||
ets_printf("clkmDecimals=%d\r\n", clkmDecimals);
|
||||
float mclk = clkmInteger + denom * clkmDecimals;
|
||||
ets_printf("MCLK=%f\r\n", (float)I2S_BASE_CLK / mclk);
|
||||
rtc_plla_ena(1,10,2);
|
||||
#if 0
|
||||
CLEAR_PERI_REG_MASK(I2S_CLKM_CONF_REG, (I2S_CLKM_DIV_NUM_M
|
||||
| I2S_CLKM_DIV_A_M
|
||||
| I2S_CLKM_DIV_B_M));
|
||||
SET_PERI_REG_MASK(I2S_CLKM_CONF_REG, I2S_CLK_EN | ((0 & I2S_CLKM_DIV_A_V) << I2S_CLKM_DIV_A_S)
|
||||
| ((0) << I2S_CLKM_DIV_B_S) | (20 & I2S_CLKM_DIV_NUM_V));
|
||||
|
||||
CLEAR_PERI_REG_MASK(I2S_SAMPLE_RATE_CONF_REG, I2S_RX_BCK_DIV_NUM_M | I2S_TX_BCK_DIV_NUM_M);
|
||||
SET_PERI_REG_MASK(I2S_SAMPLE_RATE_CONF_REG, ((4 & I2S_RX_BCK_DIV_NUM_V) << I2S_RX_BCK_DIV_NUM_S)
|
||||
| ((4 & I2S_TX_BCK_DIV_NUM_V) << I2S_TX_BCK_DIV_NUM_S));
|
||||
|
||||
#else
|
||||
#if 0 // Fs= 48kHz
|
||||
CLEAR_PERI_REG_MASK(I2S_CLKM_CONF_REG, (I2S_CLKM_DIV_NUM_M
|
||||
| I2S_CLKM_DIV_A_M
|
||||
| I2S_CLKM_DIV_B_M));
|
||||
I2S_SET_CLKA_ENA(1);
|
||||
I2S_SET_CLKM_DIV_A(63);
|
||||
I2S_SET_CLKM_DIV_B(32);
|
||||
I2S_SET_CLKM_DIV_NUM(6);
|
||||
|
||||
CLEAR_PERI_REG_MASK(I2S_SAMPLE_RATE_CONF_REG, I2S_RX_BCK_DIV_NUM_M | I2S_TX_BCK_DIV_NUM_M);
|
||||
I2S_SET_RX_BCK_DIV_NUM(4);
|
||||
I2S_SET_TX_BCK_DIV_NUM(2);
|
||||
I2S_SET_TX_PDM_FS(480);
|
||||
#else
|
||||
// Fs = 44.1kHz
|
||||
CLEAR_PERI_REG_MASK(I2S_CLKM_CONF_REG(i2sNum), (I2S_CLKM_DIV_NUM_M | I2S_CLKM_DIV_A_M | I2S_CLKM_DIV_B_M));
|
||||
SET_PERI_REG_BITS(I2S_CLKM_CONF_REG(i2sNum), I2S_CLKM_DIV_A_V, 64, I2S_CLKM_DIV_A_S);
|
||||
SET_PERI_REG_BITS(I2S_CLKM_CONF_REG(i2sNum), I2S_CLKM_DIV_B_V,8, I2S_CLKM_DIV_B_S);
|
||||
SET_PERI_REG_BITS(I2S_CLKM_CONF_REG(i2sNum), I2S_CLKM_DIV_NUM_V, 78, I2S_CLKM_DIV_NUM_S);
|
||||
|
||||
CLEAR_PERI_REG_MASK(I2S_SAMPLE_RATE_CONF_REG(i2sNum), I2S_RX_BCK_DIV_NUM_M | I2S_TX_BCK_DIV_NUM_M);
|
||||
SET_PERI_REG_BITS(I2S_SAMPLE_RATE_CONF_REG(i2sNum), I2S_RX_BCK_DIV_NUM_V, 4, I2S_RX_BCK_DIV_NUM_S);
|
||||
SET_PERI_REG_BITS(I2S_SAMPLE_RATE_CONF_REG(i2sNum), I2S_TX_BCK_DIV_NUM_V, 2, I2S_TX_BCK_DIV_NUM_S);
|
||||
SET_PERI_REG_BITS(I2S_PDM_FREQ_CONF_REG(i2sNum), I2S_TX_PDM_FS_V, 441, I2S_TX_PDM_FS_S);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
CLEAR_PERI_REG_MASK(0x60009000, (0xf));
|
||||
CLEAR_PERI_REG_MASK(I2S_PDM_CONF_REG(i2sNum), 0x0f);
|
||||
|
||||
|
||||
#if 0 // Fs= 48kHz
|
||||
CLEAR_PERI_REG_MASK(I2S_CLKM_CONF_REG, (I2S_CLKM_DIV_NUM_M
|
||||
|I2S_CLKM_DIV_A_M
|
||||
|I2S_CLKM_DIV_B_M));
|
||||
I2S_SET_CLKA_ENA(1);
|
||||
I2S_SET_CLKM_DIV_A(63);
|
||||
I2S_SET_CLKM_DIV_B(32);
|
||||
I2S_SET_CLKM_DIV_NUM(6);
|
||||
|
||||
CLEAR_PERI_REG_MASK(I2S_SAMPLE_RATE_CONF_REG, I2S_RX_BCK_DIV_NUM_M |I2S_TX_BCK_DIV_NUM_M);
|
||||
I2S_SET_RX_BCK_DIV_NUM(4);
|
||||
I2S_SET_TX_BCK_DIV_NUM(2);
|
||||
I2S_SET_TX_PDM_FS(480);
|
||||
#else
|
||||
// Fs = 44.1kHz
|
||||
CLEAR_PERI_REG_MASK(I2S_CLKM_CONF_REG(i2sNum), (I2S_CLKM_DIV_NUM_M
|
||||
|I2S_CLKM_DIV_A_M
|
||||
|I2S_CLKM_DIV_B_M));
|
||||
SET_PERI_REG_BITS(I2S_CLKM_CONF_REG(i2sNum),I2S_CLKM_DIV_A_V,64,I2S_CLKM_DIV_A_S);
|
||||
SET_PERI_REG_BITS(I2S_CLKM_CONF_REG(i2sNum),I2S_CLKM_DIV_B_V,8,I2S_CLKM_DIV_B_S);
|
||||
SET_PERI_REG_BITS(I2S_CLKM_CONF_REG(i2sNum),I2S_CLKM_DIV_NUM_V,78,I2S_CLKM_DIV_NUM_S);
|
||||
|
||||
CLEAR_PERI_REG_MASK(I2S_SAMPLE_RATE_CONF_REG(i2sNum), I2S_RX_BCK_DIV_NUM_M |I2S_TX_BCK_DIV_NUM_M);
|
||||
SET_PERI_REG_BITS(I2S_SAMPLE_RATE_CONF_REG(i2sNum),I2S_RX_BCK_DIV_NUM_V,4,I2S_RX_BCK_DIV_NUM_S);
|
||||
SET_PERI_REG_BITS(I2S_SAMPLE_RATE_CONF_REG(i2sNum),I2S_TX_BCK_DIV_NUM_V,8,I2S_TX_BCK_DIV_NUM_S);
|
||||
SET_PERI_REG_BITS(I2S_PDM_FREQ_CONF_REG(i2sNum),I2S_TX_PDM_FS_V,441,I2S_TX_PDM_FS_S);
|
||||
|
||||
#endif
|
||||
CLEAR_PERI_REG_MASK(0x60009000,(0xf));
|
||||
CLEAR_PERI_REG_MASK(I2S_PDM_CONF_REG(i2sNum),0x0f);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reset I2s with a given module.
|
||||
*
|
||||
*/
|
||||
void i2s_reset(i2s_num_t i2sNum)
|
||||
{
|
||||
SET_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_TX_RESET_M);
|
||||
SET_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_RX_RESET_M);
|
||||
SET_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_TX_FIFO_RESET_M);
|
||||
SET_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_RX_FIFO_RESET_M);
|
||||
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_TX_RESET_M);
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_RX_RESET_M);
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_TX_FIFO_RESET_M);
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_RX_FIFO_RESET_M);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialize the I2S module
|
||||
*
|
||||
*/
|
||||
void i2s_init(i2s_num_t i2sNum, i2s_attr_t *pAttr)
|
||||
{
|
||||
if ((i2sNum > I2S_NUM_MAX)
|
||||
|| (NULL == pAttr)) {
|
||||
return ;
|
||||
}
|
||||
if (i2sNum == I2S_NUM_I2S0) {
|
||||
SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S0_CLK_EN);
|
||||
CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S0_RST);
|
||||
} else if (i2sNum == I2S_NUM_I2S1) {
|
||||
SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S1_CLK_EN);
|
||||
CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S1_RST);
|
||||
}
|
||||
|
||||
// configure I2S data port interface.
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF2_REG(i2sNum), I2S_LCD_EN);
|
||||
CLEAR_PERI_REG_MASK(I2S_PDM_CONF_REG(i2sNum), I2S_PCM2PDM_CONV_EN | I2S_PDM2PCM_CONV_EN);
|
||||
SET_PERI_REG_BITS(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_SOC_CLK_SEL, 0x1, RTC_CNTL_SOC_CLK_SEL_S);
|
||||
|
||||
if (0 != pAttr->rx_mode.mode) {
|
||||
if (I2S_IFACE_TYPE_DMA == pAttr->rx_mode.iface) {
|
||||
SET_PERI_REG_MASK(I2S_FIFO_CONF_REG(i2sNum), I2S_DSCR_EN);
|
||||
} else {
|
||||
CLEAR_PERI_REG_MASK(I2S_FIFO_CONF_REG(i2sNum), I2S_DSCR_EN);
|
||||
}
|
||||
// Working mode
|
||||
if (I2S_MODE_MASTER_RX == pAttr->rx_mode.mode) {
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_RX_SLAVE_MOD);
|
||||
// configure I2S communication standard format
|
||||
i2s_clk_set(pAttr->rx_mode.rate, pAttr->rx_mode.bits);
|
||||
} else if (I2S_MODE_SLAVE_RX == pAttr->rx_mode.mode) {
|
||||
SET_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_RX_SLAVE_MOD);
|
||||
} else {
|
||||
// To do nothing.
|
||||
}
|
||||
// configure I2S communication standard format
|
||||
if (I2S_STD_FORMAT_I2S == pAttr->rx_mode.std) {
|
||||
SET_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_RX_MSB_SHIFT);
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF1_REG(i2sNum), I2S_RX_SHORT_SYNC);
|
||||
} else if (I2S_STD_FORMAT_MSB == pAttr->rx_mode.std) {
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_RX_MSB_SHIFT);
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_RX_SHORT_SYNC);
|
||||
} else if (I2S_STD_FORMAT_LSB == pAttr->rx_mode.std) {
|
||||
|
||||
} else if (I2S_STD_FORMAT_PCM_SHORT == pAttr->rx_mode.std) {
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_RX_MSB_SHIFT);
|
||||
SET_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_RX_SHORT_SYNC);
|
||||
} else if (I2S_STD_FORMAT_PCM_LONG == pAttr->rx_mode.std) {
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_RX_MSB_SHIFT);
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_RX_SHORT_SYNC);
|
||||
} else {
|
||||
// To do nothing.
|
||||
}
|
||||
// configure bit width format.
|
||||
SET_PERI_REG_BITS(I2S_SAMPLE_RATE_CONF_REG(i2sNum), I2S_RX_BITS_MOD, pAttr->rx_mode.bits, I2S_RX_BITS_MOD_S);
|
||||
|
||||
SET_PERI_REG_MASK(I2S_FIFO_CONF_REG(i2sNum), I2S_RX_FIFO_MOD_FORCE_EN);
|
||||
// setting channel mode.
|
||||
if (I2S_CHANNEL_FMT_RIGHT_LEFT == pAttr->rx_mode.channel) {
|
||||
// set rx,tx channel mode, both are "two channel" here
|
||||
SET_PERI_REG_BITS(I2S_FIFO_CONF_REG(i2sNum), I2S_RX_FIFO_MOD_V, 0, I2S_RX_FIFO_MOD_S); // 0-right&left channel;1-one channel
|
||||
SET_PERI_REG_BITS(I2S_CONF_CHAN_REG(i2sNum), I2S_RX_CHAN_MOD, I2S_CHANNEL_FMT_RIGHT_LEFT, I2S_RX_CHAN_MOD_S);// 0-two channel;1-right;2-left
|
||||
} else if (I2S_CHANNEL_FMT_ALL_RIGHT == pAttr->rx_mode.channel) {
|
||||
SET_PERI_REG_BITS(I2S_FIFO_CONF_REG(i2sNum), I2S_RX_FIFO_MOD_V, 0, I2S_RX_FIFO_MOD_S); // 0-right&left channel;1-one channel
|
||||
SET_PERI_REG_BITS(I2S_CONF_CHAN_REG(i2sNum), I2S_RX_CHAN_MOD, I2S_CHANNEL_FMT_ALL_RIGHT, I2S_RX_CHAN_MOD_S);
|
||||
} else if (I2S_CHANNEL_FMT_ALL_LEFT == pAttr->rx_mode.channel) {
|
||||
SET_PERI_REG_BITS(I2S_FIFO_CONF_REG(i2sNum), I2S_RX_FIFO_MOD_V, 0, I2S_RX_FIFO_MOD_S); // 0-right&left channel;1-one channel
|
||||
SET_PERI_REG_BITS(I2S_CONF_CHAN_REG(i2sNum), I2S_RX_CHAN_MOD, I2S_CHANNEL_FMT_ALL_LEFT, I2S_RX_CHAN_MOD_S);
|
||||
} else if (I2S_CHANNEL_FMT_ONLY_RIGHT == pAttr->rx_mode.channel) {
|
||||
SET_PERI_REG_BITS(I2S_FIFO_CONF_REG(i2sNum), I2S_RX_FIFO_MOD_V, 1, I2S_RX_FIFO_MOD_S); // 0-right&left channel;1-one channel
|
||||
SET_PERI_REG_BITS(I2S_CONF_CHAN_REG(i2sNum), I2S_RX_CHAN_MOD, 1, I2S_RX_CHAN_MOD_S);
|
||||
} else if (I2S_CHANNEL_FMT_ONLY_LEFT == pAttr->rx_mode.channel) {
|
||||
SET_PERI_REG_BITS(I2S_FIFO_CONF_REG(i2sNum), I2S_RX_FIFO_MOD_V, 1, I2S_RX_FIFO_MOD_S); // 0-right&left channel;1-one channel
|
||||
SET_PERI_REG_BITS(I2S_CONF_CHAN_REG(i2sNum), I2S_RX_CHAN_MOD, 2, I2S_RX_CHAN_MOD_S);
|
||||
} else {
|
||||
// To do nothing.
|
||||
}
|
||||
|
||||
if (I2S_MODULE_WORK_TYPE_PDM == pAttr->rx_mode.type) {
|
||||
if (PDM_SAMPLE_RATE_RATIO_64 == pAttr->rx_mode.ratio) {
|
||||
CLEAR_PERI_REG_MASK(I2S_PDM_CONF_REG(i2sNum), I2S_RX_PDM_SINC_DSR_16_EN); // Clear:64*fs;set:128*fs
|
||||
} else if (PDM_SAMPLE_RATE_RATIO_128 == pAttr->rx_mode.ratio) {
|
||||
SET_PERI_REG_MASK(I2S_PDM_CONF_REG(i2sNum), I2S_RX_PDM_SINC_DSR_16_EN); // Clear:64*fs;set:128*fs
|
||||
}
|
||||
if (PDM_PCM_CONV_ENABLE == pAttr->rx_mode.conv) {
|
||||
SET_PERI_REG_MASK(I2S_PDM_CONF_REG(i2sNum), I2S_PDM2PCM_CONV_EN);
|
||||
} else if (PDM_PCM_CONV_DISABLE == pAttr->rx_mode.conv) {
|
||||
CLEAR_PERI_REG_MASK(I2S_PDM_CONF_REG(i2sNum), I2S_PDM2PCM_CONV_EN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (0 != pAttr->tx_mode.mode) {
|
||||
if (I2S_IFACE_TYPE_DMA == pAttr->tx_mode.iface) {
|
||||
SET_PERI_REG_MASK(I2S_FIFO_CONF_REG(i2sNum), I2S_DSCR_EN);
|
||||
} else {
|
||||
CLEAR_PERI_REG_MASK(I2S_FIFO_CONF_REG(i2sNum), I2S_DSCR_EN);
|
||||
}
|
||||
|
||||
if (I2S_MODE_MASTER_TX == pAttr->tx_mode.mode) {
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_TX_SLAVE_MOD);
|
||||
// configure I2S communication standard format
|
||||
i2s_clk_set(pAttr->tx_mode.rate, pAttr->tx_mode.bits);
|
||||
// rtc_plla_ena(1, 621, 14);
|
||||
// SET_PERI_REG_MASK(I2S_CLKM_CONF_REG(i2sNum), I2S_CLKA_ENA);
|
||||
printf("rtc_plla_ena is ok\r\n");
|
||||
} else if (I2S_MODE_SLAVE_RX == pAttr->tx_mode.mode) {
|
||||
SET_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_TX_SLAVE_MOD);
|
||||
} else {
|
||||
// To do nothing.
|
||||
}
|
||||
// configure I2S communication standard format
|
||||
if (I2S_STD_FORMAT_I2S == pAttr->tx_mode.std) {
|
||||
SET_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_TX_MSB_SHIFT);
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_TX_SHORT_SYNC);
|
||||
} else if (I2S_STD_FORMAT_MSB == pAttr->tx_mode.std) {
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_TX_MSB_SHIFT);
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_TX_SHORT_SYNC);
|
||||
} else if (I2S_STD_FORMAT_LSB == pAttr->tx_mode.std) {
|
||||
|
||||
} else if (I2S_STD_FORMAT_PCM_SHORT == pAttr->tx_mode.std) {
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_TX_MSB_SHIFT);
|
||||
SET_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_TX_SHORT_SYNC);
|
||||
} else if (I2S_STD_FORMAT_PCM_LONG == pAttr->tx_mode.std) {
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_TX_MSB_SHIFT);
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_TX_SHORT_SYNC);
|
||||
} else {
|
||||
// To do nothing.
|
||||
}
|
||||
// configure bit width format.
|
||||
SET_PERI_REG_BITS(I2S_SAMPLE_RATE_CONF_REG(i2sNum), I2S_TX_BITS_MOD, pAttr->tx_mode.bits, I2S_TX_BITS_MOD_S);
|
||||
SET_PERI_REG_MASK(I2S_FIFO_CONF_REG(i2sNum), I2S_TX_FIFO_MOD_FORCE_EN);
|
||||
|
||||
if (I2S_CHANNEL_FMT_RIGHT_LEFT == pAttr->tx_mode.channel) {
|
||||
// set rx,tx channel mode, both are "two channel" here
|
||||
SET_PERI_REG_BITS(I2S_FIFO_CONF_REG(i2sNum), I2S_TX_FIFO_MOD_V, 0, I2S_TX_FIFO_MOD_S); // 0-right&left channel;1-one channel
|
||||
SET_PERI_REG_BITS(I2S_CONF_CHAN_REG(i2sNum), I2S_TX_CHAN_MOD, I2S_CHANNEL_FMT_RIGHT_LEFT, I2S_TX_CHAN_MOD_S);// 0-two channel;1-right;2-left
|
||||
} else if (I2S_CHANNEL_FMT_ALL_RIGHT == pAttr->tx_mode.channel) {
|
||||
SET_PERI_REG_BITS(I2S_FIFO_CONF_REG(i2sNum), I2S_TX_FIFO_MOD_V, 0, I2S_TX_FIFO_MOD_S); // 0-right&left channel;1-one channel
|
||||
SET_PERI_REG_BITS(I2S_CONF_CHAN_REG(i2sNum), I2S_TX_CHAN_MOD, I2S_CHANNEL_FMT_ALL_RIGHT, I2S_TX_CHAN_MOD_S);
|
||||
} else if (I2S_CHANNEL_FMT_ALL_LEFT == pAttr->tx_mode.channel) {
|
||||
SET_PERI_REG_BITS(I2S_FIFO_CONF_REG(i2sNum), I2S_TX_FIFO_MOD_V, 0, I2S_TX_FIFO_MOD_S); // 0-right&left channel;1-one channel
|
||||
SET_PERI_REG_BITS(I2S_CONF_CHAN_REG(i2sNum), I2S_TX_CHAN_MOD, I2S_CHANNEL_FMT_ALL_LEFT, I2S_TX_CHAN_MOD_S);
|
||||
} else if (I2S_CHANNEL_FMT_ONLY_RIGHT == pAttr->tx_mode.channel) {
|
||||
SET_PERI_REG_BITS(I2S_FIFO_CONF_REG(i2sNum), I2S_TX_FIFO_MOD_V, 1, I2S_TX_FIFO_MOD_S); // 0-right&left channel;1-one channel
|
||||
SET_PERI_REG_BITS(I2S_CONF_CHAN_REG(i2sNum), I2S_TX_CHAN_MOD, 1, I2S_TX_CHAN_MOD_S);
|
||||
} else if (I2S_CHANNEL_FMT_ONLY_LEFT == pAttr->tx_mode.channel) {
|
||||
SET_PERI_REG_BITS(I2S_FIFO_CONF_REG(i2sNum), I2S_TX_FIFO_MOD_V, 1, I2S_TX_FIFO_MOD_S); // 0-right&left channel;1-one channel
|
||||
SET_PERI_REG_BITS(I2S_CONF_CHAN_REG(i2sNum), I2S_TX_CHAN_MOD, 2, I2S_TX_CHAN_MOD_S);
|
||||
} else {
|
||||
// To do nothing.
|
||||
}
|
||||
if (I2S_MODULE_WORK_TYPE_PDM == pAttr->tx_mode.type) {
|
||||
if (PDM_SAMPLE_RATE_RATIO_64 == pAttr->tx_mode.ratio) {
|
||||
SET_PERI_REG_BITS(I2S_PDM_CONF_REG(i2sNum), I2S_TX_PDM_SINC_OSR2_M, 1, I2S_TX_PDM_SINC_OSR2_S); // TX: 2---128*fs;1---64*fs
|
||||
} else if (PDM_SAMPLE_RATE_RATIO_128 == pAttr->tx_mode.ratio) {
|
||||
SET_PERI_REG_BITS(I2S_PDM_CONF_REG(i2sNum), I2S_TX_PDM_SINC_OSR2_M, 2, I2S_TX_PDM_SINC_OSR2_S); // TX: 2---128*fs;1---64*fs
|
||||
}
|
||||
if (PDM_PCM_CONV_ENABLE == pAttr->rx_mode.conv) {
|
||||
SET_PERI_REG_MASK(I2S_PDM_CONF_REG(i2sNum), I2S_PDM2PCM_CONV_EN);
|
||||
} else if (PDM_PCM_CONV_DISABLE == pAttr->rx_mode.conv) {
|
||||
CLEAR_PERI_REG_MASK(I2S_PDM_CONF_REG(i2sNum), I2S_PDM2PCM_CONV_EN);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Clear all of the interrupt sources.
|
||||
WRITE_PERI_REG(I2S_INT_CLR_REG(i2sNum), 0xffffffff);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable the interrupt source.
|
||||
*
|
||||
*/
|
||||
void i2s_int_enable(i2s_num_t i2sNum, i2s_int_src_t intSrc)
|
||||
{
|
||||
SET_PERI_REG_MASK(I2S_INT_ENA_REG(i2sNum), intSrc);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable the interrupt source.
|
||||
*
|
||||
*/
|
||||
void i2s_int_disable(i2s_num_t i2sNum, i2s_int_src_t intSrc)
|
||||
{
|
||||
CLEAR_PERI_REG_MASK(I2S_INT_ENA_REG(i2sNum), intSrc);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clear the interrupt source.
|
||||
*
|
||||
*/
|
||||
void i2s_int_clear(i2s_num_t i2sNum, i2s_int_src_t intSrc)
|
||||
{
|
||||
SET_PERI_REG_MASK(I2S_INT_CLR_REG(i2sNum), intSrc);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the I2S interrupt status
|
||||
*/
|
||||
uint32_t i2s_int_status_get(i2s_num_t i2sNum)
|
||||
{
|
||||
return READ_PERI_REG(I2S_INT_ST_REG(i2sNum));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Start I2S work
|
||||
*
|
||||
*/
|
||||
void i2s_start(i2s_module_work_type_t type, i2s_num_t i2sNum, i2s_mode_t mode)
|
||||
{
|
||||
if (i2sNum > I2S_NUM_MAX) {
|
||||
return;
|
||||
}
|
||||
if (I2S_MODULE_WORK_TYPE_I2S == type) {
|
||||
if ((I2S_MODE_MASTER_RX == mode)
|
||||
|| (I2S_MODE_SLAVE_RX == mode)) {
|
||||
SET_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_RX_START);
|
||||
SET_PERI_REG_MASK(GPIO_ENABLE_REG, BIT(0));
|
||||
} else if ((I2S_MODE_MASTER_TX == mode)
|
||||
|| (I2S_MODE_SLAVE_TX == mode)) {
|
||||
SET_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_TX_START);
|
||||
SET_PERI_REG_MASK(GPIO_ENABLE_REG, BIT(0));
|
||||
}
|
||||
} else if (I2S_MODULE_WORK_TYPE_PDM == type) {
|
||||
if ((I2S_MODE_MASTER_RX == mode)
|
||||
|| (I2S_MODE_SLAVE_RX == mode)) {
|
||||
SET_PERI_REG_MASK(I2S_PDM_CONF_REG(i2sNum), I2S_RX_PDM_EN);
|
||||
SET_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_RX_START);
|
||||
} else if ((I2S_MODE_MASTER_TX == mode)
|
||||
|| (I2S_MODE_SLAVE_TX == mode)) {
|
||||
SET_PERI_REG_MASK(I2S_PDM_CONF_REG(i2sNum), I2S_TX_PDM_EN);
|
||||
SET_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_TX_START);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Stop I2S work
|
||||
*
|
||||
*/
|
||||
void i2s_stop(i2s_module_work_type_t type, i2s_num_t i2sNum, i2s_mode_t mode)
|
||||
{
|
||||
if (i2sNum > I2S_NUM_MAX) {
|
||||
return;
|
||||
}
|
||||
if (I2S_MODULE_WORK_TYPE_I2S == type) {
|
||||
if ((I2S_MODE_MASTER_RX == mode)
|
||||
|| (I2S_MODE_SLAVE_RX == mode)) {
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_RX_START);
|
||||
SET_PERI_REG_MASK(GPIO_ENABLE_REG, BIT(0));
|
||||
} else if ((I2S_MODE_MASTER_TX == mode)
|
||||
|| (I2S_MODE_SLAVE_TX == mode)) {
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_TX_START);
|
||||
}
|
||||
} else if (I2S_MODULE_WORK_TYPE_PDM == type) {
|
||||
if ((I2S_MODE_MASTER_RX == mode)
|
||||
|| (I2S_MODE_SLAVE_RX == mode)) {
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_RX_START);
|
||||
CLEAR_PERI_REG_MASK(I2S_PDM_CONF_REG(i2sNum), I2S_RX_PDM_EN);
|
||||
} else if ((I2S_MODE_MASTER_TX == mode)
|
||||
|| (I2S_MODE_SLAVE_TX == mode)) {
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_TX_START);
|
||||
CLEAR_PERI_REG_MASK(I2S_PDM_CONF_REG(i2sNum), I2S_TX_PDM_EN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
1077
examples/09_a2dp/components/MediaHal/Driver/psram.c
Normal file
1077
examples/09_a2dp/components/MediaHal/Driver/psram.c
Normal file
File diff suppressed because it is too large
Load diff
827
examples/09_a2dp/components/MediaHal/Driver/spi.c
Normal file
827
examples/09_a2dp/components/MediaHal/Driver/spi.c
Normal file
|
@ -0,0 +1,827 @@
|
|||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <string.h>
|
||||
#include "spi.h"
|
||||
#include "soc/spi_reg.h"
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
#include "rom/ets_sys.h"
|
||||
#include "esp_intr.h"
|
||||
#include "soc/dport_reg.h"
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Make sure all of the definitions in this header have a C binding.
|
||||
//
|
||||
//*****************************************************************************
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Defines slave commands.Default value based on slave ESP8266 & ESP32.
|
||||
*/
|
||||
#define MASTER_WRITE_DATA_TO_SLAVE_CMD 2
|
||||
#define MASTER_READ_DATA_FROM_SLAVE_CMD 3
|
||||
#define MASTER_WRITE_STATUS_TO_SLAVE_CMD 1
|
||||
#define MASTER_READ_STATUS_FROM_SLAVE_CMD 4
|
||||
|
||||
|
||||
static void spi_intr_func_set(void * isr, spi_num_t spiNum)
|
||||
{
|
||||
if (SPI_NUM_SPI1 == spiNum) {
|
||||
intr_matrix_set(0, ETS_SPI1_DMA_INTR_SOURCE, ETS_SPI1_INUM);
|
||||
ESP_SPI1_INTR_ATTACH(isr, NULL);
|
||||
// enable intr in cpu
|
||||
ESP_SPI1_INTR_ENABLE();
|
||||
} else if (SPI_NUM_SPI2 == spiNum) {
|
||||
intr_matrix_set(0, ETS_SPI2_DMA_INTR_SOURCE, ETS_SPI2_INUM);
|
||||
ESP_SPI2_INTR_ATTACH(isr, NULL);
|
||||
// enable intr in cpu
|
||||
ESP_SPI2_INTR_ENABLE();
|
||||
} else if (SPI_NUM_SPI3 == spiNum) {
|
||||
intr_matrix_set(0, ETS_SPI3_DMA_INTR_SOURCE, ETS_SPI3_INUM);
|
||||
ESP_SPI3_INTR_ATTACH(isr, NULL);
|
||||
// enable intr in cpu
|
||||
ESP_SPI3_INTR_ENABLE();
|
||||
} else {
|
||||
// To do nothing
|
||||
}
|
||||
}
|
||||
#if 1
|
||||
|
||||
/**
|
||||
* @brief Get SPI ping buffer address.
|
||||
*
|
||||
*/
|
||||
uint32_t* spi_dma_ping_buf_get(spi_dma_attr_t *obj)
|
||||
{
|
||||
if (NULL == obj) {
|
||||
return NULL;
|
||||
}
|
||||
return obj->buf->ping->buffer_addr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get SPI ping buffer address.
|
||||
*
|
||||
*/
|
||||
uint32_t* spi_dma_pong_buf_get(spi_dma_attr_t *obj)
|
||||
{
|
||||
if (NULL == obj) {
|
||||
return NULL;
|
||||
}
|
||||
return obj->buf->pong->buffer_addr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get without work ping-pong buffer address.
|
||||
*
|
||||
*/
|
||||
uint32_t* spi_dma_status_get(spi_dma_attr_t *obj)
|
||||
{
|
||||
if ((NULL == obj)
|
||||
|| (obj->spi_num > SPI_NUM_MAX)) {
|
||||
return NULL;
|
||||
}
|
||||
switch (obj->dir) {
|
||||
case SPI_DMA_DIR_OUT:
|
||||
if (READ_PERI_REG(SPI_OUT_EOF_DES_ADDR_REG(obj->spi_num)) == ((uint32_t)obj->buf->ping->last_queue)) {
|
||||
return obj->buf->ping->buffer_addr;
|
||||
} else if (READ_PERI_REG(SPI_OUT_EOF_DES_ADDR_REG(obj->spi_num)) == ((uint32_t)obj->buf->pong->last_queue)) {
|
||||
return obj->buf->pong->buffer_addr;
|
||||
}
|
||||
break;
|
||||
case SPI_DMA_DIR_IN:
|
||||
if (READ_PERI_REG(SPI_IN_SUC_EOF_DES_ADDR_REG(obj->spi_num)) == ((uint32_t)obj->buf->ping->last_queue)) {
|
||||
return obj->buf->ping->buffer_addr;
|
||||
} else if (READ_PERI_REG(SPI_IN_SUC_EOF_DES_ADDR_REG(obj->spi_num)) == ((uint32_t)obj->buf->pong->last_queue)) {
|
||||
return obj->buf->pong->buffer_addr;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configrate the Ping-Pong buffer to the destination
|
||||
*
|
||||
*/
|
||||
void spi_dma_dest_add_set(spi_dma_attr_t *obj)
|
||||
{
|
||||
if ((NULL == obj)
|
||||
|| (obj->spi_num > SPI_NUM_MAX)) {
|
||||
return;
|
||||
}
|
||||
if (SPI_DMA_DIR_IN == obj->dir) {
|
||||
SET_PERI_REG_BITS(SPI_DMA_IN_LINK_REG(obj->spi_num), SPI_INLINK_ADDR, ((uint32_t)(obj->buf->ping->first_queue)), SPI_INLINK_ADDR_S);
|
||||
} else if (SPI_DMA_DIR_OUT == obj->dir) {
|
||||
SET_PERI_REG_BITS(SPI_DMA_OUT_LINK_REG(obj->spi_num), SPI_OUTLINK_ADDR, ((uint32_t)(obj->buf->ping->first_queue)), SPI_OUTLINK_ADDR_S);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reset SPI ping buffer address.
|
||||
*
|
||||
*/
|
||||
void spi_dma_rest(spi_dma_attr_t *obj)
|
||||
{
|
||||
if ((NULL == obj)
|
||||
|| (obj->spi_num > SPI_NUM_MAX)) {
|
||||
return;
|
||||
}
|
||||
dma_buf_len_reset(obj->buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialize DMA and create a SPI DMA instance.
|
||||
*
|
||||
*/
|
||||
int spi_dma_init(spi_dma_attr_t *obj, void *isr)
|
||||
{
|
||||
if ((NULL == obj)
|
||||
|| (obj->spi_num > SPI_NUM_MAX)) {
|
||||
return -1;
|
||||
}
|
||||
obj->buf = dma_buf_create(obj->buf_size);
|
||||
if (NULL == obj->buf) {
|
||||
return -2;
|
||||
}
|
||||
// Reset DMA
|
||||
SET_PERI_REG_MASK(SPI_DMA_CONF_REG(obj->spi_num), SPI_OUT_RST | SPI_AHBM_RST | SPI_AHBM_FIFO_RST);
|
||||
CLEAR_PERI_REG_MASK(SPI_DMA_OUT_LINK_REG(obj->spi_num), SPI_OUTLINK_START);
|
||||
CLEAR_PERI_REG_MASK(SPI_DMA_IN_LINK_REG(obj->spi_num), SPI_INLINK_START);
|
||||
CLEAR_PERI_REG_MASK(SPI_DMA_CONF_REG(obj->spi_num), SPI_OUT_RST | SPI_AHBM_RST | SPI_AHBM_FIFO_RST);
|
||||
|
||||
// Select DMA channel.
|
||||
SET_PERI_REG_BITS(DPORT_SPI_DMA_CHAN_SEL_REG, 3, obj->channel, ((obj->spi_num - 1) * 2));
|
||||
|
||||
SET_PERI_REG_MASK(SPI_USER_REG(obj->spi_num), SPI_USR_MOSI);//////add
|
||||
if ((SPI_MODE_MASTER == obj->mode)) {
|
||||
// enable send intr
|
||||
SET_PERI_REG_MASK(SPI_DMA_INT_ENA_REG(obj->spi_num ), SPI_INT_SRC_ONE_BUF_SEND_DONE);
|
||||
SET_PERI_REG_MASK(SPI_DMA_INT_ENA_REG(obj->spi_num ), SPI_INT_SRC_ONE_BUF_RECV_DONE);
|
||||
|
||||
} else if ((SPI_MODE_SLAVE == obj->mode)) {
|
||||
SET_PERI_REG_MASK(SPI_SLV_RDBUF_DLEN_REG(obj->spi_num), ((obj->buf_size << 3) - 1));
|
||||
SET_PERI_REG_MASK(SPI_SLV_WRBUF_DLEN_REG(obj->spi_num), ((obj->buf_size << 3) - 1));
|
||||
// enable receive intr
|
||||
SET_PERI_REG_MASK(SPI_DMA_INT_ENA_REG(obj->spi_num), SPI_INT_SRC_ONE_BUF_RECV_DONE);
|
||||
}
|
||||
// Clear all of interrupt source
|
||||
spi_int_clear(obj->spi_num);
|
||||
|
||||
spi_intr_func_set(isr, obj->spi_num);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Destroy the SPI DMA instance
|
||||
*
|
||||
*/
|
||||
int spi_dma_uninit(spi_dma_attr_t *obj)
|
||||
{
|
||||
if (NULL == obj) {
|
||||
return -1;
|
||||
}
|
||||
dma_buf_destroy(obj->buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable the SPI DMA work mode.
|
||||
*
|
||||
*/
|
||||
static void spi_dma_enable(spi_dma_attr_t *obj)
|
||||
{
|
||||
if ((NULL == obj)
|
||||
|| (obj->spi_num > SPI_NUM_MAX)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (SPI_DMA_DIR_IN == obj->dir) {
|
||||
WRITE_PERI_REG(0x3ff000c4,1<<22);
|
||||
WRITE_PERI_REG(0x3ff000c4,0);
|
||||
SET_PERI_REG_MASK(SPI_DMA_OUT_LINK_REG(obj->spi_num), SPI_OUTLINK_START);
|
||||
SET_PERI_REG_MASK(SPI_DMA_IN_LINK_REG(obj->spi_num), SPI_INLINK_START);
|
||||
// LOGD("recv-01:length=%x",READ_PERI_REG(SPI_DMA_TSTATUS_REG(obj->spi_num))>>18);
|
||||
// while (((READ_PERI_REG(SPI_DMA_TSTATUS_REG(obj->spi_num))>>18)&0x3)!=0x3){
|
||||
//LOGD("recv-01:length=%x",READ_PERI_REG(SPI_DMA_TSTATUS_REG(obj->spi_num))>>18);
|
||||
// }
|
||||
} else if (SPI_DMA_DIR_OUT == obj->dir) {
|
||||
SET_PERI_REG_MASK(SPI_DMA_IN_LINK_REG(obj->spi_num), SPI_INLINK_START);
|
||||
SET_PERI_REG_MASK(SPI_DMA_OUT_LINK_REG(obj->spi_num), SPI_OUTLINK_START);
|
||||
// Waiting DMA controller fill TX FIFO
|
||||
while ((READ_PERI_REG(SPI_DMA_RSTATUS_REG(obj->spi_num))&0x80000000));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable the SPI DMA work mode.
|
||||
*
|
||||
*/
|
||||
static void spi_dma_disable(spi_dma_attr_t *obj)
|
||||
{
|
||||
if ((NULL == obj)
|
||||
|| (obj->spi_num > SPI_NUM_MAX)) {
|
||||
return;
|
||||
}
|
||||
if (SPI_DMA_DIR_IN == obj->dir) {
|
||||
CLEAR_PERI_REG_MASK(SPI_DMA_IN_LINK_REG(obj->spi_num), SPI_INLINK_STOP);
|
||||
} else if (SPI_DMA_DIR_OUT == obj->dir) {
|
||||
CLEAR_PERI_REG_MASK(SPI_DMA_OUT_LINK_REG(obj->spi_num), SPI_OUTLINK_STOP);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable SPI DMA interrupt source.
|
||||
*
|
||||
*/
|
||||
void spi_dma_int_enable(spi_num_t spiNum, spi_int_src_t intSrc)
|
||||
{
|
||||
if (spiNum > SPI_NUM_MAX) {
|
||||
return;
|
||||
}
|
||||
SET_PERI_REG_MASK(SPI_DMA_INT_ENA_REG(spiNum), intSrc);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable SPI DMA interrupt source.
|
||||
*
|
||||
*/
|
||||
void spi_dma_int_disable(spi_num_t spiNum, spi_int_src_t intSrc)
|
||||
{
|
||||
if (spiNum > SPI_NUM_MAX) {
|
||||
return;
|
||||
}
|
||||
SET_PERI_REG_MASK(SPI_DMA_INT_ENA_REG(spiNum), intSrc);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clear all of SPI DMA interrupt source.
|
||||
*
|
||||
*/
|
||||
void spi_dma_int_clear(spi_num_t spiNum)
|
||||
{
|
||||
if (spiNum > SPI_NUM_MAX) {
|
||||
return;
|
||||
}
|
||||
SET_PERI_REG_MASK(SPI_DMA_INT_CLR_REG(spiNum), 0x1FF);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the SPI DMA interrupt status.
|
||||
*
|
||||
*/
|
||||
int32_t spi_dma_int_status_get(spi_num_t spiNum)
|
||||
{
|
||||
if (spiNum > SPI_NUM_MAX) {
|
||||
return -1;
|
||||
}
|
||||
return READ_PERI_REG(SPI_DMA_INT_ST_REG(spiNum));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Start SPI work by DMA
|
||||
*
|
||||
*/
|
||||
void spi_dma_start(spi_dma_attr_t *obj, uint32_t len)
|
||||
{
|
||||
if ((NULL == obj)
|
||||
|| (obj->spi_num > SPI_NUM_MAX)) {
|
||||
return;
|
||||
}
|
||||
// Reset DMA controller
|
||||
|
||||
SET_PERI_REG_MASK(SPI_DMA_CONF_REG(obj->spi_num), SPI_OUT_RST | SPI_IN_RST | SPI_AHBM_RST | SPI_AHBM_FIFO_RST);
|
||||
CLEAR_PERI_REG_MASK(SPI_DMA_CONF_REG(obj->spi_num), SPI_OUT_RST | SPI_IN_RST | SPI_AHBM_RST | SPI_AHBM_FIFO_RST);
|
||||
|
||||
if (SPI_MODE_MASTER == obj->mode) {
|
||||
CLEAR_PERI_REG_MASK(SPI_DMA_CONF_REG(obj->spi_num), SPI_DMA_CONTINUE);
|
||||
if (obj->dir == SPI_DMA_DIR_IN) {
|
||||
SET_PERI_REG_BITS(SPI_MISO_DLEN_REG(obj->spi_num), SPI_USR_MISO_DBITLEN, ((len << 3) - 1), SPI_USR_MISO_DBITLEN_S);
|
||||
SET_PERI_REG_BITS(SPI_MOSI_DLEN_REG(obj->spi_num), SPI_USR_MOSI_DBITLEN, ((len << 3) - 1), SPI_USR_MOSI_DBITLEN_S);
|
||||
}else{
|
||||
SET_PERI_REG_BITS(SPI_MISO_DLEN_REG(obj->spi_num), SPI_USR_MISO_DBITLEN, ((len << 3) - 1), SPI_USR_MISO_DBITLEN_S);
|
||||
SET_PERI_REG_BITS(SPI_MOSI_DLEN_REG(obj->spi_num), SPI_USR_MOSI_DBITLEN, ((len << 3) - 1), SPI_USR_MOSI_DBITLEN_S);
|
||||
}
|
||||
} else if (SPI_MODE_SLAVE == obj->mode) {
|
||||
if (0 == len) {
|
||||
SET_PERI_REG_MASK(SPI_DMA_CONF_REG(obj->spi_num), SPI_DMA_CONTINUE);
|
||||
} else {
|
||||
CLEAR_PERI_REG_MASK(SPI_DMA_CONF_REG(obj->spi_num), SPI_DMA_CONTINUE);
|
||||
}
|
||||
}
|
||||
// 1.Enable DMA
|
||||
|
||||
|
||||
spi_dma_enable(obj);
|
||||
//LOGD("recv start before:%08x\n",obj->buf->ping->first_queue->data_length);
|
||||
|
||||
// LOGD("SPI_DMA_STATUS_REG=%x",READ_PERI_REG(SPI_DMA_STATUS_REG(obj->spi_num)));
|
||||
|
||||
// 2.Start SPI
|
||||
SET_PERI_REG_MASK(SPI_CMD_REG(obj->spi_num), SPI_USR);
|
||||
//LOGD("recv start after:%08x\n",obj->buf->ping->first_queue->data_length);
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Stop SPI work by DMA
|
||||
*
|
||||
*/
|
||||
void spi_dma_stop(spi_dma_attr_t *obj)
|
||||
{
|
||||
if ((NULL == obj)
|
||||
|| (obj->spi_num > SPI_NUM_MAX)) {
|
||||
return;
|
||||
}
|
||||
if (SPI_MODE_MASTER == obj->mode) {
|
||||
SET_PERI_REG_MASK(SPI_DMA_CONF_REG(obj->spi_num), SPI_DMA_TX_STOP);
|
||||
} else if (SPI_MODE_SLAVE == obj->mode) {
|
||||
SET_PERI_REG_MASK(SPI_DMA_CONF_REG(obj->spi_num), SPI_DMA_RX_STOP);
|
||||
}
|
||||
spi_dma_disable(obj);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Based on pAttr initialize SPI module.
|
||||
*
|
||||
*/
|
||||
void spi_init(spi_num_t spiNum, spi_attr_t* pAttr)
|
||||
{
|
||||
if ((spiNum > SPI_NUM_MAX)
|
||||
|| (NULL == pAttr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI_CLK_EN);
|
||||
CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI_RST);
|
||||
SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI_CLK_EN_1);
|
||||
CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI_RST_1);
|
||||
SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI_CLK_EN_2);
|
||||
CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI_RST_2);
|
||||
|
||||
CLEAR_PERI_REG_MASK(SPI_SLAVE_REG(spiNum), SPI_TRANS_DONE << 5);
|
||||
SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_CS_SETUP);
|
||||
// By default clear command
|
||||
CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_COMMAND);
|
||||
|
||||
// SPI_CPOL & SPI_CPHA
|
||||
switch (pAttr->sub_mode) {
|
||||
case SPI_SUBMODE_1:
|
||||
CLEAR_PERI_REG_MASK(SPI_PIN_REG(spiNum), SPI_CK_IDLE_EDGE);
|
||||
SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_CK_OUT_EDGE); // CHPA_FALLING_EDGE_SAMPLE
|
||||
break;
|
||||
case SPI_SUBMODE_2:
|
||||
SET_PERI_REG_MASK(SPI_PIN_REG(spiNum), SPI_CK_IDLE_EDGE);
|
||||
SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_CK_OUT_EDGE); // CHPA_FALLING_EDGE_SAMPLE
|
||||
break;
|
||||
case SPI_SUBMODE_3:
|
||||
SET_PERI_REG_MASK(SPI_PIN_REG(spiNum), SPI_CK_IDLE_EDGE);
|
||||
CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_CK_OUT_EDGE);
|
||||
break;
|
||||
case SPI_SUBMODE_0:
|
||||
default:
|
||||
CLEAR_PERI_REG_MASK(SPI_PIN_REG(spiNum), SPI_CK_IDLE_EDGE);
|
||||
CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_CK_OUT_EDGE);
|
||||
// To do nothing
|
||||
break;
|
||||
}
|
||||
|
||||
// SPI bit order
|
||||
if (SPI_BIT_ORDER_MSB_FIRST == pAttr->bit_order) {
|
||||
CLEAR_PERI_REG_MASK(SPI_CTRL_REG(spiNum), SPI_WR_BIT_ORDER);
|
||||
CLEAR_PERI_REG_MASK(SPI_CTRL_REG(spiNum), SPI_RD_BIT_ORDER);
|
||||
} else if (SPI_BIT_ORDER_LSB_FIRST == pAttr->bit_order) {
|
||||
SET_PERI_REG_MASK(SPI_CTRL_REG(spiNum), SPI_WR_BIT_ORDER);
|
||||
SET_PERI_REG_MASK(SPI_CTRL_REG(spiNum), SPI_RD_BIT_ORDER);
|
||||
} else {
|
||||
// To do nothing
|
||||
}
|
||||
|
||||
// SPI bit order
|
||||
if (SPI_WORK_MODE_HALF == pAttr->half_mode) {
|
||||
CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_DOUTDIN);
|
||||
} else if (SPI_WORK_MODE_FULL == pAttr->half_mode) {
|
||||
SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_DOUTDIN);
|
||||
}
|
||||
// May be not must to do.
|
||||
WRITE_PERI_REG(SPI_USER1_REG(spiNum), 0);
|
||||
// SPI mode type
|
||||
if (SPI_MODE_MASTER == pAttr->mode) {
|
||||
// SPI mode type
|
||||
SET_PERI_REG_BITS(SPI_CTRL2_REG(spiNum), SPI_MISO_DELAY_MODE, 0, SPI_MISO_DELAY_MODE_S); ////??????
|
||||
// SPI_SET_MISO_DELAY_NUM(spiNum,0);////???????
|
||||
//SET_PERI_REG_BITS(SPI_CTRL2_REG(spiNum), SPI_MISO_DELAY_NUM,0,SPI_MISO_DELAY_NUM_S);////??????
|
||||
|
||||
CLEAR_PERI_REG_MASK(SPI_SLAVE_REG(spiNum), SPI_SLAVE_MODE);
|
||||
// SPI Send buffer
|
||||
// CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MISO_HIGHPART );// By default slave send buffer C0-C7
|
||||
// SPI Speed
|
||||
if (1 < (pAttr->speed)) {
|
||||
uint8_t i, k;
|
||||
i = (pAttr->speed / 40) ? (pAttr->speed / 40) : 1;
|
||||
|
||||
k = pAttr->speed / i;
|
||||
CLEAR_PERI_REG_MASK(SPI_CLOCK_REG(spiNum), SPI_CLK_EQU_SYSCLK);
|
||||
WRITE_PERI_REG(SPI_CLOCK_REG(spiNum),
|
||||
(((i - 1) & SPI_CLKDIV_PRE) << SPI_CLKDIV_PRE_S) |
|
||||
(((k - 1) & SPI_CLKCNT_N) << SPI_CLKCNT_N_S) |
|
||||
((((k + 1) / 2 - 1) & SPI_CLKCNT_H) << SPI_CLKCNT_H_S) |
|
||||
(((k - 1) & SPI_CLKCNT_L) << SPI_CLKCNT_L_S)); //clear bit 31,set SPI clock div
|
||||
} else {
|
||||
WRITE_PERI_REG(SPI_CLOCK_REG(spiNum), SPI_CLK_EQU_SYSCLK); // 80Mhz speed
|
||||
}
|
||||
// Enable MOSI
|
||||
SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_CS_SETUP | SPI_CS_HOLD | SPI_USR_MOSI);
|
||||
|
||||
// CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_CS_HOLD);/////////////add
|
||||
SET_PERI_REG_MASK(SPI_CTRL2_REG(spiNum), ((0x4 & SPI_MISO_DELAY_NUM) << SPI_MISO_DELAY_NUM_S)); //delay num
|
||||
|
||||
} else if (SPI_MODE_SLAVE == pAttr->mode) {
|
||||
|
||||
// SPI mode type
|
||||
SET_PERI_REG_MASK(SPI_SLAVE_REG(spiNum), SPI_SLAVE_MODE);
|
||||
// SPI mode type
|
||||
SET_PERI_REG_MASK(SPI_SLAVE_REG(spiNum), SPI_SLV_WR_RD_BUF_EN);
|
||||
// SPI Send buffer
|
||||
// SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MISO_HIGHPART);// By default slave send buffer C8-C15
|
||||
|
||||
// If do not set delay cycles, slave not working,master cann't get the data.
|
||||
SET_PERI_REG_MASK(SPI_CTRL2_REG(spiNum), ((0x2 & SPI_MOSI_DELAY_NUM) << SPI_MOSI_DELAY_NUM_S)); //delay num
|
||||
// SPI Speed
|
||||
WRITE_PERI_REG(SPI_CLOCK_REG(spiNum), 0);
|
||||
|
||||
CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_CS_SETUP);/////////////add
|
||||
SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MOSI);
|
||||
|
||||
// By default format::CMD(8bits)+ADDR(8bits)+DATA(32bytes)
|
||||
// set pAttr->cmd_len bit slave recieve command length
|
||||
// set 1 bytes status buffer length
|
||||
// set pAttr->addr_len bit slave recieve read address length
|
||||
// set pAttr->addr_len bit slave recieve write address length
|
||||
// set 32 bytes slave recieve buffer length
|
||||
SET_PERI_REG_BITS(SPI_USER2_REG(spiNum), SPI_USR_COMMAND_BITLEN,
|
||||
(7), SPI_USR_COMMAND_BITLEN_S);
|
||||
SET_PERI_REG_BITS(SPI_SLAVE1_REG(spiNum), SPI_SLV_STATUS_BITLEN,
|
||||
(7), SPI_SLV_STATUS_BITLEN_S);
|
||||
SET_PERI_REG_BITS(SPI_SLAVE1_REG(spiNum), SPI_SLV_WR_ADDR_BITLEN,
|
||||
(7), SPI_SLV_WR_ADDR_BITLEN_S);
|
||||
SET_PERI_REG_BITS(SPI_SLAVE1_REG(spiNum), SPI_SLV_RD_ADDR_BITLEN,
|
||||
(7), SPI_SLV_RD_ADDR_BITLEN_S);
|
||||
SET_PERI_REG_BITS(SPI_SLV_WRBUF_DLEN_REG(spiNum), SPI_SLV_WRBUF_DBITLEN,
|
||||
(32 * 8 - 1), SPI_SLV_WRBUF_DBITLEN_S);
|
||||
SET_PERI_REG_BITS(SPI_SLV_RDBUF_DLEN_REG(spiNum), SPI_SLV_RDBUF_DBITLEN,
|
||||
(32 * 8 - 1), SPI_SLV_RDBUF_DBITLEN_S);
|
||||
} else {
|
||||
// To do nothing
|
||||
}
|
||||
|
||||
char i;
|
||||
for (i = 0; i < 16; ++i) {
|
||||
WRITE_PERI_REG((SPI_W0_REG(spiNum) + (i << 2)), 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set address value by master mode.
|
||||
*
|
||||
*/
|
||||
void spi_master_cfg_addr(spi_num_t spiNum, uint32_t addr)
|
||||
{
|
||||
if (spiNum > SPI_NUM_MAX) {
|
||||
return;
|
||||
}
|
||||
// Set address
|
||||
SET_PERI_REG_BITS(SPI_ADDR_REG(spiNum), SPI_USR_ADDR_VALUE, addr, SPI_USR_ADDR_VALUE_S);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set command value by master mode.
|
||||
*
|
||||
*/
|
||||
void spi_master_cfg_cmd(spi_num_t spiNum, uint32_t cmd)
|
||||
{
|
||||
if (spiNum > SPI_NUM_MAX) {
|
||||
return;
|
||||
}
|
||||
// SPI_USER2 bit28-31 is cmd length,cmd bit length is value(0-15)+1,
|
||||
// bit15-0 is cmd value.
|
||||
SET_PERI_REG_BITS(SPI_USER2_REG(spiNum), SPI_USR_COMMAND_VALUE, cmd, SPI_USR_COMMAND_VALUE_S);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Send data to slave.
|
||||
*
|
||||
*/
|
||||
int spi_master_send_data(spi_num_t spiNum, spi_data_t* pInData)
|
||||
{
|
||||
char idx = 0;
|
||||
if ((spiNum > SPI_NUM_MAX)
|
||||
|| (NULL == pInData)
|
||||
|| (64 < pInData->tx_data_len)) {
|
||||
return -1;
|
||||
}
|
||||
uint32_t *value = pInData->tx_data;
|
||||
while (READ_PERI_REG(SPI_CMD_REG(spiNum))&SPI_USR);
|
||||
// Set command by user.
|
||||
if (pInData->cmd_len != 0) {
|
||||
// Max command length 16 bits.
|
||||
SET_PERI_REG_BITS(SPI_USER2_REG(spiNum), SPI_USR_COMMAND_BITLEN,
|
||||
((pInData->cmd_len << 3) - 1), SPI_USR_COMMAND_BITLEN_S);
|
||||
// Enable command
|
||||
SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_COMMAND);
|
||||
// Load command
|
||||
spi_master_cfg_cmd(spiNum, pInData->cmd);
|
||||
} else {
|
||||
CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_COMMAND);
|
||||
SET_PERI_REG_BITS(SPI_USER2_REG(spiNum), SPI_USR_COMMAND_BITLEN,
|
||||
0, SPI_USR_COMMAND_BITLEN_S);
|
||||
}
|
||||
// Set Address by user.
|
||||
if (pInData->addr_len == 0) {
|
||||
CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_ADDR);
|
||||
SET_PERI_REG_BITS(SPI_USER1_REG(spiNum), SPI_USR_ADDR_BITLEN,
|
||||
0, SPI_USR_ADDR_BITLEN_S);
|
||||
} else {
|
||||
if (NULL == pInData->addr) {
|
||||
return -1;
|
||||
}
|
||||
SET_PERI_REG_BITS(SPI_USER1_REG(spiNum), SPI_USR_ADDR_BITLEN,
|
||||
((pInData->addr_len << 3) - 1), SPI_USR_ADDR_BITLEN_S);
|
||||
// Enable address
|
||||
SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_ADDR);
|
||||
// Load address
|
||||
spi_master_cfg_addr(spiNum, *pInData->addr);
|
||||
}
|
||||
// Set data by user.
|
||||
if (pInData->tx_data_len != 0) {
|
||||
if (NULL == value) {
|
||||
return -1;
|
||||
}
|
||||
CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MISO);
|
||||
// Enable MOSI
|
||||
SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MOSI);
|
||||
// Load send buffer
|
||||
do {
|
||||
WRITE_PERI_REG((SPI_W0_REG(spiNum) + (idx << 2)), *value++);
|
||||
} while (++idx < ((pInData->tx_data_len / 4) + ((pInData->tx_data_len % 4) ? 1 : 0)));
|
||||
|
||||
// Set data send buffer length.Max data length 64 bytes.
|
||||
SET_PERI_REG_BITS(SPI_MOSI_DLEN_REG(spiNum), SPI_USR_MOSI_DBITLEN, ((pInData->tx_data_len << 3) - 1), SPI_USR_MOSI_DBITLEN_S);
|
||||
|
||||
SET_PERI_REG_BITS(SPI_MISO_DLEN_REG(spiNum), SPI_USR_MISO_DBITLEN, ((pInData->rx_data_len << 3) - 1), SPI_USR_MISO_DBITLEN_S);
|
||||
} else {
|
||||
CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MOSI);
|
||||
CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MISO);
|
||||
SET_PERI_REG_BITS(SPI_MOSI_DLEN_REG(spiNum), SPI_USR_MOSI_DBITLEN,
|
||||
0, SPI_USR_MOSI_DBITLEN_S);
|
||||
|
||||
}
|
||||
// Start send data
|
||||
SET_PERI_REG_MASK(SPI_CMD_REG(spiNum), SPI_USR);
|
||||
while (!(READ_PERI_REG(SPI_SLAVE_REG(spiNum))&SPI_TRANS_DONE));
|
||||
CLEAR_PERI_REG_MASK(SPI_SLAVE_REG(spiNum), SPI_TRANS_DONE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Receive data from slave.
|
||||
*
|
||||
*/
|
||||
int spi_master_recv_data(spi_num_t spiNum, spi_data_t* pData)
|
||||
{
|
||||
char idx = 0;
|
||||
if ((spiNum > SPI_NUM_MAX)
|
||||
|| (NULL == pData)) {
|
||||
return -1;
|
||||
}
|
||||
uint32_t *value = pData->rx_data;
|
||||
while (READ_PERI_REG(SPI_CMD_REG(spiNum))&SPI_USR);
|
||||
// Set command by user.
|
||||
if (pData->cmd_len != 0) {
|
||||
// Max command length 16 bits.
|
||||
SET_PERI_REG_BITS(SPI_USER2_REG(spiNum), SPI_USR_COMMAND_BITLEN,
|
||||
((pData->cmd_len << 3) - 1), SPI_USR_COMMAND_BITLEN_S);
|
||||
// Enable command
|
||||
SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_COMMAND);
|
||||
// Load command
|
||||
spi_master_cfg_cmd(spiNum, pData->cmd);
|
||||
} else {
|
||||
CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_COMMAND);
|
||||
SET_PERI_REG_BITS(SPI_USER2_REG(spiNum), SPI_USR_COMMAND_BITLEN,
|
||||
0, SPI_USR_COMMAND_BITLEN_S);
|
||||
}
|
||||
// Set Address by user.
|
||||
if (pData->addr_len == 0) {
|
||||
CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_ADDR);
|
||||
SET_PERI_REG_BITS(SPI_USER1_REG(spiNum), SPI_USR_ADDR_BITLEN,
|
||||
0, SPI_USR_ADDR_BITLEN_S);
|
||||
} else {
|
||||
if (NULL == pData->addr) {
|
||||
return -1;
|
||||
}
|
||||
SET_PERI_REG_BITS(SPI_USER1_REG(spiNum), SPI_USR_ADDR_BITLEN,
|
||||
((pData->addr_len << 3) - 1), SPI_USR_ADDR_BITLEN_S);
|
||||
// Enable address
|
||||
SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_ADDR);
|
||||
// Load address
|
||||
spi_master_cfg_addr(spiNum, *pData->addr);
|
||||
}
|
||||
// Set data by user.
|
||||
if (pData->rx_data_len != 0) {
|
||||
if (NULL == value) {
|
||||
return -1;
|
||||
}
|
||||
// Clear MOSI enable
|
||||
CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MOSI);
|
||||
// Enable MOSI
|
||||
SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MISO);
|
||||
// Set data send buffer length.Max data length 64 bytes.
|
||||
SET_PERI_REG_BITS(SPI_MISO_DLEN_REG(spiNum), SPI_USR_MISO_DBITLEN, ((pData->rx_data_len << 3) - 1), SPI_USR_MISO_DBITLEN_S);
|
||||
} else {
|
||||
CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MOSI);
|
||||
CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MISO);
|
||||
SET_PERI_REG_BITS(SPI_MISO_DLEN_REG(spiNum), SPI_USR_MISO_DBITLEN, 0, SPI_USR_MISO_DBITLEN_S);
|
||||
}
|
||||
// Start send data
|
||||
SET_PERI_REG_MASK(SPI_CMD_REG(spiNum), SPI_USR);
|
||||
|
||||
while (READ_PERI_REG(SPI_CMD_REG(spiNum))&SPI_USR);
|
||||
// Read data out
|
||||
do {
|
||||
*value++ = READ_PERI_REG(SPI_W0_REG(spiNum) + (idx << 2));
|
||||
} while (++idx < ((pData->rx_data_len / 4) + ((pData->rx_data_len % 4) ? 1 : 0)));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Load data to send buffer by slave mode.
|
||||
|
||||
*
|
||||
*/
|
||||
int spi_slave_send_data(spi_num_t spiNum, uint32_t *pOutData, uint8_t outLen)
|
||||
{
|
||||
if (NULL == pOutData) {
|
||||
return -1;
|
||||
}
|
||||
char i;
|
||||
uint32_t *value = pOutData;
|
||||
for (i = 0; i < outLen; ++i) {
|
||||
WRITE_PERI_REG((SPI_W0_REG(spiNum) + (i << 2)), *value++);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configurate slave prepare for receive data.
|
||||
*
|
||||
*/
|
||||
int spi_slave_recv_data(spi_num_t spiNum, void(*isrFunc)(void*))
|
||||
{
|
||||
char idx = 0;
|
||||
if (spiNum > SPI_NUM_MAX) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
spi_int_enable(spiNum, SPI_INT_SRC_WR_STA_DONE
|
||||
| SPI_INT_SRC_RD_STA_DONE | SPI_INT_SRC_WR_BUF_DONE | SPI_INT_SRC_RD_BUF_DONE);
|
||||
spi_int_disable(spiNum, SPI_INT_SRC_TRANS_DONE);
|
||||
|
||||
spi_intr_func_set(isrFunc, spiNum);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Send data to slave(ESP32,RD_STATUS or WR_STATUS).
|
||||
*
|
||||
*/
|
||||
void spi_master_send_status(spi_num_t spiNum, uint8_t data)
|
||||
{
|
||||
if (spiNum > SPI_NUM_MAX) {
|
||||
return;
|
||||
}
|
||||
while (READ_PERI_REG(SPI_CMD_REG(spiNum))&SPI_USR);
|
||||
// enable MOSI
|
||||
SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MOSI);
|
||||
CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MISO | SPI_USR_DUMMY | SPI_USR_ADDR);
|
||||
|
||||
// 8bits cmd, 0x04 is eps32 slave write cmd value
|
||||
WRITE_PERI_REG(SPI_USER2_REG(spiNum),
|
||||
((7 & SPI_USR_COMMAND_BITLEN) << SPI_USR_COMMAND_BITLEN_S)
|
||||
| MASTER_WRITE_STATUS_TO_SLAVE_CMD);
|
||||
// Set data send buffer length.
|
||||
SET_PERI_REG_BITS(SPI_MOSI_DLEN_REG(spiNum), SPI_USR_MOSI_DBITLEN,
|
||||
((sizeof(data) << 3) - 1), SPI_USR_MOSI_DBITLEN_S);
|
||||
|
||||
WRITE_PERI_REG(SPI_W0_REG(spiNum), (uint32_t)(data));
|
||||
// start SPI
|
||||
SET_PERI_REG_MASK(SPI_CMD_REG(spiNum), SPI_USR);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Receive data from slave(ESP32).
|
||||
*
|
||||
*/
|
||||
int spi_master_recv_status(spi_num_t spiNum)
|
||||
{
|
||||
if (spiNum > SPI_NUM_MAX) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (READ_PERI_REG(SPI_CMD_REG(spiNum))&SPI_USR);
|
||||
// enable MISO
|
||||
SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MISO);
|
||||
CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MOSI | SPI_USR_DUMMY | SPI_USR_ADDR);
|
||||
|
||||
// 8bits cmd, 0x06 is eps32 slave read cmd value
|
||||
WRITE_PERI_REG(SPI_USER2_REG(spiNum),
|
||||
((7 & SPI_USR_COMMAND_BITLEN) << SPI_USR_COMMAND_BITLEN_S)
|
||||
| MASTER_READ_STATUS_FROM_SLAVE_CMD);
|
||||
// Set revcive buffer length.
|
||||
SET_PERI_REG_BITS(SPI_MISO_DLEN_REG(spiNum), SPI_USR_MISO_DBITLEN,
|
||||
7, SPI_USR_MISO_DBITLEN_S);
|
||||
|
||||
// start spi module.
|
||||
SET_PERI_REG_MASK(SPI_CMD_REG(spiNum), SPI_USR);
|
||||
|
||||
while (READ_PERI_REG(SPI_CMD_REG(spiNum))&SPI_USR);
|
||||
|
||||
uint8_t data = (uint8_t)(READ_PERI_REG(SPI_W0_REG(spiNum)) & 0xff);
|
||||
return (uint8_t)(READ_PERI_REG(SPI_W0_REG(spiNum)) & 0xff);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Enable SPI interrupt source.
|
||||
*
|
||||
*/
|
||||
void spi_int_enable(spi_num_t spiNum, spi_int_src_t intSrc)
|
||||
{
|
||||
if (spiNum > SPI_NUM_MAX) {
|
||||
return;
|
||||
}
|
||||
SET_PERI_REG_MASK(SPI_SLAVE_REG(spiNum), intSrc << 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable SPI interrupt source.
|
||||
*
|
||||
*/
|
||||
void spi_int_disable(spi_num_t spiNum, spi_int_src_t intSrc)
|
||||
{
|
||||
if (spiNum > SPI_NUM_MAX) {
|
||||
return;
|
||||
}
|
||||
CLEAR_PERI_REG_MASK(SPI_SLAVE_REG(spiNum), intSrc);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clear all of SPI interrupt source.
|
||||
*
|
||||
*/
|
||||
void spi_int_clear(spi_num_t spiNum)
|
||||
{
|
||||
if (spiNum > SPI_NUM_MAX) {
|
||||
return;
|
||||
}
|
||||
CLEAR_PERI_REG_MASK(SPI_SLAVE_REG(spiNum), SPI_INT_SRC_TRANS_DONE
|
||||
| SPI_INT_SRC_WR_STA_DONE
|
||||
| SPI_INT_SRC_RD_STA_DONE
|
||||
| SPI_INT_SRC_WR_BUF_DONE
|
||||
| SPI_INT_SRC_RD_BUF_DONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the SPI interrupt status.
|
||||
*
|
||||
*/
|
||||
int32_t spi_int_status_get(spi_num_t i2sNum)
|
||||
{
|
||||
if (i2sNum > SPI_NUM_MAX) {
|
||||
return -1;
|
||||
}
|
||||
return READ_PERI_REG(SPI_SLAVE_REG(i2sNum));
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
469
examples/09_a2dp/components/MediaHal/ES8388/ES7242.c
Normal file
469
examples/09_a2dp/components/MediaHal/ES8388/ES7242.c
Normal file
|
@ -0,0 +1,469 @@
|
|||
#include "driver/i2c.h"
|
||||
#include "esp_types.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/xtensa_api.h"
|
||||
#include "esp_err.h"
|
||||
#include "driver/i2c_soft.h"
|
||||
#include "ES7242.h"
|
||||
#include "driver/gpio.h"
|
||||
//#include "driver/gpio_sig_map.h"
|
||||
#include "rom/ets_sys.h"
|
||||
|
||||
|
||||
|
||||
#define I2C_FREQ 100000 //HZ
|
||||
#define I2C_SLAVE_DEV_ADDR 0x60
|
||||
|
||||
#define I2C_SDA_OUT_IO_NUM 21
|
||||
#define I2C_SDA_OUT_IO_SIG I2CEXT0_SDA_OUT_IDX
|
||||
#define I2C_SDA_OUT_IO_PIN GPIO_SEL_21
|
||||
|
||||
#define I2C_SCL_OUT_IO_NUM 19
|
||||
#define I2C_SCL_OUT_IO_SIG I2CEXT0_SCL_OUT_IDX
|
||||
#define I2C_SCL_OUT_IO_PIN GPIO_SEL_19
|
||||
|
||||
#define I2C_SDA_IN_IO_SIG I2CEXT0_SDA_IN_IDX
|
||||
#define I2C_SCL_IN_IO_SIG I2CEXT0_SCL_IN_IDX
|
||||
|
||||
#define ES8388_ADDR 0x20
|
||||
|
||||
#if 0
|
||||
|
||||
|
||||
void I2C_GpioInit()
|
||||
{
|
||||
#if 1
|
||||
ets_printf("Configuring GPIO...........\n");
|
||||
gpio_config_t gpio_conf;
|
||||
gpio_conf.gpio_pin_sel = I2C_SDA_OUT_IO_PIN | I2C_SCL_OUT_IO_PIN ;
|
||||
gpio_conf.gpio_mode_sel = GPIO_MODE_INPUT_OUTPUT_OD;
|
||||
gpio_conf.gpio_pulldown_sel = GPIO_PULLDOWN_DISABLE;
|
||||
gpio_conf.gpio_pullup_sel = GPIO_PULLUP_ENABLE;
|
||||
gpio_conf.gpio_intry_type_sel = GPIO_PIN_INTR_DISABLE;
|
||||
gpio_config(&gpio_conf);
|
||||
#if 0
|
||||
SET_PERI_REG_BITS(GPIO_PIN_REG_19, FUN_DRV, 3, FUN_DRV_S);
|
||||
SET_PERI_REG_BITS(GPIO_PIN_REG_23, FUN_DRV, 3, FUN_DRV_S);
|
||||
CLEAR_PERI_REG_MASK(GPIO_PIN_REG_19, FUN_PD);
|
||||
CLEAR_PERI_REG_MASK(GPIO_PIN_REG_23, FUN_PD);
|
||||
#endif
|
||||
|
||||
gpio_matrix_out(I2C_SDA_OUT_IO_NUM, I2C_SDA_OUT_IO_SIG, 0, 0);
|
||||
gpio_matrix_out(I2C_SCL_OUT_IO_NUM, I2C_SCL_OUT_IO_SIG, 0, 0);
|
||||
gpio_matrix_in(I2C_SDA_OUT_IO_NUM, I2C_SDA_IN_IO_SIG, 0);
|
||||
gpio_matrix_in(I2C_SCL_OUT_IO_NUM, I2C_SCL_IN_IO_SIG, 0);
|
||||
#else
|
||||
// SDA OUT
|
||||
gpio_matrix_out(19, I2C_SDA_OUT_IO_SIG, 0, 0);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO19_U, FUNC_GPIO19_GPIO19);
|
||||
SET_PERI_REG_MASK(PERIPHS_IO_MUX_GPIO19_U, FUN_IE | FUN_PU);
|
||||
CLEAR_PERI_REG_MASK(PERIPHS_IO_MUX_GPIO19_U, FUN_PD);
|
||||
|
||||
SET_PERI_REG_MASK(GPIO_PIN19_REG, GPIO_PIN19_PAD_DRIVER);
|
||||
//====debug====
|
||||
gpio_matrix_out(23, I2C_SCL_OUT_IO_SIG, 0, 0);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO23_U, FUNC_GPIO23_GPIO23);
|
||||
SET_PERI_REG_MASK(PERIPHS_IO_MUX_GPIO23_U, FUN_IE | FUN_PU);
|
||||
CLEAR_PERI_REG_MASK(PERIPHS_IO_MUX_GPIO23_U, FUN_PD);
|
||||
SET_PERI_REG_MASK(GPIO_PIN23_REG, GPIO_PIN23_PAD_DRIVER);
|
||||
//============================
|
||||
//SDA IN
|
||||
gpio_matrix_in(19, I2C_SDA_IN_IO_SIG, 0);
|
||||
//SCL IN
|
||||
gpio_matrix_in(23, I2C_SCL_IN_IO_SIG, 0);
|
||||
|
||||
#endif
|
||||
|
||||
ets_printf("GPIO Configured! ! ! ! ! ! ! ! ! !\n");
|
||||
}
|
||||
|
||||
|
||||
void disp_cmd(uint8_t i2c_no, uint8_t idx)
|
||||
{
|
||||
// ets_printf("---cmd %d ---\n",idx);
|
||||
|
||||
// ets_printf("opcode: %d \n",I2C_GET_COMMAND_OP_CODE(i2c_no,idx));
|
||||
// ets_printf("acken: %d \n",I2C_GET_COMMAND_ACK_EN(i2c_no,idx));
|
||||
// ets_printf("ackexp: %d \n",I2C_GET_COMMAND_ACK_EXP(i2c_no,idx));
|
||||
// ets_printf("ack val: %d \n",I2C_GET_COMMAND_ACK_VALUE(i2c_no,idx));
|
||||
// ets_printf("byte num: %d \n",I2C_GET_COMMAND_BYTE_NUM(i2c_no,idx));
|
||||
// ets_printf("done: %d \n",I2C_GET_COMMAND_DONE(i2c_no,idx));
|
||||
|
||||
}
|
||||
|
||||
|
||||
void i2c_master_read_test()
|
||||
|
||||
{
|
||||
uint8_t i2c_no = 0;
|
||||
uint8_t idx = 0;
|
||||
|
||||
uint8_t data_buf[] = {I2C_SLAVE_DEV_ADDR, //addr
|
||||
0x10,
|
||||
0x01,
|
||||
0x12,
|
||||
0x13,
|
||||
0x14,
|
||||
};
|
||||
uint8_t byte_num = 3;//sizeof(data_buf);
|
||||
|
||||
I2C_SET_TX_FIFO_RST(0, 1);
|
||||
I2C_SET_TX_FIFO_RST(0, 0);
|
||||
|
||||
//command0 : sending restart signal
|
||||
idx = 0;
|
||||
I2C_SET_COMMAND_OP_CODE(i2c_no, idx, 0);
|
||||
I2C_SET_COMMAND_ACK_EN(i2c_no, idx, 0);
|
||||
I2C_SET_COMMAND_BYTE_NUM(i2c_no, 0, 1);
|
||||
disp_cmd( i2c_no, 0);
|
||||
|
||||
//command1 : picking slave and sending data
|
||||
idx = 1;
|
||||
I2C_SET_COMMAND_ACK_EN(i2c_no, idx, 0);
|
||||
I2C_SET_COMMAND_OP_CODE(i2c_no, idx, 1); //WRITE COMMAND
|
||||
I2C_SET_COMMAND_BYTE_NUM(i2c_no, idx, byte_num); //BYTE NUMBER
|
||||
disp_cmd( i2c_no, 1);
|
||||
|
||||
//command2 : master generating stop
|
||||
idx = 2;
|
||||
I2C_SET_COMMAND_OP_CODE(i2c_no, idx, 0x3); //STOP
|
||||
I2C_SET_COMMAND_ACK_EN(i2c_no, idx, 0); //NO ACK
|
||||
disp_cmd( i2c_no, 2);
|
||||
|
||||
int i = 0;
|
||||
for (i = 0; i < byte_num; i++) {
|
||||
WRITE_PERI_REG(I2C_DATA_REG(i2c_no), data_buf[i]);
|
||||
}
|
||||
|
||||
//start sending
|
||||
I2C_SET_TRANS_START(i2c_no, 1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void I2C_MasterInit(uint8_t init_num)
|
||||
{
|
||||
|
||||
//step 1: gpio init
|
||||
I2C_GpioInit();
|
||||
#if 1
|
||||
ets_delay_us(500000);
|
||||
//step 2: i2c init
|
||||
ets_printf("Initializing I2C Master.............\r\n");
|
||||
I2C_InitTypeDef i2c_master;
|
||||
i2c_master.mode = I2C_MASTER_MODE; //master mode
|
||||
i2c_master.addr_10bit_en = 0; //not used
|
||||
i2c_master.clk_speed = 100000; //clk set
|
||||
i2c_master.slave_addr = 0x0; //no slave addr for master mode
|
||||
I2C_Init(init_num, &i2c_master);
|
||||
#else
|
||||
uint8_t i2c_no = init_num;
|
||||
if (i2c_no > 1) {
|
||||
ets_printf("invalid i2c number...\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
//set master mode
|
||||
//I2C_SET_RX_LSB_FIRST(i2c_no,0); //MSB FIRST
|
||||
//I2C_SET_TX_LSB_FIRST(i2c_no,0); //MSB FIRST
|
||||
I2C_SET_MS_MODE(i2c_no, 1); //MASTER MODE
|
||||
//I2C_SET_SCL_FORCE_OUT(i2c_no,1); //out put practical level
|
||||
//I2C_SET_SDA_FORCE_OUT(i2c_no,1); //out put practical level
|
||||
|
||||
//SET FREQ/DUTY
|
||||
I2C_SET_SCL_LOW_PERIOD(i2c_no, (APB_CLK_FREQ / I2C_FREQ) / 2);
|
||||
I2C_SET_SCL_HIGH_PERIOD(i2c_no, (APB_CLK_FREQ / I2C_FREQ) / 2);
|
||||
|
||||
//SET CLK RE/START HOLD/SETUP
|
||||
I2C_SET_SCL_START_HOLD_TIME(i2c_no, 50); //400);
|
||||
I2C_SET_SCL_RSTART_SETUP_TIME(i2c_no, 50); //400);
|
||||
|
||||
//SET CLK STOP HOLD/SETUP
|
||||
I2C_SET_SCL_STOP_HOLD_TIME(i2c_no, 50); //400);
|
||||
I2C_SET_SCL_STOP_SETUP_TIME(i2c_no, 50); //400);
|
||||
|
||||
//SET DATA I/O HOLD/SAMPLE
|
||||
I2C_SET_SDA_HOLD_TIME(i2c_no, 40);
|
||||
I2C_SET_SDA_SAMPLE_TIME(i2c_no, 40);
|
||||
|
||||
//SET CLK TIME OUT
|
||||
//I2C_SET_TIME_OUT_THRSH(i2c_no,2000);
|
||||
I2C_SET_TIME_OUT_REG(i2c_no, 2000);
|
||||
|
||||
//SET FIFO MODE
|
||||
//I2C_SET_NONFIFO_EN(i2c_no,0);
|
||||
//SET SCL FILTER
|
||||
//I2C_SET_SCL_FILTER_EN(i2c_no,1);
|
||||
//SET SDA FILTER
|
||||
//I2C_SET_SDA_FILTER_EN(i2c_no,0);
|
||||
|
||||
//i2c_intr_config();
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void i2c_send_data_test(uint8_t i2c_num, uint8_t slave_addr, uint8_t reg_addr, uint8_t data)
|
||||
{
|
||||
|
||||
|
||||
//struct I2C_DEV * I2Cx = I2C(i2c_num);
|
||||
uint8_t data_buf[] = {
|
||||
slave_addr,
|
||||
reg_addr,
|
||||
data
|
||||
};
|
||||
|
||||
uint8_t byte_num = sizeof(data_buf);
|
||||
struct I2C_CmdDef cmd;
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
|
||||
//reset tx fifo
|
||||
I2C_ResetTxFifo(i2c_num);
|
||||
|
||||
//setup command 0
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.ack_en = 0;
|
||||
cmd.ack_exp = 0;
|
||||
cmd.ack_val = 0;
|
||||
cmd.byte_num = 0;
|
||||
cmd.op_code = I2C_CMD_RESTART;
|
||||
|
||||
I2C_ConfigCmd(i2c_num, 0, &cmd);
|
||||
|
||||
disp_cmd( i2c_num, 0);
|
||||
|
||||
//setup command 1
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.ack_en = 0;
|
||||
cmd.ack_exp = 0;
|
||||
cmd.ack_val = 0;
|
||||
cmd.byte_num = byte_num;
|
||||
cmd.op_code = I2C_CMD_WRITE;
|
||||
I2C_ConfigCmd(i2c_num, 1, &cmd);
|
||||
disp_cmd( i2c_num, 1);
|
||||
|
||||
//setup command 2
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.byte_num = 0;
|
||||
cmd.op_code = I2C_CMD_STOP;
|
||||
I2C_ConfigCmd(i2c_num, 2, &cmd);
|
||||
disp_cmd( i2c_num, 2);
|
||||
|
||||
//push the sending data to tx fifo
|
||||
I2C_TxFifoPush(i2c_num, data_buf , byte_num);
|
||||
|
||||
//I2C start sending
|
||||
I2C_Start(i2c_num);
|
||||
|
||||
I2C_WaitTxDone(i2c_num, 2);
|
||||
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
void ES8388_PowerOn_Init1(void)
|
||||
{
|
||||
ES7242_WriteReg(ES8388_ADDR, 0x08, 0x00); //CODEC IN I2S SLAVE MODE -
|
||||
|
||||
ES7242_WriteReg(ES8388_ADDR, 0x00, 0x07); //PLAY BACK,ENREFR=0 //changed
|
||||
ES7242_WriteReg(ES8388_ADDR, 0x2d, 0x00); //vroi=0
|
||||
|
||||
ets_delay_us(10000);
|
||||
|
||||
ES7242_WriteReg(ES8388_ADDR, 0x01, 0x40); //pdn_ana=1,ibiasgen_pdn=0,lpvrefbuf=1
|
||||
|
||||
ets_delay_us(10000);
|
||||
|
||||
ES7242_WriteReg(ES8388_ADDR, 0x02, 0xf3); //Reset STM and DLL
|
||||
ES7242_WriteReg(ES8388_ADDR, 0x03, 0xFF); //Reset STM and DLL
|
||||
ES7242_WriteReg(ES8388_ADDR, 0x04, 0xC0); //power up L/R DAC,Enable LO1/RO1,LO2/RO2,OUT3/MONO
|
||||
|
||||
ES7242_WriteReg(ES8388_ADDR, 0x0A, 0x00); //LIN1/RIN1 as ADC Input
|
||||
ES7242_WriteReg(ES8388_ADDR, 0x0C, 0x0C); //I2S-16BIT,LADC=Left data,RADC=right data W
|
||||
ES7242_WriteReg(ES8388_ADDR, 0x0d, 0x02); //SINGLE SPEED,RATIO=256
|
||||
ES7242_WriteReg(ES8388_ADDR, 0x10, 0x00); //ADC Left Volume=0db
|
||||
ES7242_WriteReg(ES8388_ADDR, 0x11, 0x00); //ADC Right Volume=0db
|
||||
|
||||
ES7242_WriteReg(ES8388_ADDR, 0x17, 0x18); //I2S-16BIT 0x18 //PCM 16BIT 0x5E
|
||||
ES7242_WriteReg(ES8388_ADDR, 0x18, 0x02); //SINGLE SPEED,RATIO=256
|
||||
ES7242_WriteReg(ES8388_ADDR, 0x19, 0x36); //SOFT RAMP RATE=32LRCKS/STEP,Enable ZERO-CROSS CHECK,DAC MUTE
|
||||
ES7242_WriteReg(ES8388_ADDR, 0x1A, 0x00); //LDAC volume=0db,RDAC Volume=0db
|
||||
ES7242_WriteReg(ES8388_ADDR, 0x1B, 0x00);
|
||||
ES7242_WriteReg(ES8388_ADDR, 0x19, 0x32); //SOFT RAMP RATE=32LRCKS/STEP,Enable ZERO-CROSS CHECK,DAC MUTE
|
||||
ES7242_WriteReg(ES8388_ADDR, 0x27, 0xB8); //Left DAC TO Left MIXER
|
||||
ES7242_WriteReg(ES8388_ADDR, 0x28, 0x38);
|
||||
ES7242_WriteReg(ES8388_ADDR, 0x29, 0x38);
|
||||
ES7242_WriteReg(ES8388_ADDR, 0x2A, 0xB8); //RIGHT DAC TO RIGHT MIXER
|
||||
ES7242_WriteReg(ES8388_ADDR, 0x04, 0x30); //Enable DAC and Enable Lout/Rout
|
||||
ES7242_WriteReg(ES8388_ADDR, 0x2e, 0X10); //LOUT/ROUT volume
|
||||
ES7242_WriteReg(ES8388_ADDR, 0x2f, 0X10);
|
||||
|
||||
ets_delay_us(50000);
|
||||
|
||||
|
||||
ES7242_WriteReg(ES8388_ADDR, 0x2e, 0x1A); //LOUT/ROUT volume
|
||||
ES7242_WriteReg(ES8388_ADDR, 0x2f, 0x1A);
|
||||
|
||||
ES7242_WriteReg(ES8388_ADDR, 0x04, 0xc0); //Disable DAC and Lout/Rout
|
||||
}
|
||||
|
||||
void ES8388_DAC_Play1(void)
|
||||
{
|
||||
int Vol = 0x1f;
|
||||
ES7242_WriteReg(ES8388_ADDR, 0x02, 0xAA); //START DAC DLL and State Machine
|
||||
ES7242_WriteReg(ES8388_ADDR, 0x2d, 0X00); //vroi=0 DelayT0(10); //Delay 10mS
|
||||
ES7242_WriteReg(ES8388_ADDR, 0x04, 0x3C); //Enable DAC and Enable Lout/Rout
|
||||
|
||||
ets_delay_us(10000);
|
||||
|
||||
|
||||
ES7242_WriteReg(ES8388_ADDR, 0x2e, Vol); //LOUT2/ROUT2
|
||||
ES7242_WriteReg(ES8388_ADDR, 0x2f, Vol);
|
||||
ES7242_WriteReg(ES8388_ADDR, 0x30, Vol); //LOUT1/ROUT1
|
||||
ES7242_WriteReg(ES8388_ADDR, 0x31, Vol);
|
||||
|
||||
ES7242_WriteReg(ES8388_ADDR, 0x19, 0xF2); //DAC un-Mute
|
||||
ES7242_WriteReg(ES8388_ADDR, 0x01, 0x40); //LPVrefBuf=0,Pdn_ana=0
|
||||
ES7242_WriteReg(ES8388_ADDR, 0x00, 0x07); //Enfr=0,Play&Record Mode,(0x17-both of mic&paly)
|
||||
}
|
||||
|
||||
|
||||
void ES7242_Poweron_Init(void)
|
||||
{
|
||||
ets_printf("Writing Data to Registers\n");
|
||||
#if 0
|
||||
ES7242_WriteReg(ES7242_Address1, 0x00, 0x01);
|
||||
ets_delay_us(10000);
|
||||
ES7242_WriteReg(ES7242_Address1, 0x01, 0x00);
|
||||
ets_delay_us(10000);
|
||||
ES7242_WriteReg(ES7242_Address2, 0x00, 0x01);
|
||||
ets_delay_us(10000);
|
||||
ES7242_WriteReg(ES7242_Address2, 0x01, 0x00);
|
||||
ets_delay_us(10000);
|
||||
#endif
|
||||
#if 1
|
||||
ES7242_WriteReg(ES7242_Address3, 0x00, 0x01);
|
||||
ets_delay_us(10000);
|
||||
ES7242_WriteReg(ES7242_Address3, 0x01, 0x00);
|
||||
ets_delay_us(10000);
|
||||
ES7242_WriteReg(ES7242_Address4, 0x00, 0x01);
|
||||
ets_delay_us(10000);
|
||||
ES7242_WriteReg(ES7242_Address4, 0x01, 0x00);
|
||||
ets_delay_us(10000);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ES7242_ADC_Record()
|
||||
{
|
||||
|
||||
#if 0
|
||||
ES7242_WriteReg(ES7242_Address1, 0x01, 0x0F);
|
||||
ES7242_WriteReg(ES7242_Address1, 0x07, 0x00);
|
||||
ES7242_WriteReg(ES7242_Address1, 0x08, 0x11);
|
||||
ES7242_WriteReg(ES7242_Address1, 0x09, 0x00);
|
||||
|
||||
ES7242_WriteReg(ES7242_Address2, 0x01, 0x8F);
|
||||
ES7242_WriteReg(ES7242_Address2, 0x07, 0x00);
|
||||
ES7242_WriteReg(ES7242_Address2, 0x08, 0x11);
|
||||
ES7242_WriteReg(ES7242_Address2, 0x09, 0x00);
|
||||
#endif
|
||||
#if 1
|
||||
ES7242_WriteReg(ES7242_Address3, 0x01, 0x0F);
|
||||
ES7242_WriteReg(ES7242_Address3, 0x07, 0x00);
|
||||
ES7242_WriteReg(ES7242_Address3, 0x08, 0x11);
|
||||
ES7242_WriteReg(ES7242_Address3, 0x09, 0x00);
|
||||
#endif
|
||||
#if 1
|
||||
ES7242_WriteReg(ES7242_Address4, 0x01, 0x8F);
|
||||
ES7242_WriteReg(ES7242_Address4, 0x07, 0x00);
|
||||
ES7242_WriteReg(ES7242_Address4, 0x08, 0x11);
|
||||
ES7242_WriteReg(ES7242_Address4, 0x09, 0x00);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ES7242_ADC_StandBy()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
void ES7242_init(void)
|
||||
{
|
||||
//I2C_MasterInit(0x0);
|
||||
i2c_master_gpio_init();
|
||||
ES8388_PowerOn_Init1();
|
||||
ES8388_DAC_Play1();
|
||||
//ES7242_Poweron_Init();
|
||||
// ES7242_ADC_Record();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
static bool I2C_Write_Byte(uint8_t data, uint8_t iter)
|
||||
{
|
||||
if (iter == 0) {
|
||||
iter = 1;
|
||||
}
|
||||
|
||||
while (iter--) {
|
||||
i2c_master_writeByte(data);
|
||||
|
||||
if (i2c_master_getAck()) {
|
||||
i2c_master_stop();
|
||||
i2c_master_wait(500); // Wait 500us and retry.
|
||||
i2c_master_start();
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
i2c_master_stop();
|
||||
return false;
|
||||
}
|
||||
#if 1
|
||||
void ES7242_WriteReg(uint8_t slave_add, uint8_t reg_add, uint8_t data)
|
||||
{
|
||||
i2c_master_start();
|
||||
if (false == I2C_Write_Byte(slave_add, 10)) {
|
||||
ets_printf("Slave is busy, TIME OUT");
|
||||
}
|
||||
if (false == I2C_Write_Byte(reg_add, 10)) {
|
||||
ets_printf("Slave is busy, TIME OUT");
|
||||
}
|
||||
if (false == I2C_Write_Byte(data, 10)) {
|
||||
ets_printf("Slave is busy, TIME OUT");
|
||||
}
|
||||
i2c_master_stop();
|
||||
}
|
||||
#endif
|
||||
#if 0
|
||||
void ES7242_WriteReg(uint8_t slave_add, uint8_t reg_add, uint8_t data)
|
||||
{
|
||||
i2c_send_data_test(0x0, slave_add, reg_add, data);
|
||||
//ets_delay_us(10000);
|
||||
}
|
||||
#endif
|
||||
uint8_t ES7242_ReadReg(uint8_t slave_add, uint8_t reg_add, uint8_t dat)
|
||||
{
|
||||
i2c_master_start();
|
||||
if (false == I2C_Write_Byte(slave_add, 0)) {
|
||||
printf("Slave is busy, TIME OUT");
|
||||
}
|
||||
if (false == I2C_Write_Byte(reg_add, 0)) {
|
||||
printf("Slave is busy, TIME OUT");
|
||||
}
|
||||
i2c_master_start();
|
||||
i2c_master_writeByte(0x21);
|
||||
uint8_t ack = i2c_master_getAck();
|
||||
uint8_t Reve = i2c_master_readByte();
|
||||
i2c_master_setAck(1);
|
||||
i2c_master_stop();
|
||||
return Reve;
|
||||
}
|
273
examples/09_a2dp/components/MediaHal/ES8388/ES8388.c
Normal file
273
examples/09_a2dp/components/MediaHal/ES8388/ES8388.c
Normal file
|
@ -0,0 +1,273 @@
|
|||
#include "i2c_soft.h"
|
||||
#include "rom/ets_sys.h"
|
||||
#include "freertos/xtensa_api.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include <stdio.h>
|
||||
#include "ES8388.h"
|
||||
|
||||
#define ES8388_ADDR 0x22 // 0x22:CE=1;0x20:CE=0
|
||||
|
||||
static bool I2C_Write_Byte(uint8_t data, uint8_t iter);
|
||||
void ES8388_WriteReg(uint8_t slave_add, uint8_t reg_add, uint8_t data);
|
||||
uint8_t ES8388_ReadReg(uint8_t slave_add, uint8_t reg_add, uint8_t dat);
|
||||
|
||||
|
||||
void ES8388_Init(uint32_t mode, uint32_t channel, uint32_t bits, uint32_t rate)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void ES8388_Start()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void ES8388_Stop()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void ES8388_Pause()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void ES8388_Resume()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void ES8388_SetVolume()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void ES8388_SetDacChannel(int32_t channel, int32_t value)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void ES8388_SetMute(int32_t channel)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void ES8388_SetMicGain()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
void ES8388_PowerOn_Init(void)
|
||||
{
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x08, 0x00); //CODEC IN I2S SLAVE MODE -
|
||||
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x00, 0x07); //PLAY BACK,ENREFR=0 //changed
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x2d, 0x00); //vroi=0
|
||||
|
||||
vTaskDelay(1);
|
||||
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x01, 0x40); //pdn_ana=1,ibiasgen_pdn=0,lpvrefbuf=1
|
||||
|
||||
vTaskDelay(1);
|
||||
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x02, 0xf3); //Reset STM and DLL
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x03, 0xFF); //Reset STM and DLL
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x04, 0xC0); //power up L/R DAC,Enable LO1/RO1,LO2/RO2,OUT3/MONO
|
||||
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x0A, 0x00); //LIN1/RIN1 as ADC Input
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x0C, 0x0C); //I2S-16BIT,LADC=Left data,RADC=right data W
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x0d, 0x02); //SINGLE SPEED,RATIO=256
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x10, 0x00); //ADC Left Volume=0db
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x11, 0x00); //ADC Right Volume=0db
|
||||
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x17, 0x18); //I2S-16BIT
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x18, 0x02); //SINGLE SPEED,RATIO=256
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x19, 0x36); //SOFT RAMP RATE=32LRCKS/STEP,Enable ZERO-CROSS CHECK,DAC MUTE
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x1A, 0x00); //LDAC volume=0db,RDAC Volume=0db
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x1B, 0x00);
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x19, 0x32); //SOFT RAMP RATE=32LRCKS/STEP,Enable ZERO-CROSS CHECK,DAC MUTE
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x27, 0xB8); //Left DAC TO Left MIXER
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x28, 0x38);
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x29, 0x38);
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x2A, 0xB8); //RIGHT DAC TO RIGHT MIXER
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x04, 0x30); //Enable DAC and Enable Lout/Rout
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x2e, 0X10); //LOUT/ROUT volume
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x2f, 0X10);
|
||||
|
||||
vTaskDelay(5);
|
||||
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x2e, 0x1A); //LOUT/ROUT volume
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x2f, 0x1A);
|
||||
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x04, 0xc0); //Disable DAC and Lout/Rout
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ES8388_DAC_Play()
|
||||
{
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x02, 0x00); //START DAC DLL and State Machine
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x2d, 0X00); //vroi=0 DelayT0(10); //Delay 10mS
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x04, 0x3C); //Enable DAC and Enable Lout/Rout
|
||||
|
||||
vTaskDelay(1);
|
||||
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x2e, Vol); //LOUT2/ROUT2
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x2f, Vol);
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x30, Vol); //LOUT1/ROUT1
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x31, Vol);
|
||||
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x19, 0xF2); //DAC un-Mute
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x01, 0x40); //LPVrefBuf=0,Pdn_ana=0
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x00, 0x07); //Enfr=0,Play&Record Mode,(0x17-both of mic&paly)
|
||||
}
|
||||
void ES8388_ALC()
|
||||
{
|
||||
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x12, 0xf2); //ALC for Microphone
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x13, 0xb0);
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x14, 0x05);
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x15, 0x06);
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x16, 0x7b);
|
||||
|
||||
}
|
||||
void ES8388_ADC_Record()
|
||||
{
|
||||
|
||||
/*
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x08, 0x00); //Codec in I2S slave mode
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x02, 0xF3); //ADC Power-up
|
||||
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x00, 0x05); //DAC Power-DN,LOUT/ROUT disable
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x01, 0x40); //DAC Power-DN,LOUT/ROUT disable
|
||||
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x03, 0x00); //ADC Power-up
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x04, 0xC0); //DAC Power-DN,LOUT/ROUT disable
|
||||
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x09, 0x77); //Analog In PGA=24db
|
||||
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x0A, 0x00); //MIC INPUT FROM LIN1/RIN1
|
||||
// ES8388_WriteReg(0x0A,0x50); //MIC INPUT FROM LIN2/RIN2
|
||||
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x0C, 0x0C); //I2S-16BIT, leftADC-Left Channel, RightADC-Right Channel
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x0D, 0x02); //MCLK/LRCK=256
|
||||
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x10, 0x00); //ADC VOLUME = 0dB
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x10, 0x00); //ADC VOLUME = 0dB
|
||||
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x02, 0x55);
|
||||
|
||||
vTaskDelay(1); //Delay 10mS
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x01, 0x40); //pdn_ana=0,ibiasgen_pdn=0
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x00, 0x05); //置ES8350于PLAYBACK & RECORD 模式,且EnRefr=1
|
||||
ES8388_ALC();
|
||||
ES8388_ADC_StandBy();
|
||||
*/
|
||||
//unsigned int i;
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x01, 0x36); //Power down whole chip analog
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x01, 0x72); //power up whole chip analog
|
||||
//ES8388_WriteReg(ES8388_ADDR, 0x02, 0xF3); //stop STM and DLL, power down DAC&ADC vref
|
||||
//ES8388_WriteReg(ES8388_ADDR, 0x02, 0xF0); //power up DAC&ADC vref
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x2B, 0x80); //set internal ADC and DAC use the same LRCK clock, ADC LRCK as internal LRCK
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x02, 0xF3); //ADC clock is same as DAC. Use ADC MCLK as internal MCLK
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x08, 0x00); //CODEC IN I2S SLAVE MODE-0x00;master-0x80
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x04, 0xC0); //power down DAC, Disable LOUT&ROUT
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x05, 0x00); //low power setting
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x06, 0xC3);
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x0A, 0x00); //select LIN1&RIN1 as Microphone
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x0B, 0x00);
|
||||
// ES8388_WriteReg(ES8388_ADDR, 0x0C, 0x6F); //ADC 16BIT PCM & right=left
|
||||
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x0C, 0x0C); //ADC I2S-16BIT
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x0D, 0x02); //ADCLRCK = MCLK/256
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x10, 0x00); //ADC VOLUME = 0DB
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x11, 0x00);
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x09, 0x88); //MIC PGA =24DB
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x12, 0xE2); //MIC ALC SETTING
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x13, 0xC0);
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x14, 0x12);
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x15, 0x06);
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x16, 0xC3);
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x02, 0x00); //startup FSM and DLL
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x03, 0x00); //Power up ADC, Enable LIN&RIN, Power down MICBIAS, set int1lp to low power mode
|
||||
vTaskDelay(1);
|
||||
//ES8388_WriteReg(ES8388_ADDR, 0x01, 0x40); //pdn_ana=0,ibiasgen_pdn=0
|
||||
//ES8388_WriteReg(ES8388_ADDR, 0x00, 0x05); //置ES8350于PLAYBACK & RECORD 模式,且EnRefr=1
|
||||
|
||||
}
|
||||
void ES8388_ADC_StandBy()
|
||||
{
|
||||
|
||||
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x00, 0x01); //置ES8350于PLAYBACK & RECORD 模式,且EnRefr=1
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x01, 0x58); //pdn_ana=0,ibiasgen_pdn=0
|
||||
vTaskDelay(1); //Delay 10mS
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x03, 0xFF); //ADC Power-Down
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x04, 0xC0); //DAC Power-DN,LOUT/ROUT disable
|
||||
ES8388_WriteReg(ES8388_ADDR, 0x02, 0xf3); //关闭录音
|
||||
|
||||
}
|
||||
void ES8388_init(void)
|
||||
{
|
||||
i2c_master_gpio_init();
|
||||
ES8388_PowerOn_Init();
|
||||
// ES8388_ADC_Record();
|
||||
//ES8388_DAC_Play();
|
||||
|
||||
}
|
||||
|
||||
static bool I2C_Write_Byte(uint8_t data, uint8_t iter)
|
||||
{
|
||||
if (iter == 0) {
|
||||
iter = 1;
|
||||
}
|
||||
|
||||
while (iter--) {
|
||||
i2c_master_writeByte(data);
|
||||
|
||||
if (i2c_master_getAck()) {
|
||||
i2c_master_stop();
|
||||
ets_delay_us(500); // Wait 500us and retry.
|
||||
i2c_master_start();
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
i2c_master_stop();
|
||||
return false;
|
||||
}
|
||||
|
||||
void ES8388_WriteReg(uint8_t slave_add, uint8_t reg_add, uint8_t data)
|
||||
{
|
||||
i2c_master_start();
|
||||
if (false == I2C_Write_Byte(slave_add, 30)) {
|
||||
printf("Slave is busy, TIME OUT");
|
||||
}
|
||||
if (false == I2C_Write_Byte(reg_add, 30)) {
|
||||
printf("Slave is busy, TIME OUT");
|
||||
}
|
||||
if (false == I2C_Write_Byte(data, 30)) {
|
||||
printf("Slave is busy, TIME OUT");
|
||||
}
|
||||
i2c_master_stop();
|
||||
}
|
||||
|
||||
uint8_t ES8388_ReadReg(uint8_t slave_add, uint8_t reg_add, uint8_t dat)
|
||||
{
|
||||
i2c_master_start();
|
||||
if (false == I2C_Write_Byte(slave_add, 10)) {
|
||||
printf("Slave is busy, TIME OUT");
|
||||
}
|
||||
if (false == I2C_Write_Byte(reg_add, 10)) {
|
||||
printf("Slave is busy, TIME OUT");
|
||||
}
|
||||
i2c_master_start();
|
||||
i2c_master_writeByte(0x21);
|
||||
uint8_t ack = i2c_master_getAck();
|
||||
uint8_t Reve = i2c_master_readByte();
|
||||
i2c_master_setAck(1);
|
||||
i2c_master_stop();
|
||||
return Reve;
|
||||
}
|
388
examples/09_a2dp/components/MediaHal/MediaHal.c
Normal file
388
examples/09_a2dp/components/MediaHal/MediaHal.c
Normal file
|
@ -0,0 +1,388 @@
|
|||
/*
|
||||
* ESPRSSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2015 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* 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 "MediaHal.h"
|
||||
#include "audio_log.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_types.h"
|
||||
//#include "inc/Vs10xx.h"
|
||||
#include "AP80/Ap80xx.h"
|
||||
#include "EspAudioCom.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "MyString.h"
|
||||
#include "ES8388.h"
|
||||
|
||||
// 2---ES8388
|
||||
// 1---AP8048
|
||||
// 0---VS1053
|
||||
|
||||
#define PA_POINT_PWR 25 // GPIO25
|
||||
#define AP_POINT_PWR 26 // GPIO26
|
||||
|
||||
#define CODECTYPE 1
|
||||
static char* LOGPRE = "[mediaHal Err]";
|
||||
static char* LOGPRD = "[mediaHal Info]";
|
||||
|
||||
|
||||
static MediaState mediaStatus = 0;
|
||||
static uint32_t mediaVol = 50;
|
||||
|
||||
void mediaHalInit(void)
|
||||
{
|
||||
#if CODECTYPE==0
|
||||
VS_Init();
|
||||
VS_Sine_Test();
|
||||
VS_HD_Reset();
|
||||
VS_Soft_Reset();
|
||||
VS_Set_All();
|
||||
#elif CODECTYPE==1
|
||||
// AP8048 PWRKEY
|
||||
gpio_config_t io_conf;
|
||||
memset(&io_conf, 0, sizeof(io_conf));
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO26_U, FUNC_GPIO26_GPIO26);
|
||||
SET_PERI_REG_MASK(PERIPHS_IO_MUX_GPIO26_U, FUN_PU);
|
||||
|
||||
io_conf.pin_bit_mask = GPIO_SEL_26;
|
||||
io_conf.mode = GPIO_MODE_OUTPUT;
|
||||
io_conf.intr_type = GPIO_PIN_INTR_DISABLE ;
|
||||
gpio_config(&io_conf);
|
||||
gpio_set_level(AP_POINT_PWR, 0x01); // Enable the AP80 powerkey
|
||||
|
||||
// PA PWR
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO25_U, FUNC_GPIO25_GPIO25);
|
||||
SET_PERI_REG_MASK(PERIPHS_IO_MUX_GPIO25_U, FUN_PU);
|
||||
gpio_set_level(PA_POINT_PWR, 0x01);
|
||||
|
||||
apInit();
|
||||
#elif CODECTYPE==2
|
||||
ES8388_init();
|
||||
|
||||
#endif
|
||||
mediaStatus = MediaState_Initialized;
|
||||
LOGI("mediaHalInit ok");
|
||||
}
|
||||
|
||||
MediaErr mediaHalDataRead(uint8_t *dat, int *len)
|
||||
{
|
||||
if ((NULL == dat)
|
||||
/*|| (MediaState_Playing != mediaStatus)*/) {
|
||||
printf("%s,[func]%s,MediaState is not playing[%x]\r\n", LOGPRE, __func__, mediaStatus);
|
||||
return MediaErr_ParaError;
|
||||
}
|
||||
uint32_t ret = 0;
|
||||
#if CODECTYPE==0
|
||||
ret = VS_Send_MusicData(dat);
|
||||
#elif CODECTYPE==1
|
||||
ret = apMicReadData(dat, (uint16_t*)len);
|
||||
#endif
|
||||
if (ret != MediaErr_NoError) {
|
||||
printf("%s,[func]%s,Send data to codec failed,ret=%d\r\n", LOGPRE, __func__, ret);
|
||||
return MediaErr_CodecError;
|
||||
} else {
|
||||
return MediaErr_NoError;
|
||||
}
|
||||
}
|
||||
|
||||
MediaErr mediaHalDataWrite(uint8_t *dat, int len)
|
||||
{
|
||||
if ((NULL == dat)
|
||||
|| (MediaState_Playing != mediaStatus)) {
|
||||
printf("%s,[func]%s,MediaState is not playing[%x]\r\n", LOGPRE, __func__, mediaStatus);
|
||||
return MediaErr_ParaError;
|
||||
}
|
||||
uint32_t ret = 0;
|
||||
#if CODECTYPE==0
|
||||
ret = VS_Send_MusicData(dat);
|
||||
#elif CODECTYPE==1
|
||||
ret = apSendData(dat, len);
|
||||
#endif
|
||||
if (ret != MediaErr_NoError) {
|
||||
printf("%s,[func]%s,Send data to codec failed,ret=%d\r\n", LOGPRE, __func__, ret);
|
||||
return MediaErr_CodecError;
|
||||
} else {
|
||||
return MediaErr_NoError;
|
||||
}
|
||||
}
|
||||
|
||||
void mediaHalReset(void)
|
||||
{
|
||||
// VS_HD_Reset();
|
||||
//VS_Soft_Reset();
|
||||
}
|
||||
|
||||
MediaErr mediaHalPlay(EspAudioMeidaType type)
|
||||
{
|
||||
uint32_t ret = 0;
|
||||
#if CODECTYPE==0
|
||||
VS_Restart_Play(); //
|
||||
VS_Reset_DecodeTime(); //
|
||||
VS_SPI_SpeedHigh();
|
||||
#else
|
||||
if ((MediaState_Initialized == mediaStatus)
|
||||
|| (MediaState_Stoped == mediaStatus)) {
|
||||
if (EspAudioMeidaType_Aac == type) {
|
||||
ret = apPlayStart("radio", sizeof("radio"), AAC_DECODER);
|
||||
} else if (EspAudioMeidaType_Mp3 == type) {
|
||||
ret = apPlayStart("radio", sizeof("radio"), MP3_DECODER);
|
||||
} else if (EspAudioMeidaType_Wav == type) {
|
||||
ret = apPlayStart("radio", sizeof("radio"), WAV_DECODER);
|
||||
} else if (EspAudioMeidaType_Flac == type) {
|
||||
ret = apPlayStart("radio", sizeof("radio"), FLAC_DECODER);
|
||||
} else if (EspAudioMeidaType_Opus == type) {
|
||||
ret = apPlayStart("radio", sizeof("radio"), OPUS_DECODER);
|
||||
} else if (EspAudioMeidaType_Pcm == type) {
|
||||
ret = apPlayStart("radio", sizeof("radio"), PCM_DECODER);
|
||||
}
|
||||
else {
|
||||
printf("%s,[func]%s,Music type[%d] does not support\r\n", LOGPRE, __func__, type);
|
||||
}
|
||||
} else {
|
||||
apPlayResume();
|
||||
}
|
||||
|
||||
printf("%s,[func]%s, mediaStatus=%d\r\n", LOGPRD, __func__, mediaStatus);
|
||||
#endif
|
||||
mediaStatus = MediaState_Playing;
|
||||
if (ret != OK_RESPONSE) {
|
||||
printf("%s,[func]%s,ret=%d\r\n", LOGPRE, __func__, ret);
|
||||
ret = MediaErr_CodecError;
|
||||
}
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
MediaErr mediaHalPause(void)
|
||||
{
|
||||
uint32_t ret = 0;
|
||||
if (MediaState_Playing == mediaStatus) {
|
||||
apPlayPause();
|
||||
mediaStatus = MediaState_Paused;
|
||||
}
|
||||
if (ret != OK_RESPONSE) {
|
||||
printf("%s,[func]%s,ret=%d\r\n", LOGPRE, __func__, ret);
|
||||
ret = MediaErr_CodecError;
|
||||
}
|
||||
printf("%s,[func]%s,mediaStatus=%d\r\n", LOGPRD, __func__, mediaStatus);
|
||||
return ret;
|
||||
}
|
||||
|
||||
MediaErr mediaHalStop(void)
|
||||
{
|
||||
|
||||
uint32_t ret = 0;
|
||||
#if CODECTYPE==0
|
||||
VS_Cancel();
|
||||
#elif CODECTYPE==1
|
||||
|
||||
apPlayStop();
|
||||
#endif
|
||||
mediaStatus = MediaState_Stoped;
|
||||
if (ret != OK_RESPONSE) {
|
||||
printf("%s,[func]%s,ret=%d\r\n", LOGPRE, __func__, ret);
|
||||
ret = MediaErr_CodecError;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
MediaErr mediaHalVolumeSet(uint8_t value)
|
||||
{
|
||||
uint32_t ret = 0;
|
||||
uint32_t tmp = value;
|
||||
LOGD("volmue=%d", tmp);
|
||||
|
||||
#if CODECTYPE==0
|
||||
vsset.mvol = value;
|
||||
mediaVol = vsset.mvol;
|
||||
tmp = (value * 200) / 100 + 50;
|
||||
mediaVol = tmp;
|
||||
VS_Set_Vol(tmp); // when vs1053 does not init,this call will be hang.
|
||||
#elif CODECTYPE==1
|
||||
|
||||
ret = apVolSet(tmp);
|
||||
#endif
|
||||
if (ret != OK_RESPONSE) {
|
||||
printf("%s,[func]%s,ret=%d\r\n", LOGPRE, __func__, ret);
|
||||
ret = MediaErr_CodecError;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
MediaErr mediaHalMute(void)
|
||||
{
|
||||
uint32_t ret = 0;
|
||||
#if CODECTYPE==0
|
||||
VS_Set_Vol(0);
|
||||
#elif CODECTYPE==1
|
||||
|
||||
ret = apVolMuteEnable();
|
||||
#endif
|
||||
mediaVol = 0;
|
||||
if (ret != OK_RESPONSE) {
|
||||
printf("%s,[func]%s,ret=%d\r\n", LOGPRE, __func__, ret);
|
||||
ret = MediaErr_CodecError;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
MediaErr mediaHalStatusGet(MediaState *staus)
|
||||
{
|
||||
if (NULL == staus) {
|
||||
return MediaErr_ParaError;
|
||||
}
|
||||
*staus = mediaStatus;
|
||||
return MediaErr_NoError;
|
||||
}
|
||||
|
||||
void mediaHalSleep(void)
|
||||
{
|
||||
// GPIO_OUTPUT_SET(PA_POINT_PWR, 0);
|
||||
// GPIO_OUTPUT_SET(AP_POINT_PWR, 0);
|
||||
printf("%s mediaHal sleep\r\n", LOGPRE);
|
||||
}
|
||||
|
||||
void mediaHalWakeup(void)
|
||||
{
|
||||
// GPIO_OUTPUT_SET(PA_POINT_PWR, 1);
|
||||
// GPIO_OUTPUT_SET(AP_POINT_PWR, 1);
|
||||
printf("%s Codec wakeup\r\n", LOGPRE);
|
||||
}
|
||||
|
||||
MediaErr mediaHalDecodeTimeRest()
|
||||
{
|
||||
uint32_t ret = apRestDecodeTime();
|
||||
if (ret != OK_RESPONSE) {
|
||||
printf("%s,[func]%s,ret=%d\r\n", LOGPRE, __func__, ret);
|
||||
ret = MediaErr_CodecError;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
MediaErr mediaHalDecodeTimeGet(uint32_t *time)
|
||||
{
|
||||
if (NULL == time) {
|
||||
return MediaErr_ParaError;
|
||||
}
|
||||
uint32_t ret = apGetDecodeTime((DecodeTime*)time);
|
||||
if (ret != OK_RESPONSE) {
|
||||
printf("%s,[func]%s,ret=%d\r\n", LOGPRE, __func__, ret);
|
||||
ret = MediaErr_CodecError;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
MediaErr mediaHalMusicInfoGet(MusicInfo *info)
|
||||
{
|
||||
if (NULL == info) {
|
||||
return MediaErr_ParaError;
|
||||
}
|
||||
uint32_t ret = apGetInfo((SongInformation*)info);
|
||||
if (ret != OK_RESPONSE) {
|
||||
printf("%s,[func]%s,ret=%d\r\n", LOGPRE, __func__, ret);
|
||||
ret = MediaErr_CodecError;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
MediaErr mediaHalModeSet(MediaMode mode, MusicInfo* info)
|
||||
{
|
||||
MediaErr err = MediaErr_NoError;
|
||||
uint8_t ret = OK_RESPONSE;
|
||||
|
||||
|
||||
switch (mode) {
|
||||
case MediaMode_Encode:
|
||||
{
|
||||
setEnccodeInfo tmpInfo;
|
||||
memset(&tmpInfo, 0, sizeof(tmpInfo));
|
||||
ret = apSetEncodeMode();
|
||||
tmpInfo.streamDirection = 1;
|
||||
tmpInfo.numChannels = info->num_channels;
|
||||
tmpInfo.sampleRate = info->sampling_rate;
|
||||
tmpInfo.encoderType = info->stream_type; //OPUS_ENCODER;
|
||||
ret = apEncodeStart();
|
||||
ret += apSetEncodeInfo(&tmpInfo);
|
||||
LOGD("apSetEncodeInfo ret = %d %d\n", ret, tmpInfo.encoderType,
|
||||
tmpInfo.sampleRate, tmpInfo.numChannels);
|
||||
break;
|
||||
}
|
||||
case MediaMode_Decode:
|
||||
{
|
||||
setDecodeInfo tmpInfo;
|
||||
memset(&tmpInfo, 0, sizeof(tmpInfo));
|
||||
ret = apSetDecodeMode();
|
||||
tmpInfo.streamDirection = 0;
|
||||
tmpInfo.numChannels = info->num_channels;
|
||||
tmpInfo.sampleRate = info->sampling_rate;
|
||||
|
||||
ret += apSetDecodeInfo(&tmpInfo);
|
||||
LOGD("apSetDecodeInfo ret=%d\n", ret);
|
||||
|
||||
break;
|
||||
}
|
||||
case MediaMode_AuxIn:
|
||||
ret = apSetDecodeMode();
|
||||
break;
|
||||
default:
|
||||
err = MediaErr_NotSuport;
|
||||
break;
|
||||
}
|
||||
if ((ret != OK_RESPONSE) && (ERROR_OTHER!= ret)) {
|
||||
printf("%s,[func]%s,ret=%d\r\n", LOGPRE, __func__, ret);
|
||||
err = MediaErr_CodecError;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
EspAudioMeidaType checkMediaType(const char* targetUri)
|
||||
{
|
||||
EspAudioMeidaType type;
|
||||
if (EndsWith(targetUri, ".wav", 1) != 0) {
|
||||
type = EspAudioMeidaType_Wav;
|
||||
} else if (EndsWith(targetUri, ".aac", 1) != 0) {
|
||||
type = EspAudioMeidaType_Aac;
|
||||
} else if (EndsWith(targetUri, ".mp3", 1) != 0) {
|
||||
type = EspAudioMeidaType_Mp3;
|
||||
} else if (EndsWith(targetUri, ".amr", 1) != 0) {
|
||||
type = EspAudioMeidaType_Amr;
|
||||
} else if (EndsWith(targetUri, ".alac", 1) != 0) {
|
||||
type = EspAudioMeidaType_Alac;
|
||||
} else if (EndsWith(targetUri, ".flac", 1) != 0) {
|
||||
type = EspAudioMeidaType_Flac;
|
||||
} else if (EndsWith(targetUri, ".ape", 1) != 0) {
|
||||
type = EspAudioMeidaType_Ape;
|
||||
} else if (EndsWith(targetUri, ".m3u8", 1) != 0) {
|
||||
type = EspAudioMeidaType_M3u;
|
||||
} else if (EndsWith(targetUri, ".opu", 1) != 0) {
|
||||
type = EspAudioMeidaType_Opus;
|
||||
} else if (EndsWith(targetUri, ".pcm", 1) != 0) {
|
||||
type = EspAudioMeidaType_Pcm;
|
||||
} else {
|
||||
type = EspAudioMeidaType_Unknown;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
// end
|
15
examples/09_a2dp/components/MediaHal/component.mk
Normal file
15
examples/09_a2dp/components/MediaHal/component.mk
Normal file
|
@ -0,0 +1,15 @@
|
|||
#
|
||||
# Component Makefile
|
||||
#
|
||||
# This Makefile should, at the very least, just include $(SDK_PATH)/Makefile. By default,
|
||||
# this will take the sources in the src/ directory, compile them and link them into
|
||||
# lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable,
|
||||
# please read the SDK documents if you need to do this.
|
||||
#
|
||||
|
||||
COMPONENT_ADD_INCLUDEDIRS := include include/AP80 include/ES8388 include/driver \
|
||||
../misc/include
|
||||
|
||||
COMPONENT_SRCDIRS := AP80 ES8388 Driver test .
|
||||
|
||||
include $(IDF_PATH)/make/component_common.mk
|
253
examples/09_a2dp/components/MediaHal/include/AP80/Ap80xx.h
Normal file
253
examples/09_a2dp/components/MediaHal/include/AP80/Ap80xx.h
Normal file
|
@ -0,0 +1,253 @@
|
|||
/*
|
||||
* ESPRSSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2015 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP32 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.
|
||||
*
|
||||
*/
|
||||
#ifndef __AP80XX_H__
|
||||
#define __AP80XX_H__
|
||||
#include <stdint.h>
|
||||
#pragma pack (1)
|
||||
|
||||
#define CHIPTYPE 32
|
||||
|
||||
#if CHIPTYPE == 32
|
||||
#include "soc/gpio_sig_map.h"
|
||||
|
||||
#define SPIMasterSendData spi_master_send_data
|
||||
|
||||
#define HSPICLK_OUT_MUX_IDX HSPICLK_OUT_IDX
|
||||
#define SpiNum_HSPI SPI_NUM_SPI2
|
||||
|
||||
#define AP80XXENABLEDMA 1
|
||||
#define AP80XXENABLEINT 1
|
||||
#define CALLPLAYOBJ_EN 1
|
||||
|
||||
#define SPIM_STREAM_CONTROL_GET_STATUS() (gpio_get_level(GPIO_NUM_22))
|
||||
|
||||
#elif CHIPTYPE == 31
|
||||
#define SPIM_STREAM_CONTROL_GET_STATUS() (GPIO_INPUT_GET(22))
|
||||
#endif
|
||||
|
||||
#define EAU_SYNC_BYTE 'S'
|
||||
|
||||
#define EAU_COMMAND_LENGTH (1)
|
||||
#define EAU_SYNC_WORD_LENGTH (1)
|
||||
#define EAU_CRC_VALUE_LENGTH (2)
|
||||
#define EAU_RESEND_IF_CRC_ERROR (1)
|
||||
|
||||
#define EAU_SEND_DATA_LENGTH (32 * 48)
|
||||
#define EAU_SEND_FARMA_LENGTH (32)
|
||||
#define EAU_RECV_FARMA_LENGTH (32)
|
||||
|
||||
#define OK_RESPONSE (0x00)
|
||||
//Òì³£¶¨Òå
|
||||
#define ERROR_TIME_OUT (0x01)
|
||||
#define ERROR_STREAM_FULL (0x02)
|
||||
#define ERROR_CRC (0x03)
|
||||
#define ERROR_RESPONSE (0x04)
|
||||
#define ERROR_CMD (0x05)
|
||||
#define ERROR_PARAMETER (0x06)
|
||||
#define ERROR_INIT (0x07)
|
||||
#define ERROR_OTHER (0x08)
|
||||
#define ERROR_PROMODE (0x09)
|
||||
#define ERROR_DEVICE_TIME_OUT (0x0A)
|
||||
#define ERROR_START (0x0B)
|
||||
#define ERROR_DMABUSY (0x0C)
|
||||
|
||||
#define SPIDATABUFMAXLEN (64)
|
||||
|
||||
typedef uint32_t DecodeTime;
|
||||
|
||||
typedef enum _SSPP_CMD
|
||||
{
|
||||
EAU_CMD_UNKOWN = 0,
|
||||
EAU_CMD_START,
|
||||
EAU_CMD_PAUSE,
|
||||
EAU_CMD_RESUME,
|
||||
EAU_CMD_STOP,
|
||||
EAU_CMD_MUTE,
|
||||
EAU_CMD_UNMUTE,
|
||||
EAU_CMD_DATA,
|
||||
EAU_CMD_WRITE_DATA = EAU_CMD_DATA,
|
||||
EAU_CMD_VOL_SET,
|
||||
EAU_CMD_VOL_ADD,
|
||||
EAU_CMD_VOL_SUB,
|
||||
EAU_CMD_INFO_GET,
|
||||
EAU_CMD_INFO_SET,
|
||||
EAU_CMD_TIME_REST,
|
||||
EAU_CMD_TIME_GET,
|
||||
EAU_CMD_VERSION_GET,
|
||||
EAU_CMD_ENCODE_MODE,
|
||||
EAU_CMD_DECODE_MODE,
|
||||
EAU_CMD_READ_DATA,
|
||||
EAU_CMD_LIN_SWITCH,
|
||||
EAU_CMD_MIC_SWITCH,
|
||||
EAU_CMD_ENCODE_START,
|
||||
}SSPP_CMD;
|
||||
|
||||
typedef struct _MASTERCmdContext
|
||||
{
|
||||
uint8_t SyncWord;
|
||||
uint8_t Command;
|
||||
uint16_t Content;
|
||||
uint16_t CrcValue;
|
||||
}MASTERCmdContext,EAUCmdContext;
|
||||
|
||||
typedef struct _EAUCmdResponseContext
|
||||
{
|
||||
uint8_t SyncWord;
|
||||
uint8_t Command;
|
||||
uint16_t Response;
|
||||
uint16_t CrcValue;
|
||||
}EAUCmdResponseContext;
|
||||
|
||||
|
||||
typedef struct _DataContext
|
||||
{
|
||||
uint8_t SyncWord;
|
||||
uint8_t data[EAU_SEND_DATA_LENGTH+EAU_CRC_VALUE_LENGTH];
|
||||
}EAUDataContext;
|
||||
|
||||
typedef enum __EAU_CMD_RESPONSE
|
||||
{
|
||||
EAU_CMD_RESP_UNKOWN = 0,
|
||||
EAU_CMD_RESP_OKCMD,
|
||||
EAU_CMD_RESP_ERCMD,
|
||||
EAU_CMD_RESP_OKSEND,
|
||||
EAU_CMD_RESP_RESEND,
|
||||
EAU_CMD_RESP_NEXTSEND,
|
||||
EAU_CMD_RESP_INITERROR,
|
||||
EAU_CMD_RESP_STATEERROR,
|
||||
}EAU_CMD_RESPONSE;
|
||||
|
||||
/**
|
||||
* @ly Audio encoder type Ex
|
||||
*/
|
||||
typedef enum _EncoderTypeEx
|
||||
{
|
||||
OPUS_ENCODER_EX = 1, /**< OPUS encoder */
|
||||
PCM_ENCODER_EX, /**< PCM encoder */
|
||||
} EncoderTypeEx;
|
||||
|
||||
/**
|
||||
* @ly Audio Decoder Type Set
|
||||
*/
|
||||
typedef enum _DecoderType
|
||||
{
|
||||
UNKOWN_DECODER = 0, /**< Unknown decoder */
|
||||
PURE_SOFTWARE_DECODERS = 1, /**< Pure software decoders as follows */
|
||||
WAV_DECODER, /**< WAV decoder */
|
||||
FLAC_DECODER, /**< FLAC decoder */
|
||||
AAC_DECODER, /**< AAC decoder */
|
||||
AIF_DECODER, /**< AIFF and AIFC decoder */
|
||||
ALAC_DECODER, /**< ALAC and AIFC decoder */
|
||||
OPUS_DECODER, /**< OPUS decoder */
|
||||
PCM_DECODER, /**< PCM decoder */
|
||||
WITH_HARDWARE_DECODERS = 128, /**< Decoders with hardware as follows */
|
||||
MP3_DECODER, /**< MP3 decoder */
|
||||
WMA_DECODER, /**< WAM decoder */
|
||||
SBC_DECODER, /**< SBC decoder */
|
||||
} DecoderType;
|
||||
|
||||
/**
|
||||
* @ly Song Information
|
||||
*/
|
||||
typedef struct _SongInformation
|
||||
{
|
||||
int32_t stream_type; /**< Stream type, must be in @code StreamTypeSet */
|
||||
uint32_t num_channels; /**< Number of channels */
|
||||
uint32_t sampling_rate; /**< Sampling rate, unit: Hz */
|
||||
uint32_t bitrate; /**< Bit rate, unit:bps */
|
||||
uint32_t duration; /**< Total play time, unit:ms */
|
||||
uint32_t file_size; /**< Song file size in bytes . */
|
||||
uint16_t firmware_ver; /**< AP80xx firmware version . */
|
||||
uint16_t firmware_num; /**< AP80xx firmware number . */
|
||||
uint8_t Stream_buf_is_Empty; /**< Stream_buf_is_Empty . */
|
||||
uint8_t RFU; /**< RFU . */
|
||||
} SongInformation;
|
||||
|
||||
/**
|
||||
* @ly code Information
|
||||
*/
|
||||
typedef struct _setdeccodeInfo
|
||||
{
|
||||
int32_t streamDirection; /**< Stream direction */
|
||||
uint32_t numChannels; /**< Number of channels */
|
||||
uint32_t sampleRate; /**< Bit rate, unit:bps */
|
||||
uint32_t decoderType; /**< Decoder Type:OPUS,PCM */
|
||||
uint32_t frameSize; /**< opus and pcm */
|
||||
uint32_t RFU2; /**< RFU */
|
||||
uint32_t RFU3; /**< RFU */
|
||||
uint32_t RFU4; /**< RFU */
|
||||
uint32_t RFU5; /**< RFU */
|
||||
uint32_t RFU6; /**< RFU */
|
||||
uint32_t RFU7; /**< RFU */
|
||||
} setDecodeInfo;
|
||||
|
||||
/**
|
||||
* @ly encode Information
|
||||
*/
|
||||
typedef struct _set_enccode_info
|
||||
{
|
||||
int32_t streamDirection; /**< Stream direction */
|
||||
uint32_t numChannels; /**< Number of channels */
|
||||
uint32_t sampleRate; /**< Sample rate, unit:bps */
|
||||
uint32_t encoderType; /**< Encoder Type:OPUS,PCM */
|
||||
uint32_t frameSize; /**< RFU */
|
||||
uint32_t RFU2; /**< RFU */
|
||||
uint32_t RFU3; /**< RFU */
|
||||
uint32_t RFU4; /**< RFU */
|
||||
uint32_t RFU5; /**< RFU */
|
||||
uint32_t RFU6; /**< RFU */
|
||||
uint32_t RFU7; /**< RFU */
|
||||
}setEnccodeInfo;
|
||||
|
||||
//public function
|
||||
void apInit();
|
||||
uint8_t apPlayStop(void);
|
||||
uint8_t apPlayPause(void);
|
||||
uint8_t apLinSwitch(void);
|
||||
uint8_t apMicSwitch(void);
|
||||
uint8_t apPlayResume(void);
|
||||
uint8_t apEncodeStart(void);
|
||||
uint8_t apVolSet(uint16_t vol);
|
||||
uint8_t apSetEncodeMode(void);
|
||||
uint8_t apSetDecodeMode(void);
|
||||
uint8_t apVolMuteEnable(void);
|
||||
uint8_t apVolMuteDisable(void);
|
||||
uint8_t apRestDecodeTime(void);
|
||||
uint8_t apSetWaitTime(uint32_t waitTime);
|
||||
uint8_t apGetDecodeTime(DecodeTime *time);
|
||||
uint8_t apGetInfo(SongInformation *songInfo);
|
||||
uint8_t apSetDecodeInfo(setDecodeInfo *decodeInfo);
|
||||
uint8_t apSetEncodeInfo(setEnccodeInfo *encodeInfo);
|
||||
uint8_t apSendData(uint8_t *sendData, uint16_t sendLen);
|
||||
uint8_t apMicReadData(uint8_t *readData, uint16_t *readLen);
|
||||
uint8_t apPlayStart(const char *songFileName, uint8_t len, DecoderType decType);
|
||||
|
||||
//private function
|
||||
void audio_test_main();
|
||||
void mic_test();
|
||||
void audio_test_main();
|
||||
void apSetResponse(bool responseEnable);
|
||||
void printfByteS(uint8_t *indata, uint16_t len);
|
||||
|
||||
#endif // __AP80XX_H__
|
28
examples/09_a2dp/components/MediaHal/include/AP80/crc.h
Normal file
28
examples/09_a2dp/components/MediaHal/include/AP80/crc.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
/**
|
||||
**************************************************************************************
|
||||
* @file crc.h
|
||||
* @brief Calculate CRC Value
|
||||
*
|
||||
* @author Aissen Li
|
||||
* @version V1.0.0
|
||||
*
|
||||
* © Shanghai Mountain View Silicon Technology Co.,Ltd. All rights reserved.
|
||||
**************************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef __CRC_H__
|
||||
#define __CRC_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif//__cplusplus
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
uint16_t GetCRC16NBS(uint8_t* data, uint32_t length);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif//__cplusplus
|
||||
|
||||
#endif//__CRC_H__
|
27
examples/09_a2dp/components/MediaHal/include/ES8388/ES7242.h
Normal file
27
examples/09_a2dp/components/MediaHal/include/ES8388/ES7242.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
#ifndef __ES8388_H
|
||||
#define __ES8388_H
|
||||
|
||||
#include "esp_types.h"
|
||||
#include "rom/ets_sys.h"
|
||||
|
||||
#define ES7154_Address 0x00
|
||||
#define ES7242_Address1 0x20
|
||||
#define ES7242_Address2 0x22
|
||||
#define ES7242_Address3 0x24
|
||||
#define ES7242_Address4 0x26
|
||||
|
||||
void ES7242_init(void);
|
||||
void ES7242_Poweron_Init(void);
|
||||
//void ES8388_DAC_Play(void);
|
||||
//void ES8388_ALC(void);
|
||||
void ES7242_ADC_Record(void);
|
||||
void ES7242_ADC_StandBy(void);
|
||||
static bool I2C_Write_Byte(uint8_t data, uint8_t iter);
|
||||
void ES7242_WriteReg(uint8_t slave_add, uint8_t reg_add, uint8_t data);
|
||||
uint8_t ES7242_ReadReg(uint8_t slave_add, uint8_t reg_add, uint8_t dat);
|
||||
void I2C_MasterInit(uint8_t init_num);
|
||||
void i2c_master_read_test();
|
||||
|
||||
|
||||
#endif
|
||||
|
78
examples/09_a2dp/components/MediaHal/include/ES8388/ES8388.h
Normal file
78
examples/09_a2dp/components/MediaHal/include/ES8388/ES8388.h
Normal file
|
@ -0,0 +1,78 @@
|
|||
#ifndef __ES8388_H
|
||||
#define __ES8388_H
|
||||
#include "esp_types.h"
|
||||
|
||||
#define ES8388_CONTROL1 0x00
|
||||
#define ES8388_CONTROL2 0x01
|
||||
|
||||
#define ES8388_CHIPPOWER 0x02
|
||||
|
||||
#define ES8388_ADCPOWER 0x03
|
||||
#define ES8388_DACPOWER 0x04
|
||||
|
||||
#define ES8388_CHIPLOPOW1 0x05
|
||||
#define ES8388_CHIPLOPOW2 0x06
|
||||
|
||||
#define ES8388_ANAVOLMANAG 0x07
|
||||
|
||||
#define ES8388_MASTERMODE 0x08
|
||||
|
||||
#define ES8388_ADCCONTROL1 0x09
|
||||
#define ES8388_ADCCONTROL2 0x0a
|
||||
#define ES8388_ADCCONTROL3 0x0b
|
||||
#define ES8388_ADCCONTROL4 0x0c
|
||||
#define ES8388_ADCCONTROL5 0x0d
|
||||
#define ES8388_ADCCONTROL6 0x0e
|
||||
#define ES8388_ADCCONTROL7 0x0f
|
||||
#define ES8388_ADCCONTROL8 0x10
|
||||
#define ES8388_ADCCONTROL9 0x11
|
||||
#define ES8388_ADCCONTROL10 0x12
|
||||
#define ES8388_ADCCONTROL11 0x13
|
||||
#define ES8388_ADCCONTROL12 0x14
|
||||
#define ES8388_ADCCONTROL13 0x15
|
||||
#define ES8388_ADCCONTROL14 0x16
|
||||
|
||||
#define ES8388_DACCONTROL1 0x17
|
||||
#define ES8388_DACCONTROL2 0x18
|
||||
#define ES8388_DACCONTROL3 0x19
|
||||
#define ES8388_DACCONTROL4 0x1a
|
||||
#define ES8388_DACCONTROL5 0x1b
|
||||
#define ES8388_DACCONTROL6 0x1c
|
||||
#define ES8388_DACCONTROL7 0x1d
|
||||
#define ES8388_DACCONTROL8 0x1e
|
||||
#define ES8388_DACCONTROL9 0x1f
|
||||
#define ES8388_DACCONTROL10 0x20
|
||||
#define ES8388_DACCONTROL11 0x21
|
||||
#define ES8388_DACCONTROL12 0x22
|
||||
#define ES8388_DACCONTROL13 0x23
|
||||
#define ES8388_DACCONTROL14 0x24
|
||||
#define ES8388_DACCONTROL15 0x25
|
||||
#define ES8388_DACCONTROL16 0x26
|
||||
#define ES8388_DACCONTROL17 0x27
|
||||
#define ES8388_DACCONTROL18 0x28
|
||||
#define ES8388_DACCONTROL19 0x29
|
||||
#define ES8388_DACCONTROL20 0x2a
|
||||
#define ES8388_DACCONTROL21 0x2b
|
||||
#define ES8388_DACCONTROL22 0x2c
|
||||
#define ES8388_DACCONTROL23 0x2d
|
||||
#define ES8388_DACCONTROL24 0x2e
|
||||
#define ES8388_DACCONTROL25 0x2f
|
||||
#define ES8388_DACCONTROL26 0x30
|
||||
#define ES8388_DACCONTROL27 0x31
|
||||
#define ES8388_DACCONTROL28 0x32
|
||||
#define ES8388_DACCONTROL29 0x33
|
||||
#define ES8388_DACCONTROL30 0x34
|
||||
|
||||
#define Vol 0x0F
|
||||
|
||||
|
||||
void ES8388_init(void);
|
||||
void ES8388_PowerOn_Init(void);
|
||||
void ES8388_DAC_Play(void);
|
||||
void ES8388_ALC(void);
|
||||
void ES8388_ADC_Record(void);
|
||||
void ES8388_ADC_StandBy(void);
|
||||
|
||||
|
||||
#endif
|
||||
|
130
examples/09_a2dp/components/MediaHal/include/MediaHal.h
Normal file
130
examples/09_a2dp/components/MediaHal/include/MediaHal.h
Normal file
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
* ESPRSSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2016 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP32 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.
|
||||
*
|
||||
*/
|
||||
#ifndef __MEDIAHAL_H__
|
||||
#define __MEDIAHAL_H__
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Make sure all of the definitions in this header have a C binding.
|
||||
//
|
||||
//*****************************************************************************
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#define AP_POINT_PWR 26 // GPIO26 AP8048
|
||||
#define PA_POINT_PWR 25 // GPIO25
|
||||
|
||||
typedef enum {
|
||||
MediaState_Initialized = 0, /* codec is initialized */
|
||||
MediaState_Stoped, /* codec is stoped */
|
||||
MediaState_Transit, /* codec is busy in a transition */
|
||||
MediaState_Playing, /* codec is currently playing */
|
||||
MediaState_Paused, /* codec is in the paused state for playback */
|
||||
MediaState_Ended, /* codec finished decoding media, media has stopped without user request. */
|
||||
MediaState_Error, /* codec was given a URI that could not be played */
|
||||
|
||||
MediaState_Unknow /* unknown playstate */
|
||||
}MediaState;
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
EspAudioMeidaType_Unknown = 0,
|
||||
EspAudioMeidaType_Wav,
|
||||
EspAudioMeidaType_Aac,
|
||||
EspAudioMeidaType_Mp3,
|
||||
EspAudioMeidaType_Amr,
|
||||
EspAudioMeidaType_Alac,
|
||||
EspAudioMeidaType_Flac,
|
||||
EspAudioMeidaType_Ape,
|
||||
EspAudioMeidaType_M3u,
|
||||
EspAudioMeidaType_Opus,
|
||||
EspAudioMeidaType_Pcm,
|
||||
EspAudioMeidaType_Max,
|
||||
}EspAudioMeidaType;
|
||||
|
||||
|
||||
typedef enum {
|
||||
MediaErr_NoError = 0,
|
||||
MediaErr_ParaError,
|
||||
MediaErr_CodecInitFailed,
|
||||
MediaErr_CodecError,
|
||||
MediaErr_NotSuport,
|
||||
} MediaErr;
|
||||
|
||||
typedef enum {
|
||||
MediaMode_Decode = 0,
|
||||
MediaMode_Encode = 1,
|
||||
MediaMode_AuxIn = 2,
|
||||
MediaMode_Max = 3,
|
||||
} MediaMode;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int32_t stream_type; /**< Stream type, must be in @code StreamTypeSet */
|
||||
uint32_t num_channels; /**< Number of channels */
|
||||
uint32_t sampling_rate; /**< Sampling rate, unit: Hz */
|
||||
uint32_t bitrate; /**< Bit rate, unit:bps */
|
||||
uint32_t duration; /**< Total play time, unit:ms */
|
||||
uint32_t file_size; /**< Song file size in bytes . */
|
||||
uint16_t firmware_ver; /**< AP80xx firmware version . */
|
||||
uint16_t firmware_num; /**< AP80xx firmware number . */
|
||||
uint8_t bufEmpty; /**< Stream_buf_is_Empty . */
|
||||
uint8_t RFU; /**< RFU . */
|
||||
|
||||
} MusicInfo;
|
||||
|
||||
void mediaHalInit();
|
||||
MediaErr mediaHalDataWrite(uint8_t *dat, int len);
|
||||
MediaErr mediaHalDataRead(uint8_t *dat, int *len);
|
||||
|
||||
MediaErr mediaHalPlay(EspAudioMeidaType type);
|
||||
MediaErr mediaHalPause(void);
|
||||
MediaErr mediaHalStop(void);
|
||||
void mediaHalReset(void);
|
||||
MediaErr mediaHalVolumeSet(uint8_t value);
|
||||
MediaErr mediaHalMute(void);
|
||||
MediaErr mediaHalStatusGet(MediaState *staus);
|
||||
void mediaHalSleep(void);
|
||||
void mediaHalWakeup(void);
|
||||
MediaErr mediaHalModeSet(MediaMode mode, MusicInfo* info);
|
||||
|
||||
|
||||
MediaErr mediaHalDecodeTimeRest(void);
|
||||
MediaErr mediaHalDecodeTimeGet(uint32_t *time);
|
||||
MediaErr mediaHalMusicInfoGet(MusicInfo *info);
|
||||
|
||||
EspAudioMeidaType checkMediaType(const char* targetUri);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // __MEDIAHAL_H__
|
127
examples/09_a2dp/components/MediaHal/include/driver/dma.h
Normal file
127
examples/09_a2dp/components/MediaHal/include/driver/dma.h
Normal file
|
@ -0,0 +1,127 @@
|
|||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef _DRIVER_DMA_H_
|
||||
#define _DRIVER_DMA_H__
|
||||
#include <esp_types.h>
|
||||
|
||||
#include "esp_err.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** \defgroup Driver_APIs Driver APIs
|
||||
* @brief Driver APIs
|
||||
*/
|
||||
|
||||
/** @addtogroup Driver_APIs
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief DMA queue description.
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t block_size: 12;
|
||||
uint32_t data_length: 12;
|
||||
uint32_t unused: 5;
|
||||
uint32_t sub_sof: 1;
|
||||
uint32_t eof: 1;
|
||||
uint32_t owner: 1;
|
||||
uint32_t buf_ptr;
|
||||
uint32_t next_link_ptr;
|
||||
} dma_queue_t;
|
||||
|
||||
/**
|
||||
* @brief DMA element description
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t *buffer_addr;
|
||||
dma_queue_t *first_queue;
|
||||
dma_queue_t *last_queue;
|
||||
dma_queue_t backup_queue;
|
||||
} dma_element_t;
|
||||
|
||||
/**
|
||||
* @brief DMA ping-pong buffer object description
|
||||
*/
|
||||
typedef struct {
|
||||
dma_element_t *ping;
|
||||
dma_element_t *pong;
|
||||
uint32_t len;
|
||||
uint32_t queue_cnt;
|
||||
} ping_pong_buf_t;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Create a ping-pong buffer object used by DMA.
|
||||
*
|
||||
* @param [in] bufLen
|
||||
* Set the buffer length.
|
||||
* --------------------
|
||||
* | ping | Pong |
|
||||
* --------------------
|
||||
* | bufLen | bufLen |
|
||||
* --------------------
|
||||
*
|
||||
* @return uint32*, NULL:indicates parameter error, others indicates ping-pong buffer address.
|
||||
*/
|
||||
ping_pong_buf_t* dma_buf_create(uint32_t bufLen);
|
||||
|
||||
/**
|
||||
* @brief Reset the dma buffer length.
|
||||
*
|
||||
* @param [in] obj
|
||||
* Pointer to a struct ping_pong_buf_t that indicates the object length to be reset to bufLen.
|
||||
*
|
||||
* @return uint32*, ESP_FAIL:indicates parameter error, ESP_OK :indicates success.
|
||||
*/
|
||||
esp_err_t dma_buf_len_reset(ping_pong_buf_t *obj);
|
||||
|
||||
/**
|
||||
* @brief Set the buffer length before the start.
|
||||
*
|
||||
* @param [in] obj
|
||||
* Pointer to a struct spi_dma_attr_t.
|
||||
* @param [in] len
|
||||
* Set the transmit length .
|
||||
*
|
||||
* @return uint32*, ESP_FAIL:indicates parameter error, ESP_OK: indicates success.
|
||||
*/
|
||||
esp_err_t dma_buf_len_set(ping_pong_buf_t *obj, dma_element_t *element, uint32_t len);
|
||||
|
||||
/**
|
||||
* @brief Destroy the ping-pong buffer instance.
|
||||
*
|
||||
* @param [in] obj
|
||||
* Pointer to a struct ping_pong_buf_t that indicates the object to be destroy.
|
||||
*
|
||||
* @return NULL
|
||||
*/
|
||||
void dma_buf_destroy(ping_pong_buf_t *obj);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // __DMA_H__
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue