⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cvc_headset.c

📁 CSR蓝牙芯片 无线蓝牙耳机的语音网关程序 蓝牙耳机程序已经上传
💻 C
字号:
/****************************************************************************
Copyright (C) Cambridge Silicon Radio Ltd. 2004

FILE NAME
	cvc_headset.c        

DESCRIPTION
    Support for Clarity CVC in av_headset_hfp
	
	Only active if INCLUDE_CVC is defined in the project properties.
	
NOTES
	The supporting DSP code is supplied as a preassembled .kap file and is
	time limited until licenced.
*/

#ifdef INCLUDE_CVC

/****************************************************************************
	Header files
*/

#include "headset_private.h"
#include "av_headset_kalimba.h"
#include "av_headset_controls.h"
#include "cvc_headset.h"
#include "hfp_headset_indicators.h"
#include "cvcdsp.h"

#include <codec.h>
#include <file.h>
#include <kalimba.h>
#include <kalimba_standard_messages.h>
#include <pcm.h>
#include <stdlib.h>
#include <string.h>
#include <transform.h>
#include <panic.h>
#include <ps.h>
#include <pio.h>
#include <message.h>
#include <stream.h>


#define CLARITY_HFK_VERSION		0x0261

/* Cvc Audio Steam Ports */
#define CODEC_READ_PORT			0x0000
#define SCO_READ_PORT			0x0001
#define CODEC_WRITE_PORT		0x0004
#define SCO_WRITE_PORT			0x0005

/* Clarity Message IDs */
#define CLARITY_READY			0x1000
#define CLARITY_SETMODE			0x1001
#define CLARITY_VOLUME			0x1002

#define CLARITY_SETPARAM		0x1004
#define CLARITY_TESTSTATE		0x1005
#define CLARITY_CODEC			0x1006
#define CLARITY_STATUS          0x1007
#define CLARITY_PING			0x1008
#define CLARITY_PINGRESP		0x1009

#define CLARITY_KEY_CMD			0x100A
#define CLARITY_KEY_RESP		0x100B

/* System Modes */
#define SYSMODE_HFK			1
#define SYSMODE_ASR			2
#define SYSMODE_PSTHRGH		3
#define SYSMODE_LPBACK		5
#define SYSMODE_STANDBY		6

/* Call State */
#define CALLST_CONNECTED	1
#define CALLST_CONNECTING	2
#define CALLST_MUTE			3


typedef struct _tagModeTone_t
{
   audio_note tone_info[7];
} ModeTone_t;

static const ModeTone_t ModeTone[] =
{
   {{AUDIO_TEMPO(90), AUDIO_VOLUME(64), AUDIO_TIMBRE(sine), AUDIO_NOTE(F7, QUAVER), AUDIO_END,              AUDIO_END,              AUDIO_END}},
   {{AUDIO_TEMPO(90), AUDIO_VOLUME(64), AUDIO_TIMBRE(sine), AUDIO_NOTE(F7, QUAVER), AUDIO_NOTE(F7, QUAVER), AUDIO_END,              AUDIO_END}},
   {{AUDIO_TEMPO(90), AUDIO_VOLUME(64), AUDIO_TIMBRE(sine), AUDIO_NOTE(F7, QUAVER), AUDIO_NOTE(F7, QUAVER), AUDIO_NOTE(F7, QUAVER), AUDIO_END}}
};

static unsigned short CvcKey[4];

#define KALIMBA_MSG_GO									0x7000
#define PS_CODEC_GAIN									9
#define PS_PARAM_BASE									10
#define	PS_SEC_KEY										28

/*#define MODEPLAY_DELAY 									100*/

/*#define DEBUG_FLAG_DEBUG_OUTPUT                          1*/



/*	Filename containing the CHF DSP code.	*/
static const char enc_codec[] = "cvc/cvc.kap";

static void dsp_handler(Task, MessageId, Message);
        
typedef struct
{
    TaskData task;
} CvcTask;

static CvcTask cvc_task = {
    { dsp_handler }
};

static uint16 CvcMode;          /* The following variable maintains */
                                    /* a state that indicates if we are */
                                    /* operating in Handsfree, Noise    */
                                    /* Reduction or Pass Through state. */
                                    /* Handsfree state is the default   */
                                    /* state, and will only be swithed  */
                                    /* out of that state at specific    */
                                    /* times.                           */

static uint16 CvcCallState;     /* The following variable maintains */
                                    /* a Call State for the connection. */

static uint8 CvcCodecGain;      /* The following variable holds the */
                                    /* value that the Codec output gain */
                                    /* should be set to when the DSP is */
                                    /* processing the SCO audio data.   */

static uint8 hfkdspready;		    /* Flag that indicates if the DSP	*/
                                    /* is up and running.				*/



   /* The following function is used to start the DSP code.  The code   */
   /* for the DSP resides in the constant data area as a file in a file */
   /* system.  Once the file is located, the file is loaded into the DSP*/
   /* and started.                                                      */

static void start_kalimba(headsetTaskData* app)
{
  /* Find the codec file in the file system                            */
   FILE_INDEX index = FileFind(FILE_ROOT,enc_codec,sizeof(enc_codec)-1/*don't pass terminator*/);

   /* Initialize the startup mode.                                      */
   CvcMode      = SYSMODE_STANDBY;
   CvcCallState = CALLST_MUTE;

   DEBUG(("CHF file index = %x \n",index));
   if(index == FILE_NONE)
   {
      /* Error - can't find file        */
	    DEBUG(("CHF file index = %x \n",index));
	   Panic();
   }
   
   MessageKalimbaTask(&cvc_task.task);
   
   /* Load the codec into Kalimba                                       */
   if(!KalimbaLoad(index))
   {
     /* PioSet(PIO_LED_CONNECT, PIO_LED_CONNECT);*/
	    DEBUG(("Kalimba load fail\n"));
      Panic();
   }
   
   /* Disconnect anything already connected to PCM slots 0 and 1 */
   StreamDisconnect(StreamPcmSource(0), StreamPcmSink(0));
   StreamDisconnect(StreamPcmSource(1), StreamPcmSink(1));

   /*
      Set both ports to none to allow reassigning of internal DACs below.
      (A DAC can only be routed to one port at a time!)
   */
   (void) PanicFalse(PcmRoute(0, VM_PCM_NONE, PCM_NO_SYNC));
   (void) PanicFalse(PcmRoute(1, VM_PCM_NONE, PCM_NO_SYNC));
   
   /* Configure port 0 to be routed to internal codec A, with a sample rate of 16k. */
   (void) PcmRateAndRoute(0, PCM_NO_SYNC, 8000, 8000, VM_PCM_INTERNAL_A);
   (void) PcmRateAndRoute(1, 0, 8000, 8000, VM_PCM_INTERNAL_B);
   
   /* Set the default Codec gain.  This will be the values that we will */
   /* use when tones are to be generated by the codec.  The value in    */
   /* which the codec is set is retreived from the PS Store.  If the    */
   /* value has not been defined, then a default value is used and the  */
   /* PS Store is inialized to this value.                              */
   CodecSetInputGainA(CodecInputGainRange()/2);
   CodecSetInputGainB(CodecInputGainRange()/2);
   if(PsRetrieve(PS_CODEC_GAIN, &CvcCodecGain, sizeof(uint8)) == 0)
   {
      PsStore(PS_CODEC_GAIN, &CvcCodecGain, sizeof(uint8));
   }
   avHeadsetUpdateHfVolume(app->codec_task, CvcCodecGain<<VOLUME_SHIFT);

   	/* Check for Security */
	PsRetrieve(PS_SEC_KEY,CvcKey, sizeof(uint16)*4);
	
   /* Send the DSP a message to start the processing of the data.       */
   if(!KalimbaSendMessage(KALIMBA_MSG_GO, 0, 0, 0, 0))
   {
      	DEBUG(("File Send Message Failure.\n"));
		PioSet(LED_CONNECTABLE, LED_CHARGE);
		Panic();
   }
   DEBUG(("KSM:Message GO OK\n"));

}

static void connect_sco_streams(headsetTaskData *app)
{
	/* Set the analog gain to the recommended value.         */
	avHeadsetUpdateHfVolume(app->codec_task, CvcCodecGain << VOLUME_SHIFT);

	/* Plug Incoming SCO link into DSP Channel 1 Input.                   */
	if(StreamConnect(StreamSourceFromSink(app->sco_sink),StreamKalimbaSink(1)) == 0)
	{
		DEBUG(("SCO to Kalimba Error\n"));
	}
	/* Plug DSP Channel 1 Output into Outoing SCO Link */
	if(StreamConnect(StreamKalimbaSource(1),app->sco_sink) == 0)
	{
		DEBUG(("Kalimba Error to SCO\n"));
	}
}


   /* The following function is processed when the Rewind button is     */
   /* pressed.                                                          */
void CvcHeadsetRewind(headsetTaskData *app)
{
	/* Only change mode if in a call */
	if(app->hfp_state == headsetActiveCall)
	{
		Source audio;

		/* The Rewind button is defined to start the DSP Test Mode.  This    */
		/* mode will generate a multifrequency tone at 3 different levels.   */
		/* When the Test is complete, the DSP will revert to suspend mode.   */
		if(++CvcMode > SYSMODE_PSTHRGH)
		{
			CvcMode = SYSMODE_HFK;
		}

		audio = StreamAudioSource(ModeTone[CvcMode-1].tone_info);
	  
		/* Register to get the MESSAGE_DISCONNECT so we know to reconnect the DSP */
		MessageSinkTask(StreamSinkFromSource(audio), &cvc_task.task);
		
		StreamDisconnect(0, StreamPcmSink(0));

		if(!StreamConnect(audio, StreamPcmSink(0)))
			StreamConnectDispose(audio);

	  	if(!KalimbaSendMessage(CLARITY_SETMODE, CvcMode, 0, (CvcMode == SYSMODE_HFK)?CvcCallState:0, 0))
		{
			DEBUG(("KSM:SetCallState FAILURE\n"));
		}
		
		DEBUG(("Mode: %d %d\n", CvcMode, CvcCallState));
	}
}

   /* The following function is used to handle a speaker gain request.  */
   /* When the Volume Up or Volume Down button is pressed, this function*/
   /* will be called in order to update that gain.  The gain will be    */
   /* adusted by the DSP code.                                          */
void CvcHeadsetGainRequest(uint16 vol)
{
	DEBUG(("Cvc volume = %x\n",vol));
	if(!KalimbaSendMessage(CLARITY_VOLUME, vol>>VOLUME_SHIFT, 0 ,0, 0))
	{
		DEBUG(("KSM:SetVolume FAILURE\n"));
	}
}

   /* The following function is used to handle messages that are        */
   /* dispatched from the DSP.                                          */

typedef struct
{
    uint16 id;
    uint16 a;
    uint16 b;
    uint16 c;
    uint16 d;
} DSP_REGISTER_T;

static void dsp_handler(Task task, MessageId id, Message message) 
{
	if (id== MESSAGE_FROM_KALIMBA)
	{
		const DSP_REGISTER_T *m = (const DSP_REGISTER_T *) message;
		uint16 a      = m->a;
		uint16 b      = m->b;

		DEBUG(("dsp_handler dsp_id = %x a= %x b= %x c= %x d= %x\n" ,m->id,a,b,m->c,m->d));
	
		switch (m->id) 
		 {
         case CLARITY_READY:
            /* This command is set to us to indicate that the DSP is    */
            /* initialized and ready.  At this point we need to send the*/
            /* configuration parameters to the DSP.  Allocate memory to */
            /* hold a configuration recrod.                             */
			a = CvcConfigureDsp(PS_PARAM_BASE,NULL,0); 
            DEBUG(("DSP is initialized and ready (%x)\n",a));
        
            /* Connect the streams from the Mic to the DSP and the      */
            /* stream from the DSP to the Speaker.                      */
            (void)StreamConnect(StreamPcmSource(0),StreamKalimbaSink(0));
            (void)StreamConnect(StreamKalimbaSource(0),StreamPcmSink(0));

            CvcMode      = SYSMODE_HFK;
            CvcCallState = CALLST_CONNECTED;

            /* Set the DSP mode to the Handsfree state.                 */
            if(!KalimbaSendMessage(CLARITY_SETMODE, SYSMODE_HFK, 0, CALLST_CONNECTED, 0))
            {
				 DEBUG(("KSM:SetMode FAILURE\n"));
            }
			
			/* DSP is up and running */
   			hfkdspready = 1;
			
			connect_sco_streams(getApp());
			
            break;
			
		case CLARITY_CODEC:
            /* We have received a message that defines the values that  */
            /* are to be loaded for gain levels.  Parameter 1 (a)       */
            /* defines the Digital gain and should be set via the       */
            /* Cvc Volume command.  Parameter 2 (b) defines the     */
            /* Analog level and should be used to set the Codec level.  */
            /* The Digital level is maintained via a PS key by the lower*/
            /* layer, so we will ignore this value.                     */
            CvcCodecGain = a;
   			avHeadsetUpdateHfVolume(getAppTask(), CvcCodecGain << VOLUME_SHIFT);
   			DEBUG(("Cvc Codec Gain = %d\n",CvcCodecGain));
            CodecSetInputGainA(b);
            CodecSetInputGainB(b);
            break;
			
		case CLARITY_KEY_CMD:
			
			b = CvcSecurityCheck(CvcKey,a);
			DEBUG(("CLKEYCMD: %x %x\n",a,b));
			break;
      }
	}
	else if(id == MESSAGE_STREAM_DISCONNECT)
	{
		/*
		  Called when the beep in CvcHeadsetRewind has finished playing; 
		  reconnect the Kalimba to the PCM port.
 		*/
		(void) StreamConnect(StreamKalimbaSource(0),StreamPcmSink(0));
	}
}

void CvcHeadsetConnect(headsetTaskData *app)
{
	DEBUG(("hfkdspready = %x\n",hfkdspready));
	DEBUG(("hfp_state = %x\n",app->hfp_state));
	/* only start Kalimba if it is not running HFK app*/
	if (!hfkdspready)
	{
		start_kalimba(app);
		DEBUG(("Kalimba Started.\n"));
	}
	else
	{
		avHeadsetUpdateHfVolume(app->codec_task, CvcCodecGain << VOLUME_SHIFT);
		connect_sco_streams(app);
	}
}

void CvcHeadsetUnloaded(void)
{
    /* The DSP has been reloaded by some other part of the application */
    hfkdspready = 0;
}

void CvcHeadsetVolume(uint16 gain)
{
	if(hfkdspready)
	{
		CvcHeadsetGainRequest(gain);
	}
	else
	{
    	avHeadsetUpdateHfVolume(getApp()->codec_task, gain);		
	}
}

#else /* ndef INCLUDE_CVC */

extern int cvc_headset_dummy_int; /* Suppress empty-file error */

#endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -