/* ****************************************************************************** * * @file VOX_Module.c * @brief VOL/R module * * * @version 1.0 * @date 2022/07/18 09:59:40 * @author Alex Xu * * Copyright (c) 2013-2099,Tkplusemi Technology Co.,Ltd. * All Rights Reserved * * History: * Revision Date Author Desc * 1.0.0 2022/07/18 Alex build this file ****************************************************************************** */ #include "vox_module.h" #include "led.h" #include "system.h" #include "discharge_module.h" #include "sleep.h" #include "bat.h" #include "hall.h" #include "key.h" #include "sys_tim.h" #include "sys_tim.h" bit Vox_Vout_Enable = OFF; //Vox功率输出标志位 #if VOX_ENABLE /******************************************************************************\ Macro definitions \******************************************************************************/ #define VOX_TX_CNT 50 //VOX发送指令时间 #define EARPHONR_WKUP_CNT 2 #define BES_RST_PULS_CNT 20 #define Vox_TX_Interval 2 //Vox定时发送指令时间间隔 #define TIM_SHUTDOWN_DEBOUNCE 600 //关机前debounce时间 /******************************************************************************\ Variables definitions \******************************************************************************/ uint8_t Vox_TX_Timer = 0; //VOX发送指令持续时间计数,在Hall_Handler检测中清0. //uint8_t BES_Rst_Puls_Timer = 0; //关盖15s后发送BES Reset 脉冲 bit BES_Rst_Puls_Flag = 0; //uint8_t WkUp_EarPhone_Debounce = 0; bit Cover_Close_Flag = 0; bit Cover_Open_Flag = 0; bit EarPhone_ShutDown_Flag = 0; //耳机关机标志位 bit Boost_Open_Flag = 0; //用于开启Boost后延时开启Vox 5V。 uint8_t Vox_Output_Short_Debounce = 0; uint16_t Boost_Open_Atleast_Tim_Cnt = 0; /******************************************************************************\ Functions definitions \******************************************************************************/ /* ******************************************************************************* * void VOX_EN_Type(VOR_Enable_Type_e VOR_Enable_Type) * * Description : VOL Open(EN_VO) * Arguments : * Returns : * Notes : * ******************************************************************************* */ void VOX_EN_Type(VOX_Enable_Mode_e VOX_Enable_Mode) { COM_CTRL = ON; switch(VOX_Enable_Mode) { case VOX_VOUT_Mode: VOX_CTL0 &= ~0x30; //VOX Disable 5V And Disable VOX ADT VOX_CTL0 |= 0x30; //VOX Enable 5V break; case VOX_ADT_Mode: VOX_CTL0 &= ~0x30; //VOX 5v Off VOX_CTL0 |= 0x03; //VOX load detect On break; default: break; } } /* ******************************************************************************* * void Vox_Det_Machine(void) * * Description : Vox Detect:耳机识别。 (100ms调用周期) * * Arguments : NONE * Returns : NONE * Notes : NONE * ******************************************************************************* */ /* 1、关盖开启Boost denounce一段时间(ms级延时)后开启Vox 5v;显示灯效。 2、开盖开启Boost denounce一段时间(ms级延时)后开启Vox 5v至少500ms用于唤醒耳机;后发送开盖指令,持续10s,间隔250-300ms。 3、发送开盖指令间隔(250-300ms)期间,Vox转入ADT模式,检测都Loadon状态需要有灯效。 4、两只耳机电池都充满或仓低电,则发送关机指令。 */ void Vox_Det_Machine(void) { #if 1 /*Vox 过流保护,两只耳机都每隔200ms打嗝一次(28Bytes)*/ if( IRQ_FLAG0 & 0x0C ) { Vox_Output_Short_Debounce++; if( Vox_Output_Short_Debounce >= 2 ) //Vox短路保护200ms后,重新开启Vox 5V。 { Vox_Output_Short_Debounce = 0; IRQ_FLAG0 = 0x0C; VOX_EN_Type(VOX_VOUT_Mode); return; } } #endif if( CoverEvent_Flg ) //Hall事件。 { #if 0 if(gBoost_Prepared_Flag && ( CHIP_STA1 & 0xA0 ) ) //1、Boost开启条件不满足,则Vox一直处于ADT模式。2、存在loadon,有耳机在仓,开启Vox 5V输出 #else if( gBoost_Prepared_Flag ) #endif { if( !Boost_Open_Flag ) { BST_EN = 1; //Boost Enable;异常时由硬件主动关闭。开启Boost,开启Vox 5v会在开启Boost之后(100ms延时)。 Boost_Open_Flag = 1; return; } BES_Rst_Puls_Flag = 0; // BES_Rst_Puls_Timer = 0; EarPhone_ShutDown_Flag = 0; // Vox_TX_Timer = 0; SFRADDR = MFP_CTL0; SFRDATA |= 0x04; //P01 as UART's TX if( CoverStatus == CLOSE ) //1、关盖关闭COM_CTRL;显示灯效。(无需查询Loadon、IOFF状态,无论耳机是否在仓,关盖发送指令间隔300ms持续10s,间隔之间关闭COM_CTRL。) { //WkUp_EarPhone_Debounce = 0; Cover_Close_Flag = 1; Cover_Open_Flag = 0; CoverEvent_Flg = 0; Vox_Vout_Enable = ON; Boost_Open_Flag = 0; Boost_Open_Atleast_Tim_Cnt = 0; COM_CTRL = OFF; } else //2、开盖处理,Vox 5V输出500ms用于唤醒耳机;500ms后vox设置为ADT模式,关Boost。 { Cover_Close_Flag = 0; /*开启VOUT 500ms用于唤醒耳机。*/ if( Vox_TX_Timer < EARPHONR_WKUP_CNT ) //debounce 500ms { if( (VOX_CTL0 & 0x30) != 0x30 ) //1、当前已经开启了VOUT,则无需重复开启;原因:在使能VOUT前需要先关闭VOUT使能,如果连续开,会出现一段时间断开的情况。 { VOX_EN_Type(VOX_VOUT_Mode); } Vox_TX_Timer++; } else { BST_EN = 0; //Boost Disable Cover_Open_Flag = 1; CoverEvent_Flg = 0; Boost_Open_Flag = 0; Vox_TX_Timer = 0; VOX_EN_Type(VOX_ADT_Mode); } } } else { VOX_EN_Type(VOX_ADT_Mode); } } if( Cover_Open_Flag || Cover_Close_Flag || EarPhone_ShutDown_Flag ) { /*间隔300ms发送指令,持续5s,关盖间隔之间开启VOUT;开盖间隔之间开启ADT。*/ if(Vox_TX_Timer < VOX_TX_CNT) { if( (Vox_TX_Timer % Vox_TX_Interval) == 0 ) //200ms发送一次 { if( EarPhone_ShutDown_Flag ) { #ifdef VOX_TX HandleTxCommand(CMD_SHUT_DOWN,VOX_BOTH); /*耳机电池充满或仓处于低电,发关机指令*/ #endif #ifdef _DEBUG_VOX printf("Shut Down,Cnt:%d\r\n",(uint16_t)Vox_TX_Timer); #endif } else if( CoverStatus == CLOSE ) { #ifdef VOX_TX HandleTxCommand(CMD_BOX_CLOSE,VOL_CHAN); //发送关盖指令 ,按耳机通道发。 #endif #ifdef _DEBUG_VOX printf("Cover Close,Cnt:%d\r\n",(uint16_t)Vox_TX_Timer); #endif } else if( CoverStatus == OPEN ) { #ifdef VOX_TX HandleTxCommand(CMD_BOX_OPEN,VOX_BOTH); //发开盖指令,不区分耳机通道。 #endif #ifdef _DEBUG_VOX printf("Cover Open,Cnt:%d\r\n",(uint16_t)Vox_TX_Timer); #endif } } #if 0 else if( (Vox_TX_Timer % (Vox_TX_Interval + 1) ) == 0 ) //300ms发送一次 { if( CoverStatus == CLOSE ) { #ifdef VOX_TX HandleTxCommand(CMD_BOX_CLOSE,VOR_CHAN); //发送关盖指令 ,按耳机通道发。 #endif } } else { if( CoverStatus == OPEN ) //Vox处于ADT模式,开启COM_CTRL用于识别耳机入仓。 { COM_CTRL = ON; } } #endif Vox_TX_Timer++; } else //5s后清标志位。 { if(EarPhone_ShutDown_Flag) { EarPhone_ShutDown_Flag = 0; Cover_Close_Flag = 0; Vox_Vout_Enable = OFF; BST_EN = 0; //Boost Disable VOX_EN_Type(VOX_ADT_Mode); } else if( CoverStatus == CLOSE ) //关盖发送完相应的指令后,VOX 5V充电,等待耳机电池充满。充满 { if( ((CHIP_STA1 & 0xAC) == 0xAC) || F_batlevel_low ) //一、loadon和ioff状态同时存在,说明1、耳机电池充满;2、耳机锂保;3、盒中没耳机;二、盒电池低电。两种情况都发SHUT_DOWN。等待开盖重新插拔耳机。 { if( Boost_Open_Atleast_Tim_Cnt >= TIM_SHUTDOWN_DEBOUNCE ) //Boost必须工作满10分钟软件才允许关机,原因,给耳机电池处于锂保状态进行充电。 { EarPhone_ShutDown_Flag = 1; Vox_TX_Timer = 0; //为了后面10s发送SHUT_DOWN指令。 } } if( !BES_Rst_Puls_Flag ) { //BES_Rst_Puls_Timer++; Vox_TX_Timer++; if( Vox_TX_Timer > (BES_RST_PULS_CNT + VOX_TX_CNT) ) //关盖后5+2s后发送BES 复位 pattern { BES_Rst_Puls_Flag = 1; #ifdef _DEBUG_VOX printf("Bes Reset.\r\n"); #endif #ifdef VOX_TX SFRADDR = MFP_CTL0; //Set P01 Pinmux As GPIO Function,目的:保证BES Reset Pattern低电平能拉到0V SFRDATA &= ~0x0C; HandleTxCommand(BES_RESET,VOX_BOTH); //发送BES Reset脉冲,只发一次。 23*5=115ms, #endif return; /*return的原因:Vox_Det_Machine() 100ms调用周期,BES_RESET在Timer1中5ms调用。整个复位Pattern需要115ms, 在此处return可以保证在200ms内只有BES 复位pattern在操作COM_CTRL。*/ } } if( (VOX_CTL0 & 0x30) != 0x30 ) //1、当前已经开启了VOUT,则无需重复开启;原因:在使能VOUT前需要先关闭VOUT使能,如果连续开,会出现一段时间断开的情况。 { VOX_EN_Type(VOX_VOUT_Mode); } } else if( CoverStatus == OPEN ) { Cover_Open_Flag = 0; #ifdef VOX_TX // HandleTxCommand(CMD_BES_HEARTBEAT,VOX_BOTH); //发心跳包指令,不区分耳机通道。心跳包指令如何发?间隔多久发一次?发多久? #endif } COM_CTRL = ON; } } } #ifdef VOX_TX /* ******************************************************************************* * void HandleTxCommand(VOX_BES_COMMAND_E RxCommand, e_Vox_Chan nVox_Chn_Select) * * Description : 发送数据包的封装,并打开相应的双向通信通道 * Command payload * --Header--cmd----len_h---len_l-----Data------CRC16 * 4bytes 2byte 1byte 1byte Len bytes 1byte * * Arguments : VOX_BES_COMMAND_E TxCommand: , e_Vox_Chan nVox_Chn_Select * Returns : * * Notes : * ******************************************************************************* */ idata uint8_t BES_ShutDown_State = 0; //耳机关机状态,0:耳机满电;1:盒子低电 //idata uint8_t BES_Addr[2][6] = 0; //耳机蓝牙地址,BES_Addr[0][6]:左耳;BES_Addr[1][6]:右耳。 void HandleTxCommand(VOX_BES_COMMAND_E TxCommand, e_Vox_Chan nVox_Chn_Select) { uint8_t tx_pData[8] = 0; uint8_t i = 0; /*数据包头*/ tx_pData[0] = BOXHEADER; /*耳机通道*/ tx_pData[2] = nVox_Chn_Select; /*指令编号*/ tx_pData[3] = TxCommand; switch(TxCommand) { case CMD_BOX_OPEN: case CMD_BOX_CLOSE: /*Data Length*/ tx_pData[4] = 0x02; tx_pData[5] = bat_level; tx_pData[6] = FW_VER; break; case CMD_SHUT_DOWN: /*Data Length*/ tx_pData[4] = 0x03; tx_pData[5] = bat_level; tx_pData[6] = FW_VER; tx_pData[7] = BES_ShutDown_State; break; case CMD_BES_PAIRING: /*Data Length*/ tx_pData[4] = 0x02; tx_pData[5] = 0x03; //是否重新让耳机配对 tx_pData[6] = 0x03; //耳机在和的个数 break; case CMD_BES_CLEAN: break; #if 0 case CMD_BES_HEARTBEAT: /*Data Length*/ tx_pData[6] = 0x03; tx_pData[7] = bat_level; tx_pData[8] = FW_VER; break; case CMD_OTA: /*Data Length*/ tx_pData[6] = 0x03; tx_pData[7] = bat_level; tx_pData[8] = FW_VER; break; #endif case BES_RESET: //BES 复位patten BES_Puls_Start = 1; return; default: break; } for(i=2 ;i<(tx_pData[4] + 3);i++) { tx_pData[1] += tx_pData[i]; //求校验和 } COM_CTRL = OFF; //VOX切换到通讯TX功能模式(1.8V)。 #if UART0_ENABLE Uart0SendPacket(tx_pData[4] + 5, tx_pData); #endif } #endif #ifdef VOX_RX /* ******************************************************************************* * char HandleRxCommand(ACK_TYPE_E RxCommand) * * Description : 耳机端发送的数据包的解析及处理 * Ack payload: * Header cmd Ack type len_h len_l Data CRC16 * 4bytes 2byte 1byte 1byte 1byte Len bytes 1byte * * Arguments : ACK_TYPE_E RxCommand: * Returns : * * Notes : * ******************************************************************************* */ //idata uint8_t Vox_BatLevel[2] = 0; //耳机电量:Vox_BatLevel[0]:VOL;Vox_BatLevel[1]:VOR idata uint8_t Vox_Pairing_State[2] = 0; //耳机配对状态,VOL:低4bit;VOR:高4bit。0是无效,1是正在配对,2是配对成功,3不处理,保持当前状态。 idata uint8_t Vox_Paired_State[2] = 0; //耳机配对记录,VOL:低4bit;VOR:高4bit;1是有过配对记录,0是没有 char HandleRxMsg(VOX_BES_COMMAND_E RxCommand) { uint8_t i = 0; #if 1 switch(RxCommand) { case CMD_BOX_OPEN: case CMD_BOX_CLOSE: if( RX0_Buffer[2] == VOL_CHAN ) //根据耳机Side参数 { Vox_Pairing_State[0] = RX0_Buffer[6]; //获取左耳机配对状态 Vox_Paired_State[0] = RX0_Buffer[7]; //获取左耳机配对记录 } else { Vox_Pairing_State[1] = RX0_Buffer[6]; //获取右耳机配对状态 Vox_Paired_State[1] = RX0_Buffer[7]; //获取右耳机配对记录 } break; case CMD_SHUT_DOWN: break; case CMD_BES_PAIRING: if( RX0_Buffer[2] == VOL_CHAN ) //根据耳机Side参数 { Vox_Pairing_State[0] = RX0_Buffer[5]; //获取左耳机配对状态 } else { Vox_Pairing_State[1] = RX0_Buffer[5]; //获取右耳机配对状态 } break; case CMD_BES_CLEAN: break; #if 0 case CMD_BES_HEARTBEAT: if( RX0_Buffer[2] == VOL_CHAN ) //根据耳机Side参数 { Vox_BatLevel[VOL_CHAN] = RX0_Buffer[7]; //获取左耳机电量 Vox_Pairing_State[VOL_CHAN] = RX0_Buffer[8]; //获取左耳机配对状态 Vox_Paired_State[VOL_CHAN] = RX0_Buffer[9]; //获取左耳机配对记录 } else { Vox_BatLevel[VOR_CHAN] = RX0_Buffer[7]; //获取右耳机电量 Vox_Pairing_State[VOR_CHAN] = RX0_Buffer[8]; //获取右耳机配对状态 Vox_Paired_State[VOR_CHAN] = RX0_Buffer[9]; //获取右耳机配对记录 } break; #endif default: break; } #endif return 1; } /* ******************************************************************************* * void HandleVoxCommMsg(void) * * Description : Vox 通讯功能处理函数,100ms定时调用。由于和耳机通信前需要打开耳机端的TRX功能,并且每次通信只能一只耳机。通过切换VOL/VOR通信开关进行通信 * * Arguments : NONE * Returns : NONE * Notes : NONE * ******************************************************************************* */ uint8_t Box_To_Bes_Comm_Debounce = 0; //uint16_t Bes_Pairing_Debounce = 0; void HandleVoxCommMsg(void) { uint8_t CrcCheckSum = 0; uint8_t i = 0; /*RX数据处理*/ if(Uart0_RX_Finish_Flag == 1) { Uart0_RX_Finish_Flag = 0; for(i=3 ;i<(RX0_Buffer[4] + 3);i++) //计算校验和 { CrcCheckSum += RX0_Buffer[i]; //求校验和 } if( CrcCheckSum == RX0_Buffer[1] ) { HandleRxMsg((VOX_BES_COMMAND_E)RX0_Buffer[3]); } else { return; } } #if 1 if(IRQ_FLAG7 & 0x20) //长按按键,开盖,并有耳机在仓,进入耳机配对流程。 { if( (CoverStatus == OPEN) && ( CHIP_STA1 & 0xA0 ) ) //1、开盖;2、有耳机在盒。 { if(Box_To_Bes_Comm_Debounce < 1) { #ifdef VOX_TX HandleTxCommand(CMD_BES_CLEAN,VOX_BOTH); /*耳机配对,发清双耳地址指令*/ #endif } else if(Box_To_Bes_Comm_Debounce < 2) //只有一个耳机在仓,如何操作? { #ifdef VOX_TX HandleTxCommand(CMD_BES_PAIRING,VOL_CHAN); /*耳机配对,发左耳配对指令*/ Vox_Pairing_State[VOL_CHAN] = 0x00; // BES_Addr[VOL_CHAN][6] = 0x00; #endif } else { if( (Vox_Pairing_State[VOL_CHAN] > VOX_PAIR_ING) && (Vox_Pairing_State[VOR_CHAN] > VOX_PAIR_ING) ) //双耳配对成功或不处理保存当前状态。 { IRQ_FLAG7 = 0x20; // Bes_Pairing_Debounce = 0; Boost_Open_Atleast_Tim_Cnt = 0; /*todo 配对成功灯效*/ } else if( Vox_Pairing_State[VOL_CHAN] != 0x00 ) //收到左耳回复的配对指令 { #ifdef VOX_TX HandleTxCommand(CMD_BES_PAIRING,VOR_CHAN); /*耳机配对,发右耳配对指令*/ Vox_Pairing_State[VOL_CHAN] = 0x00; // BES_Addr[VOR_CHAN][6] = 0x00; Box_To_Bes_Comm_Debounce = 0; /*重复发左耳配对指令。*/ #endif } else if(Vox_Pairing_State[VOL_CHAN] == 0x00 || Vox_Pairing_State[VOR_CHAN] == 0x00) { IRQ_FLAG7 = 0x20; /*显示禁止配对灯效。*/ LED_R_FLASH(20,6); //5Hz闪烁6次 Display_Sta=DISPLAY_FLASH; return; } } // if(Bes_Pairing_Debounce > 600) //配对10分钟超时 if( Boost_Open_Atleast_Tim_Cnt >= TIM_SHUTDOWN_DEBOUNCE ) { IRQ_FLAG7 = 0x20; //Bes_Pairing_Debounce = 0; Boost_Open_Atleast_Tim_Cnt = 0; LED_R_FLASH(20,10); //5Hz闪烁10次 Display_Sta=DISPLAY_FLASH; } Box_To_Bes_Comm_Debounce++; // Bes_Pairing_Debounce++; } else { IRQ_FLAG7 = 0x20; } } #endif } #endif #endif