FM驱动实现打开FM,音频驱动自动切换音频的方法(原创)

来源:互联网 发布:仿卷皮优惠券网站源码 编辑:程序博客网 时间:2024/05/01 02:00

FM驱动中实现打开FM,音频驱动自动切换音频的方法:

一:声明一个事件句柄:
static HANDLE g_hEventFMOpen = NULL;

二:编写创建事件函数:
BOOL FMR_CreatEvent()
{
 DWORD dwRet;
 g_hEventFMOpen = OpenEvent(EVENT_ALL_ACCESS, FALSE, TEXT("FMWAVOUT_EVENT"));
 if(g_hEventFMOpen == NULL)
 {
  g_hEventFMOpen = CreateEvent(NULL, FALSE, FALSE, TEXT

("FMWAVOUT_EVENT"));
  if(NULL == g_hEventFMOpen)
  {
   dwRet = GetLastError();
   RETAILMSG(ZONE_ERROR, (TEXT("FMR_KT0801_Init:Open

FMWAVOUT_EVENT fail,ERROR:%d /r/n"),dwRet));
   return FALSE;
  }             
 }
 return TRUE;
}

三:在打开FM驱动时,同时执行步骤二创建的事件函数:
if (FMR_I2C_Init())
    {            
     RETAILMSG(ZONE_ERROR,(TEXT("<FMR>

FMR_KT0801_Init failed!/r/n")));
    }
    MapVirtualAddress();
    FMR_CreatEvent();
    //上电,复位,GPIO初始化
    if(FMR_KT0801_Power_Set(1))
    {
     g_FMSTATE=1; //g_FMSTATE==1 FM  POWER ON

    FM TX
     //FMR_SendMessageId(1);//masked by lqm.
    }

四:在FM模块工作时,通过SetEventData()和SetEvent()函数通知音频驱动,FM驱动已经打开:
if((pArg->dwFreqBuffer>=OMITFREQUENT_MIN) & (pArg->dwFreqBuffer<=OMITFREQUENT_MAX))
 {
  RETAILMSG(1,  (TEXT("<FMR> Set KT0801_Frequent:%d!/r/n"),pArg-

>dwFreqBuffer));
  FMR_KT0801_I2C_Write(0x00,(USHORT)(pArg->dwFreqBuffer & 0xff));
  FMR_KT0801_I2C_Write(0x01,(USHORT)((pArg->dwFreqBuffer>>8) & 0x7 |

0xC0));// PGA Gain:0dB
  FMR_KT0801_I2C_Write(0x02,0x40);//清掉CHSEL[0],使用

step=100K.RFGAIN:112.5dBuV
  FMR_KT0801_I2C_Write(0x13,0x84);
  FMR_KT0801_I2C_Write(0x0B,0x00);//打开PA
  // 通知音频驱动,FM已经打开
  SetEventData(g_hEventFMOpen,1);
  SetEvent(g_hEventFMOpen);
 }
 else
 {
  RETAILMSG(1,  (TEXT("<FMR> Not support Frequent:%d!/r/n"),pArg-

>dwFreqBuffer));
  FMR_KT0801_I2C_Write(0x0B,0x20);//关闭PA
  FMR_KT0801_Power_Set(FALSE);
  // 通知音频驱动,FM已经关闭
  SetEventData(g_hEventFMOpen,0);
  SetEvent(g_hEventFMOpen);
  FMR_KT0801_Deinit();
  return TRUE;
 }

五:在关闭FM模块时,通过SetEventData()和SetEvent()函数通知音频驱动,FM驱动已经关闭:
在IOCTL的IOCTL_FMR_KT0801_POWERSTATE_SET中,代码如下:
if((0 == *pBufOut)&&(1==g_FMSTATE))
   {
     //断电。
    FMR_KT0801_I2C_Write(0x0B,0x20);//关闭PA
    FMR_KT0801_Power_Set(0);
    // 通知音频驱动,FM已经关闭
    SetEventData(g_hEventFMOpen,0);
    SetEvent(g_hEventFMOpen);
    FMR_KT0801_Deinit();
    g_FMSTATE=0; //g_FMSTATE==0; FM  POWER OFF    FM

TX
    //FMR_SendMessageId(0);//masked by lqm.
   }

六:在音频驱动中定义一个事件的句柄:
在Hwctxt.h的前面,添加事件句柄如下:
HANDLE g_hEventFMOpen;
在Hwctxt.h的前面,添加线程句柄如下:
HANDLE g_hThreadFMOpen;

七:在音频驱动中编写FM线程函数:
void FMWavOutThread(HardwareContext *pHWContext)
{
    DWORD dwret; 
    DWORD dwFMdata = 0;
 
    RETAILMSG(1, (_T("FMWavOutThread start!/r/n"))); 

    HardwareContext *pHWContexttmp = pHWContext;   
 
    while(TRUE)
    {  
       dwret = WaitForSingleObject(pHWContexttmp->g_hEventFMOpen, INFINITE); 

 if(dwret == WAIT_OBJECT_0)
 {
  dwFMdata = GetEventData(pHWContexttmp->g_hEventFMOpen);
  if(dwFMdata == 1)
  {
   RETAILMSG(1, (_T("FMWavOutThread:Open FM /r/n")));  

  
   pHWContexttmp->g_WavOutChannel = WAV_FM;
   pHWContexttmp->SetOutChannel(pHWContexttmp-

>g_WavOutChannel); 
  }
  else if(dwFMdata == 0)
  {
   RETAILMSG(1, (_T("FMWavOutThread:Close FM /r/n")));
   pHWContexttmp->g_WavOutChannel = WAV_UNKNOW;
   SetEvent(pHWContexttmp->g_hEventHpDet);
  }
 }      
    }    
}
上面程序中,WaitForSingleObject()函数等待FM驱动发送事件,检测到FM驱动打开时,即切换

音频通道为WAV_FM;检测到FM驱动关闭时,将音频通道切换到WAV_UNKNOW状态,同时将耳机侦测

事件置1,这时该事件会检测是耳机状态还是喇叭状态,再一次切换声音通道。

八:在音频初始化函数BOOL HardwareContext::Initialize(DWORD Index)中,创建事件和线程


g_hEventFMOpen = OpenEvent(EVENT_ALL_ACCESS, FALSE, TEXT("FMWAVOUT_EVENT"));
 if(g_hEventFMOpen == NULL)
 {
  g_hEventFMOpen = CreateEvent(NULL, FALSE, FALSE, TEXT

("FMWAVOUT_EVENT"));
  if(NULL == g_hEventFMOpen)
  {
   RETAILMSG(1, (_T(" %s() : CreateEvent() g_hEventFMOpen event

Failed /n/r"), _T(__FUNCTION__)));
   return FALSE;
  }             
 }      
 
    g_hThreadFMOpen = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) FMWavOutThread,

this, 0, NULL);
    if (g_hThreadFMOpen == NULL )
    {
        RETAILMSG(1, (_T(" %s() : CreateThread() FM open thread Failed /n/r"), _T

(__FUNCTION__)));
        return FALSE;
    }

整个FM切换过程至此为止,也就结束了。我们将上面用到的函数总结一下:
CreateEvent();
SetEvent();
SetEventData();
GetEventData();
OpenEvent();
CreateThread();
WaitForSingleObject();

a:CreateEvent()

HANDLE CreateEvent(
  LPSECURITY_ATTRIBUTES
  lpEventAttributes,
  BOOL bManualReset,
  BOOL InitialState,
  LPTSTR lpName
);

lpEventAttributes:必须是NULL.
bManualReset:为1时为手动复位,为0时为自动复位。
InitialState:为1时初始化为有信号,为0时初始化为无信号。
lpName:指向一个以0结束的字符串。为0时创建一个没有名字的事件。

b:SetEvent()

BOOL SetEvent(
  HANDLE hEvent
);

该函数设置相应的事件对象为有信号。
返回为非0表示设置成功。
CreateEvent函数返回hEvent这个句柄。
当CreateEvent函数中设置为手动复位时,在SetEvent之后,对应的事件对象仍然为有信号,直

到执行ResetEvent函数之后,方变为无信号。任意数目的等待线程或者并发线程,当指定释放。
当CreateEvent函数中设置为自动复位时,在SetEvent之后,对应的事件对象会自动设置为无信

号,同时等待的线程就被释放。如果SetEvent后,没有任何等待的线程,那么相应的事件对象仍

然保持为有信号。

c:SetEventData()

BOOL SetEventData(
  HANDLE hEvent,
  DWORD dwData
);

hEvent:由CreateEvent函数创建的事件的句柄。
dwData:与一个事件相关联的特定数据。

返回1表示成功,返回0表示失败。

d:GetEventData()

DWORD GetEventData(
  HANDLE hEvent
);

hEvent:由CreateEvent函数创建的事件的句柄。

返回值:当SetEventData()设置的数据不是0时,如果GetEventData()返回0,则表示获取数据失

败。该函数返回由SetEventData函数发送的数据。

e:OpenEvent()

HANDLE OpenEvent(
  DWORD dwDesiredAccess,
  BOOL bInheritHandle,
  LPCTSTR lpName
);

该函数打开一个存在的指定名字的事件对象。

dwDesiredAccess:事件对象指定的需要的访问方式,必须设置成EVENT_ALL_ACCESS。
bInheritHandle:必须设置为FALSE.
lpName:指向要打开的事件对象的字符串名称。

返回成功,返回要打开的事件对象的句柄。
返回失败,返回值为NULL。

f:CreateThread()

HANDLE CreateThread(
  LPSECURITY_ATTRIBUTES lpsa,
  DWORD cbStack,
  LPTHREAD_START_ROUTINE lpStartAddr,
  LPVOID lpvThreadParam,
  DWORD fdwCreate,
  LPDWORD lpIDThread
);

该函数创建一个线程,并在所在地址空间范围内执行调用的程序。

lpsa:必须为NULL。
cbStack:如果标志位STACK_SIZE_PARAM_IS_A_RESERVATION没有用到将被忽略。
lpStartAddr:指向线程的起始地址。
lpvThreadParam:指向一个单独的32位参数值,用于传给该线程。
fdwCreate:线程的指向标识位。当该值为CREATE_SUSPENDED时,线程创建了一个空闲状态,线

程并不运行,直到ResumeThread函数被调用。如果这个标识位没有指定,那么线程创建后会立即

运行。
lpIDThread:指向一个32位的接收线程标识符。

该函数创建成功时返回该线程的句柄,创建失败时返回0.

g:WaitForSingleObject()

DWORD WaitForSingleObject(
  HANDLE hHandle,
  DWORD dwMilliseconds
);

当指定对象为有信号时,或者等待超时将会返回。
hHandle:指定对象的句柄。
dwMilliseconds:等待时间。当为0时,表示检测对象状态后马上返回;当为INFINITE时,表示

一直等待,走到等待对象为有信号。

返回值:返回WAIT_OBJECT_0时表示等待的对象有信号;
        返回WAIT_TIMEOUT时表示超时返回。