📄 cvc_headset.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 + -