feat: Add rfid feature and .gitignore file
This commit is contained in:
257
apps/common/device/gSensor/EPMotion.h
Normal file
257
apps/common/device/gSensor/EPMotion.h
Normal file
@ -0,0 +1,257 @@
|
||||
/*******************************************************************************/
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file EPMotion.h
|
||||
* @author ycwang@miramems.com
|
||||
* @version V2.0
|
||||
* @date 2019-01-31
|
||||
* @brief
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
|
||||
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
|
||||
* TIME. AS A RESULT, MiraMEMS SHALL NOT BE HELD LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
|
||||
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
|
||||
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
|
||||
*
|
||||
*/
|
||||
/*******************************************************************************/
|
||||
#ifndef __EPMOTION_h
|
||||
#define __EPMOTION_h
|
||||
|
||||
/*******************************************************************************
|
||||
Includes
|
||||
********************************************************************************/
|
||||
#include "mira_std.h"
|
||||
|
||||
/*******************************************************************************
|
||||
Macro definitions - Algorithm Build Options
|
||||
********************************************************************************/
|
||||
#define D_TAP_ENABLE 1
|
||||
#define M_TAP_ENABLE 1
|
||||
#define STEP_ENABLE 1
|
||||
|
||||
/*******************************************************************************
|
||||
Typedef definitions
|
||||
********************************************************************************/
|
||||
enum {
|
||||
DEBUG_ERR = 1,
|
||||
DEBUG_MSG = 1 << 1,
|
||||
DEBUG_DATA = 1 << 2,
|
||||
DEBUG_RAW = 1 << 3,
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
PIN_NONE,
|
||||
PIN_ONE,
|
||||
PIN_TWO
|
||||
} tPIN_NUM;
|
||||
|
||||
typedef enum {
|
||||
PIN_LEVEL_NONE,
|
||||
PIN_LEVEL_LOW,
|
||||
PIN_LEVEL_HIGH
|
||||
} tPIN_LEVEL;
|
||||
|
||||
typedef enum {
|
||||
NO_LATCHED,
|
||||
LATCHED_250MS,
|
||||
LATCHED_500MS,
|
||||
LATCHED_1S,
|
||||
LATCHED_2S,
|
||||
LATCHED_4S,
|
||||
LATCHED_8S,
|
||||
LATCHED_1MS = 10,
|
||||
LATCHED_2MS,
|
||||
LATCHED_25MS,
|
||||
LATCHED_50MS,
|
||||
LATCHED_100MS,
|
||||
LATCHED
|
||||
} tLATCH_MODE;
|
||||
|
||||
typedef enum {
|
||||
TEVENT_NONE,
|
||||
TEVENT_TAP_NOTIFY,
|
||||
} EPMotion_EVENT;
|
||||
|
||||
typedef enum {
|
||||
NONE_T,
|
||||
D_TAP_T,
|
||||
M_TAP_T,
|
||||
STEP_T,
|
||||
} tAlgorithm;
|
||||
|
||||
typedef enum {
|
||||
DISABLE_T,
|
||||
ENABLE_T
|
||||
} tSwitchCmd;
|
||||
|
||||
struct tInt_Pin_Config {
|
||||
tPIN_NUM num;
|
||||
tPIN_LEVEL level;
|
||||
};
|
||||
|
||||
struct tREG_Func {
|
||||
s8_m(*read)(u8_m addr, u8_m *data_m, u8_m len);
|
||||
s8_m(*write)(u8_m addr, u8_m data_m);
|
||||
};
|
||||
|
||||
struct tDEBUG_Func {
|
||||
s32_m(*myprintf)(const char *fmt, ...);
|
||||
};
|
||||
|
||||
struct EPMotion_op_s {
|
||||
struct tInt_Pin_Config pin;
|
||||
s8_m(*mir3da_event_handle)(EPMotion_EVENT event, u8_m data_m);
|
||||
struct tREG_Func reg;
|
||||
struct tDEBUG_Func debug;
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
Global variables and functions
|
||||
********************************************************************************/
|
||||
|
||||
/*******************************************************************************
|
||||
* Function Name: EPMotion_Init
|
||||
* Description : This function initializes the EPMotion.
|
||||
* Arguments : EPMotion_op_s *ops
|
||||
* Return Value : 0: OK; -1: Type Error; -2: OP Error; -3: Chip Error
|
||||
********************************************************************************/
|
||||
s8_m EPMotion_Init(struct EPMotion_op_s *ops);
|
||||
|
||||
/*******************************************************************************
|
||||
* Function Name: EPMotion_Tap_Set_Parma
|
||||
* Description : This function sets tap parmas.
|
||||
* Arguments :
|
||||
* threshold - set interrupt threshold 0~31 ,(threshold*125)mg
|
||||
* default is 21(2625mg)
|
||||
* latch_mode - set interrupt latched mode ,(tLATCH_MODE)
|
||||
* default is NO_LATCHED
|
||||
* duration - set interrupt duration 0~7(50~700)ms,
|
||||
* default is 0(50ms)
|
||||
* Return Value : None
|
||||
********************************************************************************/
|
||||
void EPMotion_Tap_Set_Parma(u8_m threshold, tLATCH_MODE latch_mode, u8_m duration);
|
||||
|
||||
#if D_TAP_ENABLE
|
||||
/*******************************************************************************
|
||||
* Function Name: EPMotion_Tap_Set_Filter
|
||||
* Description : This function sets filter.
|
||||
* Arguments :
|
||||
* level - set level of checking data 1~3 ,default is 1
|
||||
* ths - set the value of filter ,(ths*1)mg
|
||||
* Return Value : None
|
||||
********************************************************************************/
|
||||
void EPMotion_D_Tap_Set_Filter(u8_m level, u16_m ths);
|
||||
#endif
|
||||
|
||||
#if M_TAP_ENABLE
|
||||
/*******************************************************************************
|
||||
* Function Name: EPMotion_M_Tap_Set_Dur
|
||||
* Description : This function sets M tap duration.
|
||||
* Arguments :
|
||||
* m_dur_int - set interrupt duration 20~70,(m_dur_int*10)ms,
|
||||
* default is 50(500ms)
|
||||
* m_dur_event - set m tap event duration 20~6000,(m_dur_event*10)ms,
|
||||
* default is 100(1000ms)
|
||||
*EPMotion_M_Tap_Set_Dur第一个参数是设置两次敲击间隔的最大时间 第二参数是连续多次敲击总的有效时间
|
||||
* Return Value : None
|
||||
********************************************************************************/
|
||||
void EPMotion_M_Tap_Set_Dur(u8_m m_dur_int, u16_m m_dur_event);
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
* Function Name: EPMotion_Reset_Tap_INT
|
||||
* Description : This function reset tap INT.
|
||||
* Arguments : None
|
||||
* Return Value : None
|
||||
********************************************************************************/
|
||||
void EPMotion_Reset_Tap_INT(void);
|
||||
|
||||
/*******************************************************************************
|
||||
* Function Name: EPMotion_Resume_Tap_INT
|
||||
* Description : This function resume tap INT.
|
||||
* Arguments : None
|
||||
* Return Value : None
|
||||
********************************************************************************/
|
||||
void EPMotion_Resume_Tap_INT(void);
|
||||
|
||||
#if STEP_ENABLE
|
||||
/*******************************************************************************
|
||||
* Function Name: EPMotion_Reset_Step
|
||||
* Description : This function reset step counter.
|
||||
* Arguments : None
|
||||
* Return Value : None
|
||||
********************************************************************************/
|
||||
void EPMotion_Reset_Step(void);
|
||||
|
||||
/*******************************************************************************
|
||||
* Function Name: EPMotion_Get_Step
|
||||
* Description : This function gets the step.
|
||||
* Arguments : None
|
||||
* Return Value : step
|
||||
********************************************************************************/
|
||||
u16_m EPMotion_Get_Step(void);
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
* Function Name: EPMotion_Control
|
||||
* Description : This function initializes the xMotion.
|
||||
* Arguments : name - select which algorithm to control
|
||||
cmd - enable/disable
|
||||
* Return Value : 0->Success, -1->Init Fail£¬-2£¬No Supported
|
||||
********************************************************************************/
|
||||
s8_m EPMotion_Control(tAlgorithm name, tSwitchCmd cmd);
|
||||
|
||||
/*******************************************************************************
|
||||
* Function Name: EPMotion_Process_Data
|
||||
* Description : This function runs the EPMotion Algorithm.
|
||||
* Arguments : None
|
||||
* Return Value : None
|
||||
********************************************************************************/
|
||||
void EPMotion_Process_Data(s8_m int_active);
|
||||
|
||||
/*******************************************************************************
|
||||
* Function Name: EPMotion_Chip_Read_XYZ
|
||||
* Description : This function reads the chip xyz.
|
||||
* Arguments : x, y, z - acc data
|
||||
* Return Value : 0: OK; -1: Error
|
||||
********************************************************************************/
|
||||
s8_m EPMotion_Chip_Read_XYZ(s16_m *x, s16_m *y, s16_m *z);
|
||||
|
||||
/*******************************************************************************
|
||||
* Function Name: EPMotion_Get_Version
|
||||
* Description : This function gets EPMotion version.
|
||||
* Arguments : ver - EPMotion version Num
|
||||
* Return Value : None
|
||||
********************************************************************************/
|
||||
void EPMotion_Get_Version(u8_m *ver);
|
||||
|
||||
/*******************************************************************************
|
||||
* Function Name: EPMotion_Chip_Power_On
|
||||
* Description : This function enables the chip.
|
||||
* Arguments : None
|
||||
* Return Value : 0: OK; -1: Error
|
||||
********************************************************************************/
|
||||
s8_m EPMotion_Chip_Power_On(void);
|
||||
|
||||
/*******************************************************************************
|
||||
* Function Name: EPMotion_Chip_Power_Off
|
||||
* Description : This function disables on the chip.
|
||||
* Arguments : None
|
||||
* Return Value : 0: OK; -1: Error
|
||||
********************************************************************************/
|
||||
s8_m EPMotion_Chip_Power_Off(void);
|
||||
|
||||
/*******************************************************************************
|
||||
* Function Name: EPMotion_Set_Debug_level
|
||||
* Description : This function sets the debug log level
|
||||
* Arguments : Log level
|
||||
* Return Value : None
|
||||
********************************************************************************/
|
||||
void EPMotion_Set_Debug_level(u8_m level);
|
||||
#endif
|
||||
|
||||
|
||||
371
apps/common/device/gSensor/SC7A20.c
Normal file
371
apps/common/device/gSensor/SC7A20.c
Normal file
@ -0,0 +1,371 @@
|
||||
#include "gSensor/SC7A20.h"
|
||||
#include "gSensor/gSensor_manage.h"
|
||||
#include "app_config.h"
|
||||
|
||||
#include "gSensor/SC7A20.h"
|
||||
#include "math.h"
|
||||
|
||||
|
||||
#if TCFG_SC7A20_EN
|
||||
|
||||
u8 volatile sl_click_timer_en = 0;
|
||||
|
||||
#define INT_IO IO_PORTC_02
|
||||
#define SL_Sensor_Algo_Release_Enable 1
|
||||
|
||||
|
||||
u8 Click_time = 0X00;
|
||||
u8 Click_add_flag = 0X00;
|
||||
|
||||
|
||||
u32 SL_MEMS_i2cRead(u8 addr, u8 reg, u8 len, u8 *buf)
|
||||
{
|
||||
return _gravity_sensor_get_ndata(addr, reg, buf, len);
|
||||
}
|
||||
|
||||
u8 SL_MEMS_i2cWrite(u8 addr, u8 reg, u8 data)
|
||||
{
|
||||
gravity_sensor_command(addr, reg, data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
char SC7A20_Check()
|
||||
{
|
||||
u8 reg_value = 0;
|
||||
SL_MEMS_i2cRead(SC7A20_R_ADDR, SC7A20_WHO_AM_I, 1, ®_value);
|
||||
if (reg_value == 0x11) {
|
||||
return 0x01;
|
||||
} else {
|
||||
return 0x00;
|
||||
}
|
||||
}
|
||||
|
||||
u8 SC7A20_Config(void)
|
||||
{
|
||||
u8 Check_Flag = 0;
|
||||
u8 write_num = 0, i = 0;
|
||||
|
||||
u8 ODR = 0x6f; //400HZ/6f 200HZ
|
||||
u8 HP = 0x0c; //开启高通滤波
|
||||
u8 click_int = 0x04;//0x82 //将Click中断映射到INT1 OVERRUN
|
||||
u8 range = 0x90; //4g量程
|
||||
u8 fifo_en = 0x40; //使能fifo
|
||||
u8 fifo_mode = 0x9c; //0x9d //Stream模式,0-29(WTM30个)
|
||||
u8 click_mode = 0x15; //单击3轴触发
|
||||
|
||||
Check_Flag = SC7A20_Check();
|
||||
if (Check_Flag == 1) {
|
||||
SL_MEMS_i2cWrite(SC7A20_W_ADDR, SC7A20_CTRL_REG1, ODR);
|
||||
SL_MEMS_i2cWrite(SC7A20_W_ADDR, SC7A20_CTRL_REG2, HP);
|
||||
SL_MEMS_i2cWrite(SC7A20_W_ADDR, SC7A20_CTRL_REG3, click_int);// click int1
|
||||
SL_MEMS_i2cWrite(SC7A20_W_ADDR, SC7A20_CTRL_REG4, range);
|
||||
SL_MEMS_i2cWrite(SC7A20_W_ADDR, SC7A20_CTRL_REG5, fifo_en);
|
||||
SL_MEMS_i2cWrite(SC7A20_W_ADDR, SC7A20_FIFO_CTRL_REG, fifo_mode);
|
||||
/*
|
||||
SL_MEMS_i2cWrite(SC7A20_W_ADDR, SC7A20_CLICK_CFG, click_mode);//单Z轴
|
||||
SL_MEMS_i2cWrite(SC7A20_W_ADDR, SC7A20_CLICK_THS, SC7A20_CLICK_TH);//62.6mg(4g)*10
|
||||
SL_MEMS_i2cWrite(SC7A20_W_ADDR, SC7A20_TIME_LIMIT, SC7A20_CLICK_WINDOWS);
|
||||
SL_MEMS_i2cWrite(SC7A20_W_ADDR, SC7A20_TIME_LATENCY, SC7A20_CLICK_LATENCY);
|
||||
*/
|
||||
SL_MEMS_i2cWrite(SC7A20_W_ADDR, SC7A20_CTRL_REG6, SC7A20_INT_LEVEL);
|
||||
printf("check ok\n");
|
||||
return 0;
|
||||
} else {
|
||||
printf("check fail\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
u8 SC7A20_disable(void)
|
||||
{
|
||||
u8 Check_Flag = SC7A20_Check();
|
||||
if (Check_Flag == 1) {
|
||||
u8 ODR = 0x00;
|
||||
SL_MEMS_i2cWrite(SC7A20_W_ADDR, SC7A20_CTRL_REG1, ODR);
|
||||
printf("check ok\n");
|
||||
return 0;
|
||||
} else {
|
||||
printf("check fail\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#if SL_Sensor_Algo_Release_Enable==0
|
||||
extern signed short SL_DEBUG_DATA[10][128];
|
||||
extern u8 SL_DEBUG_DATA_LEN;
|
||||
#endif
|
||||
|
||||
u8 sl_pp_num = 0;
|
||||
|
||||
u8 SL_Get_CLICK_PP_CNT(u8 fun_flag)
|
||||
{
|
||||
if (fun_flag == 0) {
|
||||
sl_pp_num = 0;
|
||||
}
|
||||
return sl_pp_num;
|
||||
}
|
||||
|
||||
unsigned int SL_Click_Sqrt(unsigned int sqrt_data)
|
||||
{
|
||||
unsigned int SL_SQRT_LOW, SL_SQRT_UP, SL_SQRT_MID;
|
||||
u8 sl_sqrt_num = 0;
|
||||
|
||||
SL_SQRT_LOW = 0;
|
||||
SL_SQRT_UP = sqrt_data;
|
||||
SL_SQRT_MID = (SL_SQRT_UP + SL_SQRT_LOW) / 2;
|
||||
while (sl_sqrt_num < 200) {
|
||||
if (SL_SQRT_MID * SL_SQRT_MID > sqrt_data) {
|
||||
SL_SQRT_UP = SL_SQRT_MID;
|
||||
} else {
|
||||
SL_SQRT_LOW = SL_SQRT_MID;
|
||||
}
|
||||
if (SL_SQRT_UP - SL_SQRT_LOW == 1) {
|
||||
if (SL_SQRT_UP * SL_SQRT_UP - sqrt_data > sqrt_data - SL_SQRT_LOW * SL_SQRT_LOW) {
|
||||
return SL_SQRT_LOW;
|
||||
} else {
|
||||
return SL_SQRT_UP;
|
||||
}
|
||||
}
|
||||
SL_SQRT_MID = (SL_SQRT_UP + SL_SQRT_LOW) / 2;
|
||||
sl_sqrt_num++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
char SC7A20_Click_Read(int TH1, int TH2)
|
||||
{
|
||||
u8 i = 0, j = 0, k = 0;
|
||||
u8 click_num = 0;
|
||||
u8 fifo_len;
|
||||
unsigned int sc7a20_data = 0;
|
||||
unsigned int fifo_data_xyz[32];
|
||||
u8 click_result = 0x00;
|
||||
unsigned int click_sum = 0;
|
||||
u8 data1[6];
|
||||
signed char data[6];
|
||||
|
||||
g_printf("INT_HAPPEN!\r\n");
|
||||
|
||||
SL_MEMS_i2cRead(SC7A20_R_ADDR, SC7A20_SRC_REG, 1, &fifo_len);
|
||||
if ((fifo_len & 0x40) == 0x40) {
|
||||
fifo_len = 32;
|
||||
} else {
|
||||
fifo_len = fifo_len & 0x1f;
|
||||
}
|
||||
|
||||
for (i = 0; i < fifo_len; i++) {
|
||||
SL_MEMS_i2cRead(SC7A20_R_ADDR, 0xA8, 6, &data1[0]);
|
||||
data[1] = (signed char)data1[1];
|
||||
data[3] = (signed char)data1[3];
|
||||
data[5] = (signed char)data1[5];
|
||||
sc7a20_data = (data[1]) * (data[1]) + (data[3]) * (data[3]) + (data[5]) * (data[5]);
|
||||
sc7a20_data = SL_Click_Sqrt(sc7a20_data);
|
||||
fifo_data_xyz[i] = sc7a20_data;
|
||||
|
||||
#if SL_Sensor_Algo_Release_Enable==0
|
||||
SL_DEBUG_DATA[0][i] = data[1];
|
||||
SL_DEBUG_DATA[1][i] = data[3];
|
||||
SL_DEBUG_DATA[2][i] = data[5];
|
||||
SL_DEBUG_DATA[3][i] = fifo_data_xyz[i];
|
||||
SL_DEBUG_DATA_LEN = fifo_len;
|
||||
#endif
|
||||
}
|
||||
|
||||
k = 0;
|
||||
for (i = 1; i < fifo_len - 1; i++) {
|
||||
if ((fifo_data_xyz[i + 1] > TH1) && (fifo_data_xyz[i - 1] < 30)) {
|
||||
g_printf("in_th\r\n");
|
||||
if (click_num == 0) {
|
||||
click_sum = 0; //first peak
|
||||
for (j = 0; j < i - 1; j++) {
|
||||
if (fifo_data_xyz[j] > fifo_data_xyz[j + 1]) {
|
||||
click_sum += fifo_data_xyz[j] - fifo_data_xyz[j + 1];
|
||||
} else {
|
||||
click_sum += fifo_data_xyz[j + 1] - fifo_data_xyz[j];
|
||||
}
|
||||
}
|
||||
#if SL_Sensor_Algo_Release_Enable==0
|
||||
g_printf("click_sum:%d!\r\n", click_sum);
|
||||
#endif
|
||||
if (click_sum > TH2) {
|
||||
sl_pp_num++;
|
||||
break;
|
||||
}
|
||||
k = i;
|
||||
} else {
|
||||
k = i; //sencond peak
|
||||
}
|
||||
}
|
||||
|
||||
if (k != 0) {
|
||||
if (fifo_data_xyz[i - 1] - fifo_data_xyz[i + 1] > TH1 - 10) {
|
||||
if (i - k < 5) {
|
||||
click_num = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (click_num == 1) {
|
||||
click_result = 1;
|
||||
} else {
|
||||
click_result = 0;
|
||||
}
|
||||
|
||||
return click_result;
|
||||
}
|
||||
|
||||
//GPIO?????,??INT2
|
||||
//Service function in Int Function
|
||||
//u8 sl_click_timer_en =0;
|
||||
u8 sl_click_status = 0;
|
||||
unsigned short click_timer_cnt = 0;
|
||||
unsigned short click_timer_total_cnt = 0;
|
||||
u8 click_click_final_cnt = 0;
|
||||
|
||||
char SC7A20_Click_Alog(void)
|
||||
{
|
||||
u8 click_status = 0;
|
||||
|
||||
SL_MEMS_i2cWrite(SC7A20_W_ADDR, SC7A20_CTRL_REG3, 0x00);
|
||||
click_status = SC7A20_Click_Read(SC7A20_TH1, SC7A20_TH2); //40,50
|
||||
|
||||
g_printf("click_status = 0x%x\n", click_status);
|
||||
if (click_status == 1) {
|
||||
if (sl_click_timer_en == 0) {
|
||||
//set click timer flag
|
||||
sl_click_timer_en = 1;
|
||||
//clear click timer cnt value
|
||||
click_timer_cnt = 0;
|
||||
click_timer_total_cnt = 0;
|
||||
click_click_final_cnt = 0;
|
||||
}
|
||||
sl_click_status = 1;
|
||||
}
|
||||
SL_MEMS_i2cWrite(SC7A20_W_ADDR, SC7A20_CTRL_REG3, 0x82);
|
||||
return click_status;
|
||||
}
|
||||
|
||||
//This fuction is execute in 50ms timer when the timer is opened
|
||||
char SC7A20_click_status(void)
|
||||
{
|
||||
u8 click_e_cnt = 0;
|
||||
if (sl_click_timer_en == 1) {
|
||||
click_timer_cnt++;
|
||||
if ((click_timer_cnt < click_pp_num) && (sl_click_status == 1)) {
|
||||
g_printf("status:%d\r\n", sl_click_status);
|
||||
g_printf("fin_num:%d\r\n", click_click_final_cnt);
|
||||
sl_click_status = 0;
|
||||
click_timer_total_cnt = click_timer_total_cnt + click_timer_cnt;
|
||||
click_timer_cnt = 0;
|
||||
click_click_final_cnt++;
|
||||
}
|
||||
|
||||
click_e_cnt = SL_Get_CLICK_PP_CNT(1);
|
||||
|
||||
if ((((click_timer_cnt >= click_pp_num) || (click_timer_total_cnt >= click_max_num)) && (click_e_cnt < 1)) ||
|
||||
((click_timer_cnt >= click_pp_num) && (click_e_cnt > 0)))
|
||||
// if((click_timer_cnt>=click_pp_num)||(click_timer_total_cnt>=click_max_num))
|
||||
{
|
||||
//clear click timer flag
|
||||
sl_click_timer_en = 0;
|
||||
//clear click timer cnt value
|
||||
click_timer_cnt = 0;
|
||||
click_timer_total_cnt = 0;
|
||||
g_printf("fin_num:%d\r\n", click_click_final_cnt);
|
||||
if (click_e_cnt > 0) {
|
||||
click_e_cnt = SL_Get_CLICK_PP_CNT(0);
|
||||
return 0;
|
||||
} else {
|
||||
return click_click_final_cnt;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SC7A20_int_io_detect(u8 int_io_status)
|
||||
{
|
||||
static u8 int_io_status_old;
|
||||
/* u8 int_io_status = 0; */
|
||||
/* int_io_status = gpio_read(INT_IO); */
|
||||
if ((int_io_status) && (int_io_status_old == 0)) {
|
||||
log_e("sc7a20_int_io_detect\n");
|
||||
SC7A20_Click_Alog();
|
||||
} else {
|
||||
}
|
||||
int_io_status_old = int_io_status;
|
||||
}
|
||||
|
||||
void SC7A20_read_data(axis_info_t *sl_accel)
|
||||
{
|
||||
u8 data[6];
|
||||
u8 fifo_len = 0;
|
||||
SL_MEMS_i2cRead(SC7A20_R_ADDR, SC7A20_SRC_REG, 1, &fifo_len);
|
||||
if ((fifo_len & 0x40) == 0x40) {
|
||||
fifo_len = 32;
|
||||
} else {
|
||||
fifo_len = fifo_len & 0x1f;
|
||||
}
|
||||
for (u8 i = 0; i < fifo_len; i++) {
|
||||
SL_MEMS_i2cRead(SC7A20_R_ADDR, 0xA8, 6, data);
|
||||
sl_accel[i].x = (short)((data[1] << 8) | data[0]);
|
||||
// sl_accel[i].x = sl_accel[i].x >> 4;
|
||||
sl_accel[i].y = (short)((data[3] << 8) | data[2]);
|
||||
// sl_accel[i].y = sl_accel[i].y >> 4;
|
||||
sl_accel[i].z = (short)((data[5] << 8) | data[4]);
|
||||
// sl_accel[i].z = sl_accel[i].z >> 4;
|
||||
// printf("group:%2d,sl_accel_x:%5d, sl_accel_y:%5d, sl_accel_z:%5d\n", i, sl_accel[i].x, sl_accel[i].y, sl_accel[i].z);
|
||||
}
|
||||
}
|
||||
void SC7A20_ctl(u8 cmd, void *arg)
|
||||
{
|
||||
char res;
|
||||
switch (cmd) {
|
||||
case GSENSOR_DISABLE:
|
||||
res = SC7A20_disable();
|
||||
memcpy(arg, &res, 1);
|
||||
break;
|
||||
case GSENSOR_RESET_INT:
|
||||
res = SC7A20_Config();
|
||||
memcpy(arg, &res, 1);
|
||||
break;
|
||||
case GSENSOR_RESUME_INT:
|
||||
break;
|
||||
case GSENSOR_INT_DET:
|
||||
SC7A20_int_io_detect(*(u8 *)arg);
|
||||
break;
|
||||
case READ_GSENSOR_DATA:
|
||||
SC7A20_read_data((axis_info_t *)arg);
|
||||
break;
|
||||
case SEARCH_SENSOR:
|
||||
res = SC7A20_Check();
|
||||
memcpy(arg, &res, 1);
|
||||
break;
|
||||
default:
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static u8 sc7a20_idle_query(void)
|
||||
{
|
||||
return !sl_click_timer_en;
|
||||
}
|
||||
|
||||
REGISTER_GRAVITY_SENSOR(gSensor) = {
|
||||
.logo = "sc7a20",
|
||||
.gravity_sensor_init = SC7A20_Config,
|
||||
.gravity_sensor_check = SC7A20_click_status,
|
||||
.gravity_sensor_ctl = SC7A20_ctl,
|
||||
};
|
||||
|
||||
REGISTER_LP_TARGET(sc7a20_lp_target) = {
|
||||
.name = "sc7a20",
|
||||
.is_idle = sc7a20_idle_query,
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
116
apps/common/device/gSensor/SC7A20.h
Normal file
116
apps/common/device/gSensor/SC7A20.h
Normal file
@ -0,0 +1,116 @@
|
||||
/*
|
||||
Copyright (c) 2019 Silan MEMS. All Rights Reserved.
|
||||
*/
|
||||
#ifndef SC7A20_H
|
||||
#define SC7A20_H
|
||||
|
||||
/********添加IIC头文件******************/
|
||||
//#include "i2c.h"
|
||||
/***************************************/
|
||||
|
||||
|
||||
/***使用驱动前请根据实际接线情况配置(7bit)IIC地址******/
|
||||
/**SC7A20的SDO 脚接地: 0x18****************/
|
||||
/**SC7A20的SDO 脚接电源: 0x19****************/
|
||||
#define SC7A20_W_ADDR (0x19U << 1 | 0x0)
|
||||
#define SC7A20_R_ADDR (0x19U << 1 | 0x1)
|
||||
/*******************************************************/
|
||||
|
||||
#define SC7A20_CLICK_TH 0x38 //Click触发阈值,如果单次敲击无法触发中断,请将下面这个参数适当调小,如果单次敲击太过灵敏,请将下面这个参数适当调大
|
||||
#define SC7A20_CLICK_WINDOWS 0x05 //Click有效窗口
|
||||
#define SC7A20_CLICK_LATENCY 0x10 //Click中断持续时间,odr = 0x10时, 时间 = 16 * 2.5ms
|
||||
#define SC7A20_INT_LEVEL 0x02 //0x02为中断时低电平,0x0为高电平
|
||||
//如果中断能够触发,但是无法识别为单击,请调小如下函数中的参数 TH1
|
||||
//如果单击能够触发,摇晃都会触发多击,请调小如下函数中的参数 TH2
|
||||
//如果单击能够触发,多击功能比较难实现,请调大如下函数中的参数 TH2
|
||||
#define SC7A20_TH1 40
|
||||
#define SC7A20_TH2 50
|
||||
|
||||
#define click_pp_num (unsigned short)10*25 //10对应0.5s(不需要管后面的*25)
|
||||
#define click_max_num (unsigned short)60*25 // 60对应3s
|
||||
|
||||
|
||||
|
||||
/*************驱动初始化函数**************/
|
||||
unsigned char SC7A20_Config(void);
|
||||
/**SC7A20_Config 函数中, ODR 默认0x7f 400HZ/6f 200HZ ************/
|
||||
/**SC7A20_Config 函数中, HP 默认0xOC 开启高通滤波 ************/
|
||||
/**SC7A20_Config 函数中, click_int 默认0x80 将Click中断映射到INT1************/
|
||||
/**SC7A20_Config 函数中, range 默认0x90 4g量程************/
|
||||
/**SC7A20_Config 函数中, fifo_en 默认0x40 使能fifo************/
|
||||
/**SC7A20_Config 函数中, fifo_mode 默认0x80 Stream模式************/
|
||||
/**SC7A20_Config 函数中, click_mode 默认0x15 单击3轴触发************/
|
||||
/**SC7A20_Config 函数中, click_th 默认0x38 Click触发阈值************/
|
||||
/**SC7A20_Config 函数中, click_window 默认0x05 Click有效窗口************/
|
||||
/**SC7A20_Config 函数中, click_latency 默认0x10 Click中断持续时间************/
|
||||
|
||||
/*************返回数据情况如下*****************/
|
||||
/**return : 1 IIC通讯正常IC在线***************/
|
||||
/**return : 0; IIC通讯异常或IC不在线***************/
|
||||
|
||||
/*************单击状态检测**************/
|
||||
char SC7A20_Click_Read(int TH1, int TH2);
|
||||
/*************TH1 调节单击灵敏度,默认9000*****************/
|
||||
/*************TH2 默认6000*****************/
|
||||
/*************TH3 默认7000*****************/
|
||||
/*************返回数据情况如下*****************/
|
||||
/**return : 1 单次敲击有效***************/
|
||||
/**return : 0; 单次敲击无效***************/
|
||||
|
||||
|
||||
/*************外部中断调用Click敲击函数**************/
|
||||
char SC7A20_Click_Alog(void);
|
||||
/*************返回数据情况如下*****************/
|
||||
/**return : 1 单次敲击有效***************/
|
||||
/**return : 0; 单次敲击无效***************/
|
||||
|
||||
|
||||
/*************定时器中断调用Click状态函数**************/
|
||||
char SC7A20_click_status(void);
|
||||
/*************返回数据情况如下*****************/
|
||||
/**return : N N次敲击有效***************/
|
||||
|
||||
|
||||
/**reg map***************/
|
||||
#define SC7A20_OUT_TEMP_L 0x0C
|
||||
#define SC7A20_OUT_TEMP_H 0x0D
|
||||
#define SC7A20_WHO_AM_I 0x0F
|
||||
#define SC7A20_USER_CAL_START 0x13
|
||||
#define SC7A20_USER_CAL_END 0x1A
|
||||
#define SC7A20_NVM_WR 0x1E
|
||||
#define SC7A20_TEMP_CFG 0x1F
|
||||
#define SC7A20_CTRL_REG1 0x20
|
||||
#define SC7A20_CTRL_REG2 0x21
|
||||
#define SC7A20_CTRL_REG3 0x22
|
||||
#define SC7A20_CTRL_REG4 0x23
|
||||
#define SC7A20_CTRL_REG5 0x24
|
||||
#define SC7A20_CTRL_REG6 0x25
|
||||
#define SC7A20_REFERENCE 0x26
|
||||
#define SC7A20_STATUS_REG 0x27
|
||||
#define SC7A20_OUT_X_L 0x28
|
||||
#define SC7A20_OUT_X_H 0x29
|
||||
#define SC7A20_OUT_Y_L 0x2A
|
||||
#define SC7A20_OUT_Y_H 0x2B
|
||||
#define SC7A20_OUT_Z_L 0x2C
|
||||
#define SC7A20_OUT_Z_H 0x2D
|
||||
#define SC7A20_FIFO_CTRL_REG 0x2E
|
||||
#define SC7A20_SRC_REG 0x2F
|
||||
#define SC7A20_INT1_CFG 0x30
|
||||
#define SC7A20_INT1_SOURCE 0x31
|
||||
#define SC7A20_INT1_THS 0x32
|
||||
#define SC7A20_INT1_DURATION 0x33
|
||||
#define SC7A20_INT2_CFG 0x34
|
||||
#define SC7A20_INT2_SOURCE 0x35
|
||||
#define SC7A20_INT2_THS 0x36
|
||||
#define SC7A20_INT2_DURATION 0x37
|
||||
#define SC7A20_CLICK_CFG 0x38
|
||||
#define SC7A20_CLICK_SRC 0x39
|
||||
#define SC7A20_CLICK_THS 0x3A
|
||||
#define SC7A20_TIME_LIMIT 0x3B
|
||||
#define SC7A20_TIME_LATENCY 0x3C
|
||||
#define SC7A20_TIME_WINDOW 0x3D
|
||||
#define SC7A20_ACT_THS 0x3E
|
||||
#define SC7A20_ACT_DURATION 0x3F
|
||||
|
||||
#endif // SC7A20_H
|
||||
|
||||
141
apps/common/device/gSensor/STK8321.c
Normal file
141
apps/common/device/gSensor/STK8321.c
Normal file
@ -0,0 +1,141 @@
|
||||
#include "gSensor/STK8321.h"
|
||||
#include "gSensor/gSensor_manage.h"
|
||||
#include "app_config.h"
|
||||
|
||||
#if TCFG_STK8321_EN
|
||||
|
||||
static u8 stk8321_timeout_start = 0;
|
||||
|
||||
u8 STK8321_Read(u8 addr)
|
||||
{
|
||||
u8 data = 0;
|
||||
_gravity_sensor_get_ndata(I2C_ADDR_STK8321_R, addr, &data, 1);
|
||||
return data;
|
||||
}
|
||||
|
||||
void STK8321_Write(u8 addr, u8 data)
|
||||
{
|
||||
//g_sensor_write(G_SlaveAddr,addr,data);
|
||||
gravity_sensor_command(I2C_ADDR_STK8321_W, addr, data);
|
||||
}
|
||||
|
||||
u8 STK8321_init(void)
|
||||
{
|
||||
u8 k = 0, init_cnt = 10;
|
||||
u8 chip_id = 0;
|
||||
printf("\n###############>> [ init STK8321 start] <<################\n");
|
||||
|
||||
do {
|
||||
|
||||
chip_id = STK8321_Read(0x00);
|
||||
printf("\n STK8321 ID = [%x]\n", chip_id);
|
||||
init_cnt--;
|
||||
|
||||
} while ((chip_id != 0x86) && (init_cnt));
|
||||
|
||||
STK8321_Write(0x14, 0xB6); //software reset
|
||||
delay(1000);
|
||||
|
||||
if (chip_id != 0x86) {
|
||||
return -1;
|
||||
}
|
||||
STK8321_Write(0x14, 0xB6); //software reset
|
||||
delay(100);
|
||||
// mode settings
|
||||
STK8321_Write(0x11, 0x00); //active mode
|
||||
STK8321_Write(0x0F, 0x08); //range = +-8g
|
||||
STK8321_Write(0x10, 0x0D); //BW = 250Hz or ODR = 500Hz
|
||||
STK8321_Write(0x34, 0x04); //Enable I2C WatchDog
|
||||
// INT mode
|
||||
STK8321_Write(0x20, 0x00); //INT1 and INT2 active high
|
||||
STK8321_Write(0x21, 0x8F); //latched & clear
|
||||
// slope settings
|
||||
STK8321_Write(0x16, 0x04); // enable slope on Z-axis
|
||||
STK8321_Write(0x19, 0x01); // map sig-motion to INT 1
|
||||
STK8321_Write(0x27, 0x01); // The actual number of samples SLP_DUR[1:0]+1
|
||||
STK8321_Write(0x28, 0x25); // SLP_THD[7:0]*15.64_mg
|
||||
STK8321_Write(0x2A, 0x06); //Enable significant and any-motion interrupt
|
||||
STK8321_Write(0x29, 0x05); //skip_time 1LSB=20ms
|
||||
STK8321_Write(0x2B, 0x0A); //proof_time 1LSB=20ms
|
||||
printf("\n###############>> [ init STK8321 end ] <<################\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char STK8321_check_event()
|
||||
{
|
||||
static u16 timeout_cnt = 125; //需要等250ms
|
||||
u8 click_cnt = 0;
|
||||
if (stk8321_timeout_start) {
|
||||
if (timeout_cnt) {
|
||||
timeout_cnt --;
|
||||
} else {
|
||||
u8 RegReadValue = 0;
|
||||
g_printf("stk8321_timeout");
|
||||
RegReadValue = STK8321_Read(0x09);
|
||||
if ((RegReadValue & 0x04) == 0x00) {
|
||||
g_printf("Double Tap");
|
||||
click_cnt = 2;
|
||||
} else if ((RegReadValue & 0x04) == 0x04) {
|
||||
g_printf("Triple Tap");
|
||||
click_cnt = 3;
|
||||
} else {
|
||||
g_printf("NO Tap");
|
||||
click_cnt = 0;
|
||||
}
|
||||
STK8321_Write(0x2A, 0x02);
|
||||
STK8321_Write(0x21, 0x8F);
|
||||
stk8321_timeout_start = 0;
|
||||
timeout_cnt = 125;
|
||||
}
|
||||
}
|
||||
return click_cnt;
|
||||
}
|
||||
|
||||
void STK8321_int_io_detect(u8 int_io_status)
|
||||
{
|
||||
static u8 int_io_status_old;
|
||||
if (!stk8321_timeout_start) {
|
||||
if (!(int_io_status) && (int_io_status_old == 1)) {
|
||||
g_printf("STK8321_int_io_detect\n");
|
||||
stk8321_timeout_start = 1;
|
||||
STK8321_Write(0x2A, 0x04);
|
||||
STK8321_Write(0x21, 0x8F);
|
||||
}
|
||||
int_io_status_old = int_io_status;
|
||||
}
|
||||
}
|
||||
|
||||
void STK8321_ctl(u8 cmd, void *arg)
|
||||
{
|
||||
switch (cmd) {
|
||||
case GSENSOR_RESET_INT:
|
||||
break;
|
||||
case GSENSOR_RESUME_INT:
|
||||
break;
|
||||
case GSENSOR_INT_DET:
|
||||
STK8321_int_io_detect(*(u8 *)arg);
|
||||
break;
|
||||
default:
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static u8 STK8321_idle_query(void)
|
||||
{
|
||||
return !stk8321_timeout_start;
|
||||
}
|
||||
|
||||
REGISTER_GRAVITY_SENSOR(gSensor) = {
|
||||
.logo = "STK8321",
|
||||
.gravity_sensor_init = STK8321_init,
|
||||
.gravity_sensor_check = STK8321_check_event,
|
||||
.gravity_sensor_ctl = STK8321_ctl,
|
||||
};
|
||||
|
||||
REGISTER_LP_TARGET(da230_lp_target) = {
|
||||
.name = "STK8321",
|
||||
.is_idle = STK8321_idle_query,
|
||||
};
|
||||
#endif
|
||||
11
apps/common/device/gSensor/STK8321.h
Normal file
11
apps/common/device/gSensor/STK8321.h
Normal file
@ -0,0 +1,11 @@
|
||||
#ifndef __STK8321_H__
|
||||
#define __STK8321_H__
|
||||
|
||||
#include "typedef.h"
|
||||
|
||||
#define STK8321_ID 0x30
|
||||
|
||||
#define I2C_ADDR_STK8321_W (STK8321_ID | 0x0)
|
||||
#define I2C_ADDR_STK8321_R (STK8321_ID | 0x1)
|
||||
|
||||
#endif
|
||||
393
apps/common/device/gSensor/da230.c
Normal file
393
apps/common/device/gSensor/da230.c
Normal file
@ -0,0 +1,393 @@
|
||||
#include "gSensor/EPMotion.h"
|
||||
#include "gSensor/da230.h"
|
||||
#include "gSensor/gSensor_manage.h"
|
||||
#include "app_config.h"
|
||||
|
||||
#if TCFG_DA230_EN
|
||||
|
||||
#define LOG_TAG "[DA230]"
|
||||
#define LOG_ERROR_ENABLE
|
||||
#define LOG_DEBUG_ENABLE
|
||||
#define LOG_INFO_ENABLE
|
||||
/* #define LOG_DUMP_ENABLE */
|
||||
#define LOG_CLI_ENABLE
|
||||
#include "debug.h"
|
||||
|
||||
static u8 da230_init_ok = 0;
|
||||
static u8 tap_data = 0;
|
||||
static u8 tap_start = 0;
|
||||
static u8 event_ocur = 0;
|
||||
static u8 da230_is_idle = 1;
|
||||
|
||||
void da230_set_idle_flag(u8 flag)
|
||||
{
|
||||
da230_is_idle = flag;
|
||||
}
|
||||
|
||||
u32 da230_register_read(u8 addr, u8 *data)
|
||||
{
|
||||
_gravity_sensor_get_ndata(I2C_ADDR_DA230_R, addr, data, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
s8_m da230_register_write(u8_m addr, u8_m data)
|
||||
{
|
||||
gravity_sensor_command(I2C_ADDR_DA230_W, addr, data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
s8_m da230_read_nbyte_data(u8_m addr, u8_m *data, u8_m len)
|
||||
{
|
||||
_gravity_sensor_get_ndata(I2C_ADDR_DA230_R, addr, data, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
s8_m da230_register_mask_write(unsigned char addr, unsigned char mask, unsigned char data)
|
||||
{
|
||||
int res = 0;
|
||||
unsigned char tmp_data;
|
||||
|
||||
/* iic_readn(I2C_ADDR_DA230_R, addr, &tmp_data, 1); */
|
||||
da230_read_nbyte_data(addr, &tmp_data, 1);
|
||||
|
||||
tmp_data &= ~mask;
|
||||
tmp_data |= data & mask;
|
||||
/* iic_write(I2C_ADDR_DA230_W, addr, &tmp_data, 1); */
|
||||
da230_register_write(addr, tmp_data);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
s8_m handleEvent(EPMotion_EVENT event, u8 data)
|
||||
{
|
||||
event_ocur = 0;
|
||||
tap_start = 0;
|
||||
da230_set_idle_flag(1);
|
||||
log_info("da230_set_idle_flag:1");
|
||||
switch (event) {
|
||||
case TEVENT_TAP_NOTIFY: {
|
||||
tap_data = data;
|
||||
printf("*******DATA:%d \n", data);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 da230_register_write_bit(u8 addr, u8 start, u8 len, u8 data)
|
||||
{
|
||||
u32 res = 0;
|
||||
u8 tmp_data;
|
||||
|
||||
res = da230_register_read(addr, &tmp_data);
|
||||
if (res) {
|
||||
return res;
|
||||
}
|
||||
|
||||
SFR(tmp_data, start, len, data);
|
||||
|
||||
res = da230_register_write(addr, tmp_data);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
u32 da230_close_i2c_pullup(void)
|
||||
{
|
||||
u32 res = 0;
|
||||
|
||||
res |= da230_register_write(0x7f, 0x83);
|
||||
res |= da230_register_write(0x7f, 0x69);
|
||||
res |= da230_register_write(0x7f, 0xBD);
|
||||
|
||||
/**********将0x8f bit1写0,去掉da230内部i2c弱上拉*********/
|
||||
res |= da230_register_write_bit(0x8f, 1, 1, 0);
|
||||
|
||||
return res;
|
||||
}
|
||||
#if 0
|
||||
u32 da230_read_block_data(u8 base_addr, u8 count, u8 *data)
|
||||
{
|
||||
u32 i = 0;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
if (da230_register_read(base_addr + i, (data + i))) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
u32 da230_register_read_continuously(u8 addr, u8 count, u8 *data)
|
||||
{
|
||||
u32 res = 0;
|
||||
|
||||
res = (count == da230_read_block_data(addr, count, data)) ? 0 : 1;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
u32 da230_open_step_counter(void)
|
||||
{
|
||||
u32 res = 0;
|
||||
|
||||
res |= da230_register_write(NSA_REG_STEP_CONGIF1, 0x01);
|
||||
res |= da230_register_write(NSA_REG_STEP_CONGIF2, 0x62);
|
||||
res |= da230_register_write(NSA_REG_STEP_CONGIF3, 0x46);
|
||||
res |= da230_register_write(NSA_REG_STEP_CONGIF4, 0x32);
|
||||
res |= da230_register_write(NSA_REG_STEP_FILTER, 0xa2);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
u16 da230_get_step(void)
|
||||
{
|
||||
u8 tmp_data[4] = {0};
|
||||
u16 f_step = 0;
|
||||
|
||||
if (da230_register_read_continuously(NSA_REG_STEPS_MSB, 4, tmp_data) == 0) {
|
||||
if (0x40 == tmp_data[2] && 0x07 == tmp_data[3]) {
|
||||
f_step = ((tmp_data[0] << 8 | tmp_data[1])) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return (f_step);
|
||||
}
|
||||
|
||||
u32 da230_close_step_counter(void)
|
||||
{
|
||||
u32 res = 0;
|
||||
|
||||
res = da230_register_write(NSA_REG_STEP_FILTER, 0x22);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
u32 da230_register_write_bit(u8 addr, u8 start, u8 len, u8 data)
|
||||
{
|
||||
u32 res = 0;
|
||||
u8 tmp_data;
|
||||
|
||||
res = da230_register_read(addr, &tmp_data);
|
||||
if (res) {
|
||||
return res;
|
||||
}
|
||||
|
||||
SFR(tmp_data, start, len, data);
|
||||
|
||||
res = da230_register_write(addr, tmp_data);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
u32 da230_open_i2c_pullup(void)
|
||||
{
|
||||
u32 res = 0;
|
||||
|
||||
res |= da230_register_write(0x7f, 0x83);
|
||||
res |= da230_register_write(0x7f, 0x69);
|
||||
res |= da230_register_write(0x7f, 0xBD);
|
||||
|
||||
/**********将0x8f bit1写1,开启da230内部i2c弱上拉*********/
|
||||
res |= da230_register_write_bit(0x8f, 1, 1, 1);
|
||||
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct EPMotion_op_s ops_handle = {
|
||||
{PIN_ONE, PIN_LEVEL_LOW},
|
||||
handleEvent,
|
||||
{da230_read_nbyte_data, da230_register_write},
|
||||
printf
|
||||
};
|
||||
u8 da230_init(void)
|
||||
{
|
||||
u8 data = 0;
|
||||
|
||||
JL_PORTB->DIR &= ~BIT(2);
|
||||
JL_PORTB->DIE |= BIT(2);
|
||||
JL_PORTB->OUT |= BIT(2);
|
||||
da230_register_read(NSA_REG_WHO_AM_I, &data);
|
||||
|
||||
if (data != 0x13) {
|
||||
log_e("da230 init err1!!!!!!!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (EPMotion_Init(&ops_handle)) {
|
||||
log_e("da230 init err2!!!!!!!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
EPMotion_Set_Debug_level(DEBUG_ERR);
|
||||
EPMotion_Tap_Set_Parma(0x0d, LATCHED_100MS, 0x00); //0x05~0x1f
|
||||
//EPMotion_D_Tap_Set_Filter(1, 130);
|
||||
EPMotion_M_Tap_Set_Dur(70, 500);
|
||||
// EPMotion_M_Tap_Set_Dur(60,150);
|
||||
da230_register_mask_write(0x10, 0xe0, 0xc0);
|
||||
EPMotion_Control(M_TAP_T, ENABLE_T);
|
||||
// EPMotion_Tap_Set_Parma(0x08,LATCHED_25MS,0x00); //0x05~0x1f
|
||||
|
||||
|
||||
//close i2c pullup
|
||||
da230_close_i2c_pullup();
|
||||
da230_register_mask_write(0x8f, 0x02, 0x00);
|
||||
|
||||
da230_init_ok = 1;
|
||||
|
||||
log_info("da230 init success!!!\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 da230_set_enable(u8 enable)
|
||||
{
|
||||
u32 res = 0;
|
||||
|
||||
if (da230_init_ok) {
|
||||
|
||||
if (enable) {
|
||||
EPMotion_Chip_Power_On();
|
||||
} else {
|
||||
EPMotion_Chip_Power_Off();
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
void da230_read_XYZ(short *x, short *y, short *z)
|
||||
{
|
||||
if (da230_init_ok) {
|
||||
EPMotion_Chip_Read_XYZ(x, y, z);
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
u16 da230_open_interrupt(u16 num)
|
||||
{
|
||||
u16 res = 0;
|
||||
res = da230_register_write(NSA_REG_INTERRUPT_SETTINGS1, 0x87);
|
||||
res = da230_register_write(NSA_REG_ACTIVE_THRESHOLD, 0x05);
|
||||
switch (num) {
|
||||
case 0:
|
||||
res = da230_register_write(NSA_REG_INTERRUPT_MAPPING1, 0x04);
|
||||
break;
|
||||
case 1:
|
||||
res = da230_register_write(NSA_REG_INTERRUPT_MAPPING3, 0x04);
|
||||
break;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
|
||||
void da230_check_tap_int(void)
|
||||
{
|
||||
static int count = 0;
|
||||
if (tap_start) {
|
||||
if (event_ocur == 1) {
|
||||
count = 0;
|
||||
}
|
||||
if ((count % 5) == 0) {
|
||||
//printf("====process event %d\r\n",event_ocur);
|
||||
// gpio_direction_output(IO_PORT_DM, 1);
|
||||
EPMotion_Process_Data(event_ocur);
|
||||
// gpio_direction_output(IO_PORT_DM, 0);
|
||||
}
|
||||
count++;
|
||||
|
||||
if (count >= 300000) {
|
||||
count = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void da230_low_energy_mode(void)
|
||||
{
|
||||
da230_register_write(0x11, 0x04);
|
||||
}
|
||||
|
||||
void da230_int_io_detect(u8 int_io_status)
|
||||
{
|
||||
static u8 int_io_status_old = 0;
|
||||
/* u8 int_io_status = 0; */
|
||||
if (da230_init_ok) {
|
||||
/* int_io_status = gpio_read(INT_IO); */
|
||||
if ((int_io_status) && (int_io_status_old == 0)) {
|
||||
log_e("da230_int_io_detect\n");
|
||||
if (tap_start == 0) {
|
||||
tap_start = 1;
|
||||
da230_set_idle_flag(0);
|
||||
log_info("da230_set_idle_flag:0");
|
||||
}
|
||||
event_ocur = 1;
|
||||
putchar('A');
|
||||
} else {
|
||||
event_ocur = 0;
|
||||
}
|
||||
int_io_status_old = int_io_status;
|
||||
|
||||
da230_check_tap_int();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static char da230_check_event()
|
||||
{
|
||||
u8 tmp_tap_data = 0;
|
||||
tmp_tap_data = tap_data;
|
||||
if (tap_data) {
|
||||
tap_data = 0;
|
||||
printf("tmp_tap_data = %d\n", tmp_tap_data);
|
||||
}
|
||||
return tmp_tap_data;
|
||||
/* return EPMotion_Process_Data(); */
|
||||
}
|
||||
|
||||
void da230_ctl(u8 cmd, void *arg)
|
||||
{
|
||||
switch (cmd) {
|
||||
case GSENSOR_RESET_INT:
|
||||
EPMotion_Reset_Tap_INT();
|
||||
break;
|
||||
case GSENSOR_RESUME_INT:
|
||||
EPMotion_Resume_Tap_INT();
|
||||
break;
|
||||
case GSENSOR_INT_DET:
|
||||
da230_int_io_detect(*(u8 *)arg);
|
||||
break;
|
||||
default:
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static u8 da230_idle_query(void)
|
||||
{
|
||||
return da230_is_idle;
|
||||
}
|
||||
|
||||
REGISTER_GRAVITY_SENSOR(gSensor) = {
|
||||
.logo = "da230",
|
||||
.gravity_sensor_init = da230_init,
|
||||
.gravity_sensor_check = da230_check_event,
|
||||
.gravity_sensor_ctl = da230_ctl,
|
||||
};
|
||||
|
||||
REGISTER_LP_TARGET(da230_lp_target) = {
|
||||
.name = "da230",
|
||||
.is_idle = da230_idle_query,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
25
apps/common/device/gSensor/da230.h
Normal file
25
apps/common/device/gSensor/da230.h
Normal file
@ -0,0 +1,25 @@
|
||||
#ifndef __da230_h
|
||||
#define __da230_h
|
||||
|
||||
#include "typedef.h"
|
||||
#include "mira_std.h"
|
||||
|
||||
|
||||
|
||||
#define LATCHED_MODE LATCHED_1S //interrupt latched mode
|
||||
#define INTERRUPT_THRESHOLD 15 //interrupt threshold 0~31 ,(threshold*125)mg
|
||||
#define INTERRUPT_DURATION 5 //interrupt duration 0~7 ,(50~700)ms 0:50ms 1:100ms 2:150ms 3:200ms 4:250ms 5:375ms 6:500ms 7:700ms
|
||||
#define TAP_SAMPLE_LEVEL 1 //采样次数 = 25-TAP_SAMPLE_LEVEL*5
|
||||
#define TAP_FILTER 30 //噪声大小,大于TAP_FILTER认为是噪声
|
||||
|
||||
#define I2C_ADDR_DA230_W 0x4e
|
||||
#define I2C_ADDR_DA230_R 0x4f
|
||||
|
||||
extern u32 da230_register_read(u8 addr, u8 *data);
|
||||
extern s8_m da230_register_write(u8_m addr, u8_m data);
|
||||
extern u32 da230_register_write_bit(u8 addr, u8 start, u8 len, u8 data);
|
||||
|
||||
// extern u8 da230_int_event_detect(void);
|
||||
|
||||
#endif
|
||||
|
||||
488
apps/common/device/gSensor/gSensor_manage.c
Normal file
488
apps/common/device/gSensor/gSensor_manage.c
Normal file
@ -0,0 +1,488 @@
|
||||
#include "gSensor/gSensor_manage.h"
|
||||
#include "device/device.h"
|
||||
#include "app_config.h"
|
||||
#include "debug.h"
|
||||
#include "key_event_deal.h"
|
||||
#include "btstack/avctp_user.h"
|
||||
#include "app_main.h"
|
||||
#include "tone_player.h"
|
||||
#include "user_cfg.h"
|
||||
#include "system/os/os_api.h"
|
||||
#include "asm/power/power_wakeup.h"
|
||||
/* #include "audio_config.h" */
|
||||
/* #include "app_power_manage.h" */
|
||||
/* #include "system/timer.h" */
|
||||
/* #include "event.h" */
|
||||
|
||||
#if TCFG_USER_TWS_ENABLE
|
||||
#include "bt_tws.h"
|
||||
#endif
|
||||
|
||||
#define ENABLE_XLOG 1
|
||||
#ifdef xlog
|
||||
#undef xlog
|
||||
#endif
|
||||
#if ENABLE_XLOG
|
||||
#define xlog(format, ...) printf("[XT:%s] " format, __func__, ##__VA_ARGS__)
|
||||
#else
|
||||
#define xlog(format, ...) ((void)0)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
spinlock_t iic_lock;
|
||||
|
||||
#define LOG_TAG "[GSENSOR]"
|
||||
#define LOG_ERROR_ENABLE
|
||||
#define LOG_DEBUG_ENABLE
|
||||
#define xlog_ENABLE
|
||||
/* #define LOG_DUMP_ENABLE */
|
||||
#define LOG_CLI_ENABLE
|
||||
#include "debug.h"
|
||||
|
||||
static const struct gsensor_platform_data *platform_data;
|
||||
G_SENSOR_INTERFACE *gSensor_hdl = NULL;
|
||||
G_SENSOR_INFO __gSensor_info = {.iic_delay = 10};
|
||||
#define gSensor_info (&__gSensor_info)
|
||||
static cbuffer_t *data_w_cbuf;
|
||||
//static short read_buf[256];
|
||||
extern int gsensorlen;
|
||||
extern OS_MUTEX SENSOR_IIC_MUTEX;
|
||||
|
||||
|
||||
// extern spinlock_t sensor_iic;
|
||||
extern u8 sensor_iic_init_status;
|
||||
|
||||
#define BUF_SIZE gsensorlen*3
|
||||
static short *data_buf;
|
||||
u8 read_write_status = 0;
|
||||
#if TCFG_GSENOR_USER_IIC_TYPE
|
||||
#define iic_init(iic) hw_iic_init(iic)
|
||||
#define iic_uninit(iic) hw_iic_uninit(iic)
|
||||
#define iic_start(iic) hw_iic_start(iic)
|
||||
#define iic_stop(iic) hw_iic_stop(iic)
|
||||
#define iic_tx_byte(iic, byte) hw_iic_tx_byte(iic, byte)
|
||||
#define iic_rx_byte(iic, ack) hw_iic_rx_byte(iic, ack)
|
||||
#define iic_read_buf(iic, buf, len) hw_iic_read_buf(iic, buf, len)
|
||||
#define iic_write_buf(iic, buf, len) hw_iic_write_buf(iic, buf, len)
|
||||
#define iic_suspend(iic) hw_iic_suspend(iic)
|
||||
#define iic_resume(iic) hw_iic_resume(iic)
|
||||
#else
|
||||
#define iic_init(iic) soft_iic_init(iic)
|
||||
#define iic_uninit(iic) soft_iic_uninit(iic)
|
||||
#define iic_start(iic) soft_iic_start(iic)
|
||||
#define iic_stop(iic) soft_iic_stop(iic)
|
||||
#define iic_tx_byte(iic, byte) soft_iic_tx_byte(iic, byte)
|
||||
#define iic_rx_byte(iic, ack) soft_iic_rx_byte(iic, ack)
|
||||
#define iic_read_buf(iic, buf, len) soft_iic_read_buf(iic, buf, len)
|
||||
#define iic_write_buf(iic, buf, len) soft_iic_write_buf(iic, buf, len)
|
||||
#define iic_suspend(iic) soft_iic_suspend(iic)
|
||||
#define iic_resume(iic) soft_iic_resume(iic)
|
||||
#endif
|
||||
|
||||
void gSensor_event_to_user(u8 event)
|
||||
{
|
||||
struct sys_event e;
|
||||
e.type = SYS_KEY_EVENT;
|
||||
e.u.key.event = event;
|
||||
e.u.key.value = 0;
|
||||
sys_event_notify(&e);
|
||||
}
|
||||
|
||||
void gSensor_int_io_detect(void *priv)
|
||||
{
|
||||
u8 int_io_status = 0;
|
||||
u8 det_result = 0;
|
||||
int_io_status = gpio_read(platform_data->gSensor_int_io);
|
||||
//xlog("status %d\n",int_io_status);
|
||||
gSensor_hdl->gravity_sensor_ctl(GSENSOR_INT_DET, &int_io_status);
|
||||
if (gSensor_hdl->gravity_sensor_check == NULL) {
|
||||
return;
|
||||
}
|
||||
det_result = gSensor_hdl->gravity_sensor_check();
|
||||
if (det_result == 1) {
|
||||
xlog("GSENSOR_EVENT_CLICK\n");
|
||||
gSensor_event_to_user(KEY_EVENT_CLICK);
|
||||
} else if (det_result == 2) {
|
||||
xlog("GSENSOR_EVENT_DOUBLE_CLICK\n");
|
||||
gSensor_event_to_user(KEY_EVENT_DOUBLE_CLICK);
|
||||
} else if (det_result == 3) {
|
||||
xlog("GSENSOR_EVENT_THREE_CLICK\n");
|
||||
gSensor_event_to_user(KEY_EVENT_TRIPLE_CLICK);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int gSensor_read_data(u8 *buf, u8 buflen)
|
||||
{
|
||||
if (buflen < 32) {
|
||||
return 0;
|
||||
}
|
||||
axis_info_t accel_data[32];
|
||||
if (!gpio_read(platform_data->gSensor_int_io)) {
|
||||
gSensor_hdl->gravity_sensor_ctl(READ_GSENSOR_DATA, accel_data);
|
||||
}
|
||||
memcpy(buf, accel_data, sizeof(accel_data));
|
||||
return sizeof(accel_data) / sizeof(axis_info_t);
|
||||
}
|
||||
//输出三轴数组和数据长度
|
||||
//
|
||||
int get_gSensor_data(short *buf)
|
||||
{
|
||||
// xlog("%s",__func__);
|
||||
axis_info_t accel_data[32];
|
||||
if (!gpio_read(platform_data->gSensor_int_io)) {
|
||||
gSensor_hdl->gravity_sensor_ctl(READ_GSENSOR_DATA, accel_data);
|
||||
|
||||
for (int i = 0; i < 29; i++) {
|
||||
buf[i * 2] = accel_data[i].x;
|
||||
buf[i * 2 + 1] = accel_data[i].y;
|
||||
buf[i * 2 + 2] = accel_data[i].z;
|
||||
// xlog("cnt:%1d x:%5d y:%5d z:%5d\n", i, accel_data[i].x, accel_data[i].y, accel_data[i].z);
|
||||
|
||||
}
|
||||
|
||||
return sizeof(accel_data) / sizeof(axis_info_t);
|
||||
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
int read_gsensor_buf(short *buf)
|
||||
{
|
||||
read_gsensor_nbuf(buf, 1200);
|
||||
return 1200;
|
||||
}
|
||||
static u8 wr_lock;
|
||||
int read_gsensor_nbuf(short *buf, short datalen)
|
||||
{
|
||||
// xlog("%s",__func__);
|
||||
if (data_w_cbuf == NULL) {
|
||||
return 0;
|
||||
}
|
||||
if (gSensor_info->init_flag == 1) {
|
||||
// if (read_write_status == 0) {
|
||||
// read_write_status = 1;
|
||||
// return 0;
|
||||
// }
|
||||
if (data_w_cbuf->data_len >= datalen) {
|
||||
cbuf_read(data_w_cbuf, buf, datalen);
|
||||
cbuf_clear(data_w_cbuf);
|
||||
return datalen;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
xlog("%s NOT ONLINE ", __func__);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void write_gsensor_data_handle(void)
|
||||
{
|
||||
axis_info_t accel_data[32];
|
||||
if (data_w_cbuf == NULL) {
|
||||
return ;
|
||||
}
|
||||
if (gSensor_info->init_flag == 1) {
|
||||
|
||||
// if (read_write_status == 0) {
|
||||
// xlog("%s ",__func__);
|
||||
// return;
|
||||
// }
|
||||
|
||||
if (!gpio_read(platform_data->gSensor_int_io)) {
|
||||
gSensor_hdl->gravity_sensor_ctl(READ_GSENSOR_DATA, accel_data);
|
||||
/*for(int i=0;i<29;i++){
|
||||
xlog("cnt:%1d x:%5d y:%5d z:%5d\n", i, accel_data[i].x, accel_data[i].y, accel_data[i].z);
|
||||
|
||||
}*/
|
||||
u8 wlen;
|
||||
wlen = cbuf_write(data_w_cbuf, accel_data, 2 * 3 * 29);
|
||||
/* for(int i=0;i<29;i++){ */
|
||||
/* xlog("sour x=%06d y=%06d z=%06d",accel_data[i].x,accel_data[i].y,accel_data[i].z); */
|
||||
/* } */
|
||||
if (wlen == 0) {
|
||||
xlog("data_w_cbuf_full");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// xlog("%s ",__func__);
|
||||
return ;
|
||||
}
|
||||
}
|
||||
|
||||
// 临时的设备扫描诊断函数
|
||||
void i2c_scanner_probe(u8* device_addr, u8* found_number)
|
||||
{
|
||||
printf("Starting I2C bus scan...\n");
|
||||
int devices_found = 0;
|
||||
|
||||
// I2C地址范围是 0x08 到 0x77
|
||||
for (uint8_t addr_7bit = 0x00; addr_7bit < 0x7F; addr_7bit++)
|
||||
{
|
||||
// 构建8位的写地址
|
||||
uint8_t write_addr_8bit = (addr_7bit << 1);
|
||||
|
||||
iic_start(gSensor_info->iic_hdl);
|
||||
|
||||
// 尝试发送写地址,并检查返回值
|
||||
// iic_tx_byte 返回 1 表示收到了 ACK
|
||||
if (iic_tx_byte(gSensor_info->iic_hdl, write_addr_8bit))
|
||||
{
|
||||
device_addr[devices_found] = addr_7bit;
|
||||
printf("=====================================================================\n");
|
||||
printf("I2C device found at 7-bit address: 0x%02X\n", addr_7bit);
|
||||
printf("I2C device found at 8-bit address: 0x%02X\n", write_addr_8bit);
|
||||
printf("=====================================================================\n");
|
||||
devices_found++;
|
||||
}
|
||||
|
||||
iic_stop(gSensor_info->iic_hdl);
|
||||
delay(gSensor_info->iic_delay); // 短暂延时
|
||||
}
|
||||
*found_number = devices_found;
|
||||
|
||||
if (devices_found == 0) {
|
||||
printf("Scan finished. No I2C devices found.\n");
|
||||
} else {
|
||||
printf("Scan finished. Found %d device(s).\n", devices_found);
|
||||
}
|
||||
}
|
||||
|
||||
char w_log_buffer_1[100];
|
||||
char w_log_buffer_2[100];
|
||||
char w_log_buffer_3[100];
|
||||
char w_log_buffer_4[100];
|
||||
char w_log_buffer_5[100];
|
||||
u8 gravity_sensor_command(u8 w_chip_id, u8 register_address, u8 function_command)
|
||||
{
|
||||
// spin_lock(&sensor_iic);
|
||||
/* os_mutex_pend(&SENSOR_IIC_MUTEX,0); */
|
||||
u8 ret = 1;
|
||||
// xlog("iic_start\n");
|
||||
iic_start(gSensor_info->iic_hdl);
|
||||
|
||||
// xlog("iic_tx_byte id\n");
|
||||
if (0 == iic_tx_byte(gSensor_info->iic_hdl, w_chip_id)) {
|
||||
ret = 0;
|
||||
xlog("\n gsen iic wr err 0\n");
|
||||
strcpy(&w_log_buffer_1, "gsen iic wr err 0\n");
|
||||
goto __gcend;
|
||||
}
|
||||
|
||||
// xlog("iic delay\n");
|
||||
delay(gSensor_info->iic_delay);
|
||||
|
||||
// xlog("iic_tx_byte: address\n");
|
||||
if (0 == iic_tx_byte(gSensor_info->iic_hdl, register_address)) {
|
||||
ret = 0;
|
||||
xlog("\n gsen iic wr err 1\n");
|
||||
strcpy(&w_log_buffer_2, "gsen iic wr err 1\n");
|
||||
goto __gcend;
|
||||
}
|
||||
|
||||
delay(gSensor_info->iic_delay);
|
||||
|
||||
// xlog("iic_tx_byte: command\n");
|
||||
if (0 == iic_tx_byte(gSensor_info->iic_hdl, function_command)) {
|
||||
ret = 0;
|
||||
xlog("\n gsen iic wr err 2\n");
|
||||
strcpy(&w_log_buffer_3, "gsen iic wr err 3\n");
|
||||
goto __gcend;
|
||||
}
|
||||
|
||||
strcpy(&w_log_buffer_4, "gsen iic wr sucess\n");
|
||||
// xlog("\n gsen iic wr sucess\n");
|
||||
|
||||
__gcend:
|
||||
iic_stop(gSensor_info->iic_hdl);
|
||||
// spin_unlock(&sensor_iic);
|
||||
/* os_mutex_post(&SENSOR_IIC_MUTEX); */
|
||||
|
||||
return ret;
|
||||
}
|
||||
char sen_log_buffer_1[100];
|
||||
char sen_log_buffer_2[100];
|
||||
char sen_log_buffer_3[100];
|
||||
char sen_log_buffer_4[100];
|
||||
char sen_log_buffer_5[100];
|
||||
u8 _gravity_sensor_get_ndata(u8 r_chip_id, u8 register_address, u8 *buf, u8 data_len)
|
||||
{
|
||||
// xlog("%s",__func__);
|
||||
// spin_lock(&sensor_iic);
|
||||
/* os_mutex_pend(&SENSOR_IIC_MUTEX,0); */
|
||||
u8 read_len = 0;
|
||||
|
||||
iic_start(gSensor_info->iic_hdl);
|
||||
if (0 == iic_tx_byte(gSensor_info->iic_hdl, r_chip_id - 1)) {
|
||||
xlog("I2C NACK on writing ADDR: 0x%X\n", r_chip_id - 1);
|
||||
read_len = 0;
|
||||
strcpy(&sen_log_buffer_1, "gsen iic rd err 0\n");
|
||||
goto __gdend;
|
||||
}
|
||||
|
||||
|
||||
delay(gSensor_info->iic_delay);
|
||||
if (0 == iic_tx_byte(gSensor_info->iic_hdl, register_address)) {
|
||||
xlog("I2C NACK on register ADDR: 0x%X\n", register_address);
|
||||
// xlog("\n gsen iic rd err 1\n");
|
||||
read_len = 0;
|
||||
strcpy(&sen_log_buffer_2, "gsen iic rd err 1\n");
|
||||
goto __gdend;
|
||||
}
|
||||
|
||||
iic_start(gSensor_info->iic_hdl);
|
||||
if (0 == iic_tx_byte(gSensor_info->iic_hdl, r_chip_id)) {
|
||||
xlog("\n gsen iic rd err 2\n");
|
||||
read_len = 0;
|
||||
strcpy(&sen_log_buffer_3, "gsen iic rd err 2\n" );
|
||||
goto __gdend;
|
||||
}
|
||||
|
||||
delay(gSensor_info->iic_delay);
|
||||
|
||||
for (; data_len > 1; data_len--) {
|
||||
*buf++ = iic_rx_byte(gSensor_info->iic_hdl, 1);
|
||||
read_len ++;
|
||||
}
|
||||
|
||||
*buf = iic_rx_byte(gSensor_info->iic_hdl, 0);
|
||||
read_len ++;
|
||||
strcpy(&sen_log_buffer_4, "gsen iic rd success\n");
|
||||
// xlog("\n gsen iic rd success\n");
|
||||
|
||||
__gdend:
|
||||
|
||||
iic_stop(gSensor_info->iic_hdl);
|
||||
delay(gSensor_info->iic_delay);
|
||||
// spin_unlock(&sensor_iic);
|
||||
/* os_mutex_post(&SENSOR_IIC_MUTEX); */
|
||||
// strcpy(&sen_log_buffer_5, "gsen iic rd err\n");
|
||||
return read_len;
|
||||
}
|
||||
void gsensor_io_ctl(u8 cmd, void *arg)
|
||||
{
|
||||
gSensor_hdl->gravity_sensor_ctl(cmd, arg);
|
||||
}
|
||||
//u8 gravity_sen_dev_cur; /*当前挂载的Gravity sensor*/
|
||||
int gravity_sensor_init(void *_data)
|
||||
{
|
||||
|
||||
|
||||
if (sensor_iic_init_status == 0) {
|
||||
// spin_lock_init(&sensor_iic);
|
||||
sensor_iic_init_status = 1;
|
||||
}
|
||||
gSensor_info->init_flag = 0;
|
||||
|
||||
int retval = 0;
|
||||
platform_data = (const struct gsensor_platform_data *)_data;
|
||||
gSensor_info->iic_hdl = platform_data->iic;
|
||||
retval = iic_init(gSensor_info->iic_hdl);
|
||||
|
||||
xlog("\n gravity_sensor_init\n");
|
||||
|
||||
if (retval < 0) {
|
||||
xlog("\n open iic for gsensor err\n");
|
||||
return retval;
|
||||
} else {
|
||||
xlog("\n iic open succ\n");
|
||||
}
|
||||
|
||||
retval = -EINVAL;
|
||||
list_for_each_gsensor(gSensor_hdl) {
|
||||
if (!memcmp(gSensor_hdl->logo, platform_data->gSensor_name, strlen(platform_data->gSensor_name))) {
|
||||
retval = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (retval < 0) {
|
||||
xlog(">>>gSensor_hdl logo err\n");
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (gSensor_hdl->gravity_sensor_init()) {
|
||||
xlog(">>>>gSensor_Int ERROR\n");
|
||||
} else {
|
||||
xlog(">>>>gSensor_Int SUCC\n");
|
||||
gSensor_info->init_flag = 1;
|
||||
if (platform_data->gSensor_int_io != -1) {
|
||||
gpio_set_pull_up(platform_data->gSensor_int_io, 1);
|
||||
gpio_set_pull_down(platform_data->gSensor_int_io, 0);
|
||||
gpio_set_direction(platform_data->gSensor_int_io, 1);
|
||||
gpio_set_die(platform_data->gSensor_int_io, 1);
|
||||
data_buf = zalloc(BUF_SIZE);
|
||||
if (data_buf == NULL) {
|
||||
xlog("gsensor_cbuf_error!");
|
||||
|
||||
return 0;
|
||||
}
|
||||
data_w_cbuf = zalloc(sizeof(cbuffer_t));
|
||||
if (data_w_cbuf == NULL) {
|
||||
return 0;
|
||||
}
|
||||
cbuf_init(data_w_cbuf, data_buf, BUF_SIZE);
|
||||
/* port_edge_wkup_set_callback(write_gsensor_data_handle); */
|
||||
/* 已改为使用port_edge_wkup_set_callback_by_index,使用时需要重新实现 */
|
||||
xlog("cbuf_init");
|
||||
// spin_lock_init(&iic_lock);
|
||||
|
||||
// sys_s_hi_timer_add(NULL, gSensor_int_io_detect, 10); //10ms
|
||||
// sys_s_hi_timer_add(NULL, gSensor_read_data, 2000); //2s
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int gsensor_disable(void)
|
||||
{
|
||||
if (data_w_cbuf == NULL) {
|
||||
return -1;
|
||||
} else {
|
||||
if (gSensor_info->init_flag == 1) {
|
||||
int valid = 0;
|
||||
gSensor_hdl->gravity_sensor_ctl(GSENSOR_DISABLE, &valid);
|
||||
if (valid == 0) {
|
||||
free(data_w_cbuf);
|
||||
data_w_cbuf = NULL;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int gsensor_enable(void)
|
||||
{
|
||||
|
||||
//查找设备
|
||||
int valid = 0;
|
||||
gSensor_hdl->gravity_sensor_ctl(SEARCH_SENSOR, &valid);
|
||||
if (valid == 0) {
|
||||
return -1;
|
||||
}
|
||||
//工作空间
|
||||
data_buf = zalloc(BUF_SIZE);
|
||||
if (data_buf == NULL) {
|
||||
xlog("gsensor_cbuf_error!");
|
||||
return -1;
|
||||
}
|
||||
data_w_cbuf = zalloc(sizeof(cbuffer_t));
|
||||
if (data_w_cbuf == NULL) {
|
||||
return -1;
|
||||
}
|
||||
cbuf_init(data_w_cbuf, data_buf, BUF_SIZE);
|
||||
xlog("cbuf_init");
|
||||
//设置参数
|
||||
valid = 0;
|
||||
gSensor_hdl->gravity_sensor_ctl(GSENSOR_RESET_INT, &valid);
|
||||
|
||||
if (valid == -1) {
|
||||
return -1;
|
||||
}
|
||||
xlog("gsensor_reset_succeed\n");
|
||||
return 0;
|
||||
}
|
||||
88
apps/common/device/gSensor/gSensor_manage.h
Normal file
88
apps/common/device/gSensor/gSensor_manage.h
Normal file
@ -0,0 +1,88 @@
|
||||
#ifndef _GSENSOR_MANAGE_H
|
||||
#define _GSENSOR_MANAGE_H
|
||||
#include "printf.h"
|
||||
#include "cpu.h"
|
||||
//#include "iic.h"
|
||||
#include "asm/iic_hw.h"
|
||||
#include "asm/iic_soft.h"
|
||||
#include "timer.h"
|
||||
#include "app_config.h"
|
||||
#include "event.h"
|
||||
#include "system/includes.h"
|
||||
|
||||
#define ACCEL_OF_GRAVITY 10
|
||||
#define ACCEL_DATA_GAIN 10
|
||||
|
||||
enum {
|
||||
GSENSOR_DISABLE = 0,
|
||||
GSENSOR_RESET_INT,
|
||||
GSENSOR_RESUME_INT,
|
||||
GSENSOR_INT_DET,
|
||||
READ_GSENSOR_DATA,
|
||||
GET_ACCEL_DATA,
|
||||
SEARCH_SENSOR,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
short x;
|
||||
short y;
|
||||
short z;
|
||||
} axis_info_t;
|
||||
|
||||
typedef struct {
|
||||
u8 logo[20];
|
||||
u8(*gravity_sensor_init)(void);
|
||||
char (*gravity_sensor_check)(void);
|
||||
void (*gravity_sensor_ctl)(u8 cmd, void *arg);
|
||||
} G_SENSOR_INTERFACE;
|
||||
|
||||
|
||||
struct gsensor_platform_data {
|
||||
u8 iic;
|
||||
char gSensor_name[20];
|
||||
u32 gSensor_int_io;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
u8 iic_hdl;
|
||||
u8 iic_delay; //这个延时并非影响iic的时钟频率,而是2Byte数据之间的延时
|
||||
u8 ctl_flag;
|
||||
int init_flag;
|
||||
int check_cnt;
|
||||
int check_timer_hdl;
|
||||
} G_SENSOR_INFO;
|
||||
|
||||
int gravity_sensor_init(void *_data);
|
||||
int gsensor_enable(void);
|
||||
int gsensor_disable(void);
|
||||
u8 gravity_sensor_command(u8 w_chip_id, u8 register_address, u8 function_command);
|
||||
u8 _gravity_sensor_get_ndata(u8 r_chip_id, u8 register_address, u8 *buf, u8 data_len);
|
||||
int get_gSensor_data(short *buf);
|
||||
int gSensor_read_data(u8 *buf, u8 buflen);
|
||||
int read_gsensor_buf(short *buf);
|
||||
int read_gsensor_nbuf(short *buf, short datalen);
|
||||
extern G_SENSOR_INTERFACE gsensor_dev_begin[];
|
||||
extern G_SENSOR_INTERFACE gsensor_dev_end[];
|
||||
|
||||
#define REGISTER_GRAVITY_SENSOR(gSensor) \
|
||||
static G_SENSOR_INTERFACE gSensor SEC_USED(.gsensor_dev)
|
||||
|
||||
#define list_for_each_gsensor(c) \
|
||||
for (c=gsensor_dev_begin; c<gsensor_dev_end; c++)
|
||||
|
||||
#define GSENSOR_PLATFORM_DATA_BEGIN(data) \
|
||||
static const struct gsensor_platform_data data = {
|
||||
|
||||
#define GSENSOR_PLATFORM_DATA_END() \
|
||||
};
|
||||
|
||||
/*
|
||||
enum {
|
||||
GSENSOR_EVENT_CLICK = 0,
|
||||
GSENSOR_EVENT_DOUBLE_CLICK,
|
||||
GSENSOR_EVENT_THREE_CLICK,
|
||||
};
|
||||
|
||||
#define DEVICE_EVENT_GSENSOR (('G' << 24) | ('S' << 16) | ('R' << 8) | '\0')
|
||||
*/
|
||||
#endif
|
||||
99
apps/common/device/gSensor/mira_std.h
Normal file
99
apps/common/device/gSensor/mira_std.h
Normal file
@ -0,0 +1,99 @@
|
||||
/*******************************************************************************/
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file mira_std.h
|
||||
* @author ycwang@miramems.com
|
||||
* @version V1.0
|
||||
* @date 26-Nov-2014
|
||||
* @brief
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
|
||||
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
|
||||
* TIME. AS A RESULT, MiraMEMS SHALL NOT BE HELD LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
|
||||
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
|
||||
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
|
||||
*
|
||||
* <h2><center>© COPYRIGHT 2014 MiraMEMS</center></h2>
|
||||
*/
|
||||
/*******************************************************************************/
|
||||
#ifndef __mira_std_h
|
||||
#define __mira_std_h
|
||||
|
||||
/*******************************************************************************
|
||||
Macro definitions - Register define for Gsensor asic
|
||||
********************************************************************************/
|
||||
#define NSA_REG_SPI_I2C 0x00
|
||||
#define NSA_REG_WHO_AM_I 0x01
|
||||
#define NSA_REG_ACC_X_LSB 0x02
|
||||
#define NSA_REG_ACC_X_MSB 0x03
|
||||
#define NSA_REG_ACC_Y_LSB 0x04
|
||||
#define NSA_REG_ACC_Y_MSB 0x05
|
||||
#define NSA_REG_ACC_Z_LSB 0x06
|
||||
#define NSA_REG_ACC_Z_MSB 0x07
|
||||
#define NSA_REG_MOTION_FLAG 0x09
|
||||
#define NSA_REG_G_RANGE 0x0f
|
||||
#define NSA_REG_ODR_AXIS_DISABLE 0x10
|
||||
#define NSA_REG_POWERMODE_BW 0x11
|
||||
#define NSA_REG_SWAP_POLARITY 0x12
|
||||
#define NSA_REG_FIFO_CTRL 0x14
|
||||
#define NSA_REG_INTERRUPT_SETTINGS0 0x15
|
||||
#define NSA_REG_INTERRUPT_SETTINGS1 0x16
|
||||
#define NSA_REG_INTERRUPT_SETTINGS2 0x17
|
||||
#define NSA_REG_INTERRUPT_MAPPING1 0x19
|
||||
#define NSA_REG_INTERRUPT_MAPPING2 0x1a
|
||||
#define NSA_REG_INTERRUPT_MAPPING3 0x1b
|
||||
#define NSA_REG_INT_PIN_CONFIG 0x20
|
||||
#define NSA_REG_INT_LATCH 0x21
|
||||
#define NSA_REG_ACTIVE_DURATION 0x27
|
||||
#define NSA_REG_ACTIVE_THRESHOLD 0x28
|
||||
#define NSA_REG_TAP_DURATION 0x2A
|
||||
#define NSA_REG_TAP_THRESHOLD 0x2B
|
||||
#define NSA_REG_ENGINEERING_MODE 0x7f
|
||||
#define NSA_REG_SENS_COMP 0x8c
|
||||
#define NSA_REG_MEMS_OPTION 0x8f
|
||||
#define NSA_REG_CHIP_INFO 0xc0
|
||||
|
||||
/*******************************************************************************
|
||||
Typedef definitions
|
||||
********************************************************************************/
|
||||
#define ARM_BIT_8 0
|
||||
|
||||
#if ARM_BIT_8
|
||||
//如下数据类型是在8位机上定义的,在其它平台(比如32位)可能存在差别,需要根据实际情况修改 。
|
||||
typedef unsigned char u8_m; /* 无符号8位整型变量*/
|
||||
typedef signed char s8_m; /* 有符号8位整型变量*/
|
||||
typedef unsigned int u16_m; /* 无符号16位整型变量*/
|
||||
typedef signed int s16_m; /* 有符号16位整型变量*/
|
||||
typedef unsigned long u32_m; /* 无符号32位整型变量*/
|
||||
typedef signed long s32_m; /* 有符号32位整型变量*/
|
||||
typedef float fp32_m; /* 单精度浮点数(32位长度)*/
|
||||
typedef double fp64_m; /* 双精度浮点数(64位长度)*/
|
||||
#else
|
||||
//如下数据类型是在32位机上定义的,在其它平台(比如8位)可能存在差别,需要根据实际情况修改 。
|
||||
typedef unsigned char u8_m; /* 无符号8位整型变量*/
|
||||
typedef signed char s8_m; /* 有符号8位整型变量*/
|
||||
typedef unsigned short u16_m; /* 无符号16位整型变量*/
|
||||
typedef signed short s16_m; /* 有符号16位整型变量*/
|
||||
typedef unsigned int u32_m; /* 无符号32位整型变量*/
|
||||
typedef signed int s32_m; /* 有符号32位整型变量*/
|
||||
typedef float fp32_m; /* 单精度浮点数(32位长度)*/
|
||||
typedef double fp64_m; /* 双精度浮点数(64位长度)*/
|
||||
#endif
|
||||
|
||||
typedef struct AccData_tag {
|
||||
s16_m ax; //加速度计原始数据结构体 数据格式 0 0 1024
|
||||
s16_m ay;
|
||||
s16_m az;
|
||||
|
||||
} AccData;
|
||||
|
||||
#define mir3da_abs(x) (((x) > 0) ? (x) : (-(x)))
|
||||
s32_m mir3da_sqrt(s32_m val);
|
||||
void mir3da_memset(void *dest, u8_m count);
|
||||
void *mir3da_memcpy(void *dest, void *source, u8_m count);
|
||||
#endif
|
||||
|
||||
|
||||
134
apps/common/device/gSensor/mpu6050.c
Normal file
134
apps/common/device/gSensor/mpu6050.c
Normal file
@ -0,0 +1,134 @@
|
||||
#include "gSensor/mpu6050.h"
|
||||
#include "gSensor/gSensor_manage.h"
|
||||
#include "app_config.h"
|
||||
#include "imuSensor_manage.h"
|
||||
|
||||
#if TCFG_MPU6050_EN
|
||||
|
||||
int gsensorlen = 32;
|
||||
OS_MUTEX SENSOR_IIC_MUTEX;
|
||||
spinlock_t sensor_iic;
|
||||
u8 sensor_iic_init_status = 0;
|
||||
|
||||
#define ACCEL_ONLY_LOW_POWER 0
|
||||
|
||||
u8 mpu6050_register_read(u8 addr, u8 *data)
|
||||
{
|
||||
_gravity_sensor_get_ndata(I2C_ADDR_MPU6050_R, addr, data, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
u8 mpu6050_register_write(u8 addr, u8 data)
|
||||
{
|
||||
gravity_sensor_command(I2C_ADDR_MPU6050_W, addr, data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
u8 mpu6050_read_nbyte_data(u8 addr, u8 *data, u8 len)
|
||||
{
|
||||
return _gravity_sensor_get_ndata(I2C_ADDR_MPU6050_R, addr, data, len);
|
||||
}
|
||||
|
||||
u8 mpu6050_get_xyz_data(u8 addr, void *xyz_data)
|
||||
{
|
||||
u8 buf[6], read_len;
|
||||
axis_info_t *data = (axis_info_t *)xyz_data;
|
||||
read_len = mpu6050_read_nbyte_data(addr, buf, 6);
|
||||
if (read_len == 6) {
|
||||
data->x = ((u16)buf[0] << 8) | buf[1];
|
||||
data->y = ((u16)buf[2] << 8) | buf[3];
|
||||
data->z = ((u16)buf[4] << 8) | buf[5];
|
||||
|
||||
data->x = 2 * ACCEL_OF_GRAVITY * ACCEL_DATA_GAIN * data->x / 32768;
|
||||
data->y = 2 * ACCEL_OF_GRAVITY * ACCEL_DATA_GAIN * data->y / 32768;
|
||||
data->z = 2 * ACCEL_OF_GRAVITY * ACCEL_DATA_GAIN * data->z / 32768;
|
||||
}
|
||||
return read_len;
|
||||
}
|
||||
|
||||
extern void step_cal_init();
|
||||
extern int step_cal();
|
||||
u8 mpu6050_init()
|
||||
{
|
||||
u8 res = 0;
|
||||
u8 data;
|
||||
res = mpu6050_register_read(MPU6050_RA_WHO_AM_I, &data); //读ID
|
||||
if (data == MPU_ADDR) {
|
||||
g_printf("read MPU6050 ID suss");
|
||||
} else {
|
||||
g_printf("read MPU6050 ID err");
|
||||
return -1;
|
||||
}
|
||||
|
||||
data = 0x80;
|
||||
mpu6050_register_write(MPU6050_RA_PWR_MGMT_1, data); //复位
|
||||
os_time_dly(10);
|
||||
|
||||
data = 0x00;
|
||||
data |= BIT(3); //关闭温度传感器
|
||||
#if ACCEL_ONLY_LOW_POWER
|
||||
data |= BIT(5); //设置accel-only低功耗模式
|
||||
#endif
|
||||
mpu6050_register_write(MPU6050_RA_PWR_MGMT_1, data); //退出休眠
|
||||
|
||||
data = 0x00;
|
||||
data |= (BIT(0) | BIT(1) | BIT(2)); //关闭陀螺仪
|
||||
#if ACCEL_ONLY_LOW_POWER
|
||||
data |= (3 << 6); //accel-only低功耗模式下,唤醒频率为40Hz
|
||||
#endif
|
||||
/*mpu6050_register_write(MPU6050_RA_PWR_MGMT_2, data);*/
|
||||
|
||||
data = ACCEL_RANGE_2G << 3;
|
||||
mpu6050_register_write(MPU6050_RA_ACCEL_CONFIG, data); //加速度计量程
|
||||
|
||||
#if (!ACCEL_ONLY_LOW_POWER)
|
||||
data = 0x06;
|
||||
mpu6050_register_write(MPU6050_RA_CONFIG, data); //设置陀螺仪输出速率
|
||||
|
||||
data = MPU6050_GYRO_OUT_RATE / MPU6050_SAMPLE_RATE - 1;
|
||||
mpu6050_register_write(MPU6050_RA_SMPLRT_DIV, data); //设置采样率, 采样率=陀螺仪输出速率/(1+SMPLRT_DIV)
|
||||
|
||||
data = 0x00;
|
||||
mpu6050_register_write(MPU6050_RA_INT_ENABLE, data); //关闭中断
|
||||
|
||||
data = 0x00;
|
||||
mpu6050_register_write(MPU6050_RA_USER_CTRL, data); //关闭主机IIC
|
||||
#endif
|
||||
|
||||
/*step_cal_init();*/
|
||||
/*sys_timer_add(NULL, step_cal, 50);*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mpu6050_ctl(u8 cmd, void *arg)
|
||||
{
|
||||
switch (cmd) {
|
||||
case GET_ACCEL_DATA:
|
||||
case IMU_GET_ACCEL_DATA:
|
||||
mpu6050_get_xyz_data(MPU6050_RA_ACCEL_XOUT_H, arg);
|
||||
break;
|
||||
case IMU_GET_GYRO_DATA:
|
||||
mpu6050_get_xyz_data(MPU6050_RA_GYRO_XOUT_H, arg);
|
||||
break;
|
||||
case READ_GSENSOR_DATA:
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
REGISTER_GRAVITY_SENSOR(gSensor) = {
|
||||
.logo = "mpu6050",
|
||||
.gravity_sensor_init = mpu6050_init,
|
||||
.gravity_sensor_check = NULL,
|
||||
.gravity_sensor_ctl = mpu6050_ctl,
|
||||
};
|
||||
|
||||
//未合到imu: init:gravity_sensor_init(&motion_sensor_data);
|
||||
REGISTER_IMU_SENSOR(mpu6050_sensor) = {
|
||||
.logo = "mpu6050",
|
||||
.imu_sensor_init = mpu6050_init,
|
||||
.imu_sensor_check = NULL,
|
||||
.imu_sensor_ctl = mpu6050_ctl,
|
||||
};
|
||||
|
||||
#endif //TCFG_MPU6050_EN
|
||||
16
apps/common/device/gSensor/mpu6050.h
Normal file
16
apps/common/device/gSensor/mpu6050.h
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef __MPU6050_H_
|
||||
#define __MPU6050_H_
|
||||
|
||||
#include "mpu6050_reg.h"
|
||||
|
||||
#define MPU6050_GYRO_OUT_RATE 1000 //1K或8K
|
||||
#define MPU6050_SAMPLE_RATE 125
|
||||
|
||||
enum {
|
||||
ACCEL_RANGE_2G,
|
||||
ACCEL_RANGE_4G,
|
||||
ACCEL_RANGE_8G,
|
||||
ACCEL_RANGE_16G,
|
||||
};
|
||||
|
||||
#endif
|
||||
598
apps/common/device/gSensor/mpu6050_reg.h
Normal file
598
apps/common/device/gSensor/mpu6050_reg.h
Normal file
@ -0,0 +1,598 @@
|
||||
#ifndef __MPU6050_REG_H_
|
||||
#define __MPU6050_REG_H_
|
||||
|
||||
#define MPU_ACK_WAIT_TIME 200 //us
|
||||
#define MPU6050_AD0_LOW
|
||||
|
||||
#ifdef MPU6050_AD0_LOW
|
||||
#define MPU_ADDR 0x68 //设备ID
|
||||
#else
|
||||
#define MPU_ADDR 0x69 //设备ID
|
||||
#endif
|
||||
|
||||
#define I2C_ADDR_MPU6050_W (MPU_ADDR<<1|0) // AD0为低的时候设备的写地址
|
||||
#define I2C_ADDR_MPU6050_R (MPU_ADDR<<1|1) // AD0为高的时候设备的写地址
|
||||
|
||||
|
||||
//技术文档未公布的寄存器 主要用于官方DMP操作
|
||||
#define MPU6050_RA_XG_OFFS_TC 0x00 //[bit7] PWR_MODE, [6:1] XG_OFFS_TC, [bit 0] OTP_BNK_VLD
|
||||
#define MPU6050_RA_YG_OFFS_TC 0x01 //[7] PWR_MODE, [6:1] YG_OFFS_TC, [0] OTP_BNK_VLD
|
||||
//bit7的定义,当设置为1,辅助I2C总线高电平是VDD。当设置为0,辅助I2C总线高电平是VLOGIC
|
||||
|
||||
#define MPU6050_RA_ZG_OFFS_TC 0x02 //[7] PWR_MODE, [6:1] ZG_OFFS_TC, [0] OTP_BNK_VLD
|
||||
#define MPU6050_RA_X_FINE_GAIN 0x03 //[7:0] X_FINE_GAIN
|
||||
#define MPU6050_RA_Y_FINE_GAIN 0x04 //[7:0] Y_FINE_GAIN
|
||||
#define MPU6050_RA_Z_FINE_GAIN 0x05 //[7:0] Z_FINE_GAIN
|
||||
|
||||
#define MPU6050_RA_XA_OFFS_H 0x06 //[15:0] XA_OFFS 两个寄存器合在一起
|
||||
#define MPU6050_RA_XA_OFFS_L_TC 0x07
|
||||
|
||||
#define MPU6050_RA_YA_OFFS_H 0x08 //[15:0] YA_OFFS 两个寄存器合在一起
|
||||
#define MPU6050_RA_YA_OFFS_L_TC 0x09
|
||||
|
||||
#define MPU6050_RA_ZA_OFFS_H 0x0A //[15:0] ZA_OFFS 两个寄存器合在一起
|
||||
#define MPU6050_RA_ZA_OFFS_L_TC 0x0B
|
||||
|
||||
#define MPU6050_RA_XG_OFFS_USRH 0x13 //[15:0] XG_OFFS_USR 两个寄存器合在一起
|
||||
#define MPU6050_RA_XG_OFFS_USRL 0x14
|
||||
|
||||
#define MPU6050_RA_YG_OFFS_USRH 0x15 //[15:0] YG_OFFS_USR 两个寄存器合在一起
|
||||
#define MPU6050_RA_YG_OFFS_USRL 0x16
|
||||
|
||||
#define MPU6050_RA_ZG_OFFS_USRH 0x17 //[15:0] ZG_OFFS_USR 两个寄存器合在一起
|
||||
#define MPU6050_RA_ZG_OFFS_USRL 0x18
|
||||
|
||||
/*陀螺仪的采样频率*/
|
||||
/*传感器的寄存器输出,FIFO输出,DMP采样、运动检测、
|
||||
*零运动检测和自由落体检测都是基于采样率。
|
||||
*通过SMPLRT_DIV把陀螺仪输出率分频即可得到采样率
|
||||
*采样率=陀螺仪输出率/ (1 + SMPLRT_DIV)
|
||||
*禁用DLPF的情况下(DLPF_CFG = 0或7) ,陀螺仪输出率= 8 khz
|
||||
*在启用DLPF(见寄存器26)时,陀螺仪输出率= 1 khz
|
||||
*加速度传感器输出率是1 khz。这意味着,采样率大于1 khz时,
|
||||
*同一个加速度传感器的样品可能会多次输入到FIFO、DMP和传感器寄存器*/
|
||||
#define MPU6050_RA_SMPLRT_DIV 0x19 //[0-7] 陀螺仪输出分频采样率
|
||||
|
||||
/*配置外部引脚采样和DLPF数字低通滤波器*/
|
||||
#define MPU6050_RA_CONFIG 0x1A
|
||||
//bit5-bit3 一个连接到FSYNC端口的外部信号可以通过配置EXT_SYNC_SET来采样
|
||||
// 也就是说,这里设置之后,FSYNC的电平0或1进入最终数据寄存器,具体如下
|
||||
// 0 不使用 1 FSYNC电平进入所有数据寄存器 2 FSYNC电平进入GYRO_XOUT_L 3 FSYNC电平进入GYRO_YOUT_L
|
||||
// 4 FSYNC电平进入GYRO_ZOUT_L 5 FSYNC电平进入ACCEL_XOUT_L 6 FSYNC电平进入ACCEL_YOUT_L
|
||||
// 7 FSYNC电平进入SYNC_ACCEL_ZOUT_L
|
||||
//bit2-bit0 数字低通滤波器 用于滤除高频干扰 高于这个频率的干扰被滤除掉
|
||||
/*对应关系如下
|
||||
* * | 加速度传感器 | 陀螺仪
|
||||
* * DLPF_CFG | 带宽 | 延迟 | 带宽 | 延迟 | 采样率
|
||||
* -------------+--------+-------+--------+------+-------------
|
||||
* 0 | 260Hz | 0ms | 256Hz | 0.98ms | 8kHz
|
||||
* 1 | 184Hz | 2.0ms | 188Hz | 1.9ms | 1kHz
|
||||
* 2 | 94Hz | 3.0ms | 98Hz | 2.8ms | 1kHz
|
||||
* 3 | 44Hz | 4.9ms | 42Hz | 4.8ms | 1kHz
|
||||
* 4 | 21Hz | 8.5ms | 20Hz | 8.3ms | 1kHz
|
||||
* 5 | 10Hz | 13.8ms | 10Hz | 13.4ms | 1kHz
|
||||
* 6 | 5Hz | 19.0ms | 5Hz | 18.6ms | 1kHz
|
||||
* 7 | Reserved | Reserved | Reserved
|
||||
* */
|
||||
|
||||
|
||||
/*陀螺仪的配置,主要是配置陀螺仪的量程与自检(通过相应的位7 6 5 开启自检)*/
|
||||
#define MPU6050_RA_GYRO_CONFIG 0x1B
|
||||
//bit4-bit3 量程设置如下
|
||||
// 0 = +/- 250 度/秒
|
||||
// 1 = +/- 500 度/秒
|
||||
// 2 = +/- 1000 度/秒
|
||||
// 3 = +/- 2000 度/秒*/
|
||||
|
||||
/*加速度计的配置,主要是配置加速度计的量程与自检(通过相应的位7 6 5 开启自检)
|
||||
*另外,还能配置系统的高通滤波器*/
|
||||
#define MPU6050_RA_ACCEL_CONFIG 0x1C
|
||||
//bit7 启动X自检 加速度计的自检
|
||||
//bit6 启动Y自检
|
||||
//bit5 启动Z自检
|
||||
//bit4-bit3 加速度传感器的量程配置
|
||||
// 0 = +/- 2g
|
||||
// 1 = +/- 4g
|
||||
// 2 = +/- 8g
|
||||
// 3 = +/- 16g*/
|
||||
//bit0到bit2 加速度传感器的高通滤波器
|
||||
/*DHPF是在路径中连接于运动探测器(自由落体,运动阈值,零运动)的一个滤波器模块。
|
||||
*高通滤波器的输出值不在数据寄存器中
|
||||
*高通滤波器有三种模式:
|
||||
*重置:在一个样本中将滤波器输出值设为零。这有效的禁用了高通滤波器。这种模式可以快速切换滤波器的设置模式。
|
||||
*开启:高通滤波器能通过高于截止频率的信号
|
||||
*持续:触发后,过滤器持续当前采样。过滤器输出值是输入样本和持续样本之间的差异
|
||||
*设置值如下所示
|
||||
* ACCEL_HPF | 高通滤波模式| 截止频率
|
||||
* ----------+-------------+------------------
|
||||
* 0 | Reset | None
|
||||
* 1 | On | 5Hz
|
||||
* 2 | On | 2.5Hz
|
||||
* 3 | On | 1.25Hz
|
||||
* 4 | On | 0.63Hz
|
||||
* 7 | Hold | None
|
||||
*/
|
||||
|
||||
#define MPU6050_RA_FF_THR 0x1D
|
||||
/*自由落体加速度的阈值
|
||||
*这个寄存器为自由落体的阈值检测进行配置。
|
||||
*FF_THR的单位是1LSB = 2mg。当加速度传感器测量而得的三个轴的绝对值
|
||||
*都小于检测阈值时,就可以测得自由落体值。这种情况下,(加速度计每次检测到就+1以下,所以还要依靠加速度采样率)
|
||||
*自由落体时间计数器计数一次 (寄存器30)。当自由落体时间计数器达到
|
||||
*FF_DUR中规定的时间时,自由落体被中断(或发生自由落体中断)
|
||||
**/
|
||||
|
||||
#define MPU6050_RA_FF_DUR 0x1E
|
||||
/*
|
||||
*自由落体加速度的时间阈值
|
||||
* 这个寄存器为自由落体时间阈值计数器进行配置。
|
||||
* 时间计数频率为1 khz,因此FF_DUR的单位是 1 LSB = 1毫秒。
|
||||
* 当加速度器测量而得的绝对值都小于检测阈值时,
|
||||
* 自由落体时间计数器计数一次。当自由落体时间计数器
|
||||
* 达到该寄存器的规定时间时,自由落体被中断。
|
||||
* (或发生自由落体中断)
|
||||
* */
|
||||
|
||||
#define MPU6050_RA_MOT_THR 0x1F
|
||||
/*
|
||||
*运动检测的加速度阈值
|
||||
*这个寄存器为运动中断的阈值检测进行配置。
|
||||
*MOT_THR的单位是 1LSB = 2mg。
|
||||
*当加速度器测量而得的绝对值都超过该运动检测的阈值时,
|
||||
*即可测得该运动。这一情况下,运动时间检测计数器计数一次。
|
||||
*当运动检测计数器达到MOT_DUR的规定时间时,运动检测被中断。
|
||||
* 运动中断表明了被检测的运动MOT_DETECT_STATUS (Register 97)的轴和极性。
|
||||
*/
|
||||
|
||||
#define MPU6050_RA_MOT_DUR 0x20
|
||||
/*
|
||||
*运动检测时间的阈值。
|
||||
*这个寄存器为运动中断的阈值检测进行配置。
|
||||
*时间计数器计数频率为1 kHz ,因此MOT_THR的单位是 1LSB = 1ms。
|
||||
*当加速度器测量而得的绝对值都超过该运动检测的阈值时(Register 31),
|
||||
*运动检测时间计数器计数一次。当运动检测计数器达到该寄存器规定的时间时,
|
||||
*运动检测被中断。
|
||||
**/
|
||||
|
||||
#define MPU6050_RA_ZRMOT_THR 0x21
|
||||
/*
|
||||
*零运动检测加速度阈值。
|
||||
* 这个寄存器为零运动中断检测进行配置。
|
||||
* ZRMOT_THR的单位是1LSB = 2mg。
|
||||
* 当加速度器测量而得的三个轴的绝对值都小于检测阈值时,
|
||||
* 就可以测得零运动。这种情况下,零运动时间计数器计数一次 (寄存器34)。
|
||||
* 当自零运动时间计数器达到ZRMOT_DUR (Register 34)中规定的时间时,零运动被中断。
|
||||
* 与自由落体或运动检测不同的是,当零运动首次检测到以及当零运动检测不到时,零运动检测都被中断。
|
||||
* 当零运动被检测到时,其状态将在MOT_DETECT_STATUS寄存器(寄存器97) 中显示出来。
|
||||
* 当运动状态变为零运动状态被检测到时,状态位设置为1。当零运动状态变为运动状态被检测到时,
|
||||
* 状态位设置为0。
|
||||
**/
|
||||
|
||||
#define MPU6050_RA_ZRMOT_DUR 0x22
|
||||
/*
|
||||
*零运动检测的时间阈值
|
||||
* 这个寄存器为零运动中断检测进行时间计数器的配置。
|
||||
* 时间计数器的计数频率为16 Hz,因此ZRMOT_DUR的单位是1 LSB = 64 ms。
|
||||
* 当加速度器测量而得的绝对值都小于检测器的阈值(Register 33)时,
|
||||
* 运动检测时间计数器计数一次。当零运动检测计数器达到该寄存器规定的时间时,
|
||||
* 零运动检测被中断。
|
||||
**/
|
||||
|
||||
|
||||
/*
|
||||
*设备的各种FIFO使能,包括温度 加速度 陀螺仪 从机
|
||||
*将相关的数据写入FIFO缓冲中
|
||||
**/
|
||||
#define MPU6050_RA_FIFO_EN 0x23
|
||||
//bit7 温度fifo使能
|
||||
//bit6 陀螺仪Xfifo使能
|
||||
//bit5 陀螺仪Yfifo使能
|
||||
//bit4 陀螺仪Zfifo使能
|
||||
//bit3 加速度传感器fifo使能
|
||||
//bit2 外部从设备2fifo使能
|
||||
//bit1 外部从设备1fifo使能
|
||||
//bit0 外部从设备0fifo使能
|
||||
|
||||
#define MPU6050_RA_I2C_MST_CTRL 0x24
|
||||
//配置单主机或者多主机下的IIC总线
|
||||
//bit7 监视从设备总线,看总线是否可用 MULT_MST_EN设置为1时,MPU-60X0的总线仲裁检测逻辑被打开
|
||||
//bit6 延迟数据就绪中断,直达从设备数据也进入主机再触发 相当于数据同步等待
|
||||
//bit5 当设置为1时,与Slave3 相连的外部传感器数据(寄存器73 到寄存器 96)写入FIFO缓冲中,每次都写入
|
||||
//bit4 主机读取一个从机到下一个从机读取之间的动作 为0 读取之间有一个restart,为1 下一次读取前会有一个重启,然后
|
||||
// 一直读取直到切换写入或者切换设备
|
||||
//bit3-bit0 配置MPU作为IIC主机时的时钟,基于MPU内部8M的分频
|
||||
/* I2C_MST_CLK | I2C 主时钟速度 | 8MHz 时钟分频器
|
||||
* ------------+------------------------+-------------------
|
||||
* 0 | 348kHz | 23
|
||||
* 1 | 333kHz | 24
|
||||
* 2 | 320kHz | 25
|
||||
* 3 | 308kHz | 26
|
||||
* 4 | 296kHz | 27
|
||||
* 5 | 286kHz | 28
|
||||
* 6 | 276kHz | 29
|
||||
* 7 | 267kHz | 30
|
||||
* 8 | 258kHz | 31
|
||||
* 9 | 500kHz | 16
|
||||
* 10 | 471kHz | 17
|
||||
* 11 | 444kHz | 18
|
||||
* 12 | 421kHz | 19
|
||||
* 13 | 400kHz | 20
|
||||
* 14 | 381kHz | 21
|
||||
* 15 | 364kHz | 22
|
||||
* */
|
||||
|
||||
|
||||
|
||||
/**************************MPU链接IIC从设备控制寄存器,没使用从机连接的基本不用考虑这些************************************/
|
||||
/*指定slave (0-3)的I2C地址
|
||||
* 注意Bit 7 (MSB)控制了读/写模式。如果设置了Bit 7,那么这是一个读取操作,
|
||||
* 如果将其清除,那么这是一个编写操作。其余位(6-0)是slave设备的7-bit设备地址。
|
||||
* 在读取模式中,读取结果是存储于最低可用的EXT_SENS_DATA寄存器中。
|
||||
* MPU-6050支持全5个slave,但Slave 4有其特殊功能(getSlave4* 和setSlave4*)。
|
||||
* 如寄存器25中所述,I2C数据转换通过采样率体现。用户负责确保I2C数据转换能够
|
||||
* 在一个采样率周期内完成。
|
||||
* I2C slave数据传输速率可根据采样率来减小。
|
||||
* 减小的传输速率是由I2C_MST_DLY(寄存器52)所决定的。
|
||||
* slave数据传输速率是否根据采样率来减小是由I2C_MST_DELAY_CTRL (寄存器103)所决定的。
|
||||
* slave的处理指令是固定的。Slave的处理顺序是Slave 1, Slave 2, Slave 3 和 Slave 4。
|
||||
* 如果某一个Slave被禁用了,那么它会被自动忽略。
|
||||
* 每个slave可按采样率或降低的采样率来读取。在有些slave以采样率读取有些以减小
|
||||
* 的采样率读取的情况下,slave的读取顺序依旧不变。然而,
|
||||
* 如果一些slave的读取速率不能在特定循环中进行读取,那么它们会被自动忽略
|
||||
* 更多降低的读取速率相关信息,请参阅寄存器52。
|
||||
* Slave是否按采样率或降低的采样率来读取由寄存器103得Delay Enable位来决定
|
||||
**/
|
||||
|
||||
//从机0设置相关
|
||||
#define MPU6050_RA_I2C_SLV0_ADDR 0x25
|
||||
//bit7 当前IIC 从设备0的操作,1为读取 0写入
|
||||
//bit6-bit0 从机设备的地址
|
||||
/* 要读取或者要写入的设备内部的寄存器地址,不管读取还是写入*/
|
||||
#define MPU6050_RA_I2C_SLV0_REG 0x26
|
||||
/*iic从机系统配置寄存器*/
|
||||
#define MPU6050_RA_I2C_SLV0_CTRL 0x27
|
||||
//bit7 启动或者禁止这个设备的IIC数据传送过程
|
||||
//bit6 当设置为1时,字节交换启用。当启用字节交换时,词对的高低字节即可交换
|
||||
//bit5 当 I2C_SLV0_REG_DIS 置 1,只能进行读取或者写入数据。当该位清 0,可以再读取
|
||||
// 或写入数据之前写入一个寄存器地址。当指定从机设备内部的寄存器地址进行发送或接收
|
||||
// 数据时,该位必须等于 0
|
||||
//bit4 指定从寄存器收到的字符对的分组顺序。当该位清 0,寄存器地址
|
||||
// 0和 1, 2 和 3 的字节是分别成对(甚至,奇数寄存器地址 ) ,作为一个字符对。当该位置 1,
|
||||
// 寄存器地址 1 和 2, 3 和 4 的字节是分别成对的,作为一个字符对
|
||||
//bit3-bit0 指定从机 0 发送字符的长度。由Slave 0转换而来和转换至Slave 0的字节数,(IIC一次传输的长度)
|
||||
// 该位清 0,I2C_SLV0_EN 位自动置 0.
|
||||
|
||||
/*IIC SLAVE1配置寄存器,与0相同*/
|
||||
|
||||
#define MPU6050_RA_I2C_SLV1_ADDR 0x28
|
||||
#define MPU6050_RA_I2C_SLV1_REG 0x29
|
||||
#define MPU6050_RA_I2C_SLV1_CTRL 0x2A
|
||||
|
||||
/*IIC SLAVE2配置寄存器,与0相同*/
|
||||
#define MPU6050_RA_I2C_SLV2_ADDR 0x2B
|
||||
#define MPU6050_RA_I2C_SLV2_REG 0x2C
|
||||
#define MPU6050_RA_I2C_SLV2_CTRL 0x2D
|
||||
|
||||
/*IIC SLAVE3配置寄存器,与0相同*/
|
||||
#define MPU6050_RA_I2C_SLV3_ADDR 0x2E
|
||||
#define MPU6050_RA_I2C_SLV3_REG 0x2F
|
||||
#define MPU6050_RA_I2C_SLV3_CTRL 0x30
|
||||
|
||||
/*slave4的I2C地址 IIC4与前几个的寄存器定义有所不同*/
|
||||
#define MPU6050_RA_I2C_SLV4_ADDR 0x31 //与IIC SLAVE1类似
|
||||
#define MPU6050_RA_I2C_SLV4_REG 0x32 /*slave4的当前内部寄存器*/
|
||||
#define MPU6050_RA_I2C_SLV4_DO 0x33
|
||||
/*写于slave4的新字节这一寄存器可储存写于slave4的数据。
|
||||
* 如果I2C_SLV4_RW设置为1(设置为读取模式),那么该寄存器无法执行操作*/
|
||||
#define MPU6050_RA_I2C_SLV4_CTRL 0x34
|
||||
//当设置为1时,此位启用了slave4的转换操作。当设置为0时,则禁用该操作
|
||||
#define MPU6050_I2C_SLV4_EN_BIT 7
|
||||
//当设置为1时,此位启用了slave4事务完成的中断信号的生成。
|
||||
// 当清除为0时,则禁用了该信号的生成。这一中断状态可在寄存器54中看到。
|
||||
#define MPU6050_I2C_SLV4_INT_EN_BIT 6
|
||||
//当设置为1时,只进行数据的读或写操作。当设置为0时,
|
||||
// 在读写数据之前将编写一个寄存器地址。当指定寄存器地址在slave设备中时
|
||||
// ,这应该等于0,而在该寄存器中会进行数据处理。
|
||||
#define MPU6050_I2C_SLV4_REG_DIS_BIT 5
|
||||
//采样率延迟,这为根据采样率减小的I2C slaves传输速率进行了配置。
|
||||
// 当一个slave的传输速率是根据采样率而降低的,那么该slave是以每1 / (1 + I2C_MST_DLY) 个样本进行传输。
|
||||
// 这一基本的采样率也是由SMPLRT_DIV (寄存器 25)和DLPF_CFG (寄存器26)所决定的的。
|
||||
// slave传输速率是否根据采样率来减小是由I2C_MST_DELAY_CTRL (寄存器103)所决定的
|
||||
#define MPU6050_I2C_SLV4_MST_DLY_BIT 4 //[4:0]
|
||||
#define MPU6050_I2C_SLV4_MST_DLY_LENGTH 5
|
||||
/*slave4中可读取的最后可用字节*/
|
||||
#define MPU6050_RA_I2C_SLV4_DI 0x35
|
||||
|
||||
/*
|
||||
* IIC辅助从机系统中断状态
|
||||
**/
|
||||
#define MPU6050_RA_I2C_MST_STATUS 0x36
|
||||
//bit7 此位反映了一个与MPU-60X0相连的外部设备的FSYNC中断状态。
|
||||
// 当设置为1且在INT_PIN_CFG(寄存器55)中断言FSYNC_INT_EN时,中断产生。
|
||||
//bit6 当slave4事务完成时,设备会自动设置为1 如果定义了INT_ENABLE中的I2C_MST_INT_EN则产生中断
|
||||
//bit5 I2C主机失去辅助I2C总线(一个错误状态)的仲裁,此位自动设置为1.如果断言了INT_ENABLE寄存器
|
||||
// (寄存器56)中的I2C_MST_INT_EN位,则中断产生
|
||||
//bit4 slave4的NACK状态
|
||||
//bit3 slave3的NACK状态
|
||||
//bit2 slave2的NACK状态
|
||||
//bit1 slave1的NACK状态
|
||||
//bit0 slave0的NACK状态
|
||||
|
||||
|
||||
/*中断引脚配置寄存器*/
|
||||
#define MPU6050_RA_INT_PIN_CFG 0x37
|
||||
//bit7 中断的逻辑电平模式,高电平时,设置为0;低电平时,设置为1
|
||||
//bit6 中断驱动模式,推拉模式设置为0,开漏模式设置为1.
|
||||
//bit5 中断锁存模式.50us-pulse模式设置为0,latch-until-int-cleared模式设置为1
|
||||
//bit4 中断锁存清除模式 status-read-only状态设置为0,any-register-read状态设置为1.
|
||||
//bit3 FSYNC中断逻辑电平模式 0=active-high, 1=active-low
|
||||
//bit2 FSYNC端口中断启用设置设置为0时禁用,设置为1时启用
|
||||
//bit1 I2C支路启用状态,此位等于1且I2C_MST_EN (寄存器 106 位[5])等于0时,主机应用程序处理器能够直接访问MPU-60X0的辅助I2C总线
|
||||
// 否则无论如何都不能直接访问
|
||||
//bit0 当此位为1时,CLKOUT端口可以输出参考时钟。当此位为0时,输出禁用
|
||||
|
||||
|
||||
/*部分中断使能*/
|
||||
#define MPU6050_RA_INT_ENABLE 0x38
|
||||
//bit7 自由落体中断使能
|
||||
//bit6 运动检测中断使能
|
||||
//bit5 零运动检测中断使能
|
||||
//bit4 FIFO溢出中断使能
|
||||
//bit3 IIC主机所有中断源使能
|
||||
//bit0 数据就绪中断使能
|
||||
|
||||
|
||||
/*DMP中断使能*/
|
||||
#define MPU6050_RA_DMP_INT_STATUS 0x39
|
||||
//不知道这些位的具体作用是什么,官方语焉不详,但是的确存在
|
||||
#define MPU6050_DMPINT_4_BIT 4
|
||||
#define MPU6050_DMPINT_3_BIT 3
|
||||
#define MPU6050_DMPINT_2_BIT 2
|
||||
#define MPU6050_DMPINT_1_BIT 1
|
||||
#define MPU6050_DMPINT_0_BIT 0
|
||||
|
||||
/*DMP中断配置*/
|
||||
#define MPU6050_RA_INT_STATUS 0x3A
|
||||
//DMP中断位之一使能
|
||||
#define MPU6050_INTERRUPT_PLL_RDY_INT_BIT 2
|
||||
//DMP中断位之二使能
|
||||
#define MPU6050_INTERRUPT_DMP_INT_BIT 1
|
||||
|
||||
/*加速度X输出*/
|
||||
#define MPU6050_RA_ACCEL_XOUT_H 0x3B
|
||||
#define MPU6050_RA_ACCEL_XOUT_L 0x3C
|
||||
|
||||
/*加速度Y输出*/
|
||||
#define MPU6050_RA_ACCEL_YOUT_H 0x3D
|
||||
#define MPU6050_RA_ACCEL_YOUT_L 0x3E
|
||||
|
||||
/*加速度Z输出*/
|
||||
#define MPU6050_RA_ACCEL_ZOUT_H 0x3F
|
||||
#define MPU6050_RA_ACCEL_ZOUT_L 0x40
|
||||
|
||||
/*温度值输出*/
|
||||
#define MPU6050_RA_TEMP_OUT_H 0x41
|
||||
#define MPU6050_RA_TEMP_OUT_L 0x42
|
||||
|
||||
/*陀螺仪X输出*/
|
||||
#define MPU6050_RA_GYRO_XOUT_H 0x43
|
||||
#define MPU6050_RA_GYRO_XOUT_L 0x44
|
||||
|
||||
/*陀螺仪Y输出*/
|
||||
#define MPU6050_RA_GYRO_YOUT_H 0x45
|
||||
#define MPU6050_RA_GYRO_YOUT_L 0x46
|
||||
|
||||
/*陀螺仪Z输出*/
|
||||
#define MPU6050_RA_GYRO_ZOUT_H 0x47
|
||||
#define MPU6050_RA_GYRO_ZOUT_L 0x48
|
||||
|
||||
/*从IIC从机上获取到的数据*/
|
||||
#define MPU6050_RA_EXT_SENS_DATA_00 0x49
|
||||
#define MPU6050_RA_EXT_SENS_DATA_01 0x4A
|
||||
#define MPU6050_RA_EXT_SENS_DATA_02 0x4B
|
||||
#define MPU6050_RA_EXT_SENS_DATA_03 0x4C
|
||||
#define MPU6050_RA_EXT_SENS_DATA_04 0x4D
|
||||
#define MPU6050_RA_EXT_SENS_DATA_05 0x4E
|
||||
#define MPU6050_RA_EXT_SENS_DATA_06 0x4F
|
||||
#define MPU6050_RA_EXT_SENS_DATA_07 0x50
|
||||
#define MPU6050_RA_EXT_SENS_DATA_08 0x51
|
||||
#define MPU6050_RA_EXT_SENS_DATA_09 0x52
|
||||
#define MPU6050_RA_EXT_SENS_DATA_10 0x53
|
||||
#define MPU6050_RA_EXT_SENS_DATA_11 0x54
|
||||
#define MPU6050_RA_EXT_SENS_DATA_12 0x55
|
||||
#define MPU6050_RA_EXT_SENS_DATA_13 0x56
|
||||
#define MPU6050_RA_EXT_SENS_DATA_14 0x57
|
||||
#define MPU6050_RA_EXT_SENS_DATA_15 0x58
|
||||
#define MPU6050_RA_EXT_SENS_DATA_16 0x59
|
||||
#define MPU6050_RA_EXT_SENS_DATA_17 0x5A
|
||||
#define MPU6050_RA_EXT_SENS_DATA_18 0x5B
|
||||
#define MPU6050_RA_EXT_SENS_DATA_19 0x5C
|
||||
#define MPU6050_RA_EXT_SENS_DATA_20 0x5D
|
||||
#define MPU6050_RA_EXT_SENS_DATA_21 0x5E
|
||||
#define MPU6050_RA_EXT_SENS_DATA_22 0x5F
|
||||
#define MPU6050_RA_EXT_SENS_DATA_23 0x60
|
||||
|
||||
//运动检测的状态
|
||||
#define MPU6050_RA_MOT_DETECT_STATUS 0x61
|
||||
//bit7 x轴反向运动检测中断状态
|
||||
//bit6 x轴正向运动检测中断状态
|
||||
//bit5 Y轴反向运动检测中断状态
|
||||
//bit4 Y轴正向运动检测中断状态
|
||||
//bit3 Z轴反向运动检测中断状态
|
||||
//bit2 Z轴正向运动检测中断状态
|
||||
//bit1
|
||||
//bit0 零运动检测中断状态
|
||||
//
|
||||
|
||||
|
||||
/*写入到IIC从机中的数据,指定的slv数据输出容器*/
|
||||
#define MPU6050_RA_I2C_SLV0_DO 0x63
|
||||
#define MPU6050_RA_I2C_SLV1_DO 0x64
|
||||
#define MPU6050_RA_I2C_SLV2_DO 0x65
|
||||
#define MPU6050_RA_I2C_SLV3_DO 0x66
|
||||
|
||||
/*外部影子寄存器的配置,这个寄存器用于指定外部传感器数据影子的时间
|
||||
*当启用了某一特定的slave,其传输速率就会减小。
|
||||
*当一个slave的传输速率是根据采样率而降低的,那么该slave是以
|
||||
*每1 / (1 + I2C_MST_DLY) 个样本进行传输。
|
||||
* 1 / (1 + I2C_MST_DLY) Samples
|
||||
* 这一基本的采样率也是由SMPLRT_DIV (寄存器 25)和DLPF_CFG (寄存器26)所决定的的。*/
|
||||
#define MPU6050_RA_I2C_MST_DELAY_CTRL 0x67
|
||||
//DELAY_ES_SHADOW设置为1,跟随外部传感器数据影子将会延迟到所有的数据接收完毕。
|
||||
#define MPU6050_DELAYCTRL_DELAY_ES_SHADOW_BIT 7
|
||||
//slv4-0的配置
|
||||
#define MPU6050_DELAYCTRL_I2C_SLV4_DLY_EN_BIT 4
|
||||
#define MPU6050_DELAYCTRL_I2C_SLV3_DLY_EN_BIT 3
|
||||
#define MPU6050_DELAYCTRL_I2C_SLV2_DLY_EN_BIT 2
|
||||
#define MPU6050_DELAYCTRL_I2C_SLV1_DLY_EN_BIT 1
|
||||
#define MPU6050_DELAYCTRL_I2C_SLV0_DLY_EN_BIT 0
|
||||
|
||||
/*用于陀螺仪,加速度计,温度传感器的模拟和数字信号通道的复位。
|
||||
复位会还原模数转换信号通道和清除他们的上电配置*/
|
||||
#define MPU6050_RA_SIGNAL_PATH_RESET 0x68
|
||||
//bit2 重置陀螺仪的信号路径
|
||||
//bit1 重置加速度传感器的信号路径
|
||||
//bit0 重置温度传感器的信号路径
|
||||
|
||||
|
||||
/*获取加速度传感器启动延迟 还有滤波器的一些配置
|
||||
* 加速度传感器数据路径为传感器寄存器、运动检测、
|
||||
* 零运动检测和自由落体检测模块提供样本。在检测模块开始操作之前,
|
||||
* 包含过滤器的信号路径必须用新样本来启用。
|
||||
* 默认的4毫秒唤醒延迟时间可以加长3毫秒以上。在ACCEL_ON_DELAY中规定
|
||||
* 这个延迟以1 LSB = 1 毫秒为单位。除非InvenSense另行指示,
|
||||
* 用户可以选择任何大于零的值。*/
|
||||
#define MPU6050_RA_MOT_DETECT_CTRL 0x69
|
||||
//具体的有效控制位
|
||||
//bit5-bit4 [5:4]1-4ms 延时时间1-4ms选择
|
||||
//bit3-bit2 自由落体检测计数器的减量配置。
|
||||
// 当指定数量的样本的加速度测量都满足其各自的阈值条件时,
|
||||
// 检测结果存储于自由落体检测模块中。当满足阈值条件时,
|
||||
// 相应的检测计数器递增1。用户可通过FF_COUNT配置不满足阈值条件来减量。
|
||||
// 减量率可根据下表进行设置:
|
||||
/* FF_COUNT | 计数器减量
|
||||
* ---------+------------------
|
||||
* 0 | 重置
|
||||
* 1 | 1
|
||||
* 2 | 2
|
||||
* 3 | 4
|
||||
* 当FF_COUNT配置为0(复位)时,任何不合格的样品都将计数器重置为0*/
|
||||
//bit1-bit0 运动检测计数器的减量配置。
|
||||
// 当指定数量的样本的加速度测量都满足其各自的阈值条件时,
|
||||
// 检测结果存储于运动检测模块中。当满足阈值条件时,相应的检测计数器递增1。
|
||||
// 用户可通过MOT_COUNT配置不满足阈值条件来减量。减量率可根据下表进行设置:
|
||||
// MOT_COUNT | 计数器减量
|
||||
/* ----------+------------------
|
||||
* 0 | 重置
|
||||
* 1 | 1
|
||||
* 2 | 2
|
||||
* 3 | 4
|
||||
* 当MOT_COUNT配置为0(复位)时,任何不合格的样品都将计数器重置为0*/
|
||||
|
||||
|
||||
/*这个寄存器允许用户使能或使能 FIFO 缓冲区,
|
||||
*I2C 主机模式和主要 I2C 接口。FIFO 缓冲
|
||||
区,I2C 主机,传感器信号通道和传感器寄存器也可以使用这个寄存器复位*/
|
||||
#define MPU6050_RA_USER_CTRL 0x6A
|
||||
//bit7 DMP禁止
|
||||
//bit6 当此位设置为0,FIFO缓冲是禁用的
|
||||
//bit5 当这个模式被启用,MPU-60X0即成为辅助I2C总线上的外部传感器slave设备的I2C主机
|
||||
// 当此位被清除为0时,辅助I2C总线线路(AUX_DA and AUX_CL)理论上是由I2C总线
|
||||
// (SDA和SCL)驱动的。这是启用旁路模式的一个前提
|
||||
//bit4 I2C转换至SPI模式(只允许MPU-6000)
|
||||
//bit3 重置DMP模式,官方文档未说明的寄存器
|
||||
//bit2 重置FIFO当设置为1时,此位将重置FIFO缓冲区,此时FIFO_EN等于0。触发重置后,此位将自动清为0
|
||||
//bit1 重置I2C主机当设置为1时,此位将重置I2C主机,此时I2C_MST_EN等于0。触发重置后,此位将自动清为0
|
||||
//bit0 重置所有传感器寄存器和信号路径 如果只重置信号路径(不重置传感器寄存器),请使用寄存器104
|
||||
|
||||
|
||||
/*允许用户配置电源模式和时钟源。还提供了复位整个设备和禁用温度传感器的位*/
|
||||
#define MPU6050_RA_PWR_MGMT_1 0x6B
|
||||
//bit7 触发一个设备的完整重置。 触发重置后,一个~ 50 毫秒的小延迟是合理的
|
||||
//bit6 寄存器的SLEEP位设置使设备处于非常低功率的休眠模式。
|
||||
//bit5 唤醒周期启用状态当此位设为1且SLEEP禁用时.在休眠模式和唤醒模式间循环,以此从活跃的传感器中获取数据样本
|
||||
//bit3 温度传感器启用状态控制内部温度传感器的使用
|
||||
//bit2-bit0 设定时钟源设置,一个频率为8 mhz的内部振荡器,基于陀螺仪的时钟或外部信息源都可以被选为MPU-60X0的时钟源
|
||||
/* CLK_SEL | 时钟源
|
||||
* --------+--------------------------------------
|
||||
* 0 | 内部振荡器
|
||||
* 1 | PLL with X Gyro reference
|
||||
* 2 | PLL with Y Gyro reference
|
||||
* 3 | PLL with Z Gyro reference
|
||||
* 4 | PLL with external 32.768kHz reference
|
||||
* 5 | PLL with external 19.2MHz reference
|
||||
* 6 | Reserved
|
||||
* 7 | Stops the clock and keeps the timing generator in reset
|
||||
* */
|
||||
|
||||
|
||||
/*这个寄存器允许用户配置加速度计在低功耗模式下唤起的频率。也允许用户让加速度计和
|
||||
陀螺仪的个别轴进入待机模式。*/
|
||||
#define MPU6050_RA_PWR_MGMT_2 0x6C
|
||||
//bit7-bit6 Accel-Only低电量模式下的唤醒频率
|
||||
/* 通过把Power Management 1寄存器(寄存器107)中的PWRSEL设为1,
|
||||
* MPU-60X0可以处于Accerlerometer Only的低电量模式。在这种模式下,
|
||||
设备将关闭除了原I2C接口以外的所有设备,只留下accelerometer以固定时间
|
||||
间隔醒来进行测量。唤醒频率可用LP_WAKE_CTRL进行配置,如下表所示:
|
||||
* LP_WAKE_CTRL | 唤醒频率
|
||||
* -------------+------------------
|
||||
* 0 | 1.25 Hz
|
||||
* 1 | 5 Hz
|
||||
* 2 | 20 Hz
|
||||
* 3 | 40 Hz
|
||||
* */
|
||||
//bit5 备用的x轴加速度传感器启用状态,也就是进入待机模式
|
||||
//bit4 备用的Y轴加速度传感器启用状态
|
||||
//bit3 备用的Z轴加速度传感器启用状态
|
||||
//bit2 备用的x轴陀螺仪启用状态
|
||||
//bit1 备用的Y轴陀螺仪启用状态
|
||||
//bit0 备用的Z轴陀螺仪启用状态
|
||||
|
||||
/*设定DMP模式下的bank*/
|
||||
#define MPU6050_RA_BANK_SEL 0x6D
|
||||
//DMP内存配置
|
||||
#define MPU6050_BANKSEL_PRFTCH_EN_BIT 6
|
||||
#define MPU6050_BANKSEL_CFG_USER_BANK_BIT 5
|
||||
#define MPU6050_BANKSEL_MEM_SEL_BIT 4
|
||||
#define MPU6050_BANKSEL_MEM_SEL_LENGTH 5
|
||||
//dmp内存地址设置
|
||||
#define MPU6050_DMP_MEMORY_BANKS 8
|
||||
#define MPU6050_DMP_MEMORY_BANK_SIZE 256
|
||||
#define MPU6050_DMP_MEMORY_CHUNK_SIZE 16
|
||||
|
||||
/*设定DMP模式下的起始地址*/
|
||||
#define MPU6050_RA_MEM_START_ADDR 0x6E
|
||||
/*一个字节的dmp数据缓存*/
|
||||
#define MPU6050_RA_MEM_R_W 0x6F
|
||||
/*DMP配置寄存器1*/
|
||||
#define MPU6050_RA_DMP_CFG_1 0x70
|
||||
/*DMP配置寄存器2*/
|
||||
#define MPU6050_RA_DMP_CFG_2 0x71
|
||||
|
||||
/*当前FIFO缓冲区大小
|
||||
* 这个值表明了存储于FIFO缓冲区的字节数。
|
||||
* 而这个数字也是能从FIFO缓冲区读取的字节数,
|
||||
* 它与存储在FIFO(寄存器35和36)中的传感器数据组所提供的可用样本数成正比。
|
||||
* 两个寄存器一起构成一个16位数据*/
|
||||
#define MPU6050_RA_FIFO_COUNTH 0x72
|
||||
#define MPU6050_RA_FIFO_COUNTL 0x73
|
||||
|
||||
/*这个寄存器用于从FIFO缓冲区中读取和编写数据。数据在寄存器编号(从低到高)的指
|
||||
*令下编写入数据写入FIFO。如果所有的FIFO启用标志(见下文)都被启用了且
|
||||
*所有外部传感器数据寄存器(寄存器73至寄存器96)都与一个slave设备相连
|
||||
*,那么寄存器59到寄存器96的内容都将在采样率的指令下编写。
|
||||
* 当传感器数据寄存器(寄存器59到寄存器96)的相关FIFO启用标志在FIFO_EN 寄存
|
||||
* 器35)中都设为1时,它们的内容将被写入FIFO缓冲区。在I2C_MST_CTRL (寄存器 36)
|
||||
* 中能找到一个与I2C Slave 3相连的额外的传感器数据寄存器标志。
|
||||
* 如果FIFO缓冲区溢出,状态位FIFO_OFLOW_INT自动设置为1。
|
||||
* 此位位于INT_STATUS (寄存器58)中。当FIFO缓冲区溢出时,最早的数据将会丢失
|
||||
* 而新数据将被写入FIFO。如果FIFO缓冲区为空, 读取将返回原来从FIFO中读取的
|
||||
* 最后一个字节,直到有可用的新数据。用户应检查FIFO_COUNT,以确保不在FIFO缓冲为空时读取。*/
|
||||
#define MPU6050_RA_FIFO_R_W 0x74
|
||||
|
||||
/*寄存器是用来验证设备的身份的 默认值是0X34*/
|
||||
#define MPU6050_RA_WHO_AM_I 0x75
|
||||
//bit6-bit1 设备身份验证 0x34 最高位和最低位都剔除掉
|
||||
|
||||
|
||||
#endif
|
||||
418
apps/common/device/gx8002_npu/gx8002_enc/gx8002_enc.c
Normal file
418
apps/common/device/gx8002_npu/gx8002_enc/gx8002_enc.c
Normal file
@ -0,0 +1,418 @@
|
||||
#include "includes.h"
|
||||
#include "app_config.h"
|
||||
#include "gx8002_enc.h"
|
||||
|
||||
#if TCFG_GX8002_ENC_ENABLE
|
||||
|
||||
#define GX8002_DEBUG_ENABLE 1
|
||||
|
||||
#define gx8002_info printf
|
||||
#if GX8002_DEBUG_ENABLE
|
||||
#define gx8002_debug printf
|
||||
#define gx8002_put_buf put_buf
|
||||
#else
|
||||
#define gx8002_debug(...)
|
||||
#define gx8002_put_buf(...)
|
||||
#endif /* #if GX8002_DEBUG_ENABLE */
|
||||
|
||||
|
||||
//====================================================================//
|
||||
// AC897N GX8002 ENC模型 //
|
||||
/*
|
||||
________ ________
|
||||
| | PCM 2CH | |
|
||||
| TX|----------------->|RX |
|
||||
| UART | | UART |
|
||||
| | PCM 1CH | |
|
||||
| RX|<-----------------|TX |
|
||||
|________| |________|
|
||||
BT_CHIP GX8002
|
||||
|
||||
NOTE:
|
||||
*/
|
||||
|
||||
//====================================================================//
|
||||
#define UART_RX_BUF_POINTS (256 * 4) // buf_len = UART_RX_BUF_POINTS x sizeof(16)
|
||||
#define UART_RX_BUF_FRAME_LEN (256 * sizeof(s16) * 2) // buf_len = UART_RX_BUF_FRAME_LEN
|
||||
#define UART_TX_BUF_POINTS (256 * 2) //buf_len = UART_TX_BUF_POINTS x sizeof(16)
|
||||
#define UART_TRANSPORT_BUAD 1000000 //发送波特率
|
||||
|
||||
#define THIS_TASK_NAME "gx8002_enc"
|
||||
|
||||
struct gx8002_enc_t {
|
||||
u8 task_init;
|
||||
u8 state;
|
||||
const uart_bus_t *uart_bus;
|
||||
OS_SEM rx_sem;
|
||||
int uart_rxbuf[(UART_RX_BUF_POINTS * sizeof(s16)) / sizeof(int)]; //uart硬件RX dma缓存, 要求buf长度为2的n次幂, 4字节对齐
|
||||
int uart_txbuf[(UART_TX_BUF_POINTS * sizeof(s16)) / sizeof(int)]; //uart硬件TX dma缓存, 要求buf4字节对齐
|
||||
int uart_rx_frame_buf[UART_RX_BUF_FRAME_LEN / sizeof(int)]; //用于读取Rx缓存中的数据, 临时buf
|
||||
};
|
||||
|
||||
enum {
|
||||
GX8002_ENC_STATE_CLOSE = 0,
|
||||
GX8002_ENC_STATE_OPEN,
|
||||
GX8002_ENC_STATE_RUN,
|
||||
};
|
||||
|
||||
|
||||
static struct gx8002_enc_t *gx8002_enc = NULL;
|
||||
|
||||
//============== extern function =================//
|
||||
/* extern void gx8002_vddio_power_ctrl(u8 on); */
|
||||
/* extern void gx8002_core_vdd_power_ctrl(u8 on); */
|
||||
|
||||
//for make
|
||||
__attribute__((weak))
|
||||
void gx8002_board_port_suspend(void)
|
||||
{
|
||||
}
|
||||
|
||||
__attribute__((weak))
|
||||
void gx8002_vddio_power_ctrl(u8 on)
|
||||
{
|
||||
}
|
||||
|
||||
__attribute__((weak))
|
||||
void gx8002_core_vdd_power_ctrl(u8 on)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
static void gx8002_device_power_on(void)
|
||||
{
|
||||
gx8002_vddio_power_ctrl(1);
|
||||
os_time_dly(2); //vddio先上电 --> wait 20ms --> core_vdd上电
|
||||
gx8002_core_vdd_power_ctrl(1);
|
||||
}
|
||||
|
||||
static void gx8002_device_power_off(void)
|
||||
{
|
||||
gx8002_vddio_power_ctrl(0);
|
||||
gx8002_core_vdd_power_ctrl(0);
|
||||
}
|
||||
|
||||
static void gx8002_enc_data_output(void)
|
||||
{
|
||||
int ret = 0;
|
||||
s16 *rxbuf = NULL;
|
||||
s16 magic_code = 0;
|
||||
static u8 cnt = 0;
|
||||
if (gx8002_enc && (gx8002_enc->state == GX8002_ENC_STATE_RUN)) {
|
||||
if (gx8002_enc->uart_bus && gx8002_enc->uart_bus->read) {
|
||||
rxbuf = (s16 *)(gx8002_enc->uart_rx_frame_buf);
|
||||
putchar('r');
|
||||
ret = gx8002_enc->uart_bus->read((u8 *)rxbuf, UART_RX_BUF_FRAME_LEN, 0);
|
||||
#if 1
|
||||
//数据校验
|
||||
magic_code = rxbuf[0];
|
||||
for (int i = 1; i < ret / sizeof(s16); i++) {
|
||||
if (rxbuf[i] != magic_code) {
|
||||
if (rxbuf[i] != (magic_code + 1)) {
|
||||
gx8002_debug("data err: magic_code = 0x%x, rxbuf[%d] = 0x%x", magic_code, i, rxbuf[i]);
|
||||
printf("buf_in = %d", gx8002_enc->uart_bus->kfifo.buf_in);
|
||||
printf("buf_out = %d", gx8002_enc->uart_bus->kfifo.buf_out);
|
||||
put_buf(gx8002_enc->uart_bus->kfifo.buffer, gx8002_enc->uart_bus->kfifo.buf_size);
|
||||
ASSERT(0);
|
||||
break;
|
||||
wdt_clear();
|
||||
} else {
|
||||
magic_code++;
|
||||
gx8002_debug("increase: 0x%x", magic_code);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void gx8002_enc_uart_isr_hook(void *arg, u32 status)
|
||||
{
|
||||
if (status != UT_TX) {
|
||||
//RX pending
|
||||
os_sem_post(&(gx8002_enc->rx_sem));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void gx8002_enc_uart_porting_config(u32 baud)
|
||||
{
|
||||
struct uart_platform_data_t u_arg = {0};
|
||||
|
||||
u_arg.tx_pin = TCFG_GX8002_ENC_UART_TX_PORT;
|
||||
u_arg.rx_pin = TCFG_GX8002_ENC_UART_RX_PORT;
|
||||
u_arg.rx_cbuf = gx8002_enc->uart_rxbuf;
|
||||
u_arg.rx_cbuf_size = sizeof(gx8002_enc->uart_rxbuf);
|
||||
u_arg.frame_length = UART_RX_BUF_FRAME_LEN;
|
||||
u_arg.rx_timeout = 100;
|
||||
u_arg.isr_cbfun = gx8002_enc_uart_isr_hook;
|
||||
u_arg.baud = baud;
|
||||
u_arg.is_9bit = 0;
|
||||
|
||||
gx8002_enc->uart_bus = uart_dev_open(&u_arg);
|
||||
|
||||
if (gx8002_enc->uart_bus) {
|
||||
gx8002_info("gx8002 uart init succ");
|
||||
} else {
|
||||
gx8002_info("gx8002 uart init fail");
|
||||
ASSERT(gx8002_enc->uart_bus);
|
||||
}
|
||||
}
|
||||
|
||||
static void gx8002_enc_uart_porting_close(void)
|
||||
{
|
||||
if (gx8002_enc && gx8002_enc->uart_bus) {
|
||||
uart_dev_close((uart_bus_t *)(gx8002_enc->uart_bus));
|
||||
gx8002_board_port_suspend();
|
||||
gx8002_enc->uart_bus = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void __gx8002_enc_run(void)
|
||||
{
|
||||
//TODO: add gx8002 post start msg
|
||||
gx8002_debug("%s", __func__);
|
||||
|
||||
while (1) {
|
||||
os_sem_pend(&(gx8002_enc->rx_sem), 0);
|
||||
|
||||
if (gx8002_enc->state != GX8002_ENC_STATE_RUN) {
|
||||
break;
|
||||
}
|
||||
|
||||
gx8002_enc_data_output();
|
||||
}
|
||||
}
|
||||
|
||||
static void __gx8002_enc_close(int priv)
|
||||
{
|
||||
if (gx8002_enc) {
|
||||
if (gx8002_enc->state == GX8002_ENC_STATE_CLOSE) {
|
||||
gx8002_device_power_off();
|
||||
gx8002_enc_uart_porting_close();
|
||||
if (priv) {
|
||||
os_sem_post((OS_SEM *)priv);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void gx8002_enc_task(void *priv)
|
||||
{
|
||||
int msg[16];
|
||||
int res;
|
||||
|
||||
os_sem_create(&(gx8002_enc->rx_sem), 0);
|
||||
|
||||
gx8002_enc_uart_porting_config(UART_TRANSPORT_BUAD);
|
||||
gx8002_device_power_on();
|
||||
|
||||
gx8002_enc->state = GX8002_ENC_STATE_OPEN;
|
||||
|
||||
if (priv) {
|
||||
os_sem_post((OS_SEM *)priv);
|
||||
}
|
||||
|
||||
while (1) {
|
||||
res = os_taskq_pend(NULL, msg, ARRAY_SIZE(msg));
|
||||
if (res == OS_TASKQ) {
|
||||
switch (msg[1]) {
|
||||
case GX8002_ENC_MSG_RUN:
|
||||
__gx8002_enc_run();
|
||||
break;
|
||||
case GX8002_ENC_MSG_CLOSE:
|
||||
__gx8002_enc_close(msg[2]);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//====================================================================//
|
||||
// GX8002 ENC API //
|
||||
//====================================================================//
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/**@brief 打开gx8002_enc流程, 创建gx8002线程
|
||||
@param void
|
||||
@return void
|
||||
@note 不能在中断中调用, 需要在线程中调用;
|
||||
*/
|
||||
/*----------------------------------------------------------------------------*/
|
||||
void gx8002_enc_open(void)
|
||||
{
|
||||
gx8002_debug("%s", __func__);
|
||||
|
||||
if (gx8002_enc == NULL) {
|
||||
gx8002_enc = zalloc(sizeof(struct gx8002_enc_t));
|
||||
if (gx8002_enc == NULL) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
OS_SEM sem_wait;
|
||||
os_sem_create(&sem_wait, 0);
|
||||
gx8002_enc->task_init = 1;
|
||||
task_create(gx8002_enc_task, (void *)&sem_wait, THIS_TASK_NAME);
|
||||
|
||||
os_sem_pend(&sem_wait, 0);
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/**@brief 启动gx8002_enc流程
|
||||
@param void
|
||||
@return void
|
||||
@note
|
||||
*/
|
||||
/*----------------------------------------------------------------------------*/
|
||||
void gx8002_enc_start(void)
|
||||
{
|
||||
gx8002_debug("%s", __func__);
|
||||
|
||||
if (gx8002_enc && (gx8002_enc->state == GX8002_ENC_STATE_OPEN)) {
|
||||
gx8002_enc->state = GX8002_ENC_STATE_RUN;
|
||||
os_taskq_post_msg(THIS_TASK_NAME, 1, GX8002_ENC_MSG_RUN);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/**@brief 关闭gx8002_enc流程, 释放资源
|
||||
@param void
|
||||
@return void
|
||||
@note 不能在中断中调用, 需要在线程中调用;
|
||||
*/
|
||||
/*----------------------------------------------------------------------------*/
|
||||
void gx8002_enc_close(void)
|
||||
{
|
||||
OS_SEM sem_wait;
|
||||
|
||||
gx8002_debug("%s", __func__);
|
||||
if (gx8002_enc) {
|
||||
if (gx8002_enc->task_init) {
|
||||
os_sem_create(&sem_wait, 0);
|
||||
gx8002_enc->state = GX8002_ENC_STATE_CLOSE;
|
||||
os_sem_post(&(gx8002_enc->rx_sem));
|
||||
os_taskq_post_msg(THIS_TASK_NAME, 2, GX8002_ENC_MSG_CLOSE, (u32)&sem_wait);
|
||||
os_sem_pend(&sem_wait, 0);
|
||||
gx8002_enc->task_init = 0;
|
||||
task_kill(THIS_TASK_NAME);
|
||||
}
|
||||
|
||||
free(gx8002_enc);
|
||||
gx8002_enc = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/**@brief gx8002_enc数据输入, 支持1~2通道数据输入
|
||||
@param ch0_buf: 通道0数据buf
|
||||
@param ch1_buf: 通道1数据buf
|
||||
@param points: ch0和ch1 buf中点数
|
||||
@return
|
||||
@note 1)不能在中断中调用, 需要在线程中调用;
|
||||
@note 2)如果只有1通道数据, 把ch0_buf/ch1_buf传参为NULL即可;
|
||||
@note 3)ch0_buf和ch1_buf数据宽度为16bit;
|
||||
*/
|
||||
/*----------------------------------------------------------------------------*/
|
||||
u32 gx8002_enc_data_input(s16 *ch0_buf, s16 *ch1_buf, u32 points)
|
||||
{
|
||||
u32 send_points = 0;
|
||||
s16 *txbuf = NULL;
|
||||
u32 remain_points = points;
|
||||
u32 txbuf_points = 0;
|
||||
u8 ch_num = 0;
|
||||
|
||||
if (gx8002_enc && (gx8002_enc->state == GX8002_ENC_STATE_RUN)) {
|
||||
if (gx8002_enc->uart_bus && gx8002_enc->uart_bus->write) {
|
||||
if (ch0_buf && ch1_buf) {
|
||||
//2ch
|
||||
ch_num = 2;
|
||||
txbuf_points = (sizeof(gx8002_enc->uart_txbuf) / sizeof(s16) / 2);
|
||||
} else {
|
||||
ch_num = 1;
|
||||
if (ch0_buf == NULL) {
|
||||
ch0_buf = ch1_buf;
|
||||
}
|
||||
txbuf_points = (sizeof(gx8002_enc->uart_txbuf) / sizeof(s16));
|
||||
}
|
||||
|
||||
txbuf = (s16 *)(gx8002_enc->uart_txbuf);
|
||||
while (remain_points) {
|
||||
send_points = remain_points <= txbuf_points ? remain_points : txbuf_points;
|
||||
//gx8002_debug("send_points: %d", send_points);
|
||||
if (ch_num == 2) {
|
||||
for (int i = 0; i < send_points; i++) {
|
||||
txbuf[2 * i] = ch0_buf[i];
|
||||
txbuf[2 * i + 1] = ch1_buf[i];
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < send_points; i++) {
|
||||
txbuf[i] = ch0_buf[i];
|
||||
}
|
||||
}
|
||||
|
||||
gx8002_enc->uart_bus->write((const u8 *)txbuf, send_points * sizeof(s16) * ch_num);
|
||||
remain_points -= send_points;
|
||||
}
|
||||
|
||||
return points * sizeof(s16) * ch_num;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//====================================================================//
|
||||
// GX8002 ENC TEST //
|
||||
//====================================================================//
|
||||
|
||||
static void gx8002_enc_input_test(void *priv)
|
||||
{
|
||||
|
||||
if (gx8002_enc == NULL) {
|
||||
putchar('i');
|
||||
return;
|
||||
}
|
||||
#define BUF_TEST_POINTS 300
|
||||
static s16 cnt = 0x0;
|
||||
s16 tmp_buf[BUF_TEST_POINTS];
|
||||
putchar('w');
|
||||
cnt++;
|
||||
for (int i = 0; i < ARRAY_SIZE(tmp_buf); i++) {
|
||||
tmp_buf[i] = cnt;
|
||||
}
|
||||
//gx8002_enc_data_input(tmp_buf, NULL, BUF_TEST_POINTS); //1ch data
|
||||
gx8002_enc_data_input(tmp_buf, tmp_buf, BUF_TEST_POINTS); //two ch data
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
static void gx8002_enc_close_test(void *priv)
|
||||
{
|
||||
gx8002_enc_close();
|
||||
}
|
||||
|
||||
static int gx8002_enc_test(void)
|
||||
{
|
||||
gx8002_enc_open();
|
||||
gx8002_enc_start();
|
||||
|
||||
sys_timer_add(NULL, gx8002_enc_input_test, 50);
|
||||
sys_timer_add(NULL, gx8002_enc_close_test, 1000 * 60 * 3);
|
||||
|
||||
return 0;
|
||||
}
|
||||
//late_initcall(gx8002_enc_test);
|
||||
|
||||
|
||||
#endif /* #if TCFG_GX8002_ENC_ENABLE */
|
||||
10
apps/common/device/gx8002_npu/gx8002_enc/gx8002_enc.h
Normal file
10
apps/common/device/gx8002_npu/gx8002_enc/gx8002_enc.h
Normal file
@ -0,0 +1,10 @@
|
||||
#ifndef __GX8002_NPU_H__
|
||||
#define __GX8002_NPU_H__
|
||||
|
||||
enum GX8002_MSG {
|
||||
GX8002_ENC_MSG_RUN = ('G' << 24) | ('E' << 16) | ('N' << 8) | ('C' << 0),
|
||||
GX8002_ENC_MSG_CLOSE,
|
||||
};
|
||||
|
||||
|
||||
#endif /* #ifndef __GX8002_NPU_H__ */
|
||||
921
apps/common/device/gx8002_npu/gx8002_npu.c
Normal file
921
apps/common/device/gx8002_npu/gx8002_npu.c
Normal file
@ -0,0 +1,921 @@
|
||||
#include "includes.h"
|
||||
#include "app_config.h"
|
||||
#include "gx8002_npu.h"
|
||||
#include "gx8002_npu_api.h"
|
||||
#include "asm/pwm_led.h"
|
||||
#include "btstack/avctp_user.h"
|
||||
|
||||
#if TCFG_GX8002_NPU_ENABLE
|
||||
|
||||
#define GX8002_DEBUG_ENABLE 0
|
||||
|
||||
#define gx8002_info g_printf
|
||||
#if GX8002_DEBUG_ENABLE
|
||||
#define gx8002_debug g_printf
|
||||
#define gx8002_put_buf put_buf
|
||||
#else
|
||||
#define gx8002_debug(...)
|
||||
#define gx8002_put_buf(...)
|
||||
#endif /* #if GX8002_DEBUG_ENABLE */
|
||||
|
||||
|
||||
|
||||
//===========================================================//
|
||||
// GX8002 NPU LOGIC LAYER //
|
||||
//===========================================================//
|
||||
///// 分配内存 /////
|
||||
#define OS_MALLOC malloc
|
||||
|
||||
///// 释放内存 /////
|
||||
#define OS_FREE free
|
||||
|
||||
static const char msg_rcv_magic[MSG_MAGIC_LEN] = {
|
||||
MSG_RCV_MAGIC0, MSG_RCV_MAGIC1,
|
||||
MSG_RCV_MAGIC2, MSG_RCV_MAGIC3
|
||||
};
|
||||
|
||||
static unsigned char msg_seq = 0;
|
||||
static unsigned char initialized = 0;
|
||||
static struct message prev_snd_msg;
|
||||
static struct message prev_rcv_msg;
|
||||
static STREAM_READ stream_read = NULL;
|
||||
static STREAM_WRITE stream_write = NULL;
|
||||
static STREAM_EMPTY stream_is_empty = NULL;
|
||||
|
||||
struct msg_header {
|
||||
unsigned int magic;
|
||||
unsigned short cmd;
|
||||
unsigned char seq;
|
||||
unsigned char flags;
|
||||
unsigned short length;
|
||||
unsigned int crc32;
|
||||
} __attribute__((packed));
|
||||
|
||||
static const unsigned int crc32tab[] = {
|
||||
0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL,
|
||||
0x076dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L,
|
||||
0x0edb8832L, 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L,
|
||||
0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 0x90bf1d91L,
|
||||
0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
|
||||
0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L,
|
||||
0x136c9856L, 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL,
|
||||
0x14015c4fL, 0x63066cd9L, 0xfa0f3d63L, 0x8d080df5L,
|
||||
0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 0xa2677172L,
|
||||
0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
|
||||
0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L,
|
||||
0x32d86ce3L, 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L,
|
||||
0x26d930acL, 0x51de003aL, 0xc8d75180L, 0xbfd06116L,
|
||||
0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 0xb8bda50fL,
|
||||
0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
|
||||
0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL,
|
||||
0x76dc4190L, 0x01db7106L, 0x98d220bcL, 0xefd5102aL,
|
||||
0x71b18589L, 0x06b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L,
|
||||
0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 0xe10e9818L,
|
||||
0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
|
||||
0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL,
|
||||
0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L,
|
||||
0x65b0d9c6L, 0x12b7e950L, 0x8bbeb8eaL, 0xfcb9887cL,
|
||||
0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L,
|
||||
0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
|
||||
0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL,
|
||||
0x4369e96aL, 0x346ed9fcL, 0xad678846L, 0xda60b8d0L,
|
||||
0x44042d73L, 0x33031de5L, 0xaa0a4c5fL, 0xdd0d7cc9L,
|
||||
0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L,
|
||||
0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
|
||||
0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L,
|
||||
0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL,
|
||||
0xedb88320L, 0x9abfb3b6L, 0x03b6e20cL, 0x74b1d29aL,
|
||||
0xead54739L, 0x9dd277afL, 0x04db2615L, 0x73dc1683L,
|
||||
0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
|
||||
0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L,
|
||||
0xf00f9344L, 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL,
|
||||
0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L,
|
||||
0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 0x67dd4accL,
|
||||
0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
|
||||
0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L,
|
||||
0xd1bb67f1L, 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL,
|
||||
0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L, 0x41047a60L,
|
||||
0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 0x4669be79L,
|
||||
0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
|
||||
0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL,
|
||||
0xc5ba3bbeL, 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L,
|
||||
0xc2d7ffa7L, 0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL,
|
||||
0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 0x026d930aL,
|
||||
0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
|
||||
0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L,
|
||||
0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L,
|
||||
0x86d3d2d4L, 0xf1d4e242L, 0x68ddb3f8L, 0x1fda836eL,
|
||||
0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 0x18b74777L,
|
||||
0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
|
||||
0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L,
|
||||
0xa00ae278L, 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L,
|
||||
0xa7672661L, 0xd06016f7L, 0x4969474dL, 0x3e6e77dbL,
|
||||
0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 0x37d83bf0L,
|
||||
0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
|
||||
0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L,
|
||||
0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL,
|
||||
0xb3667a2eL, 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L,
|
||||
0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 0x2d02ef8dL
|
||||
};
|
||||
|
||||
static unsigned int crc32(const unsigned char *buf, unsigned int size)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned int crc = 0xFFFFFFFF;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
crc = crc32tab[(crc ^ buf[i]) & 0xff] ^ (crc >> 8);
|
||||
}
|
||||
|
||||
return crc ^ 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
static inline int stream_getc(char *ch)
|
||||
{
|
||||
int ret = stream_read((unsigned char *)ch, 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int msg_byte_match(char c)
|
||||
{
|
||||
char ch = 0;
|
||||
|
||||
return (stream_getc(&ch) && (ch == c));
|
||||
}
|
||||
|
||||
static int msg_find_magic(void)
|
||||
{
|
||||
int i;
|
||||
int offset = 0;
|
||||
|
||||
while (offset < MSG_LEN_MAX) {
|
||||
for (i = 0; i < MSG_MAGIC_LEN; i++) {
|
||||
offset++;
|
||||
if (!msg_byte_match(msg_rcv_magic[i])) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ((i + 1) == MSG_MAGIC_LEN) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static unsigned char msg_get_new_seq(unsigned char seq)
|
||||
{
|
||||
unsigned char next_seq;
|
||||
|
||||
next_seq = (seq + 1) % MSG_SEQ_MAX;
|
||||
|
||||
return next_seq == 0 ? next_seq + 1 : next_seq;
|
||||
}
|
||||
|
||||
static int nc_message_receive(struct message *msg)
|
||||
{
|
||||
struct msg_header msg_header;
|
||||
unsigned int newcrc32 = 0;
|
||||
unsigned int oldcrc32 = 0;
|
||||
unsigned short bodylen;
|
||||
unsigned char *pheader = (unsigned char *)&msg_header;
|
||||
|
||||
if (!msg || !initialized) {
|
||||
line_inf;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (stream_is_empty()) {
|
||||
line_inf;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Read stream until find mseeage magic */
|
||||
if (msg_find_magic() != 0) {
|
||||
line_inf;
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&msg_header, 0, sizeof(struct msg_header));
|
||||
msg_header.magic = MSG_MAGIC;
|
||||
|
||||
/* Read the rest of message header */
|
||||
stream_read(pheader + MSG_MAGIC_LEN,
|
||||
sizeof(struct msg_header) - MSG_MAGIC_LEN);
|
||||
|
||||
/* Check message header integrity */
|
||||
newcrc32 = crc32((unsigned char *)&msg_header,
|
||||
sizeof(struct msg_header) - MSG_HEAD_CHECK_LEN);
|
||||
if (newcrc32 != msg_header.crc32) {
|
||||
line_inf;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Read message body */
|
||||
if (msg_header.length > 0) {
|
||||
|
||||
msg->body = OS_MALLOC(msg_header.length);
|
||||
if (msg->body == NULL) {
|
||||
line_inf;
|
||||
return -1;
|
||||
}
|
||||
|
||||
stream_read(msg->body, msg_header.length);
|
||||
if (MSG_NEED_BCHECK(msg_header.flags)) {
|
||||
bodylen = msg_header.length - MSG_BODY_CHECK_LEN;
|
||||
newcrc32 = crc32(msg->body, bodylen);
|
||||
memcpy(&oldcrc32, msg->body + bodylen, MSG_BODY_CHECK_LEN);
|
||||
|
||||
if (oldcrc32 != newcrc32) {
|
||||
line_inf;
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
bodylen = msg_header.length;
|
||||
}
|
||||
} else {
|
||||
bodylen = 0;
|
||||
}
|
||||
|
||||
msg->cmd = msg_header.cmd;
|
||||
msg->seq = msg_header.seq;
|
||||
msg->flags = msg_header.flags;
|
||||
msg->bodylen = bodylen;
|
||||
|
||||
prev_rcv_msg.cmd = msg->cmd;
|
||||
prev_rcv_msg.seq = msg->seq;
|
||||
|
||||
return bodylen;
|
||||
}
|
||||
|
||||
static int nc_message_send(struct message *msg)
|
||||
{
|
||||
struct msg_header msg_header;
|
||||
unsigned int body_crc32 = 0;
|
||||
|
||||
if (!msg || !initialized) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&msg_header, 0, sizeof(struct msg_header));
|
||||
|
||||
msg_header.magic = MSG_MAGIC;
|
||||
msg_header.cmd = msg->cmd;
|
||||
msg_header.flags = msg->flags;
|
||||
|
||||
if ((msg->cmd == prev_snd_msg.cmd) &&
|
||||
(msg->seq == prev_snd_msg.seq) &&
|
||||
(MSG_TYPE(msg->cmd)) == MSG_TYPE_REQ) {
|
||||
msg_seq = prev_snd_msg.seq;
|
||||
} else {
|
||||
msg_seq = msg_get_new_seq(msg_seq);
|
||||
}
|
||||
|
||||
msg_header.seq = msg_seq;
|
||||
|
||||
if (!msg->body) {
|
||||
msg_header.length = 0;
|
||||
} else {
|
||||
if (MSG_NEED_BCHECK(msg->flags)) {
|
||||
body_crc32 = crc32((unsigned char *)msg->body, msg->bodylen);
|
||||
msg_header.length = msg->bodylen + MSG_BODY_CHECK_LEN;
|
||||
} else {
|
||||
msg_header.length = msg->bodylen;
|
||||
}
|
||||
}
|
||||
|
||||
msg_header.crc32 = crc32((unsigned char *)&msg_header,
|
||||
sizeof(struct msg_header) - MSG_BODY_CHECK_LEN);
|
||||
|
||||
stream_write((unsigned char *)&msg_header, sizeof(struct msg_header));
|
||||
|
||||
if (msg->body) {
|
||||
stream_write(msg->body, msg->bodylen);
|
||||
if (MSG_NEED_BCHECK(msg->flags)) {
|
||||
stream_write((unsigned char *)&body_crc32, MSG_BODY_CHECK_LEN);
|
||||
}
|
||||
}
|
||||
|
||||
prev_snd_msg.cmd = msg->cmd;
|
||||
prev_snd_msg.seq = msg_seq;
|
||||
msg->seq = msg_seq;
|
||||
|
||||
return msg->bodylen;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int nc_message_init(STREAM_READ read, STREAM_WRITE write, STREAM_EMPTY is_empty)
|
||||
{
|
||||
if (!read || !write || !is_empty) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
stream_read = read;
|
||||
stream_write = write;
|
||||
stream_is_empty = is_empty;
|
||||
|
||||
msg_seq = 0;
|
||||
memset(&prev_rcv_msg, 0xFF, sizeof(prev_rcv_msg));
|
||||
memset(&prev_snd_msg, 0xFF, sizeof(prev_snd_msg));
|
||||
initialized = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gx8002_uart_agent_query_event(unsigned short cmd)
|
||||
{
|
||||
struct message snd_msg = {0};
|
||||
gx8002_info("gx8002 task query msg");
|
||||
|
||||
//snd_msg.cmd = MSG_REQ_VOICE_EVENT;
|
||||
snd_msg.cmd = cmd;
|
||||
snd_msg.flags = 0;
|
||||
snd_msg.body = NULL;
|
||||
snd_msg.bodylen = 0;
|
||||
|
||||
return nc_message_send(&snd_msg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//===========================================================//
|
||||
// GX8002 NPU PORT LAYER //
|
||||
//===========================================================//
|
||||
|
||||
#define THIS_TASK_NAME "gx8002"
|
||||
|
||||
enum GX8002_STATE {
|
||||
GX8002_STATE_WORKING = 1,
|
||||
GX8002_STATE_SUSPEND,
|
||||
GX8002_STATE_UPGRADING,
|
||||
};
|
||||
|
||||
|
||||
struct gx8002_handle {
|
||||
u8 state;
|
||||
u8 idle; //0: busy, 1: idle
|
||||
OS_SEM rx_sem;
|
||||
const uart_bus_t *uart_bus;
|
||||
};
|
||||
|
||||
static struct gx8002_handle hdl;
|
||||
|
||||
#define __this (&hdl)
|
||||
static u8 uart_cbuf[32] __attribute__((aligned(4)));
|
||||
u8 gx_self_info[6] = {0, 0, 0, 0, //version
|
||||
0, //mic status
|
||||
0
|
||||
}; //gsensor status
|
||||
|
||||
//============== extern function =================//
|
||||
extern void gx8002_board_port_resumed(void);
|
||||
extern void gx8002_board_port_suspend(void);
|
||||
extern void gx8002_vddio_power_ctrl(u8 on);
|
||||
extern void gx8002_core_vdd_power_ctrl(u8 on);
|
||||
|
||||
static void gx8002_uart_isr_hook(void *arg, u32 status)
|
||||
{
|
||||
if (status != UT_TX) {
|
||||
gx8002_info("gx8002 uart RX pnding");
|
||||
if (__this->state == GX8002_STATE_WORKING) {
|
||||
os_sem_post(&(__this->rx_sem));
|
||||
__this->idle = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void gx8002_uart_porting_config(u32 baud)
|
||||
{
|
||||
struct uart_platform_data_t u_arg = {0};
|
||||
|
||||
if (__this->uart_bus) {
|
||||
gx8002_info("gx8002 uart have init");
|
||||
return;
|
||||
}
|
||||
u_arg.tx_pin = TCFG_GX8002_NPU_UART_TX_PORT;
|
||||
u_arg.rx_pin = TCFG_GX8002_NPU_UART_RX_PORT;
|
||||
u_arg.rx_cbuf = uart_cbuf;
|
||||
u_arg.rx_cbuf_size = sizeof(uart_cbuf);
|
||||
u_arg.frame_length = 0xFFFF;
|
||||
u_arg.rx_timeout = 100;
|
||||
u_arg.isr_cbfun = gx8002_uart_isr_hook;
|
||||
u_arg.baud = baud;
|
||||
u_arg.is_9bit = 0;
|
||||
|
||||
__this->uart_bus = uart_dev_open(&u_arg);
|
||||
if (__this->uart_bus) {
|
||||
gx8002_info("gx8002 uart init succ");
|
||||
} else {
|
||||
gx8002_info("gx8002 uart init fail");
|
||||
ASSERT(__this->uart_bus);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void gx8002_uart_porting_close(void)
|
||||
{
|
||||
if (__this->uart_bus) {
|
||||
uart_dev_close(__this->uart_bus);
|
||||
gpio_disable_fun_output_port(TCFG_GX8002_NPU_UART_TX_PORT);
|
||||
gx8002_board_port_suspend();
|
||||
__this->uart_bus = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int gx8002_uart_stream_read(unsigned char *buf, int len)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ASSERT(__this->uart_bus && __this->uart_bus->read);
|
||||
if (__this->uart_bus && __this->uart_bus->read) {
|
||||
ret = __this->uart_bus->read(buf, len, 1000);
|
||||
gx8002_debug("stream read len %d", len);
|
||||
gx8002_put_buf(buf, len);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int gx8002_uart_stream_write(const unsigned char *buf, int len)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ASSERT(__this->uart_bus && __this->uart_bus->write);
|
||||
if (__this->uart_bus && __this->uart_bus->write) {
|
||||
__this->uart_bus->write(buf, len);
|
||||
ret = len;
|
||||
gx8002_debug("stream write len %d", len);
|
||||
gx8002_put_buf(buf, len);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int gx8002_uart_stream_is_empty(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gx8002_uart_porting_poll(u32 timeout)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static void gx8002_power_off(void)
|
||||
{
|
||||
//由板级提供
|
||||
gx8002_board_port_suspend();
|
||||
gx8002_vddio_power_ctrl(0);
|
||||
gx8002_core_vdd_power_ctrl(0);
|
||||
}
|
||||
|
||||
static void gx8002_power_off_keep_vddio(void)
|
||||
{
|
||||
//由板级提供
|
||||
gx8002_board_port_suspend();
|
||||
//gx8002_vddio_power_ctrl(0); //通话是会影响mic配置, 不关MIC_LDO
|
||||
gx8002_core_vdd_power_ctrl(0);
|
||||
}
|
||||
|
||||
//======================================//
|
||||
// GX8002上电注意事项:
|
||||
// 1) 正常上电需要先将uart IO初始化为确认电平, 否则gx8002会进入升级模式;
|
||||
// 2) vddio先上电, core_vdd需要等vddio上电后之后3ms后上电;
|
||||
//======================================//
|
||||
static void gx8002_normal_power_on(void)
|
||||
{
|
||||
gx8002_board_port_resumed();
|
||||
//由板级提供
|
||||
//gx8002_core_vdd_power_ctrl(0);
|
||||
gx8002_vddio_power_ctrl(1);
|
||||
os_time_dly(2);
|
||||
gx8002_core_vdd_power_ctrl(1);
|
||||
}
|
||||
|
||||
//进升级模式
|
||||
static void gx8002_upgrade_power_on(void)
|
||||
{
|
||||
//由板级提供
|
||||
//gx8002_core_vdd_power_ctrl(0);
|
||||
gx8002_vddio_power_ctrl(1);
|
||||
os_time_dly(2);
|
||||
gx8002_core_vdd_power_ctrl(1);
|
||||
gx8002_board_port_resumed();
|
||||
}
|
||||
|
||||
static void gx8002_first_power_on(void)
|
||||
{
|
||||
//由板级提供
|
||||
//gx8002_core_vdd_power_ctrl(0);
|
||||
gx8002_vddio_power_ctrl(1);
|
||||
os_time_dly(10);
|
||||
gx8002_core_vdd_power_ctrl(1);
|
||||
|
||||
//gx8002_board_port_resumed();
|
||||
}
|
||||
|
||||
|
||||
static void __gx8002_module_suspend(u8 keep_vddio)
|
||||
{
|
||||
gx8002_info("%s", __func__);
|
||||
if (keep_vddio) {
|
||||
gx8002_power_off_keep_vddio();
|
||||
} else {
|
||||
gx8002_power_off();
|
||||
}
|
||||
|
||||
if (__this->state == GX8002_STATE_UPGRADING) {
|
||||
return;
|
||||
}
|
||||
__this->state = GX8002_STATE_SUSPEND;
|
||||
}
|
||||
|
||||
static void __gx8002_module_resumed()
|
||||
{
|
||||
gx8002_info("%s", __func__);
|
||||
gx8002_normal_power_on();
|
||||
|
||||
if (__this->state == GX8002_STATE_UPGRADING) {
|
||||
return;
|
||||
}
|
||||
__this->state = GX8002_STATE_WORKING;
|
||||
}
|
||||
|
||||
void gx8002_module_suspend(u8 keep_vddio)
|
||||
{
|
||||
os_taskq_post_msg(THIS_TASK_NAME, 2, GX8002_MSG_SUSPEND, keep_vddio);
|
||||
}
|
||||
|
||||
void gx8002_module_resumed()
|
||||
{
|
||||
os_taskq_post_msg(THIS_TASK_NAME, 1, GX8002_MSG_RESUMED);
|
||||
}
|
||||
|
||||
void gx8002_normal_cold_reset(void)
|
||||
{
|
||||
gx8002_power_off();
|
||||
os_time_dly(50);
|
||||
gx8002_normal_power_on();
|
||||
}
|
||||
|
||||
void gx8002_upgrade_cold_reset(void)
|
||||
{
|
||||
gx8002_power_off();
|
||||
os_time_dly(50);
|
||||
gx8002_upgrade_power_on();
|
||||
}
|
||||
|
||||
int gx8002_uart_spp_ota_init(void);
|
||||
static void gx8002_app_event_handler(struct sys_event *event)
|
||||
{
|
||||
gx8002_info("%s", __func__);
|
||||
struct bt_event *bt = &(event->u.bt);
|
||||
switch (event->type) {
|
||||
case SYS_BT_EVENT:
|
||||
if ((u32)event->arg == SYS_BT_EVENT_TYPE_CON_STATUS) {
|
||||
switch (bt->event) {
|
||||
case BT_STATUS_FIRST_CONNECTED:
|
||||
#if GX8002_UPGRADE_SPP_TOGGLE
|
||||
gx8002_uart_spp_ota_init();
|
||||
#endif /* #if GX8002_UPGRADE_SPP_TOGGLE */
|
||||
break;
|
||||
#if 0
|
||||
case BT_STATUS_SCO_STATUS_CHANGE:
|
||||
if (bt->value != 0xff) {
|
||||
gx8002_module_suspend();
|
||||
} else {
|
||||
gx8002_module_resumed();
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int gx8002_wakeup_handle(unsigned short cmd)
|
||||
{
|
||||
int err;
|
||||
struct message recv_msg = {0};
|
||||
unsigned short event;
|
||||
int ret = 0;
|
||||
|
||||
if (__this->state != GX8002_STATE_WORKING) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (gx8002_uart_porting_poll(1000) > 0) {
|
||||
os_sem_set(&(__this->rx_sem), 0);
|
||||
gx8002_uart_agent_query_event(cmd);
|
||||
|
||||
err = os_sem_pend(&(__this->rx_sem), 100);
|
||||
if (err != OS_NO_ERR) {
|
||||
gx8002_info("rx sem err: %d", err);
|
||||
__this->idle = 1;
|
||||
return -1;
|
||||
}
|
||||
gx8002_info("gx8002 task receive >>>>");
|
||||
// 有串口数据
|
||||
memset(&recv_msg, 0, sizeof(recv_msg));
|
||||
if (nc_message_receive(&recv_msg) < 0) {
|
||||
if (recv_msg.body) {
|
||||
OS_FREE(recv_msg.body);
|
||||
}
|
||||
gx8002_info("recv_msg NULL\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (recv_msg.cmd) {
|
||||
case MSG_RSP_VOICE_EVENT:
|
||||
//语音事件
|
||||
event = recv_msg.body[1] << 8 | recv_msg.body[0];
|
||||
//处理语音事件
|
||||
ret = event;
|
||||
gx8002_event_state_update(event);
|
||||
break;
|
||||
|
||||
case MSG_RSP_MIC_EVENT:
|
||||
event = recv_msg.body[1] << 8 | recv_msg.body[0];
|
||||
ret = event;
|
||||
break;
|
||||
case MSG_RSP_GSENSOR_EVENT:
|
||||
event = recv_msg.body[1] << 8 | recv_msg.body[0];
|
||||
ret = event;
|
||||
break;
|
||||
|
||||
case MSG_RSP_VERSION_EVENT:
|
||||
gx8002_info(">> gx version");
|
||||
memcpy(gx_self_info, recv_msg.body, recv_msg.bodylen);
|
||||
put_buf(gx_self_info, sizeof(gx_self_info));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (recv_msg.body) {
|
||||
OS_FREE(recv_msg.body);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void gx8002_self_test_handle()
|
||||
{
|
||||
int ret = 0;
|
||||
int mic_test_cnt = 0;
|
||||
int gsensor_test_cnt = 0;
|
||||
|
||||
//int self_test_result = 0;
|
||||
|
||||
gx8002_info("gx8002 self test start >>>>");
|
||||
__gsensor_test_retry:
|
||||
__this->idle = 0;
|
||||
gx8002_info("gsensor_test_cnt = %d", gsensor_test_cnt);
|
||||
ret = gx8002_wakeup_handle(MSG_REQ_GSENSOR_EVENT);
|
||||
if (ret == 0) {
|
||||
gx8002_info("gx8002 gsensor test OK");
|
||||
//self_test_result |= (0xA << 4);
|
||||
gx_self_info[5] = 0xA;
|
||||
} else {
|
||||
gsensor_test_cnt++;
|
||||
if (gsensor_test_cnt < 10) {
|
||||
gx8002_info("gx8002 gsensor no OK try again");
|
||||
os_time_dly(500 / 10);
|
||||
goto __gsensor_test_retry;
|
||||
}
|
||||
gx_self_info[5] = 1;
|
||||
}
|
||||
|
||||
//MIC状态查询
|
||||
__mic_test_retry:
|
||||
__this->idle = 0;
|
||||
gx8002_info("mic_test_cnt = %d", mic_test_cnt);
|
||||
ret = gx8002_wakeup_handle(MSG_REQ_MIC_EVENT);
|
||||
if (ret == 0) {
|
||||
gx8002_info("gx8002 mic test OK");
|
||||
//self_test_result |= 0xA;
|
||||
gx_self_info[4] = 0xA;
|
||||
} else {
|
||||
mic_test_cnt++;
|
||||
if (mic_test_cnt < 10) {
|
||||
gx8002_info("gx8002 mic no OK try again");
|
||||
os_time_dly(500 / 10);
|
||||
goto __mic_test_retry;
|
||||
}
|
||||
gx_self_info[4] = 1;
|
||||
}
|
||||
|
||||
__this->idle = 1;
|
||||
|
||||
//put_buf(gx_self_info,sizeof(gx_self_info));
|
||||
gx8002_info("gx_self_info[mic]:%x,gx_self_info[g]:%x", gx_self_info[4], gx_self_info[5]);
|
||||
}
|
||||
|
||||
|
||||
static void gx8002_sdfile_update_timer(void *priv)
|
||||
{
|
||||
gx8002_info("gx8002 post update msg >>>>");
|
||||
os_taskq_post_msg(THIS_TASK_NAME, 2, GX8002_MSG_UPDATE, GX8002_UPDATE_TYPE_SDFILE);
|
||||
}
|
||||
|
||||
void gx8002_update_end_post_msg(u8 flag)
|
||||
{
|
||||
os_taskq_post_msg(THIS_TASK_NAME, 2, GX8002_MSG_UPDATE_END, flag);
|
||||
}
|
||||
|
||||
|
||||
static void gx8002_upgrade_start(int update_type)
|
||||
{
|
||||
#if GX8002_UPGRADE_TOGGLE
|
||||
gx8002_uart_porting_close();
|
||||
__this->state = GX8002_STATE_UPGRADING;
|
||||
|
||||
switch (update_type) {
|
||||
case GX8002_UPDATE_TYPE_SDFILE:
|
||||
gx8002_uart_sdfile_ota_init();
|
||||
break;
|
||||
case GX8002_UPDATE_TYPE_SPP:
|
||||
gx8002_uart_spp_ota_init();
|
||||
break;
|
||||
case GX8002_UPDATE_TYPE_APP:
|
||||
gx8002_uart_app_ota_init();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#endif /* #if GX8002_UPGRADE_TOGGLE */
|
||||
}
|
||||
|
||||
static void gx8002_upgrade_end(u8 flag)
|
||||
{
|
||||
gx8002_uart_porting_config(115200);
|
||||
gx8002_normal_power_on();
|
||||
__this->state = GX8002_STATE_WORKING;
|
||||
}
|
||||
|
||||
void gx8002_voice_event_post_msg(u8 msg)
|
||||
{
|
||||
os_taskq_post_msg(THIS_TASK_NAME, 2, GX8002_MSG_VOICE_EVENT, msg);
|
||||
}
|
||||
|
||||
void gx8002_npu_version_check(void *priv)
|
||||
{
|
||||
if (__this->state == GX8002_STATE_WORKING) {
|
||||
__this->idle = 0;
|
||||
os_taskq_post_msg(THIS_TASK_NAME, 1, GX8002_MSG_GET_VERSION);
|
||||
} else {
|
||||
__this->idle = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void gx8002_uart_recv_task(void *param)
|
||||
{
|
||||
int msg[16];
|
||||
int res;
|
||||
|
||||
gx8002_info("gx8002 task init");
|
||||
#if 1
|
||||
//串口初始化
|
||||
gx8002_uart_porting_config(115200);
|
||||
|
||||
gx8002_first_power_on();
|
||||
|
||||
// 设置回调
|
||||
nc_message_init(gx8002_uart_stream_read, gx8002_uart_stream_write, gx8002_uart_stream_is_empty);
|
||||
#endif
|
||||
|
||||
os_sem_create(&(__this->rx_sem), 0);
|
||||
|
||||
__this->state = GX8002_STATE_WORKING;
|
||||
__this->idle = 1;
|
||||
#if GX8002_UPGRADE_SPP_TOGGLE
|
||||
register_sys_event_handler(SYS_BT_EVENT, 0, 0, gx8002_app_event_handler);
|
||||
#endif /* #if GX8002_UPGRADE_SPP_TOGGLE */
|
||||
|
||||
/* if (GX8002_UPGRADE_SDFILE_TOGGLE) { */
|
||||
/* sys_timeout_add(NULL, gx8002_sdfile_update_timer, 10000); */
|
||||
/* } */
|
||||
|
||||
#if GX8002_UPGRADE_APP_TOGGLE
|
||||
gx8002_uart_app_ota_update_register_handle();
|
||||
#endif /* #if GX8002_UPGRADE_APP_TOGGLE */
|
||||
|
||||
//gx版本查询
|
||||
sys_timeout_add(NULL, gx8002_npu_version_check, 1000);
|
||||
|
||||
while (1) {
|
||||
res = os_taskq_pend(NULL, msg, ARRAY_SIZE(msg));
|
||||
if (res == OS_TASKQ) {
|
||||
switch (msg[1]) {
|
||||
case GX8002_MSG_WAKEUP:
|
||||
gx8002_wakeup_handle(MSG_REQ_VOICE_EVENT);
|
||||
break;
|
||||
case GX8002_MSG_VOICE_EVENT:
|
||||
gx8002_voice_event_handle(msg[2]);
|
||||
break;
|
||||
case GX8002_MSG_UPDATE:
|
||||
gx8002_upgrade_start(msg[2]);
|
||||
break;
|
||||
case GX8002_MSG_UPDATE_END:
|
||||
gx8002_upgrade_end(msg[2]);
|
||||
break;
|
||||
case GX8002_MSG_SUSPEND:
|
||||
__gx8002_module_suspend(msg[2]);
|
||||
break;
|
||||
case GX8002_MSG_RESUMED:
|
||||
__gx8002_module_resumed();
|
||||
break;
|
||||
case GX8002_MSG_SELF_TEST:
|
||||
gx8002_self_test_handle();
|
||||
break;
|
||||
case GX8002_MSG_GET_VERSION:
|
||||
gx8002_wakeup_handle(MSG_REQ_VERSION_EVENT);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int gx8002_npu_init(void)
|
||||
{
|
||||
#if 0 //升级GX8002固件
|
||||
gpio_set_pull_down(TCFG_GX8002_NPU_UART_TX_PORT, 0);
|
||||
gpio_set_pull_up(TCFG_GX8002_NPU_UART_TX_PORT, 0);
|
||||
gpio_set_die(TCFG_GX8002_NPU_UART_TX_PORT, 0);
|
||||
gpio_set_dieh(TCFG_GX8002_NPU_UART_TX_PORT, 0);
|
||||
gpio_set_direction(TCFG_GX8002_NPU_UART_TX_PORT, 1);
|
||||
|
||||
gpio_set_pull_down(TCFG_GX8002_NPU_UART_RX_PORT, 0);
|
||||
gpio_set_pull_up(TCFG_GX8002_NPU_UART_RX_PORT, 0);
|
||||
gpio_set_die(TCFG_GX8002_NPU_UART_RX_PORT, 0);
|
||||
gpio_set_dieh(TCFG_GX8002_NPU_UART_RX_PORT, 0);
|
||||
gpio_set_direction(TCFG_GX8002_NPU_UART_RX_PORT, 1);
|
||||
return 0;
|
||||
#endif
|
||||
//创建recv任务
|
||||
task_create(gx8002_uart_recv_task, 0, THIS_TASK_NAME);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void gx8002_npu_int_edge_wakeup_handle(u8 index, u8 gpio)
|
||||
{
|
||||
gx8002_info("gx8002 wakeup, cut_state: %d", __this->state);
|
||||
if (__this->state == GX8002_STATE_WORKING) {
|
||||
__this->idle = 0;
|
||||
os_taskq_post_msg(THIS_TASK_NAME, 1, GX8002_MSG_WAKEUP);
|
||||
} else {
|
||||
__this->idle = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void gx8002_npu_mic_gsensor_self_test(void)
|
||||
{
|
||||
gx8002_info("gx8002 self test %d", __this->state);
|
||||
if (__this->state == GX8002_STATE_WORKING) {
|
||||
__this->idle = 0;
|
||||
os_taskq_post_msg(THIS_TASK_NAME, 1, GX8002_MSG_SELF_TEST);
|
||||
} else {
|
||||
__this->idle = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static u8 gx8002_npu_idle_query(void)
|
||||
{
|
||||
//gx8002_debug("__this->idle = %d", __this->idle);
|
||||
//return 1;
|
||||
if (__this->state == GX8002_STATE_UPGRADING) {
|
||||
return 0;
|
||||
}
|
||||
return __this->idle;
|
||||
}
|
||||
|
||||
static enum LOW_POWER_LEVEL gx8002_npu_level_query(void)
|
||||
{
|
||||
if (__this->state != GX8002_STATE_SUSPEND) {
|
||||
return LOW_POWER_MODE_LIGHT_SLEEP;
|
||||
} else {
|
||||
return LOW_POWER_MODE_DEEP_SLEEP;
|
||||
}
|
||||
}
|
||||
|
||||
REGISTER_LP_TARGET(gx8002_lp_target) = {
|
||||
.name = "gx8002",
|
||||
.level = gx8002_npu_level_query,
|
||||
.is_idle = gx8002_npu_idle_query,
|
||||
};
|
||||
|
||||
#endif /* #if TCFG_GX8002_NPU_ENABLE */
|
||||
95
apps/common/device/gx8002_npu/gx8002_npu.h
Normal file
95
apps/common/device/gx8002_npu/gx8002_npu.h
Normal file
@ -0,0 +1,95 @@
|
||||
#ifndef __GX8002_NPU_H__
|
||||
#define __GX8002_NPU_H__
|
||||
|
||||
/*
|
||||
* Message command
|
||||
*/
|
||||
#define MSG_TYPEBITS 8
|
||||
#define MSG_NRBITS 8
|
||||
|
||||
#define MSG_NRMASK ((1 << MSG_NRBITS) - 1)
|
||||
#define MSG_TYPEMASK ((1 << MSG_TYPEBITS) - 1)
|
||||
|
||||
#define MSG_NRSHIFT 0
|
||||
#define MSG_TYPESHIFT (MSG_NRSHIFT + MSG_NRBITS)
|
||||
|
||||
/* Create new message */
|
||||
#define NEW_MSG(type, nr) \
|
||||
(((type) << MSG_TYPESHIFT) | \
|
||||
((nr) << MSG_NRSHIFT))
|
||||
|
||||
/* Get message type */
|
||||
#define MSG_TYPE(cmd) (((cmd) >> MSG_TYPESHIFT) & MSG_TYPEMASK)
|
||||
|
||||
/* Get message nr */
|
||||
#define MSG_NR(cmd) (((cmd) >> MSG_NRSHIFT) & MSG_NRMASK)
|
||||
|
||||
/*
|
||||
* Message flags
|
||||
*/
|
||||
#define MSG_FLAG_BCHECK (1 << 0)
|
||||
#define MSG_FLAG_BCHECK_BITS 1
|
||||
#define MSG_FLAG_BCHECK_MASK ((1 << MSG_FLAG_BCHECK_BITS) - 1)
|
||||
#define MSG_FLAG_BCHECK_SHIFT 0
|
||||
|
||||
/* Check if need message body crc32 */
|
||||
#define MSG_NEED_BCHECK(flags) (((flags) >> MSG_FLAG_BCHECK_SHIFT) & MSG_FLAG_BCHECK_MASK)
|
||||
|
||||
|
||||
#define MSG_HEAD_LEN 14 /* Message header length */
|
||||
#define MSG_HEAD_CHECK_LEN 4 /* Message header crc32 length */
|
||||
#define MSG_MAGIC_LEN 4 /* Message magic length */
|
||||
#define MSG_BODY_LEN_MAX 3072 /* Message body maximun length */
|
||||
#define MSG_BODY_CHECK_LEN 4 /* Message body crc32 length */
|
||||
|
||||
#define MSG_SEQ_MAX 255 /* Message sequence maximum count */
|
||||
#define MSG_LEN_MAX (MSG_HEAD_LEN + MSG_BODY_LEN_MAX) /* Message maximun length */
|
||||
|
||||
#define MSG_MAGIC 0x58585542
|
||||
|
||||
#define MSG_RCV_MAGIC0 (((MSG_MAGIC) & 0x000000FF) >> 0 )
|
||||
#define MSG_RCV_MAGIC1 (((MSG_MAGIC) & 0x0000FF00) >> 8 )
|
||||
#define MSG_RCV_MAGIC2 (((MSG_MAGIC) & 0x00FF0000) >> 16)
|
||||
#define MSG_RCV_MAGIC3 (((MSG_MAGIC) & 0xFF000000) >> 24)
|
||||
|
||||
typedef enum {
|
||||
MSG_TYPE_REQ = 0x1,
|
||||
MSG_TYPE_RSP = 0x2,
|
||||
MSG_TYPE_NTF = 0x3,
|
||||
} MSG_TYPE;
|
||||
|
||||
struct message {
|
||||
unsigned short cmd;
|
||||
unsigned char seq;
|
||||
unsigned char flags;
|
||||
unsigned char *body;
|
||||
unsigned short bodylen;
|
||||
} __attribute__((packed));
|
||||
|
||||
typedef enum {
|
||||
MSG_REQ_VOICE_EVENT = NEW_MSG(MSG_TYPE_REQ, 0x0C),
|
||||
MSG_RSP_VOICE_EVENT = NEW_MSG(MSG_TYPE_RSP, 0x0C),
|
||||
|
||||
//查询gx固件版本
|
||||
MSG_REQ_VERSION_EVENT = NEW_MSG(MSG_TYPE_REQ, 0x02),
|
||||
MSG_RSP_VERSION_EVENT = NEW_MSG(MSG_TYPE_RSP, 0x02),
|
||||
|
||||
//查询MIC状态
|
||||
MSG_REQ_MIC_EVENT = NEW_MSG(MSG_TYPE_REQ, 0x70),
|
||||
MSG_RSP_MIC_EVENT = NEW_MSG(MSG_TYPE_RSP, 0x70),
|
||||
|
||||
//查询Gsensor状态
|
||||
MSG_REQ_GSENSOR_EVENT = NEW_MSG(MSG_TYPE_REQ, 0x71),
|
||||
MSG_RSP_GSENSOR_EVENT = NEW_MSG(MSG_TYPE_RSP, 0x71),
|
||||
} UART_MSG_ID;
|
||||
/* Stream read callback */
|
||||
typedef int (*STREAM_READ)(unsigned char *buf, int len);
|
||||
|
||||
/* Stream write callback */
|
||||
typedef int (*STREAM_WRITE)(const unsigned char *buf, int len);
|
||||
|
||||
/* Stream is empty callback */
|
||||
typedef int (*STREAM_EMPTY)(void);
|
||||
|
||||
|
||||
#endif /* #ifndef __GX8002_NPU_H__ */
|
||||
71
apps/common/device/gx8002_npu/gx8002_npu_api.h
Normal file
71
apps/common/device/gx8002_npu/gx8002_npu_api.h
Normal file
@ -0,0 +1,71 @@
|
||||
#ifndef __GX8002_NPU_API_H__
|
||||
#define __GX8002_NPU_API_H__
|
||||
|
||||
#include "app_config.h"
|
||||
#include "update_loader_download.h"
|
||||
|
||||
#if TCFG_GX8002_NPU_ENABLE
|
||||
|
||||
#define GX8002_UPGRADE_TOGGLE 1
|
||||
|
||||
#if GX8002_UPGRADE_TOGGLE
|
||||
#define GX8002_UPGRADE_SDFILE_TOGGLE 0 //for test, 升级文件存内置flash升级gx8002
|
||||
#define GX8002_UPGRADE_SPP_TOGGLE 0 //使用spp协议升级gx8002
|
||||
|
||||
#define GX8002_UPGRADE_APP_TOGGLE 1 //使用测试盒/手机APP传输数据, 通过ota流程升级gx8002
|
||||
#if CONFIG_DOUBLE_BANK_ENABLE
|
||||
#define GX8002_UPGRADE_APP_TWS_TOGGLE 1 //TWS同步升级使能
|
||||
#endif /* #if CONFIG_DOUBLE_BANK_ENABLE */
|
||||
#endif
|
||||
|
||||
#endif /* #if TCFG_GX8002_NPU_ENABLE */
|
||||
|
||||
//语音事件列表
|
||||
enum gx8002_voice_event {
|
||||
MAIN_WAKEUP_VOICE_EVENT = 100, //"小度小度", "天猫精灵", "小爱同学"
|
||||
MUSIC_PAUSE_VOICE_EVENT = 102, //"暂停播放"
|
||||
MUSIC_STOP_VOICE_EVENT = 103, //"停止播放"
|
||||
MUSIC_PLAY_VOICE_EVENT = 104, //"播放音乐"
|
||||
VOLUME_UP_VOICE_EVENT = 105, //"增大音量"
|
||||
VOLUME_DOWN_VOICE_EVENT = 106, //"减小音量"
|
||||
MUSIC_PREV_VOICE_EVENT = 112, //"播放上一首"
|
||||
MUSIC_NEXT_VOICE_EVENT = 113, //"播放下一首"
|
||||
CALL_ANSWER_VOICE_EVENT = 114, //"接听电话"
|
||||
CALL_HANG_UP_VOICE_EVENT = 115, //"挂掉电话"
|
||||
};
|
||||
|
||||
enum GX8002_MSG {
|
||||
GX8002_MSG_BEGIN = ('8' << 24) | ('0' << 16) | ('0' << 8) | ('2' << 0),
|
||||
GX8002_MSG_WAKEUP,
|
||||
GX8002_MSG_VOICE_EVENT,
|
||||
GX8002_MSG_UPDATE,
|
||||
GX8002_MSG_UPDATE_END,
|
||||
GX8002_MSG_SUSPEND,
|
||||
GX8002_MSG_RESUMED,
|
||||
GX8002_MSG_SELF_TEST,
|
||||
GX8002_MSG_GET_VERSION,
|
||||
};
|
||||
|
||||
enum GX8002_UPDATE_TYPE {
|
||||
GX8002_UPDATE_TYPE_SDFILE = 0x5A,
|
||||
GX8002_UPDATE_TYPE_SPP,
|
||||
GX8002_UPDATE_TYPE_APP,
|
||||
};
|
||||
|
||||
void gx8002_npu_int_edge_wakeup_handle(u8 index, u8 gpio);
|
||||
int gx8002_npu_init(void);
|
||||
void gx8002_event_state_update(u8 voice_event);
|
||||
//int gx8002_uart_ota_init(void);
|
||||
int gx8002_uart_sdfile_ota_init(void);
|
||||
int gx8002_uart_spp_ota_init(void);
|
||||
int gx8002_uart_app_ota_init(void);
|
||||
void gx8002_voice_event_handle(u8 voice_event);
|
||||
void gx8002_uart_app_ota_update_register_handle(void);
|
||||
|
||||
void gx8002_cold_reset(void);
|
||||
void gx8002_normal_cold_reset(void);
|
||||
void gx8002_upgrade_cold_reset(void);
|
||||
void gx8002_update_end_post_msg(u8 flag);
|
||||
void gx8002_voice_event_post_msg(u8 msg);
|
||||
|
||||
#endif /* #ifndef __GX8002_NPU_API_H__ */
|
||||
193
apps/common/device/gx8002_npu/gx8002_npu_event_deal.c
Normal file
193
apps/common/device/gx8002_npu/gx8002_npu_event_deal.c
Normal file
@ -0,0 +1,193 @@
|
||||
#include "includes.h"
|
||||
#include "app_config.h"
|
||||
#include "gx8002_npu.h"
|
||||
#include "gx8002_npu_api.h"
|
||||
#include "btstack/avctp_user.h"
|
||||
#include "tone_player.h"
|
||||
|
||||
#if TCFG_USER_TWS_ENABLE
|
||||
#include "bt_tws.h"
|
||||
#endif /* #if TCFG_USER_TWS_ENABLE */
|
||||
|
||||
#if TCFG_GX8002_NPU_ENABLE
|
||||
|
||||
#define gx8002_event_info printf
|
||||
|
||||
bool get_tws_sibling_connect_state(void);
|
||||
|
||||
#define TWS_FUNC_ID_VOICE_EVENT_SYNC TWS_FUNC_ID('V', 'O', 'I', 'C')
|
||||
|
||||
struct gx8002_event_hdl {
|
||||
u8 last_event;
|
||||
u32 last_event_jiffies;
|
||||
};
|
||||
|
||||
static struct gx8002_event_hdl hdl = {0};
|
||||
|
||||
#define __this (&hdl)
|
||||
|
||||
__attribute__((weak))
|
||||
void volume_down(u8 dec)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
__attribute__((weak))
|
||||
void volume_up(u8 inc)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
__attribute__((weak))
|
||||
int app_case_voice_event_handle(u8 voice_event)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gx8002_recognize_tone_play(void)
|
||||
{
|
||||
if (get_tws_sibling_connect_state() == TRUE) {
|
||||
if (tws_api_get_role() == TWS_ROLE_MASTER) {
|
||||
bt_tws_play_tone_at_same_time(SYNC_TONE_VOICE_RECOGNIZE, 200);
|
||||
}
|
||||
} else {
|
||||
tone_play(TONE_NORMAL, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void gx8002_event_handle(u8 voice_event)
|
||||
{
|
||||
u32 cur_jiffies = jiffies;
|
||||
u8 a2dp_state;
|
||||
u8 call_state;
|
||||
|
||||
if (voice_event == __this->last_event) {
|
||||
if (jiffies_to_msecs(cur_jiffies - __this->last_event_jiffies) < 1000) {
|
||||
gx8002_event_info("voice event %d same, ignore", voice_event);
|
||||
__this->last_event_jiffies = cur_jiffies;
|
||||
return;
|
||||
}
|
||||
}
|
||||
__this->last_event_jiffies = cur_jiffies;
|
||||
__this->last_event = voice_event;
|
||||
|
||||
gx8002_event_info("%s: %d", __func__, voice_event);
|
||||
|
||||
if (app_case_voice_event_handle(voice_event)) {
|
||||
return;
|
||||
}
|
||||
|
||||
//播放提示音
|
||||
if ((voice_event != VOLUME_UP_VOICE_EVENT) && (voice_event != VOLUME_DOWN_VOICE_EVENT)) {
|
||||
//gx8002_recognize_tone_play();
|
||||
}
|
||||
|
||||
switch (voice_event) {
|
||||
case MAIN_WAKEUP_VOICE_EVENT:
|
||||
gx8002_event_info("send SIRI cmd");
|
||||
user_send_cmd_prepare(USER_CTRL_HFP_GET_SIRI_OPEN, 0, NULL);
|
||||
break;
|
||||
case MUSIC_PAUSE_VOICE_EVENT:
|
||||
case MUSIC_STOP_VOICE_EVENT:
|
||||
case MUSIC_PLAY_VOICE_EVENT:
|
||||
call_state = get_call_status();
|
||||
if ((call_state == BT_CALL_OUTGOING) ||
|
||||
(call_state == BT_CALL_ALERT)) {
|
||||
//user_send_cmd_prepare(USER_CTRL_HFP_CALL_HANGUP, 0, NULL);
|
||||
} else if (call_state == BT_CALL_INCOMING) {
|
||||
//user_send_cmd_prepare(USER_CTRL_HFP_CALL_ANSWER, 0, NULL);
|
||||
} else if (call_state == BT_CALL_ACTIVE) {
|
||||
//user_send_cmd_prepare(USER_CTRL_HFP_CALL_HANGUP, 0, NULL);
|
||||
} else {
|
||||
a2dp_state = a2dp_get_status();
|
||||
if (a2dp_state == BT_MUSIC_STATUS_STARTING) {
|
||||
if (voice_event == MUSIC_PAUSE_VOICE_EVENT) {
|
||||
gx8002_event_info("send PAUSE cmd");
|
||||
user_send_cmd_prepare(USER_CTRL_AVCTP_OPID_PAUSE, 0, NULL);
|
||||
} else if (voice_event == MUSIC_STOP_VOICE_EVENT) {
|
||||
gx8002_event_info("send STOP cmd");
|
||||
user_send_cmd_prepare(USER_CTRL_AVCTP_OPID_STOP, 0, NULL);
|
||||
}
|
||||
} else {
|
||||
if (voice_event == MUSIC_PLAY_VOICE_EVENT) {
|
||||
gx8002_event_info("send PLAY cmd");
|
||||
user_send_cmd_prepare(USER_CTRL_AVCTP_OPID_PLAY, 0, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case VOLUME_UP_VOICE_EVENT:
|
||||
gx8002_event_info("volume up");
|
||||
volume_up(4); //music: 0 ~ 16, call: 0 ~ 15, step: 25%
|
||||
//gx8002_recognize_tone_play();
|
||||
break;
|
||||
case VOLUME_DOWN_VOICE_EVENT:
|
||||
gx8002_event_info("volume down");
|
||||
volume_down(4); //music: 0 ~ 16, call: 0 ~ 15, step: 25%
|
||||
//gx8002_recognize_tone_play();
|
||||
break;
|
||||
case MUSIC_PREV_VOICE_EVENT:
|
||||
gx8002_event_info("volume PREV cmd");
|
||||
user_send_cmd_prepare(USER_CTRL_AVCTP_OPID_PREV, 0, NULL);
|
||||
break;
|
||||
case MUSIC_NEXT_VOICE_EVENT:
|
||||
gx8002_event_info("volume NEXT cmd");
|
||||
user_send_cmd_prepare(USER_CTRL_AVCTP_OPID_NEXT, 0, NULL);
|
||||
break;
|
||||
case CALL_ANSWER_VOICE_EVENT:
|
||||
if (get_call_status() == BT_CALL_INCOMING) {
|
||||
gx8002_event_info("volume ANSWER cmd");
|
||||
user_send_cmd_prepare(USER_CTRL_HFP_CALL_ANSWER, 0, NULL);
|
||||
}
|
||||
break;
|
||||
case CALL_HANG_UP_VOICE_EVENT:
|
||||
gx8002_event_info("volume HANG UP cmd");
|
||||
if ((get_call_status() >= BT_CALL_INCOMING) && (get_call_status() <= BT_CALL_ALERT)) {
|
||||
user_send_cmd_prepare(USER_CTRL_HFP_CALL_HANGUP, 0, NULL);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void gx8002_event_sync_tws_state_deal(void *_data, u16 len, bool rx)
|
||||
{
|
||||
u8 *data = (u8 *)_data;
|
||||
u8 voice_event = data[0];
|
||||
//if (rx) {
|
||||
gx8002_event_info("tws event rx sync: %d", voice_event);
|
||||
//gx8002_event_handle(voice_event);
|
||||
gx8002_voice_event_post_msg(voice_event);
|
||||
//}
|
||||
}
|
||||
|
||||
static void gx8002_sync_tws_event(u8 voice_event)
|
||||
{
|
||||
if (get_tws_sibling_connect_state() == TRUE) {
|
||||
tws_api_send_data_to_sibling(&voice_event, 1, TWS_FUNC_ID_VOICE_EVENT_SYNC);
|
||||
}
|
||||
}
|
||||
|
||||
void gx8002_event_state_update(u8 voice_event)
|
||||
{
|
||||
//tone_play(TONE_NORMAL, 1);
|
||||
if (get_tws_sibling_connect_state() == TRUE) {
|
||||
gx8002_sync_tws_event(voice_event);
|
||||
} else {
|
||||
gx8002_event_handle(voice_event);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void gx8002_voice_event_handle(u8 voice_event)
|
||||
{
|
||||
gx8002_event_handle(voice_event);
|
||||
}
|
||||
|
||||
REGISTER_TWS_FUNC_STUB(gx8002_voice_event_sync) = {
|
||||
.func_id = TWS_FUNC_ID_VOICE_EVENT_SYNC,
|
||||
.func = gx8002_event_sync_tws_state_deal,
|
||||
};
|
||||
|
||||
#endif /* #if TCFG_GX8002_NPU_ENABLE */
|
||||
@ -0,0 +1,736 @@
|
||||
#include "includes.h"
|
||||
#include "../gx_uart_upgrade.h"
|
||||
#include "../../gx8002_npu_api.h"
|
||||
#include "../gx_uart_upgrade_porting.h"
|
||||
//#include "../utils/gx_fifo.h"
|
||||
|
||||
#if GX8002_UPGRADE_APP_TOGGLE
|
||||
|
||||
typedef struct _gx8002_file_head_t {
|
||||
u16 head_crc;
|
||||
u16 data_crc;
|
||||
u32 addr;
|
||||
u32 len;
|
||||
u8 attr;
|
||||
u8 res;
|
||||
u16 index;
|
||||
char name[16];
|
||||
} gx8002_file_head_t;
|
||||
|
||||
struct app_ota_info {
|
||||
int update_result;
|
||||
u32 ufw_addr;
|
||||
u8 cur_seek_file;
|
||||
u8 update_role;
|
||||
OS_SEM ota_sem;
|
||||
OS_SEM rx_sem;
|
||||
cbuffer_t *cbuf_handle;
|
||||
update_op_api_t *file_ops;
|
||||
gx8002_file_head_t file_boot_head;
|
||||
gx8002_file_head_t file_bin_head;
|
||||
int packet_buf[UPGRADE_PACKET_SIZE / sizeof(int)];
|
||||
};
|
||||
|
||||
|
||||
enum GX_APP_UPDATE_ERR {
|
||||
GX_APP_UPDATE_ERR_NONE = 0,
|
||||
GX_APP_UPDATE_ERR_NOMEM = -100,
|
||||
GX_APP_UPDATE_ERR_FILE_READ,
|
||||
GX_APP_UPDATE_ERR_FILE_DIR_VERIFY,
|
||||
GX_APP_UPDATE_ERR_FILE_HEAD_VERIFY,
|
||||
GX_APP_UPDATE_ERR_FILE_DATA_VERIFY,
|
||||
|
||||
GX_APP_UPDATE_ERR_UPDATE_LOOP,
|
||||
GX_APP_UPDATE_ERR_UPDATE_STATE,
|
||||
};
|
||||
|
||||
enum GX8002_UPDATE_ROLE {
|
||||
GX8002_UPDATE_ROLE_NORMAL = 0,
|
||||
GX8002_UPDATE_ROLE_TWS_MASTER,
|
||||
GX8002_UPDATE_ROLE_TWS_SLAVE,
|
||||
};
|
||||
|
||||
static struct app_ota_info *ota_upgrade = NULL;
|
||||
#define __this ota_upgrade
|
||||
|
||||
#define GX8002_UFW_VERIFY_BUF_LEN 512
|
||||
#define GX8002_UFW_FILE_DATA_VERIFY_ENABLE 0
|
||||
|
||||
#define GX8002_OTA_UPGRADE_DEBUG_ENABLE 1
|
||||
|
||||
#define ota_upgrade_info printf
|
||||
|
||||
#if GX8002_OTA_UPGRADE_DEBUG_ENABLE
|
||||
#define ota_upgrade_debug printf
|
||||
#define ota_upgrade_put_buf put_buf
|
||||
#else
|
||||
#define ota_upgrade_debug(...)
|
||||
#define ota_upgrade_put_buf(...)
|
||||
#endif /* #if GX8002_DEBUG_ENABLE */
|
||||
|
||||
//=================================================================//
|
||||
// tws同步升级接口 //
|
||||
//=================================================================//
|
||||
extern void gx8002_uart_app_ota_tws_update_register_handle(void);
|
||||
extern int gx8002_uart_app_ota_tws_update_init(void *priv);
|
||||
extern int gx8002_uart_app_ota_tws_update_sync_start(u8 *buf, u16 len);
|
||||
extern int gx8002_uart_app_ota_tws_update_sync_pend(void);
|
||||
extern int gx8002_uart_app_ota_tws_update_sync_post(void);
|
||||
extern int gx8002_uart_app_ota_tws_update_sync_data(u8 *buf, u16 len);
|
||||
extern int gx8002_uart_app_ota_tws_update_sync_respond(void);
|
||||
extern int gx8002_uart_app_ota_tws_update_close(void);
|
||||
extern int gx8002_uart_app_ota_tws_update_sync_result(int result);
|
||||
extern int gx8002_uart_app_ota_tws_update_sync_result_get(void);
|
||||
|
||||
//=================================================================//
|
||||
// 使用fifo作数据缓存 //
|
||||
//=================================================================//
|
||||
////////////// FW Stream Porting //////////////////
|
||||
static u32 fw_stream_get_file_addr(u32 addr)
|
||||
{
|
||||
return __this->ufw_addr + addr;
|
||||
}
|
||||
|
||||
#define STREAM_FIFO_BLOCK_TOTAL 16
|
||||
#define STREAM_FIFO_TIMEOUT_MS (5000)
|
||||
|
||||
static int fw_stream_open(FW_IMAGE_TYPE img_type)
|
||||
{
|
||||
if (__this->cbuf_handle == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fw_stream_close(FW_IMAGE_TYPE img_type)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
//gx8002线程同步数据
|
||||
static int fw_stream_read(FW_IMAGE_TYPE img_type, unsigned char *buf, unsigned int len)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
static u32 read_cnt = 0;
|
||||
|
||||
if (__this->cbuf_handle) {
|
||||
if (cbuf_get_data_len(__this->cbuf_handle) < len) {
|
||||
os_sem_set(&(__this->rx_sem), 0);
|
||||
os_sem_pend(&(__this->rx_sem), msecs_to_jiffies(STREAM_FIFO_TIMEOUT_MS));
|
||||
}
|
||||
ret = cbuf_read(__this->cbuf_handle, buf, len);
|
||||
if (ret < len) {
|
||||
ota_upgrade_info("read errm ret = 0x%x, len = 0x%x", ret, len);
|
||||
return -1;
|
||||
}
|
||||
if (__this->update_role == GX8002_UPDATE_ROLE_TWS_MASTER) {
|
||||
//TODO: tws sync data
|
||||
gx8002_uart_app_ota_tws_update_sync_data(buf, (u16)len);
|
||||
if (gx8002_uart_app_ota_tws_update_sync_pend()) {
|
||||
ota_upgrade_info("read timeout");
|
||||
ret = -1;
|
||||
}
|
||||
} else if (__this->update_role == GX8002_UPDATE_ROLE_TWS_SLAVE) {
|
||||
//TODO: tws respond
|
||||
gx8002_uart_app_ota_tws_update_sync_respond();
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fw_stream_get_flash_img_info(flash_img_info_t *info)
|
||||
{
|
||||
if (info == NULL) {
|
||||
return -1;
|
||||
}
|
||||
info->img_size = __this->file_bin_head.len;
|
||||
|
||||
ota_upgrade_debug("%s, img_size = 0x%x", __func__, info->img_size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gx8002_ota_data_receive(u8 *data, u32 size)
|
||||
{
|
||||
gx8002_file_head_t *file_receive_table[] = {
|
||||
&(__this->file_boot_head),
|
||||
&(__this->file_bin_head)
|
||||
};
|
||||
|
||||
u32 file_addr = 0;
|
||||
u32 remain_len = 0;
|
||||
u32 rlen = 0;
|
||||
u16 ret = 0;
|
||||
|
||||
for (u32 i = 0; i < ARRAY_SIZE(file_receive_table); i++) {
|
||||
file_addr = fw_stream_get_file_addr((file_receive_table[i])->addr);
|
||||
__this->file_ops->f_seek(NULL, SEEK_SET, file_addr);
|
||||
remain_len = (file_receive_table[i])->len;
|
||||
ota_upgrade_debug("receive %s data, len = 0x%x", (file_receive_table[i])->name, remain_len);
|
||||
while (remain_len) {
|
||||
if (__this->update_result != GX_APP_UPDATE_ERR_NONE) {
|
||||
return __this->update_result;
|
||||
}
|
||||
rlen = (remain_len > size) ? size : remain_len;
|
||||
ret = __this->file_ops->f_read(NULL, data, rlen);
|
||||
|
||||
if ((u16) - 1 == ret) {
|
||||
ota_upgrade_debug("f_read %s err", (file_receive_table[i])->name);
|
||||
return GX_APP_UPDATE_ERR_FILE_READ;
|
||||
}
|
||||
//TODO: TWS send data sync
|
||||
while (cbuf_is_write_able(__this->cbuf_handle, rlen) < rlen) {
|
||||
/* ota_upgrade_debug("aaa"); */
|
||||
os_time_dly(2);
|
||||
/* ota_upgrade_debug("bbb"); */
|
||||
if (__this->update_result != GX_APP_UPDATE_ERR_NONE) {
|
||||
return __this->update_result;
|
||||
}
|
||||
}
|
||||
if (cbuf_write(__this->cbuf_handle, data, rlen) != rlen) {
|
||||
ota_upgrade_debug("cbuf full !!!");
|
||||
}
|
||||
os_sem_post(&(__this->rx_sem));
|
||||
|
||||
remain_len -= rlen;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int gx8002_ota_data_passive_receive(u8 *data, u32 size)
|
||||
{
|
||||
int ret = 0;
|
||||
if ((__this == NULL) || (__this->cbuf_handle == NULL)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (__this->update_role != GX8002_UPDATE_ROLE_TWS_SLAVE) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (cbuf_is_write_able(__this->cbuf_handle, size) < size) {
|
||||
ota_upgrade_info("passive receive cbuf full !!!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = cbuf_write(__this->cbuf_handle, data, size);
|
||||
os_sem_post(&(__this->rx_sem));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int __gx8002_ufw_file_data_verify(u32 file_addr, u32 file_len, u16 target_crc, u16(*func_read)(void *fp, u8 *buff, u16 len))
|
||||
{
|
||||
u8 *rbuf = malloc(GX8002_UFW_VERIFY_BUF_LEN);
|
||||
u16 crc_interval = 0;
|
||||
u16 r_len = 0;
|
||||
int ret = GX_APP_UPDATE_ERR_NONE;
|
||||
|
||||
if (rbuf == NULL) {
|
||||
return GX_APP_UPDATE_ERR_NOMEM;
|
||||
}
|
||||
|
||||
while (file_len) {
|
||||
r_len = (file_len > GX8002_UFW_VERIFY_BUF_LEN) ? GX8002_UFW_VERIFY_BUF_LEN : file_len;
|
||||
if (func_read) {
|
||||
func_read(NULL, rbuf, r_len);
|
||||
}
|
||||
|
||||
crc_interval = CRC16_with_initval(rbuf, r_len, crc_interval);
|
||||
|
||||
file_addr += r_len;
|
||||
file_len -= r_len;
|
||||
}
|
||||
|
||||
if (crc_interval != target_crc) {
|
||||
ret = GX_APP_UPDATE_ERR_FILE_DATA_VERIFY;
|
||||
}
|
||||
|
||||
_file_data_verify_end:
|
||||
if (rbuf) {
|
||||
free(rbuf);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __gx8002_ufw_file_head_verify(gx8002_file_head_t *file_head)
|
||||
{
|
||||
int ret = GX_APP_UPDATE_ERR_NONE;
|
||||
u16 calc_crc = CRC16(&(file_head->data_crc), sizeof(gx8002_file_head_t) - 2);
|
||||
|
||||
if (calc_crc != file_head->head_crc) {
|
||||
ret = GX_APP_UPDATE_ERR_FILE_DATA_VERIFY;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int gx8002_ufw_file_verify(u32 ufw_addr, update_op_api_t *file_ops)
|
||||
{
|
||||
int ret = 0;
|
||||
u16 r_len = 0;
|
||||
u8 file_cnt = 0;
|
||||
gx8002_file_head_t *file_head;
|
||||
u8 *rbuf = (u8 *)malloc(GX8002_UFW_VERIFY_BUF_LEN);
|
||||
if (rbuf == NULL) {
|
||||
ret = GX_APP_UPDATE_ERR_NOMEM;
|
||||
goto _verify_end;
|
||||
}
|
||||
|
||||
file_ops->f_seek(NULL, SEEK_SET, ufw_addr);
|
||||
r_len = file_ops->f_read(NULL, rbuf, GX8002_UFW_VERIFY_BUF_LEN);
|
||||
|
||||
if ((u16) - 1 == r_len) {
|
||||
ret = GX_APP_UPDATE_ERR_FILE_READ;
|
||||
ota_upgrade_debug("f_read err");
|
||||
goto _verify_end;
|
||||
}
|
||||
|
||||
file_head = (gx8002_file_head_t *)rbuf;
|
||||
ret = __gx8002_ufw_file_head_verify(file_head);
|
||||
if (ret != GX_APP_UPDATE_ERR_NONE) {
|
||||
ota_upgrade_debug("gx8002 ufw file head verify err");
|
||||
goto _verify_end;
|
||||
}
|
||||
|
||||
if (strcmp(file_head->name, "gx8002")) {
|
||||
ret = GX_APP_UPDATE_ERR_FILE_HEAD_VERIFY;
|
||||
ota_upgrade_debug("gx8002 ufw file head name err");
|
||||
goto _verify_end;
|
||||
}
|
||||
|
||||
ota_upgrade_info("find: %s", file_head->name);
|
||||
do {
|
||||
file_head++;
|
||||
ret = __gx8002_ufw_file_head_verify(file_head);
|
||||
if (ret != GX_APP_UPDATE_ERR_NONE) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcmp(file_head->name, "gx8002.boot") == 0) {
|
||||
ota_upgrade_info("find: %s", file_head->name);
|
||||
memcpy(&(__this->file_boot_head), file_head, sizeof(gx8002_file_head_t));
|
||||
#if GX8002_UFW_FILE_DATA_VERIFY_ENABLE
|
||||
file_ops->f_seek(NULL, SEEK_SET, __this->ufw_addr + file_head->addr);
|
||||
ret = __gx8002_ufw_file_data_verify(__this->ufw_addr + file_head->addr, file_head->len, file_head->data_crc, file_ops->f_read);
|
||||
if (ret == GX_APP_UPDATE_ERR_NONE) {
|
||||
file_cnt++;
|
||||
} else {
|
||||
ota_upgrade_debug("gx8002.boot file head verify err");
|
||||
break;
|
||||
}
|
||||
#else
|
||||
file_cnt++;
|
||||
#endif /* #if GX8002_UFW_FILE_DATA_VERIFY_ENABLE */
|
||||
}
|
||||
if (strcmp(file_head->name, "mcu_nor.bin") == 0) {
|
||||
ota_upgrade_info("find: %s", file_head->name);
|
||||
memcpy(&(__this->file_bin_head), file_head, sizeof(gx8002_file_head_t));
|
||||
#if GX8002_UFW_FILE_DATA_VERIFY_ENABLE
|
||||
file_ops->f_seek(NULL, SEEK_SET, __this->ufw_addr + file_head->addr);
|
||||
ret = __gx8002_ufw_file_data_verify(__this->ufw_addr + file_head->addr, file_head->len, file_head->data_crc, file_ops->f_read);
|
||||
if (ret == GX_APP_UPDATE_ERR_NONE) {
|
||||
file_cnt++;
|
||||
} else {
|
||||
ota_upgrade_debug("mcu_nor.bin file head verify err");
|
||||
break;
|
||||
}
|
||||
#else
|
||||
file_cnt++;
|
||||
#endif /* #if GX8002_UFW_FILE_DATA_VERIFY_ENABLE */
|
||||
}
|
||||
} while (file_head->index == 0);
|
||||
|
||||
if ((ret != GX_APP_UPDATE_ERR_NONE) && (file_cnt != 2)) {
|
||||
ret = GX_APP_UPDATE_ERR_FILE_DATA_VERIFY;
|
||||
ota_upgrade_debug("file_cnt: %d err", file_cnt);
|
||||
goto _verify_end;
|
||||
}
|
||||
|
||||
ota_upgrade_info("find file_cnt: %d, verify ok", file_cnt);
|
||||
|
||||
_verify_end:
|
||||
if (rbuf) {
|
||||
free(rbuf);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
///////// status info /////////////
|
||||
static const char *status_info_str[UPGRADE_STAGE_NONE][UPGRADE_STATUS_NONE] = {
|
||||
// UPGRADE_STAGE_HANDSHAKE
|
||||
{"handshake start\n", NULL, "handshake ok\n", "handshake err\n"},
|
||||
// UPGRADE_STAGE_BOOT_HEADER
|
||||
{"boot header start\n", NULL, "boot header ok\n", "boot header err\n"},
|
||||
// UPGRADE_STAGE_BOOT_S1
|
||||
{"boot stage1 start\n", "boot stage1 downloading\n", "boot stage1 ok\n", "boot stage1 err\n"},
|
||||
// UPGRADE_STAGE_BOOT_S2
|
||||
{"boot stage2 start\n", "boot stage2 downloading\n", "boot stage2 ok\n", "boot stage2 err\n"},
|
||||
// UPGRADE_STAGE_FLASH_IMG
|
||||
{"flash img start\n", "flash img downloading\n", "flash img ok\n", "flash img err\n"},
|
||||
};
|
||||
|
||||
static void gx8002_upgrade_status_cb(upgrade_stage_e stage, upgrade_status_e status)
|
||||
{
|
||||
const char *reply_str = status_info_str[stage][status];
|
||||
if (reply_str != NULL) {
|
||||
ota_upgrade_info("status info: %s\n", reply_str);
|
||||
}
|
||||
}
|
||||
|
||||
static int gx8002_upgrade_task(void *param)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ota_upgrade_info("---- gx8002 ota start ----");
|
||||
gx8002_upgrade_cold_reset();
|
||||
|
||||
ret = gx_uart_upgrade_proc();
|
||||
|
||||
gx8002_normal_cold_reset();
|
||||
ota_upgrade_info("---- gx8002 ota over ----");
|
||||
|
||||
if (ret < 0) {
|
||||
gx8002_update_end_post_msg(0);
|
||||
} else {
|
||||
gx8002_update_end_post_msg(1);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
//===================================================================//
|
||||
/*
|
||||
@breif: ota流程回调: 初始化函数, 公共流程
|
||||
@parma: addr: 访问外置芯片固件地址
|
||||
@parma: file_ops: 访问外置芯片固件文件操作接口
|
||||
@return: 1) GX_APP_UPDATE_ERR_NONE = 0: 初始化成功
|
||||
2) < 0: 初始化失败
|
||||
*/
|
||||
//===================================================================//
|
||||
int gx8002_app_ota_start(int (*complete_callback)(void))
|
||||
{
|
||||
int ret = GX_APP_UPDATE_ERR_NONE;
|
||||
|
||||
ota_upgrade_debug("%s", __func__);
|
||||
|
||||
if (__this->cbuf_handle == NULL) {
|
||||
__this->cbuf_handle = (cbuffer_t *)malloc(sizeof(cbuffer_t) + (UPGRADE_PACKET_SIZE * STREAM_FIFO_BLOCK_TOTAL));
|
||||
if (__this->cbuf_handle == NULL) {
|
||||
ret = GX_APP_UPDATE_ERR_NOMEM;
|
||||
return ret;
|
||||
}
|
||||
cbuf_init(__this->cbuf_handle, __this->cbuf_handle + 1, (UPGRADE_PACKET_SIZE * STREAM_FIFO_BLOCK_TOTAL));
|
||||
}
|
||||
|
||||
os_sem_create(&(__this->rx_sem), 0);
|
||||
|
||||
os_taskq_post_msg("gx8002", 2, GX8002_MSG_UPDATE, GX8002_UPDATE_TYPE_APP);
|
||||
|
||||
if (complete_callback) {
|
||||
if (complete_callback()) {
|
||||
return GX_APP_UPDATE_ERR_UPDATE_LOOP;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
//===================================================================//
|
||||
/*
|
||||
@breif: ota流程回调: 释放资源
|
||||
@parma: void
|
||||
@return: 1) GX_APP_UPDATE_ERR_NONE = 0: 初始化成功
|
||||
2) < 0: 初始化失败
|
||||
*/
|
||||
//===================================================================//
|
||||
static int gx8002_app_ota_close(void)
|
||||
{
|
||||
if (__this->update_role == GX8002_UPDATE_ROLE_TWS_SLAVE) {
|
||||
//从机出口
|
||||
gx8002_uart_app_ota_tws_update_sync_result(__this->update_result);
|
||||
|
||||
if (__this->cbuf_handle) {
|
||||
free(__this->cbuf_handle);
|
||||
__this->cbuf_handle = NULL;
|
||||
}
|
||||
|
||||
if (__this) {
|
||||
free(__this);
|
||||
__this = NULL;
|
||||
}
|
||||
gx8002_uart_app_ota_tws_update_close();
|
||||
} else {
|
||||
os_sem_post(&(__this->ota_sem));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//===================================================================//
|
||||
/*
|
||||
@breif: 从机升级开始
|
||||
@parma: void
|
||||
@return: 1) GX_APP_UPDATE_ERR_NONE = 0: 初始化成功
|
||||
2) < 0: 初始化失败
|
||||
*/
|
||||
//===================================================================//
|
||||
int gx8002_app_ota_passive_start(int (*complete_callback)(void), u8 *ota_data, u16 len)
|
||||
{
|
||||
int ret = GX_APP_UPDATE_ERR_NONE;
|
||||
|
||||
ota_upgrade_debug("%s", __func__);
|
||||
if (__this) {
|
||||
return GX_APP_UPDATE_ERR_UPDATE_STATE;
|
||||
}
|
||||
|
||||
__this = zalloc(sizeof(struct app_ota_info));
|
||||
if (__this == NULL) {
|
||||
return GX_APP_UPDATE_ERR_NOMEM;
|
||||
}
|
||||
|
||||
ASSERT(len == sizeof(gx8002_file_head_t));
|
||||
|
||||
memcpy((u8 *) & (__this->file_bin_head), ota_data, sizeof(gx8002_file_head_t));
|
||||
|
||||
__this->update_role = GX8002_UPDATE_ROLE_TWS_SLAVE;
|
||||
|
||||
ret = gx8002_app_ota_start(complete_callback);
|
||||
|
||||
if (ret) {
|
||||
gx8002_app_ota_close();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
//===================================================================//
|
||||
/*
|
||||
@breif: ota流程回调: 初始化函数, 主机流程
|
||||
@parma: priv: 访问外置芯片固件地址
|
||||
@parma: file_ops: 访问外置芯片固件文件操作接口
|
||||
@return: 1) GX_APP_UPDATE_ERR_NONE = 0: 初始化成功
|
||||
2) < 0: 初始化失败
|
||||
*/
|
||||
//===================================================================//
|
||||
static int gx8002_chip_update_init(void *priv, update_op_api_t *file_ops)
|
||||
{
|
||||
int ret = GX_APP_UPDATE_ERR_NONE;
|
||||
|
||||
if (__this) {
|
||||
return GX_APP_UPDATE_ERR_UPDATE_STATE;
|
||||
}
|
||||
|
||||
user_chip_update_info_t *update_info = (user_chip_update_info_t *)priv;
|
||||
|
||||
__this = zalloc(sizeof(struct app_ota_info));
|
||||
if (__this == NULL) {
|
||||
return GX_APP_UPDATE_ERR_NOMEM;
|
||||
}
|
||||
|
||||
__this->ufw_addr = update_info->addr;
|
||||
__this->file_ops = file_ops;
|
||||
__this->update_role = GX8002_UPDATE_ROLE_NORMAL;
|
||||
__this->update_result = GX_APP_UPDATE_ERR_NONE;
|
||||
|
||||
__this->cur_seek_file = FW_FLASH_MAX;
|
||||
|
||||
ota_upgrade_info("%s: ufw_addr = 0x%x", __func__, __this->ufw_addr);
|
||||
|
||||
ret = gx8002_ufw_file_verify(__this->ufw_addr, file_ops);
|
||||
|
||||
ota_upgrade_info("%s, ret = %d", __func__, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
//===================================================================//
|
||||
/*
|
||||
@breif: ota流程回调: 获取升级问文件长度, 用于计算升级进度, 主机调用
|
||||
@parma: void
|
||||
@return: 1) 升级长度(int)
|
||||
2) = 0: 升级状态出错
|
||||
*/
|
||||
//===================================================================//
|
||||
static int gx8002_chip_update_get_len(void)
|
||||
{
|
||||
int update_len = 0;
|
||||
|
||||
if (__this == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
update_len = __this->file_boot_head.len + __this->file_bin_head.len;
|
||||
ota_upgrade_info("%s: boot_len = 0x%x, bin_len = 0x%x, update_len = 0x%x", __func__, __this->file_boot_head.len, __this->file_bin_head.len, update_len);
|
||||
|
||||
return update_len;
|
||||
}
|
||||
|
||||
//===================================================================//
|
||||
/*
|
||||
@breif: ota流程回调: 升级主流程, 主机调用
|
||||
@parma: void *priv 用于tws同步升级接口(update_op_tws_api_t), 非tws同步升级设置未NULL即可
|
||||
@return: 1) = 0: 升级成功
|
||||
2) < 0: 升级失败
|
||||
*/
|
||||
//===================================================================//
|
||||
static int gx8002_chip_update_loop(void *priv)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (__this == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ota_upgrade_debug("%s", __func__);
|
||||
|
||||
int (*start_callback)(void) = NULL;
|
||||
|
||||
if (priv) {
|
||||
__this->update_role = GX8002_UPDATE_ROLE_TWS_MASTER;
|
||||
|
||||
ret = gx8002_uart_app_ota_tws_update_init(priv);
|
||||
if (ret) {
|
||||
goto __update_end;
|
||||
}
|
||||
gx8002_uart_app_ota_tws_update_sync_start((u8 *) & (__this->file_bin_head), sizeof(gx8002_file_head_t));
|
||||
|
||||
start_callback = gx8002_uart_app_ota_tws_update_sync_pend;
|
||||
}
|
||||
|
||||
os_sem_create(&(__this->ota_sem), 0);
|
||||
|
||||
ret = gx8002_app_ota_start(start_callback);
|
||||
if (ret != GX_APP_UPDATE_ERR_NONE) {
|
||||
goto __update_end;
|
||||
}
|
||||
|
||||
//update 线程接收数据
|
||||
ret = gx8002_ota_data_receive((u8 *)(__this->packet_buf), sizeof(__this->packet_buf));
|
||||
if (ret != GX_APP_UPDATE_ERR_NONE) {
|
||||
goto __update_end;
|
||||
}
|
||||
|
||||
//等待升级完成
|
||||
os_sem_pend(&(__this->ota_sem), 0);
|
||||
|
||||
if (__this->update_result != GX_APP_UPDATE_ERR_NONE) {
|
||||
ota_upgrade_info("gx8002 update failed.");
|
||||
} else {
|
||||
ota_upgrade_info("gx8002 update succ.");
|
||||
}
|
||||
|
||||
ret = __this->update_result;
|
||||
|
||||
__update_end:
|
||||
if (priv) {
|
||||
ret |= gx8002_uart_app_ota_tws_update_sync_result_get();
|
||||
gx8002_uart_app_ota_tws_update_close();
|
||||
}
|
||||
if (__this->cbuf_handle) {
|
||||
free(__this->cbuf_handle);
|
||||
__this->cbuf_handle = NULL;
|
||||
}
|
||||
if (__this) {
|
||||
free(__this);
|
||||
__this = NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
//===================================================================//
|
||||
/*
|
||||
@breif: 需要升级流程提供注册接口
|
||||
@parma: user_chip_update_file_name: 外置芯片升级文件名, 包含在update.ufw文件中
|
||||
@parma: user_update_handle: 当update.ufw存在升级文件时回调该函数升级外置芯片固件
|
||||
@parma: addr: 外置芯片固件在update.ufw升级文件中地址
|
||||
@parma: file_ops: 访问外置芯片固件文件操作接口
|
||||
*/
|
||||
//===================================================================//
|
||||
static const user_chip_update_t gx8002_user_chip_update_instance = {
|
||||
.file_name = "gx8002.bin",
|
||||
.update_init = gx8002_chip_update_init,
|
||||
.update_get_len = gx8002_chip_update_get_len,
|
||||
.update_loop = gx8002_chip_update_loop,
|
||||
};
|
||||
|
||||
//===================================================================//
|
||||
/*
|
||||
@breif: 注册ota流程回调, 提供给gx8002线程调用
|
||||
@parma: void
|
||||
@return: void
|
||||
*/
|
||||
//===================================================================//
|
||||
void gx8002_uart_app_ota_update_register_handle(void)
|
||||
{
|
||||
register_user_chip_update_handle(&gx8002_user_chip_update_instance);
|
||||
|
||||
#if GX8002_UPGRADE_APP_TWS_TOGGLE
|
||||
gx8002_uart_app_ota_tws_update_register_handle();
|
||||
#endif /* #if GX8002_UPGRADE_APP_TWS_TOGGLE */
|
||||
}
|
||||
|
||||
//===================================================================//
|
||||
/*
|
||||
@breif: 外置芯片启动升级流程, 提供给gx8002线程调用
|
||||
@parma: void
|
||||
@return: 1) 0: 升级成功
|
||||
2) -1: 升级失败
|
||||
*/
|
||||
//===================================================================//
|
||||
int gx8002_uart_app_ota_init(void)
|
||||
{
|
||||
int ret = 0;
|
||||
upgrade_uart_t uart_ops;
|
||||
|
||||
ota_upgrade_info("gx8002_uart_app_ota start >>>>");
|
||||
|
||||
uart_ops.open = gx_upgrade_uart_porting_open;
|
||||
uart_ops.close = gx_upgrade_uart_porting_close;
|
||||
uart_ops.send = gx_upgrade_uart_porting_write;
|
||||
uart_ops.wait_reply = gx_uart_upgrade_porting_wait_reply;
|
||||
|
||||
fw_stream_t fw_stream_ops;
|
||||
fw_stream_ops.open = fw_stream_open;
|
||||
fw_stream_ops.close = fw_stream_close;
|
||||
fw_stream_ops.read = fw_stream_read;
|
||||
fw_stream_ops.get_flash_img_info = fw_stream_get_flash_img_info;
|
||||
|
||||
gx_uart_upgrade_init(&uart_ops, &fw_stream_ops, gx8002_upgrade_status_cb);
|
||||
|
||||
ret = gx8002_upgrade_task(NULL);
|
||||
|
||||
if (ret < 0) {
|
||||
__this->update_result = GX_APP_UPDATE_ERR_UPDATE_LOOP;
|
||||
} else {
|
||||
__this->update_result = GX_APP_UPDATE_ERR_NONE;
|
||||
}
|
||||
|
||||
gx8002_app_ota_close();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#else /* #if GX8002_UPGRADE_APP_TOGGLE */
|
||||
|
||||
int gx8002_uart_app_ota_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* #if GX8002_UPGRADE_APP_TOGGLE */
|
||||
|
||||
@ -0,0 +1,265 @@
|
||||
#include "includes.h"
|
||||
#include "../gx_uart_upgrade.h"
|
||||
#include "../../gx8002_npu_api.h"
|
||||
#include "../gx_uart_upgrade_porting.h"
|
||||
//#include "../utils/gx_fifo.h"
|
||||
|
||||
#if (GX8002_UPGRADE_APP_TWS_TOGGLE && OTA_TWS_SAME_TIME_ENABLE)
|
||||
|
||||
struct gx8002_tws_update {
|
||||
update_op_tws_api_t *tws_handle;
|
||||
OS_SEM tws_sync_sem;
|
||||
u8 slave_result;
|
||||
};
|
||||
|
||||
enum GX8002_TWS_UPDATE_CMD {
|
||||
GX8002_TWS_UPDATE_CMD_START = 'G',
|
||||
GX8002_TWS_UPDATE_CMD_UFW_DATA,
|
||||
GX8002_TWS_UPDATE_CMD_RESPOND,
|
||||
GX8002_TWS_UPDATE_CMD_RESULT,
|
||||
};
|
||||
|
||||
static struct gx8002_tws_update *tws_update = NULL;
|
||||
|
||||
#define GX8002_OTA_UPGRADE_DEBUG_ENABLE 0
|
||||
|
||||
#define ota_upgrade_info printf
|
||||
|
||||
#if GX8002_OTA_UPGRADE_DEBUG_ENABLE
|
||||
#define ota_upgrade_debug printf
|
||||
#define ota_upgrade_put_buf put_buf
|
||||
#else
|
||||
#define ota_upgrade_debug(...)
|
||||
#define ota_upgrade_put_buf(...)
|
||||
#endif /* #if GX8002_DEBUG_ENABLE */
|
||||
|
||||
#define GX8002_TWS_SYNC_TIMEOUT 300
|
||||
|
||||
|
||||
extern int gx8002_ota_data_passive_receive(u8 *data, u32 size);
|
||||
extern int gx8002_app_ota_passive_start(int (*complete_callback)(void), u8 *ota_data, u16 len);
|
||||
extern update_op_tws_api_t *get_tws_update_api(void);
|
||||
extern void tws_update_register_user_chip_update_handle(void (*update_handle)(void *data, u32 len));
|
||||
|
||||
int gx8002_uart_app_ota_tws_update_sync_pend(void)
|
||||
{
|
||||
ota_upgrade_debug("%s", __func__);
|
||||
if (tws_update) {
|
||||
if (os_sem_pend(&(tws_update->tws_sync_sem), GX8002_TWS_SYNC_TIMEOUT) == OS_TIMEOUT) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gx8002_uart_app_ota_tws_update_sync_post(void)
|
||||
{
|
||||
ota_upgrade_debug("%s", __func__);
|
||||
if (tws_update) {
|
||||
os_sem_post(&(tws_update->tws_sync_sem));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gx8002_uart_app_ota_tws_update_sync_result(int result)
|
||||
{
|
||||
ota_upgrade_info("%s: result: 0x%x", __func__, result);
|
||||
if (tws_update) {
|
||||
if (result) {
|
||||
tws_update->slave_result = 'N';
|
||||
} else {
|
||||
tws_update->slave_result = 'O';
|
||||
}
|
||||
if (tws_update->tws_handle) {
|
||||
tws_update->tws_handle->tws_ota_user_chip_update_send(GX8002_TWS_UPDATE_CMD_RESULT, &(tws_update->slave_result), 1);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gx8002_uart_app_ota_tws_update_sync_result_get(void)
|
||||
{
|
||||
if (tws_update) {
|
||||
if (gx8002_uart_app_ota_tws_update_sync_pend()) {
|
||||
ota_upgrade_info("%s timeout", __func__);
|
||||
return -1;
|
||||
}
|
||||
if (tws_update->slave_result == 'O') {
|
||||
ota_upgrade_info("%s, get: O", __func__);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
ota_upgrade_info("%s state err", __func__);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int gx8002_uart_app_ota_tws_update_sync_respond(void)
|
||||
{
|
||||
ota_upgrade_debug("%s", __func__);
|
||||
if (tws_update) {
|
||||
if (tws_update->tws_handle) {
|
||||
tws_update->tws_handle->tws_ota_user_chip_update_send(GX8002_TWS_UPDATE_CMD_RESPOND, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gx8002_uart_app_ota_tws_update_sync_start(u8 *buf, u16 len)
|
||||
{
|
||||
if (tws_update) {
|
||||
if (tws_update->tws_handle) {
|
||||
tws_update->tws_handle->tws_ota_user_chip_update_send(GX8002_TWS_UPDATE_CMD_START, buf, len);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gx8002_uart_app_ota_tws_update_sync_data(u8 *buf, u16 len)
|
||||
{
|
||||
if (tws_update) {
|
||||
if (tws_update->tws_handle) {
|
||||
tws_update->tws_handle->tws_ota_user_chip_update_send(GX8002_TWS_UPDATE_CMD_UFW_DATA, buf, len);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gx8002_uart_app_ota_tws_update_init(void *priv)
|
||||
{
|
||||
ota_upgrade_info("%s", __func__);
|
||||
|
||||
if (tws_update) {
|
||||
free(tws_update);
|
||||
}
|
||||
|
||||
if (priv == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
tws_update = zalloc(sizeof(struct gx8002_tws_update));
|
||||
if (tws_update == NULL) {
|
||||
return -1;
|
||||
}
|
||||
tws_update->tws_handle = priv;
|
||||
|
||||
os_sem_create(&(tws_update->tws_sync_sem), 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int gx8002_uart_app_ota_tws_update_close(void)
|
||||
{
|
||||
if (tws_update) {
|
||||
free(tws_update);
|
||||
|
||||
tws_update = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gx8002_uart_app_ota_tws_update_handle(void *data, u32 len)
|
||||
{
|
||||
u8 *rx_packet = (u8 *)data;
|
||||
int ret = 0;
|
||||
|
||||
ota_upgrade_debug("receive cmd 0x%x, data len = 0x%x", rx_packet[0], len - 1);
|
||||
|
||||
switch (rx_packet[0]) {
|
||||
case GX8002_TWS_UPDATE_CMD_START:
|
||||
gx8002_uart_app_ota_tws_update_init(get_tws_update_api());
|
||||
ret = gx8002_app_ota_passive_start(gx8002_uart_app_ota_tws_update_sync_respond, rx_packet + 1, len - 1);
|
||||
if (ret) {
|
||||
gx8002_uart_app_ota_tws_update_close();
|
||||
}
|
||||
break;
|
||||
|
||||
case GX8002_TWS_UPDATE_CMD_UFW_DATA:
|
||||
gx8002_ota_data_passive_receive(rx_packet + 1, len - 1);
|
||||
break;
|
||||
|
||||
case GX8002_TWS_UPDATE_CMD_RESPOND:
|
||||
gx8002_uart_app_ota_tws_update_sync_post();
|
||||
break;
|
||||
|
||||
case GX8002_TWS_UPDATE_CMD_RESULT:
|
||||
ota_upgrade_info("result: 0x%x", rx_packet[1]);
|
||||
if (tws_update) {
|
||||
tws_update->slave_result = rx_packet[1];
|
||||
}
|
||||
gx8002_uart_app_ota_tws_update_sync_post();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void gx8002_uart_app_ota_tws_update_register_handle(void)
|
||||
{
|
||||
tws_update_register_user_chip_update_handle(gx8002_uart_app_ota_tws_update_handle);
|
||||
}
|
||||
|
||||
#else /* #if (GX8002_UPGRADE_APP_TWS_TOGGLE && OTA_TWS_SAME_TIME_ENABLE) */
|
||||
|
||||
void gx8002_uart_app_ota_tws_update_register_handle(void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int gx8002_uart_app_ota_tws_update_init(void *priv)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gx8002_uart_app_ota_tws_update_sync_pend(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gx8002_uart_app_ota_tws_update_sync_post(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gx8002_uart_app_ota_tws_update_sync_data(u8 *buf, u16 len)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gx8002_uart_app_ota_tws_update_sync_respond(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gx8002_uart_app_ota_tws_update_close(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gx8002_uart_app_ota_tws_update_sync_start(u8 *buf, u16 len)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gx8002_uart_app_ota_tws_update_sync_result(int result)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int gx8002_uart_app_ota_tws_update_sync_result_get(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* #if (GX8002_UPGRADE_APP_TWS_TOGGLE && OTA_TWS_SAME_TIME_ENABLE) */
|
||||
|
||||
482
apps/common/device/gx8002_npu/gx8002_upgrade/gx_uart_upgrade.c
Normal file
482
apps/common/device/gx8002_npu/gx8002_upgrade/gx_uart_upgrade.c
Normal file
@ -0,0 +1,482 @@
|
||||
#include "includes.h"
|
||||
#include "gx_uart_upgrade.h"
|
||||
#include "../gx8002_npu_api.h"
|
||||
|
||||
#if GX8002_UPGRADE_TOGGLE
|
||||
|
||||
#define GX_UPGRADE_DEBUG 0
|
||||
#if GX_UPGRADE_DEBUG
|
||||
//#define upgrade_debug(fmt, ...) y_printf("[gx_uart_upgrade]: " fmt, ##__VA_ARGS__)
|
||||
#define upgrade_debug printf
|
||||
#else
|
||||
#define upgrade_debug(fmt, ...)
|
||||
#endif
|
||||
|
||||
#define HANDSHAKE_BAUDRATE 576000
|
||||
#define UART_REPLY_TIMEOUT_MS 5000
|
||||
|
||||
static upgrade_uart_t uart_ops;
|
||||
static fw_stream_t fw_stream_ops;
|
||||
static upgrade_status_cb status_callback;
|
||||
|
||||
typedef struct {
|
||||
unsigned short chip_id;
|
||||
unsigned char chip_type;
|
||||
unsigned char chip_version;
|
||||
|
||||
unsigned short boot_delay;
|
||||
unsigned char baud_rate;
|
||||
unsigned char reserved_1;
|
||||
|
||||
unsigned int stage1_size;
|
||||
unsigned int stage2_baud_rate;
|
||||
unsigned int stage2_size;
|
||||
unsigned int stage2_checksum;
|
||||
unsigned char reserved[8];
|
||||
} __attribute__((packed)) boot_header_t;
|
||||
|
||||
static boot_header_t boot_header;
|
||||
static unsigned char data_buf[UPGRADE_PACKET_SIZE];
|
||||
static upgrade_stage_e current_stage;
|
||||
static int upgrade_initialized = 0;
|
||||
|
||||
static inline void set_upgrade_stage(upgrade_stage_e stage)
|
||||
{
|
||||
current_stage = stage;
|
||||
}
|
||||
|
||||
static inline upgrade_stage_e get_upgrade_stage(void)
|
||||
{
|
||||
return current_stage;
|
||||
}
|
||||
|
||||
static void status_report(upgrade_status_e status)
|
||||
{
|
||||
if (status_callback) {
|
||||
status_callback(get_upgrade_stage(), status);
|
||||
}
|
||||
}
|
||||
|
||||
static int upgrade_handshake(unsigned int timeout_ms, unsigned int retry_times)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
upgrade_debug("start upgrade_handshake, timeout_ms: %d, retry_times: %d\n", timeout_ms, retry_times);
|
||||
|
||||
set_upgrade_stage(UPGRADE_STAGE_HANDSHAKE);
|
||||
status_report(UPGRADE_STATUS_START);
|
||||
|
||||
upgrade_debug("waiting 'M' ...\n");
|
||||
while (retry_times--) {
|
||||
upgrade_debug("handshake retry_times: %d", retry_times);
|
||||
unsigned char c = 0xef;
|
||||
uart_ops.send(&c, 1);
|
||||
if (!uart_ops.wait_reply((const unsigned char *)"M", 1, timeout_ms)) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
upgrade_debug("get 'M' !\n");
|
||||
status_report(UPGRADE_STATUS_OK);
|
||||
} else {
|
||||
upgrade_debug("wait 'M' err !\n");
|
||||
status_report(UPGRADE_STATUS_ERR);
|
||||
}
|
||||
|
||||
upgrade_debug("upgrade_handshake over, ret: %d\n ", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int is_little_endian(void)
|
||||
{
|
||||
int a = 0x11223344;
|
||||
unsigned char *p = (unsigned char *)&a;
|
||||
|
||||
return (*p == 0x44) ? 1 : 0;
|
||||
}
|
||||
|
||||
static unsigned int switch_endian(unsigned int v)
|
||||
{
|
||||
return (((v >> 0) & 0xff) << 24) | (((v >> 8) & 0xff) << 16) | (((v >> 16) & 0xff) << 8) | (((v >> 24) & 0xff) << 0);
|
||||
}
|
||||
|
||||
static unsigned int be32_to_cpu(unsigned int v)
|
||||
{
|
||||
if (is_little_endian()) {
|
||||
return switch_endian(v);
|
||||
} else {
|
||||
return v;
|
||||
}
|
||||
}
|
||||
|
||||
static int boot_info_baudrate[] = {300, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200};
|
||||
static void print_bootheader(const boot_header_t *header)
|
||||
{
|
||||
upgrade_debug("chip_id %x\n", header->chip_id);
|
||||
upgrade_debug("chip_type %x\n", header->chip_type);
|
||||
upgrade_debug("chip_version %x\n", header->chip_version);
|
||||
upgrade_debug("boot_delay %x\n", header->boot_delay);
|
||||
upgrade_debug("baud_rate %d\n", boot_info_baudrate[header->baud_rate]);
|
||||
upgrade_debug("stage1_size %d\n", header->stage1_size);
|
||||
upgrade_debug("stage2_baud_rate %d\n", header->stage2_baud_rate);
|
||||
upgrade_debug("stage2_size %d\n", header->stage2_size);
|
||||
upgrade_debug("stage2_checksum %d\n", header->stage2_checksum);
|
||||
}
|
||||
|
||||
int parse_bootimg_header(void)
|
||||
{
|
||||
upgrade_debug("reading boot header ...\n");
|
||||
|
||||
set_upgrade_stage(UPGRADE_STAGE_BOOT_HEADER);
|
||||
status_report(UPGRADE_STATUS_START);
|
||||
|
||||
int ret = fw_stream_ops.read(FW_BOOT_IMAGE, (unsigned char *)&boot_header, sizeof(boot_header));
|
||||
if (ret < sizeof(boot_header)) {
|
||||
upgrade_debug("read boot header err !\n");
|
||||
goto header_err;
|
||||
}
|
||||
|
||||
boot_header.stage1_size = be32_to_cpu(boot_header.stage1_size);
|
||||
boot_header.stage2_baud_rate = be32_to_cpu(boot_header.stage2_baud_rate);
|
||||
boot_header.stage2_size = be32_to_cpu(boot_header.stage2_size);
|
||||
boot_header.stage2_checksum = be32_to_cpu(boot_header.stage2_checksum);
|
||||
|
||||
print_bootheader(&boot_header);
|
||||
status_report(UPGRADE_STATUS_OK);
|
||||
return 0;
|
||||
|
||||
header_err:
|
||||
status_report(UPGRADE_STATUS_ERR);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int download_bootimg_stage1(void)
|
||||
{
|
||||
int wsize = 0;
|
||||
int len = 0;
|
||||
int size = 0;
|
||||
|
||||
upgrade_debug("start boot stage1 ...\n");
|
||||
|
||||
set_upgrade_stage(UPGRADE_STAGE_BOOT_S1);
|
||||
status_report(UPGRADE_STATUS_START);
|
||||
|
||||
size = boot_header.stage1_size;
|
||||
size = size / 4;
|
||||
data_buf[0] = 'Y';
|
||||
data_buf[1] = (size >> 0) & 0xFF;
|
||||
data_buf[2] = (size >> 8) & 0xFF;
|
||||
data_buf[3] = (size >> 16) & 0xFF;
|
||||
data_buf[4] = (size >> 24) & 0xFF;
|
||||
uart_ops.send(data_buf, 5);
|
||||
|
||||
if (boot_header.chip_type == 0x01) {
|
||||
size = size * 4;
|
||||
}
|
||||
|
||||
upgrade_debug("download boot stage1 ...\n");
|
||||
while (wsize < size) {
|
||||
if (wsize % UPGRADE_BLOCK_SIZE == 0) {
|
||||
status_report(UPGRADE_STATUS_DOWNLOADING);
|
||||
}
|
||||
len = (boot_header.stage1_size - wsize >= UPGRADE_PACKET_SIZE) ? UPGRADE_PACKET_SIZE : (boot_header.stage1_size - wsize);
|
||||
len = fw_stream_ops.read(FW_BOOT_IMAGE, data_buf, len);
|
||||
if (len <= 0) {
|
||||
upgrade_debug("read data err !\n");
|
||||
goto stage1_err;
|
||||
}
|
||||
len = uart_ops.send(data_buf, len);
|
||||
if (len <= 0) {
|
||||
upgrade_debug("send data err !\n");
|
||||
goto stage1_err;
|
||||
}
|
||||
|
||||
wsize += len;
|
||||
}
|
||||
|
||||
upgrade_debug("download size: %d, waiting 'F' ...\n", wsize);
|
||||
if (uart_ops.wait_reply((const unsigned char *)"F", 1, UART_REPLY_TIMEOUT_MS)) {
|
||||
upgrade_debug("wait 'F' err !\n");
|
||||
goto stage1_err;
|
||||
}
|
||||
upgrade_debug("get 'F' !\n");
|
||||
|
||||
///// stage1 running, change baudrate /////
|
||||
upgrade_debug("change baudrate: %d\n", boot_header.stage2_baud_rate);
|
||||
|
||||
uart_ops.close();
|
||||
uart_ops.open(boot_header.stage2_baud_rate, 8, 1, 0);
|
||||
|
||||
upgrade_debug("wait \"GET\" ...\n");
|
||||
if (uart_ops.wait_reply((const unsigned char *)"GET", 3, UART_REPLY_TIMEOUT_MS)) {
|
||||
upgrade_debug("wait 'GET' err !\n");
|
||||
goto stage1_err;
|
||||
}
|
||||
upgrade_debug("get \"GET\" !\n");
|
||||
|
||||
data_buf[0] = 'O';
|
||||
data_buf[1] = 'K';
|
||||
uart_ops.send(data_buf, 2);
|
||||
|
||||
status_report(UPGRADE_STATUS_OK);
|
||||
upgrade_debug("boot stage1 ok !\n");
|
||||
|
||||
return 0;
|
||||
|
||||
stage1_err:
|
||||
status_report(UPGRADE_STATUS_ERR);
|
||||
upgrade_debug("boot stage1 err !\n");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int download_bootimg_stage2(void)
|
||||
{
|
||||
unsigned int checksum = 0;
|
||||
unsigned int stage2_size = 0;
|
||||
int len = 0;
|
||||
int wsize = 0;
|
||||
|
||||
upgrade_debug("start boot stage2 ...\n");
|
||||
|
||||
set_upgrade_stage(UPGRADE_STAGE_BOOT_S2);
|
||||
status_report(UPGRADE_STATUS_START);
|
||||
|
||||
stage2_size = boot_header.stage2_size;
|
||||
checksum = boot_header.stage2_checksum;
|
||||
upgrade_debug("stage2_size = %u, checksum = %u\n", stage2_size, checksum);
|
||||
|
||||
if (checksum == 0 || stage2_size == 0) {
|
||||
upgrade_debug("stage2_size or checksum err !\n");
|
||||
goto stage2_err;
|
||||
}
|
||||
|
||||
data_buf[0] = 'S';
|
||||
uart_ops.send(data_buf, 1);
|
||||
uart_ops.send((const unsigned char *)&checksum, 4);
|
||||
uart_ops.send((const unsigned char *)&stage2_size, 4);
|
||||
|
||||
upgrade_debug("waiting \"ready\" ...\n");
|
||||
if (uart_ops.wait_reply((const unsigned char *)"ready", 5, UART_REPLY_TIMEOUT_MS)) {
|
||||
upgrade_debug("wait ready error !\n");
|
||||
goto stage2_err;
|
||||
}
|
||||
upgrade_debug("get \"ready\"\n");
|
||||
|
||||
upgrade_debug("download boot stage2 ...\n");
|
||||
while (wsize < stage2_size) {
|
||||
if (wsize % UPGRADE_BLOCK_SIZE == 0) {
|
||||
status_report(UPGRADE_STATUS_DOWNLOADING);
|
||||
}
|
||||
len = (stage2_size - wsize >= UPGRADE_PACKET_SIZE) ? UPGRADE_PACKET_SIZE : (stage2_size - wsize);
|
||||
len = fw_stream_ops.read(FW_BOOT_IMAGE, data_buf, len);
|
||||
if (len <= 0) {
|
||||
upgrade_debug("read data err !\n");
|
||||
goto stage2_err;
|
||||
}
|
||||
|
||||
len = uart_ops.send(data_buf, len);
|
||||
if (len <= 0) {
|
||||
upgrade_debug("send data err !\n");
|
||||
goto stage2_err;
|
||||
}
|
||||
|
||||
wsize += len;
|
||||
}
|
||||
|
||||
upgrade_debug("download size: %d, waiting 'O' ...\n", wsize);
|
||||
if (uart_ops.wait_reply((const unsigned char *)"O", 1, UART_REPLY_TIMEOUT_MS)) {
|
||||
upgrade_debug("wait 'O' err !\n");
|
||||
goto stage2_err;
|
||||
}
|
||||
upgrade_debug("get 'O' !\n");
|
||||
|
||||
upgrade_debug("waiting \"boot>\" ...\n");
|
||||
|
||||
if (uart_ops.wait_reply((const unsigned char *)"boot>", 5, UART_REPLY_TIMEOUT_MS)) {
|
||||
upgrade_debug("wait \"boot>\" err !\n");
|
||||
goto stage2_err;
|
||||
}
|
||||
upgrade_debug("get \"boot>\" !\n");
|
||||
|
||||
status_report(UPGRADE_STATUS_OK);
|
||||
upgrade_debug("boot stage2 ok !\n");
|
||||
|
||||
return 0;
|
||||
|
||||
stage2_err:
|
||||
status_report(UPGRADE_STATUS_ERR);
|
||||
upgrade_debug("boot stage2 err !\n");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int download_bootimg(void)
|
||||
{
|
||||
if (parse_bootimg_header() != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (download_bootimg_stage1() != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (download_bootimg_stage2() != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int download_flashimg(void)
|
||||
{
|
||||
int wsize = 0;
|
||||
int len = 0;
|
||||
flash_img_info_t info = {0};
|
||||
|
||||
upgrade_debug("start flash image ...\n");
|
||||
|
||||
set_upgrade_stage(UPGRADE_STAGE_FLASH_IMG);
|
||||
status_report(UPGRADE_STATUS_START);
|
||||
fw_stream_ops.get_flash_img_info(&info);
|
||||
upgrade_debug("flash image size = %d\n", info.img_size);
|
||||
|
||||
if (info.img_size == 0) {
|
||||
upgrade_debug("flash image size err !\n");
|
||||
goto flash_err;
|
||||
}
|
||||
|
||||
memset(data_buf, 0, UPGRADE_PACKET_SIZE);
|
||||
len = sprintf((char *)data_buf, "serialdown %d %d %d\n", 0, info.img_size, UPGRADE_FLASH_BLOCK_SIZE);
|
||||
uart_ops.send(data_buf, len);
|
||||
|
||||
upgrade_debug("waiting \"~sta~\" ...\n");
|
||||
if (uart_ops.wait_reply((const unsigned char *)"~sta~", 5, UART_REPLY_TIMEOUT_MS)) {
|
||||
upgrade_debug("wait ~sta~ err !\n");
|
||||
goto flash_err;
|
||||
}
|
||||
upgrade_debug("get \"~sta~\" !\n");
|
||||
|
||||
upgrade_debug("download flash image ...\n");
|
||||
|
||||
while (wsize < info.img_size) {
|
||||
if (wsize % UPGRADE_BLOCK_SIZE == 0) {
|
||||
status_report(UPGRADE_STATUS_DOWNLOADING);
|
||||
}
|
||||
|
||||
len = (info.img_size - wsize >= UPGRADE_PACKET_SIZE) ? UPGRADE_PACKET_SIZE : (info.img_size - wsize);
|
||||
len = fw_stream_ops.read(FW_FLASH_IMAGE, data_buf, len);
|
||||
if (len <= 0) {
|
||||
upgrade_debug("read data err !\n");
|
||||
goto flash_err;
|
||||
}
|
||||
|
||||
len = uart_ops.send(data_buf, len);
|
||||
if (len <= 0) {
|
||||
upgrade_debug("send data err !\n");
|
||||
goto flash_err;
|
||||
}
|
||||
wsize += len;
|
||||
|
||||
if ((wsize % UPGRADE_FLASH_BLOCK_SIZE) == 0) {
|
||||
upgrade_debug("waiting \"~sta~\" ...\n");
|
||||
if (uart_ops.wait_reply((const unsigned char *)"~sta~", 5, UART_REPLY_TIMEOUT_MS)) {
|
||||
upgrade_debug("wait \"~sta~\" err !\n");
|
||||
goto flash_err;
|
||||
}
|
||||
upgrade_debug("get \"~sta~\" !\n");
|
||||
}
|
||||
}
|
||||
|
||||
upgrade_debug("download size: %d, waiting \"~fin~\" ...\n", wsize);
|
||||
if (uart_ops.wait_reply((const unsigned char *)"~fin~", 5, UART_REPLY_TIMEOUT_MS)) {
|
||||
upgrade_debug("wait \"~fin~\" err !\n");
|
||||
goto flash_err;
|
||||
}
|
||||
upgrade_debug("get \"~fin~\" !\n");
|
||||
|
||||
status_report(UPGRADE_STATUS_OK);
|
||||
upgrade_debug("flash image ok !\n");
|
||||
return 0;
|
||||
|
||||
flash_err:
|
||||
status_report(UPGRADE_STATUS_ERR);
|
||||
upgrade_debug("flash image err !\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int gx_uart_upgrade_proc(void)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
if (!upgrade_initialized) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
set_upgrade_stage(UPGRADE_STAGE_NONE);
|
||||
|
||||
if (uart_ops.open(HANDSHAKE_BAUDRATE, 8, 1, 0) < 0) {
|
||||
upgrade_debug("open uart err !\n");
|
||||
goto upgrade_done;
|
||||
}
|
||||
|
||||
if (fw_stream_ops.open(FW_BOOT_IMAGE) < 0) {
|
||||
upgrade_debug("open boot img stream err !\n");
|
||||
goto upgrade_done;
|
||||
}
|
||||
|
||||
if (fw_stream_ops.open(FW_FLASH_IMAGE) < 0) {
|
||||
upgrade_debug("open flash img stream err !\n");
|
||||
goto upgrade_done;
|
||||
}
|
||||
|
||||
/* JL_PORTA->DIR &= ~BIT(4); */
|
||||
/* JL_PORTA->OUT |= BIT(4); */
|
||||
if (upgrade_handshake(10, 100) < 0) {
|
||||
goto upgrade_done;
|
||||
}
|
||||
|
||||
if (download_bootimg() < 0) {
|
||||
goto upgrade_done;
|
||||
}
|
||||
|
||||
if (download_flashimg() < 0) {
|
||||
goto upgrade_done;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
upgrade_done:
|
||||
uart_ops.close();
|
||||
fw_stream_ops.close(FW_BOOT_IMAGE);
|
||||
fw_stream_ops.close(FW_FLASH_IMAGE);
|
||||
set_upgrade_stage(UPGRADE_STAGE_NONE);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int gx_uart_upgrade_init(upgrade_uart_t *uart, fw_stream_t *fw_stream, upgrade_status_cb status_cb)
|
||||
{
|
||||
if ((uart == NULL) || (fw_stream == NULL)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(&uart_ops, uart, sizeof(upgrade_uart_t));
|
||||
memcpy(&fw_stream_ops, fw_stream, sizeof(fw_stream_t));
|
||||
|
||||
status_callback = status_cb;
|
||||
|
||||
upgrade_initialized = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gx_uart_upgrade_deinit(void)
|
||||
{
|
||||
upgrade_initialized = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* #if GX8002_UPGRADE_TOGGLE */
|
||||
@ -0,0 +1,17 @@
|
||||
#ifndef __GX_URAT_UPGRADE_H__
|
||||
#define __GX_URAT_UPGRADE_H__
|
||||
|
||||
#include "gx_upgrade_def.h"
|
||||
|
||||
typedef struct {
|
||||
int (*open)(int baud, int databits, int stopbits, int parity);
|
||||
int (*close)(void);
|
||||
int (*wait_reply)(const unsigned char *buf, unsigned int len, unsigned int timeout);
|
||||
int (*send)(const unsigned char *buf, unsigned int len);
|
||||
} upgrade_uart_t;
|
||||
|
||||
int gx_uart_upgrade_init(upgrade_uart_t *uart, fw_stream_t *fw_stream, upgrade_status_cb status_cb);
|
||||
int gx_uart_upgrade_deinit(void);
|
||||
int gx_uart_upgrade_proc(void);
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,136 @@
|
||||
#include "includes.h"
|
||||
#include "asm/uart_dev.h"
|
||||
#include "gx_uart_upgrade_porting.h"
|
||||
#include "../gx8002_npu_api.h"
|
||||
#include "app_config.h"
|
||||
|
||||
#if GX8002_UPGRADE_TOGGLE
|
||||
|
||||
#define GX_UART_UPGRADE_PORT_DEBUG 1
|
||||
|
||||
#ifdef GX_UART_UPGRADE_PORT_DEBUG
|
||||
//#define upgrade_debug(fmt, ...) y_printf("[gx_uart_upgrade]: " fmt, ##__VA_ARGS__)
|
||||
#define gx_uart_upgrade_port_debug y_printf
|
||||
#else
|
||||
#define gx_uart_upgrade_port_debug(fmt, ...)
|
||||
#endif
|
||||
|
||||
struct gx_upgrade_uart_port {
|
||||
const uart_bus_t *uart_bus;
|
||||
u32 cur_baud;
|
||||
};
|
||||
|
||||
static u8 uart_upgrade_cbuf[512] __attribute__((aligned(4)));
|
||||
|
||||
static struct gx_upgrade_uart_port uart_port = {0};
|
||||
|
||||
#define __this (&uart_port)
|
||||
|
||||
static void gx8002_upgrade_uart_isr_hook(void *arg, u32 status)
|
||||
{
|
||||
if (status != UT_TX) {
|
||||
//gx_uart_upgrade_port_debug("UT_RX_OT pending");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int gx_upgrade_uart_porting_open(int baud, int databits, int stopbits, int parity)
|
||||
{
|
||||
int ret = -1;
|
||||
struct uart_platform_data_t u_arg = {0};
|
||||
|
||||
if (__this->uart_bus) {
|
||||
gx_uart_upgrade_port_debug("gx8002 uart upgrade have open");
|
||||
return 0;
|
||||
}
|
||||
|
||||
u_arg.tx_pin = TCFG_GX8002_NPU_UART_TX_PORT;
|
||||
u_arg.rx_pin = TCFG_GX8002_NPU_UART_RX_PORT;
|
||||
u_arg.rx_cbuf = uart_upgrade_cbuf;
|
||||
u_arg.rx_cbuf_size = sizeof(uart_upgrade_cbuf);
|
||||
u_arg.frame_length = 0xFFFF;
|
||||
u_arg.rx_timeout = 5;
|
||||
u_arg.isr_cbfun = gx8002_upgrade_uart_isr_hook;
|
||||
u_arg.baud = baud;
|
||||
u_arg.is_9bit = 0;
|
||||
|
||||
__this->uart_bus = uart_dev_open(&u_arg);
|
||||
if (__this->uart_bus != NULL) {
|
||||
gx_uart_upgrade_port_debug("gx8002 uart upgrade open: baud: %d", baud);
|
||||
ret = 0;
|
||||
} else {
|
||||
gx_uart_upgrade_port_debug("gx8002 uart upgrade open fail");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int gx_upgrade_uart_porting_close(void)
|
||||
{
|
||||
if (__this->uart_bus) {
|
||||
uart_dev_close(__this->uart_bus);
|
||||
gpio_disable_fun_output_port(TCFG_GX8002_NPU_UART_TX_PORT);
|
||||
__this->uart_bus = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gx_upgrade_uart_porting_read(unsigned char *buf, unsigned int len, unsigned int timeout_ms)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
if (__this->uart_bus && __this->uart_bus->read) {
|
||||
ret = __this->uart_bus->read(buf, len, timeout_ms);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
//int gx_upgrade_uart_porting_write(const unsigned char *buf, unsigned int len, unsigned int timeout_ms)
|
||||
int gx_upgrade_uart_porting_write(const unsigned char *buf, unsigned int len)
|
||||
{
|
||||
int ret = len;
|
||||
|
||||
if (__this->uart_bus && __this->uart_bus->write) {
|
||||
__this->uart_bus->write(buf, len);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int gx_uart_upgrade_porting_wait_reply(const unsigned char *buf, unsigned int len, unsigned int timeout_ms)
|
||||
{
|
||||
int index = 0;
|
||||
unsigned char ch;
|
||||
|
||||
while (gx_upgrade_uart_porting_read(&ch, 1, timeout_ms) > 0) {
|
||||
//gx_uart_upgrade_port_debug("`0x%02x`\n", ch);
|
||||
if (ch == (unsigned char)buf[index]) {
|
||||
index++;
|
||||
}
|
||||
if (index == len) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void uart_clock_critical_enter(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static void uart_clock_critical_exit(void)
|
||||
{
|
||||
if (__this->uart_bus && __this->uart_bus->set_baud) {
|
||||
gx_uart_upgrade_port_debug("clock critical uart set_baud: %d", __this->cur_baud);
|
||||
__this->uart_bus->set_baud(__this->cur_baud);
|
||||
}
|
||||
}
|
||||
CLOCK_CRITICAL_HANDLE_REG(gx8002, uart_clock_critical_enter, uart_clock_critical_exit)
|
||||
|
||||
|
||||
#endif /* #if GX8002_UPGRADE_TOGGLE */
|
||||
@ -0,0 +1,16 @@
|
||||
#ifndef _GX_UART_UPGRADE_UPGRADE_PORT_
|
||||
#define _GX_UART_UPGRADE_UPGRADE_PORT_
|
||||
|
||||
|
||||
int gx_upgrade_uart_porting_open(int baud, int databits, int stopbits, int parity);
|
||||
|
||||
int gx_upgrade_uart_porting_close(void);
|
||||
|
||||
int gx_upgrade_uart_porting_read(unsigned char *buf, unsigned int len, unsigned int timeout_ms);
|
||||
|
||||
//int gx_upgrade_uart_porting_write(const unsigned char *buf, unsigned int len, unsigned int timeout_ms);
|
||||
int gx_upgrade_uart_porting_write(const unsigned char *buf, unsigned int len);
|
||||
|
||||
int gx_uart_upgrade_porting_wait_reply(const unsigned char *buf, unsigned int len, unsigned int timeout_ms);
|
||||
|
||||
#endif /* #ifndef _GX_UART_UPGRADE_UPGRADE_PORT_ */
|
||||
@ -0,0 +1,47 @@
|
||||
#ifndef __GX_UPGRADE_DEF_H__
|
||||
#define __GX_UPGRADE_DEF_H__
|
||||
|
||||
#define UPGRADE_DATA_BLOCK_SIZE 256
|
||||
|
||||
#define UPGRADE_PACKET_SIZE 256
|
||||
#define UPGRADE_BLOCK_SIZE (1024 * 4)
|
||||
#define UPGRADE_FLASH_BLOCK_SIZE (1024 * 56) //56K
|
||||
|
||||
typedef enum {
|
||||
UPGRADE_STAGE_HANDSHAKE = 0,
|
||||
UPGRADE_STAGE_BOOT_HEADER,
|
||||
UPGRADE_STAGE_BOOT_S1,
|
||||
UPGRADE_STAGE_BOOT_S2,
|
||||
UPGRADE_STAGE_FLASH_IMG,
|
||||
UPGRADE_STAGE_NONE
|
||||
} upgrade_stage_e;
|
||||
|
||||
typedef enum {
|
||||
UPGRADE_STATUS_START = 0,
|
||||
UPGRADE_STATUS_DOWNLOADING,
|
||||
UPGRADE_STATUS_OK,
|
||||
UPGRADE_STATUS_ERR,
|
||||
UPGRADE_STATUS_NONE
|
||||
} upgrade_status_e;
|
||||
|
||||
typedef void (*upgrade_status_cb)(upgrade_stage_e stage, upgrade_status_e status);
|
||||
|
||||
typedef enum {
|
||||
FW_BOOT_IMAGE = 0, //"gx8002.boot"
|
||||
FW_FLASH_IMAGE, //"mcu_nor.bin"
|
||||
|
||||
FW_FLASH_MAX,
|
||||
} FW_IMAGE_TYPE;
|
||||
|
||||
typedef struct {
|
||||
unsigned int img_size;
|
||||
} flash_img_info_t;
|
||||
|
||||
typedef struct {
|
||||
int (*open)(FW_IMAGE_TYPE img_type);
|
||||
int (*close)(FW_IMAGE_TYPE img_type);
|
||||
int (*read)(FW_IMAGE_TYPE img_type, unsigned char *buf, unsigned int len);
|
||||
int (*get_flash_img_info)(flash_img_info_t *info);
|
||||
} fw_stream_t;
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,189 @@
|
||||
#include "includes.h"
|
||||
#include "../gx_uart_upgrade.h"
|
||||
#include "../../gx8002_npu_api.h"
|
||||
#include "../gx_uart_upgrade_porting.h"
|
||||
|
||||
#if GX8002_UPGRADE_SDFILE_TOGGLE
|
||||
|
||||
#define STREAM_FIFO_BLOCK_TOTAL 20
|
||||
#define STREAM_FIFO_TIMEOUT_MS 7000
|
||||
|
||||
typedef int (*reply)(unsigned char *data, int size);
|
||||
static int ota_start = 0;
|
||||
|
||||
struct sdfile_fifo {
|
||||
FILE *boot_fp;
|
||||
FILE *bin_fp;
|
||||
};
|
||||
|
||||
static struct sdfile_fifo sdfile_upgrade = {0};
|
||||
#define __this (&sdfile_upgrade)
|
||||
|
||||
#define GX8002_SDFILE_UPGRADE_DEBUG_ENABLE 1
|
||||
|
||||
#define sdfile_upgrade_info g_printf
|
||||
|
||||
#if GX8002_SDFILE_UPGRADE_DEBUG_ENABLE
|
||||
#define sdfile_upgrade_debug r_printf
|
||||
#define sdfile_upgrade_put_buf put_buf
|
||||
#else
|
||||
#define sdfile_upgrade_debug(...)
|
||||
#define sdfile_upgrade_put_buf(...)
|
||||
#endif /* #if GX8002_DEBUG_ENABLE */
|
||||
|
||||
////////////// FW Stream Porting //////////////////
|
||||
static int fw_stream_open(FW_IMAGE_TYPE img_type)
|
||||
{
|
||||
#define BOOT_IMAGE_PATH SDFILE_RES_ROOT_PATH"gx8002.boot"
|
||||
#define BIN_IMAGE_PATH SDFILE_RES_ROOT_PATH"mcu_nor.bin"
|
||||
FILE *fp = NULL;
|
||||
if (img_type == FW_BOOT_IMAGE) {
|
||||
fp = fopen(BOOT_IMAGE_PATH, "r");
|
||||
if (fp) {
|
||||
sdfile_upgrade_info("open %s succ", BOOT_IMAGE_PATH);
|
||||
__this->boot_fp = fp;
|
||||
} else {
|
||||
sdfile_upgrade_info("open %s failed!", BOOT_IMAGE_PATH);
|
||||
return -1;
|
||||
}
|
||||
} else if (img_type == FW_FLASH_IMAGE) {
|
||||
fp = fopen(BIN_IMAGE_PATH, "r");
|
||||
if (fp) {
|
||||
sdfile_upgrade_info("open %s succ", BIN_IMAGE_PATH);
|
||||
__this->bin_fp = fp;
|
||||
} else {
|
||||
sdfile_upgrade_info("open %s failed!", BIN_IMAGE_PATH);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fw_stream_close(FW_IMAGE_TYPE img_type)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (img_type == FW_BOOT_IMAGE) {
|
||||
if (__this->boot_fp) {
|
||||
fclose(__this->boot_fp);
|
||||
__this->boot_fp = NULL;
|
||||
}
|
||||
} else if (img_type == FW_FLASH_IMAGE) {
|
||||
if (__this->bin_fp) {
|
||||
fclose(__this->bin_fp);
|
||||
__this->bin_fp = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fw_stream_read(FW_IMAGE_TYPE img_type, unsigned char *buf, unsigned int len)
|
||||
{
|
||||
int ret = 0;
|
||||
FILE *fp = NULL;
|
||||
|
||||
if (img_type == FW_BOOT_IMAGE) {
|
||||
fp = __this->boot_fp;
|
||||
} else if (img_type == FW_FLASH_IMAGE) {
|
||||
fp = __this->bin_fp;
|
||||
}
|
||||
|
||||
if (fp) {
|
||||
ret = fread(fp, buf, len);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fw_stream_get_flash_img_info(flash_img_info_t *info)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (info == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (__this->bin_fp) {
|
||||
info->img_size = flen(__this->bin_fp);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
///////// status info /////////////
|
||||
static const char *status_info_str[UPGRADE_STAGE_NONE][UPGRADE_STATUS_NONE] = {
|
||||
// UPGRADE_STAGE_HANDSHAKE
|
||||
{"handshake start\n", NULL, "handshake ok\n", "handshake err\n"},
|
||||
// UPGRADE_STAGE_BOOT_HEADER
|
||||
{"boot header start\n", NULL, "boot header ok\n", "boot header err\n"},
|
||||
// UPGRADE_STAGE_BOOT_S1
|
||||
{"boot stage1 start\n", "boot stage1 downloading\n", "boot stage1 ok\n", "boot stage1 err\n"},
|
||||
// UPGRADE_STAGE_BOOT_S2
|
||||
{"boot stage2 start\n", "boot stage2 downloading\n", "boot stage2 ok\n", "boot stage2 err\n"},
|
||||
// UPGRADE_STAGE_FLASH_IMG
|
||||
{"flash img start\n", "flash img downloading\n", "flash img ok\n", "flash img err\n"},
|
||||
};
|
||||
|
||||
static void gx8002_upgrade_status_cb(upgrade_stage_e stage, upgrade_status_e status)
|
||||
{
|
||||
const char *reply_str = status_info_str[stage][status];
|
||||
if (reply_str != NULL) {
|
||||
sdfile_upgrade_info("status info: %s\n", reply_str);
|
||||
}
|
||||
}
|
||||
|
||||
static int gx8002_upgrade_task(void *param)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
sdfile_upgrade_info("---- gx8002 ota start ----");
|
||||
gx8002_upgrade_cold_reset();
|
||||
|
||||
ret = gx_uart_upgrade_proc();
|
||||
|
||||
gx8002_normal_cold_reset();
|
||||
sdfile_upgrade_info("---- gx8002 ota over ----");
|
||||
|
||||
if (ret < 0) {
|
||||
gx8002_update_end_post_msg(0);
|
||||
} else {
|
||||
gx8002_update_end_post_msg(1);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int gx8002_uart_sdfile_ota_init(void)
|
||||
{
|
||||
upgrade_uart_t uart_ops;
|
||||
|
||||
uart_ops.open = gx_upgrade_uart_porting_open;
|
||||
uart_ops.close = gx_upgrade_uart_porting_close;
|
||||
uart_ops.send = gx_upgrade_uart_porting_write;
|
||||
uart_ops.wait_reply = gx_uart_upgrade_porting_wait_reply;
|
||||
|
||||
fw_stream_t fw_stream_ops;
|
||||
fw_stream_ops.open = fw_stream_open;
|
||||
fw_stream_ops.close = fw_stream_close;
|
||||
fw_stream_ops.read = fw_stream_read;
|
||||
fw_stream_ops.get_flash_img_info = fw_stream_get_flash_img_info;
|
||||
|
||||
gx_uart_upgrade_init(&uart_ops, &fw_stream_ops, gx8002_upgrade_status_cb);
|
||||
|
||||
gx8002_upgrade_task(NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else /* #if GX8002_UPGRADE_SDFILE_TOGGLE */
|
||||
|
||||
int gx8002_uart_sdfile_ota_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* #if GX8002_UPGRADE_SDFILE_TOGGLE */
|
||||
|
||||
@ -0,0 +1,239 @@
|
||||
#include "includes.h"
|
||||
#include "gx_fifo.h"
|
||||
|
||||
#define os_mutex_t OS_MUTEX *
|
||||
#define gx_os_mutex_lock os_mutex_pend
|
||||
#define gx_os_mutex_unlock os_mutex_post
|
||||
|
||||
#define os_sem_t OS_SEM *
|
||||
#define gx_os_sem_post os_sem_post
|
||||
#define gx_os_sem_wait os_sem_pend
|
||||
|
||||
typedef struct {
|
||||
char *data;
|
||||
unsigned int length;
|
||||
} fifoBlock;
|
||||
|
||||
typedef struct {
|
||||
int fifo_head;
|
||||
int fifo_tail;
|
||||
int block_num;
|
||||
int block_total;
|
||||
int block_size;
|
||||
fifoBlock *fifo_block;
|
||||
os_mutex_t fifo_mutex;
|
||||
os_sem_t fifo_sem;
|
||||
} GxFIFO;
|
||||
|
||||
|
||||
//======================== OS porting ======================================//
|
||||
static void *gx_os_calloc(u32 nmemb, u32 size)
|
||||
{
|
||||
return zalloc(nmemb * size);
|
||||
}
|
||||
|
||||
static void gx_os_free(void *p)
|
||||
{
|
||||
if (p) {
|
||||
free(p);
|
||||
}
|
||||
}
|
||||
|
||||
static os_mutex_t gx_os_mutex_create()
|
||||
{
|
||||
os_mutex_t mutex;
|
||||
mutex = (os_mutex_t)gx_os_calloc((sizeof(*mutex)), 1);
|
||||
|
||||
ASSERT(mutex, "mutex alloc err");
|
||||
|
||||
os_mutex_create(mutex);
|
||||
|
||||
return mutex;
|
||||
}
|
||||
|
||||
static void gx_os_mutex_destroy(os_mutex_t mutex)
|
||||
{
|
||||
if (mutex) {
|
||||
os_mutex_del(mutex, 0);
|
||||
gx_os_free(mutex);
|
||||
}
|
||||
}
|
||||
|
||||
static os_sem_t gx_os_sem_create(u32 cnt)
|
||||
{
|
||||
os_sem_t sem;
|
||||
sem = (os_mutex_t)gx_os_calloc((sizeof(*sem)), 1);
|
||||
|
||||
ASSERT(sem, "sem alloc err");
|
||||
|
||||
os_sem_create(sem, cnt);
|
||||
|
||||
return sem;
|
||||
}
|
||||
|
||||
static void gx_os_sem_destroy(os_sem_t sem)
|
||||
{
|
||||
if (sem) {
|
||||
os_sem_del(sem, 0);
|
||||
gx_os_free(sem);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//==============================================================//
|
||||
|
||||
int gx_fifo_destroy(fifo_handle_t fifo)
|
||||
{
|
||||
GxFIFO *temp_fifo = (GxFIFO *)fifo;
|
||||
int i = 0;
|
||||
|
||||
if (temp_fifo == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
gx_os_mutex_lock(temp_fifo->fifo_mutex, 0);
|
||||
if (temp_fifo->fifo_block != NULL) {
|
||||
for (i = 0; i < temp_fifo->block_total; i++) {
|
||||
if (temp_fifo->fifo_block[i].data != NULL) {
|
||||
gx_os_free(temp_fifo->fifo_block[i].data);
|
||||
temp_fifo->fifo_block[i].data = NULL;
|
||||
}
|
||||
}
|
||||
gx_os_free(temp_fifo->fifo_block);
|
||||
temp_fifo->fifo_block = NULL;
|
||||
}
|
||||
|
||||
gx_os_sem_destroy(temp_fifo->fifo_sem);
|
||||
gx_os_mutex_destroy(temp_fifo->fifo_mutex);
|
||||
|
||||
gx_os_free(temp_fifo);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
fifo_handle_t gx_fifo_create(int block_size, int block_num)
|
||||
{
|
||||
GxFIFO *temp_fifo = NULL;
|
||||
int i = 0;
|
||||
|
||||
if ((block_size == 0) || (block_num == 0)) {
|
||||
goto fifo_failed;
|
||||
}
|
||||
|
||||
if ((temp_fifo = (GxFIFO *)gx_os_calloc(sizeof(GxFIFO), 1)) == NULL) {
|
||||
goto fifo_failed;
|
||||
}
|
||||
|
||||
if ((temp_fifo->fifo_block = (fifoBlock *)gx_os_calloc(block_num * sizeof(fifoBlock), 1)) == NULL) {
|
||||
goto fifo_failed;
|
||||
}
|
||||
|
||||
temp_fifo->fifo_mutex = gx_os_mutex_create();
|
||||
temp_fifo->fifo_sem = gx_os_sem_create(0);
|
||||
|
||||
for (i = 0; i < block_num; i++) {
|
||||
if ((temp_fifo->fifo_block[i].data = (char *)gx_os_calloc(block_size, 1)) == NULL) {
|
||||
goto fifo_failed;
|
||||
}
|
||||
}
|
||||
|
||||
temp_fifo->block_total = block_num;
|
||||
temp_fifo->block_size = block_size;
|
||||
temp_fifo->fifo_head = 0;
|
||||
temp_fifo->fifo_tail = -1;
|
||||
|
||||
return (fifo_handle_t)temp_fifo;
|
||||
|
||||
fifo_failed:
|
||||
gx_fifo_destroy((fifo_handle_t)temp_fifo);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gx_fifo_write(fifo_handle_t fifo, const char *write_data, int write_size)
|
||||
{
|
||||
GxFIFO *temp_fifo = (GxFIFO *)fifo;
|
||||
int cp_size = 0;
|
||||
|
||||
if ((temp_fifo == NULL) || (write_data == NULL) || (write_size == 0)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
gx_os_mutex_lock(temp_fifo->fifo_mutex, 0);
|
||||
if (temp_fifo->block_num >= temp_fifo->block_total) {
|
||||
printf("[%s]%d: fifo full!!!\n", __func__, __LINE__);
|
||||
gx_os_mutex_unlock(temp_fifo->fifo_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
temp_fifo->fifo_tail++;
|
||||
if (temp_fifo->fifo_tail >= temp_fifo->block_total) {
|
||||
temp_fifo->fifo_tail = 0;
|
||||
}
|
||||
|
||||
(write_size >= temp_fifo->block_size)
|
||||
? (cp_size = temp_fifo->block_size) : (cp_size = write_size);
|
||||
memcpy(temp_fifo->fifo_block[temp_fifo->fifo_tail].data, write_data, cp_size);
|
||||
temp_fifo->fifo_block[temp_fifo->fifo_tail].length = cp_size;
|
||||
#if 1
|
||||
if (temp_fifo->block_num == 0) {
|
||||
//printf("[%s]%d new data: %d!!!\n", __func__, __LINE__, os_sem_query(temp_fifo->fifo_sem));
|
||||
gx_os_sem_post(temp_fifo->fifo_sem);
|
||||
}
|
||||
#endif
|
||||
temp_fifo->block_num++;
|
||||
|
||||
// gx_os_sem_post(temp_fifo->fifo_sem);
|
||||
gx_os_mutex_unlock(temp_fifo->fifo_mutex);
|
||||
|
||||
return cp_size;
|
||||
}
|
||||
|
||||
int gx_fifo_read(fifo_handle_t fifo, char *read_data, int read_size, int timeout)
|
||||
{
|
||||
GxFIFO *temp_fifo = (GxFIFO *)fifo;
|
||||
int cp_size = 0;
|
||||
|
||||
if ((temp_fifo == NULL) || (read_data == NULL) || (read_size == 0)) {
|
||||
return 0;
|
||||
}
|
||||
#if 0
|
||||
int ret = gx_os_sem_wait(temp_fifo->fifo_sem, timeout);
|
||||
if (ret != 0) {
|
||||
printf("[%s]%d: wait data timeout: %d !!!!!!!\n", __func__, __LINE__, ret);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
gx_os_mutex_lock(temp_fifo->fifo_mutex, 0);
|
||||
|
||||
while (temp_fifo->block_num == 0) {
|
||||
//printf("[%s]%d: fifo empty: %d!!!\n", __func__, __LINE__, gx_os_sem_query(temp_fifo->fifo_sem));
|
||||
gx_os_mutex_unlock(temp_fifo->fifo_mutex);
|
||||
|
||||
if (gx_os_sem_wait(temp_fifo->fifo_sem, timeout) != 0) {
|
||||
printf("[%s]%d: wait data timeout !!!!!!!\n", __func__, __LINE__);
|
||||
return 0;
|
||||
}
|
||||
//os_sem_pend(&temp_fifo->fifo_sem, 0);
|
||||
//os_mutex_pend(&temp_fifo->fifo_mutex, 0);
|
||||
gx_os_mutex_lock(temp_fifo->fifo_mutex, 0);
|
||||
//printf("[%s]%d, fifo has data: %d!!!\n", __func__, __LINE__, os_sem_query(&temp_fifo->fifo_sem));
|
||||
//return 0;
|
||||
}
|
||||
|
||||
(read_size >= temp_fifo->fifo_block[temp_fifo->fifo_head].length)
|
||||
? (cp_size = temp_fifo->fifo_block[temp_fifo->fifo_head].length) : (cp_size = read_size);
|
||||
memcpy(read_data, temp_fifo->fifo_block[temp_fifo->fifo_head].data, cp_size);
|
||||
read_size = temp_fifo->fifo_block[temp_fifo->fifo_head].length;
|
||||
|
||||
temp_fifo->fifo_head++;
|
||||
if (temp_fifo->fifo_head >= temp_fifo->block_total) {
|
||||
temp_fifo->fifo_head = 0;
|
||||
}
|
||||
|
||||
temp_fifo->block_num--;
|
||||
|
||||
gx_os_mutex_unlock(temp_fifo->fifo_mutex);
|
||||
|
||||
return cp_size;
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
#ifndef __GX_FIFO_H__
|
||||
#define __GX_FIFO_H__
|
||||
|
||||
typedef int fifo_handle_t;
|
||||
fifo_handle_t gx_fifo_create(int block_size, int block_num);
|
||||
int gx_fifo_destroy(fifo_handle_t fifo);
|
||||
int gx_fifo_write(fifo_handle_t fifo, const char *write_data, int write_size);
|
||||
int gx_fifo_read(fifo_handle_t fifo, char *read_data, int read_size, int timeout);
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,249 @@
|
||||
#include "includes.h"
|
||||
#include "../gx_uart_upgrade.h"
|
||||
#include "../../gx8002_npu_api.h"
|
||||
#include "../gx_uart_upgrade_porting.h"
|
||||
#include "btstack/avctp_user.h"
|
||||
#include "classic/hci_lmp.h"
|
||||
#include "gx_fifo.h"
|
||||
|
||||
#if GX8002_UPGRADE_SPP_TOGGLE
|
||||
|
||||
#define spp_upgrade_info g_printf
|
||||
|
||||
//=============== SPP Porting ================//
|
||||
int gx8002_ota_recv(unsigned char *data, int size);
|
||||
static void gx8002_spp_data_handler(u8 packet_type, u16 ch, u8 *packet, u16 size)
|
||||
{
|
||||
switch (packet_type) {
|
||||
case 1:
|
||||
/* cbuf_init(&spp_buf_hdl, spp_buf, sizeof(spp_buf)); */
|
||||
/* spp_timer = sys_timer_add(NULL, spp_send_data_timer, 50); */
|
||||
/* spp_printf("spp connect\n"); */
|
||||
spp_upgrade_info("gx8002 spp connect\n");
|
||||
break;
|
||||
case 2:
|
||||
spp_upgrade_info("gx8002 spp disconnect\n");
|
||||
/* if (spp_timer) { */
|
||||
/* sys_timer_del(spp_timer); */
|
||||
/* spp_timer = 0; */
|
||||
/* } */
|
||||
break;
|
||||
case 7:
|
||||
//spp_upgrade_info("gx8002 spp_rx: %d", size);
|
||||
//put_buf(packet,size);
|
||||
gx8002_ota_recv(packet, size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void gx8002_spp_send_data(u8 *data, u32 size)
|
||||
{
|
||||
user_send_cmd_prepare(USER_CTRL_SPP_SEND_DATA, size, data);
|
||||
}
|
||||
|
||||
|
||||
void gx8002_spp_ota_init(void)
|
||||
{
|
||||
spp_data_deal_handle_register(gx8002_spp_data_handler);
|
||||
}
|
||||
|
||||
////////////// FW Stream Porting //////////////////
|
||||
#define STREAM_FIFO_BLOCK_TOTAL 16
|
||||
#define STREAM_FIFO_TIMEOUT_MS (5000 / 10)
|
||||
|
||||
/* typedef int (*reply)(unsigned char *data, int size); */
|
||||
static int ota_start = 0;
|
||||
//static os_sem_t ota_sem;
|
||||
static fifo_handle_t fw_fifo;
|
||||
|
||||
static int gx8002_ota_start(void)
|
||||
{
|
||||
if (!ota_start) {
|
||||
os_taskq_post_msg("gx8002", 2, GX8002_MSG_UPDATE, GX8002_UPDATE_TYPE_SPP);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_gx8002_ota_start(void)
|
||||
{
|
||||
return ota_start;
|
||||
}
|
||||
|
||||
int gx8002_ota_recv(unsigned char *data, int size)
|
||||
{
|
||||
int i;
|
||||
|
||||
if ((data == NULL) || (size == 0)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (strncmp((char *)data, "startupgrade", strlen("startupgrade")) == 0) {
|
||||
gx8002_ota_start();
|
||||
} else {
|
||||
if (ota_start) {
|
||||
if (fw_fifo > 0) {
|
||||
int cnt = size / UPGRADE_PACKET_SIZE;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < cnt; i++) {
|
||||
gx_fifo_write(fw_fifo, (const char *)&data[UPGRADE_PACKET_SIZE * i], UPGRADE_PACKET_SIZE);
|
||||
}
|
||||
|
||||
if (size % UPGRADE_PACKET_SIZE) {
|
||||
gx_fifo_write(fw_fifo, (const char *)&data[UPGRADE_PACKET_SIZE * i], size % UPGRADE_PACKET_SIZE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int fw_stream_open(FW_IMAGE_TYPE img_type)
|
||||
{
|
||||
if (fw_fifo == 0) {
|
||||
if ((fw_fifo = gx_fifo_create(UPGRADE_PACKET_SIZE, STREAM_FIFO_BLOCK_TOTAL)) == 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fw_stream_close(FW_IMAGE_TYPE img_type)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (fw_fifo > 0) {
|
||||
ret = gx_fifo_destroy(fw_fifo);
|
||||
fw_fifo = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fw_stream_read(FW_IMAGE_TYPE img_type, unsigned char *buf, unsigned int len)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (fw_fifo > 0) {
|
||||
ret = gx_fifo_read(fw_fifo, (char *)buf, len, STREAM_FIFO_TIMEOUT_MS);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fw_stream_get_flash_img_info(flash_img_info_t *info)
|
||||
{
|
||||
unsigned int size = 0;
|
||||
|
||||
if (info == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fw_fifo == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ret = gx_fifo_read(fw_fifo, (char *)info, sizeof(flash_img_info_t), STREAM_FIFO_TIMEOUT_MS);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
///////// status info /////////////
|
||||
static const char *status_info_str[UPGRADE_STAGE_NONE][UPGRADE_STATUS_NONE] = {
|
||||
// UPGRADE_STAGE_HANDSHAKE
|
||||
{"handshake start\n", NULL, "handshake ok\n", "handshake err\n"},
|
||||
// UPGRADE_STAGE_BOOT_HEADER
|
||||
{"boot header start\n", NULL, "boot header ok\n", "boot header err\n"},
|
||||
// UPGRADE_STAGE_BOOT_S1
|
||||
{"boot stage1 start\n", "boot stage1 downloading\n", "boot stage1 ok\n", "boot stage1 err\n"},
|
||||
// UPGRADE_STAGE_BOOT_S2
|
||||
{"boot stage2 start\n", "boot stage2 downloading\n", "boot stage2 ok\n", "boot stage2 err\n"},
|
||||
// UPGRADE_STAGE_FLASH_IMG
|
||||
{"flash img start\n", "flash img downloading\n", "flash img ok\n", "flash img err\n"},
|
||||
};
|
||||
|
||||
static void gx8002_upgrade_status_cb(upgrade_stage_e stage, upgrade_status_e status)
|
||||
{
|
||||
//printf("---- [%s]: stage: %d, status: %d ----\n", __func__, stage, status);
|
||||
const char *reply_str = status_info_str[stage][status];
|
||||
if (reply_str != NULL) {
|
||||
spp_upgrade_info("status info: %s\n", reply_str);
|
||||
//user_spp_send_data((unsigned char *)reply_str, strlen(reply_str));
|
||||
gx8002_spp_send_data((u8 *)reply_str, strlen(reply_str));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int gx8002_upgrade_task(void *param)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
spp_upgrade_info("---- gx8002 ota start ----");
|
||||
gx8002_upgrade_cold_reset();
|
||||
|
||||
ret = gx_uart_upgrade_proc();
|
||||
|
||||
gx8002_normal_cold_reset();
|
||||
spp_upgrade_info("---- gx8002 ota over ----");
|
||||
|
||||
ota_start = 0;
|
||||
|
||||
if (ret < 0) {
|
||||
gx8002_update_end_post_msg(0);
|
||||
} else {
|
||||
gx8002_update_end_post_msg(1);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int gx8002_uart_spp_ota_init(void)
|
||||
{
|
||||
upgrade_uart_t uart_ops;
|
||||
fw_stream_t fw_stream_ops;
|
||||
|
||||
uart_ops.open = gx_upgrade_uart_porting_open;
|
||||
uart_ops.close = gx_upgrade_uart_porting_close;
|
||||
uart_ops.send = gx_upgrade_uart_porting_write;
|
||||
uart_ops.wait_reply = gx_uart_upgrade_porting_wait_reply;
|
||||
|
||||
|
||||
fw_stream_ops.open = fw_stream_open;
|
||||
fw_stream_ops.close = fw_stream_close;
|
||||
fw_stream_ops.read = fw_stream_read;
|
||||
fw_stream_ops.get_flash_img_info = fw_stream_get_flash_img_info;
|
||||
|
||||
gx_uart_upgrade_init(&uart_ops, &fw_stream_ops, gx8002_upgrade_status_cb);
|
||||
|
||||
ota_start = 1;
|
||||
|
||||
gx8002_upgrade_task(NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else /* #if GX8002_UPGRADE_SPP_TOGGLE */
|
||||
|
||||
int gx8002_uart_spp_ota_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int get_gx8002_ota_start(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gx8002_ota_recv(unsigned char *data, int size)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* #if GX8002_UPGRADE_SPP_TOGGLE */
|
||||
64
apps/common/device/imu_sensor/icm_42670p/InvError.h
Normal file
64
apps/common/device/imu_sensor/icm_42670p/InvError.h
Normal file
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* ________________________________________________________________________________________________________
|
||||
* Copyright (c) 2015-2015 InvenSense Inc. All rights reserved.
|
||||
*
|
||||
* This software, related documentation and any modifications thereto (collectively “Software”) is subject
|
||||
* to InvenSense and its licensors' intellectual property rights under U.S. and international copyright
|
||||
* and other intellectual property rights laws.
|
||||
*
|
||||
* InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software
|
||||
* and any use, reproduction, disclosure or distribution of the Software without an express license agreement
|
||||
* from InvenSense is strictly prohibited.
|
||||
*
|
||||
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, 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 NON-INFRINGEMENT.
|
||||
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, IN NO EVENT SHALL
|
||||
* INVENSENSE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY
|
||||
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
||||
* OF THE SOFTWARE.
|
||||
* ________________________________________________________________________________________________________
|
||||
*/
|
||||
|
||||
/** @defgroup InvError Error code
|
||||
* @brief Common error code
|
||||
*
|
||||
* @ingroup EmbUtils
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _INV_ERROR_H_
|
||||
#define _INV_ERROR_H_
|
||||
|
||||
/** @brief Common error code definition
|
||||
*/
|
||||
enum inv_error {
|
||||
INV_ERROR_SUCCESS = 0, /**< no error */
|
||||
INV_ERROR = -1, /**< unspecified error */
|
||||
INV_ERROR_NIMPL = -2, /**< function not implemented for given
|
||||
arguments */
|
||||
INV_ERROR_TRANSPORT = -3, /**< error occurred at transport level */
|
||||
INV_ERROR_TIMEOUT = -4, /**< action did not complete in the expected
|
||||
time window */
|
||||
INV_ERROR_SIZE = -5, /**< size/length of given arguments is not
|
||||
suitable to complete requested action */
|
||||
INV_ERROR_OS = -6, /**< error related to OS */
|
||||
INV_ERROR_IO = -7, /**< error related to IO operation */
|
||||
INV_ERROR_MEM = -9, /**< not enough memory to complete requested
|
||||
action */
|
||||
INV_ERROR_HW = -10, /**< error at HW level */
|
||||
INV_ERROR_BAD_ARG = -11, /**< provided arguments are not good to
|
||||
perform requested action */
|
||||
INV_ERROR_UNEXPECTED = -12, /**< something unexpected happened */
|
||||
INV_ERROR_FILE = -13, /**< cannot access file or unexpected format */
|
||||
INV_ERROR_PATH = -14, /**< invalid file path */
|
||||
INV_ERROR_IMAGE_TYPE = -15, /**< error when image type is not managed */
|
||||
INV_ERROR_WATCHDOG = -16, /**< error when device doesn't respond
|
||||
to ping */
|
||||
};
|
||||
|
||||
#endif /* _INV_ERROR_H_ */
|
||||
|
||||
/** @} */
|
||||
|
||||
1037
apps/common/device/imu_sensor/icm_42670p/icm_42670p.c
Normal file
1037
apps/common/device/imu_sensor/icm_42670p/icm_42670p.c
Normal file
File diff suppressed because it is too large
Load Diff
129
apps/common/device/imu_sensor/icm_42670p/icm_42670p.h
Normal file
129
apps/common/device/imu_sensor/icm_42670p/icm_42670p.h
Normal file
@ -0,0 +1,129 @@
|
||||
#ifndef _ICM_42670P_H_
|
||||
#define _ICM_42670P_H_
|
||||
#include "typedef.h"
|
||||
|
||||
|
||||
|
||||
#define ICM42670P
|
||||
|
||||
#if TCFG_ICM42670P_ENABLE
|
||||
|
||||
/*打开这个宏后,fifo读到的数据为
|
||||
(6(acc[s16])+6(gyro[s16]))
|
||||
*/
|
||||
#define ICM42670P_FIFO_DATA_FIT 1
|
||||
|
||||
|
||||
/******************************************************************
|
||||
* user config ICM42670P Macro Definition
|
||||
******************************************************************/
|
||||
#define ICM42670P_USE_I2C 0 /*IIC.(<=1MHz) */
|
||||
#define ICM42670P_USE_SPI 1 /*SPI.(<=24MHz) */
|
||||
#define ICM42670P_USER_INTERFACE TCFG_ICM42670P_INTERFACE_TYPE//ICM42670P_USE_I2C
|
||||
// #define ICM42670P_USER_INTERFACE ICM42670P_USE_SPI
|
||||
#define ICM42670P_SA0_IIC_ADDR 1 //1:iic模式SA0接VCC, 0:iic模式SA0接GND
|
||||
//int io config
|
||||
// #define ICM42670P_INT_IO1 IO_PORTB_03//TCFG_IOKEY_POWER_ONE_PORT //
|
||||
// #define ICM42670P_INT_IO1 IO_PORTA_06 //
|
||||
// #define ICM42670P_INT_READ_IO1() gpio_read(ICM42670P_INT_IO1)
|
||||
|
||||
|
||||
// #define ICM42670P_USE_FIFO_EN 1 //0:disable fifo 1:enable fifo(fifo size:512 bytes)
|
||||
#define ICM42670P_USE_INT_EN 0 //0:disable //中断方式不成功,疑硬件问题
|
||||
// #define ICM42670P_USE_WOM_EN 0 //0:disable
|
||||
// #define ICM42670P_USE_FSYNC_EN 0 //0:disable
|
||||
|
||||
#define SCALED_DATA_G_DPS 0 //1:output decode data; 0:Output raw data
|
||||
//解码后数据: 8(timer[u64])+12(acc[float])+12(gyro[float])+4(temp[float])
|
||||
//原始数据 : 8(timer[u64])+12(acc[int32])+12(gyro[int32])+2(temp[int16])
|
||||
/******************************************************************
|
||||
* ICM42670P I2C address Macro Definition
|
||||
* (7bit): (0x37)011 0111@SDO=1; (0x36)011 0110@SDO=0;
|
||||
******************************************************************/
|
||||
#if ICM42670P_SA0_IIC_ADDR
|
||||
#define ICM42670P_SLAVE_ADDRESS (0x69<<1)//0XD0
|
||||
#else
|
||||
#define ICM42670P_SLAVE_ADDRESS (0x68<<1)//0XD2
|
||||
#endif
|
||||
|
||||
typedef u32(*IMU_read)(unsigned char devAddr,
|
||||
unsigned char regAddr,
|
||||
unsigned char *readBuf,
|
||||
u32 readLen);
|
||||
typedef u32(*IMU_write)(unsigned char devAddr,
|
||||
unsigned char regAddr,
|
||||
unsigned char *writeBuf,
|
||||
u32 writeLen);
|
||||
|
||||
typedef struct {
|
||||
// u8 comms; //0:IIC; 1:SPI //改为宏控制
|
||||
#if (ICM42670P_USER_INTERFACE==ICM42670P_USE_I2C)
|
||||
u8 iic_hdl;
|
||||
u8 iic_delay; //这个延时并非影响iic的时钟频率,而是2Byte数据之间的延时
|
||||
// u8 iic_clk; //iic_clk: <=400kHz
|
||||
#elif (ICM42670P_USER_INTERFACE==ICM42670P_USE_SPI)
|
||||
u8 spi_hdl; //SPIx (role:master)
|
||||
u8 spi_cs_pin; //
|
||||
//u8 spi_work_mode;//icm42670p only suspport 4wire(SPI_MODE_BIDIR_1BIT) (与spi结构体一样)
|
||||
// u8 port; //SPIx group:A,B,C,D (spi结构体)
|
||||
// U8 spi_clk; //spi_clk: <=8MHz (spi结构体)
|
||||
|
||||
#endif
|
||||
} icm42670p_param;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Select communication link between SmartMotion and IMU
|
||||
*/
|
||||
#if (ICM42670P_USER_INTERFACE==ICM42670P_USE_I2C)
|
||||
#define SERIF_TYPE UI_I2C
|
||||
#elif (ICM42670P_USER_INTERFACE==ICM42670P_USE_SPI)
|
||||
#define SERIF_TYPE UI_SPI4
|
||||
// #define SERIF_TYPE UI_SPI3
|
||||
#endif
|
||||
/*
|
||||
* Set power mode flag
|
||||
* Set this flag to run example in low-noise mode.
|
||||
* Reset this flag to run example in low-power mode.
|
||||
* Note: low-noise mode is not available with sensor data frequencies less than 12.5Hz.
|
||||
*/
|
||||
#define USE_LOW_NOISE_MODE 1
|
||||
/*
|
||||
* Select Fifo resolution Mode (default is low resolution mode)
|
||||
* Low resolution mode: 16 bits data format
|
||||
* High resolution mode: 20 bits data format
|
||||
* Warning: Enabling High Res mode will force FSR to 16g and 2000dps
|
||||
*/
|
||||
#define USE_HIGH_RES_MODE 0
|
||||
/*
|
||||
* Select to use FIFO or to read data from registers
|
||||
*/
|
||||
#define USE_FIFO 1
|
||||
|
||||
enum inv_msg_level {
|
||||
INV_MSG_LEVEL_OFF = 0,
|
||||
INV_MSG_LEVEL_ERROR,
|
||||
INV_MSG_LEVEL_WARNING,
|
||||
INV_MSG_LEVEL_INFO,
|
||||
INV_MSG_LEVEL_VERBOSE,
|
||||
INV_MSG_LEVEL_DEBUG,
|
||||
INV_MSG_LEVEL_MAX
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif /*TCFG_ICM42670P_ENABLE*/
|
||||
#endif /*_ICM_42670P_H_*/
|
||||
|
||||
374
apps/common/device/imu_sensor/icm_42670p/inv_imu_apex.c
Normal file
374
apps/common/device/imu_sensor/icm_42670p/inv_imu_apex.c
Normal file
@ -0,0 +1,374 @@
|
||||
/*
|
||||
* ________________________________________________________________________________________________________
|
||||
* Copyright (c) 2017 InvenSense Inc. All rights reserved.
|
||||
*
|
||||
* This software, related documentation and any modifications thereto (collectively "Software") is subject
|
||||
* to InvenSense and its licensors' intellectual property rights under U.S. and international copyright
|
||||
* and other intellectual property rights laws.
|
||||
*
|
||||
* InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software
|
||||
* and any use, reproduction, disclosure or distribution of the Software without an express license agreement
|
||||
* from InvenSense is strictly prohibited.
|
||||
*
|
||||
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, 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 NON-INFRINGEMENT.
|
||||
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, IN NO EVENT SHALL
|
||||
* INVENSENSE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY
|
||||
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
||||
* OF THE SOFTWARE.
|
||||
* ________________________________________________________________________________________________________
|
||||
*/
|
||||
|
||||
#include "inv_imu_defs.h"
|
||||
#include "inv_imu_extfunc.h"
|
||||
#include "inv_imu_driver.h"
|
||||
#include "inv_imu_apex.h"
|
||||
|
||||
int inv_imu_apex_enable_ff(struct inv_imu_device *s)
|
||||
{
|
||||
int status = 0;
|
||||
uint8_t value;
|
||||
|
||||
status |= inv_imu_start_dmp(s);
|
||||
|
||||
status |= inv_imu_read_reg(s, APEX_CONFIG1, 1, &value);
|
||||
value &= ~APEX_CONFIG1_FF_ENABLE_MASK;
|
||||
value |= (uint8_t)APEX_CONFIG1_FF_ENABLE_EN;
|
||||
status |= inv_imu_write_reg(s, APEX_CONFIG1, 1, &value);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int inv_imu_apex_disable_ff(struct inv_imu_device *s)
|
||||
{
|
||||
int status = 0;
|
||||
uint8_t value;
|
||||
|
||||
status |= inv_imu_read_reg(s, APEX_CONFIG1, 1, &value);
|
||||
value &= ~APEX_CONFIG1_FF_ENABLE_MASK;
|
||||
value |= (uint8_t)APEX_CONFIG1_FF_ENABLE_DIS;
|
||||
status |= inv_imu_write_reg(s, APEX_CONFIG1, 1, &value);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int inv_imu_apex_enable_smd(struct inv_imu_device *s)
|
||||
{
|
||||
int status = 0;
|
||||
uint8_t value;
|
||||
|
||||
status |= inv_imu_start_dmp(s);
|
||||
|
||||
status |= inv_imu_read_reg(s, APEX_CONFIG1, 1, &value);
|
||||
value &= ~APEX_CONFIG1_SMD_ENABLE_MASK;
|
||||
value |= (uint8_t)APEX_CONFIG1_SMD_ENABLE_EN;
|
||||
status |= inv_imu_write_reg(s, APEX_CONFIG1, 1, &value);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int inv_imu_apex_disable_smd(struct inv_imu_device *s)
|
||||
{
|
||||
int status = 0;
|
||||
uint8_t value;
|
||||
|
||||
status |= inv_imu_read_reg(s, APEX_CONFIG1, 1, &value);
|
||||
value &= ~APEX_CONFIG1_SMD_ENABLE_MASK;
|
||||
value |= (uint8_t)APEX_CONFIG1_SMD_ENABLE_DIS;
|
||||
status |= inv_imu_write_reg(s, APEX_CONFIG1, 1, &value);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int inv_imu_apex_init_parameters_struct(struct inv_imu_device *s, inv_imu_apex_parameters_t *apex_inputs)
|
||||
{
|
||||
int status = 0;
|
||||
(void)s;
|
||||
|
||||
/* Default parameters at POR */
|
||||
apex_inputs->pedo_amp_th = APEX_CONFIG3_PEDO_AMP_TH_62_MG;
|
||||
apex_inputs->pedo_step_cnt_th = 0x5;
|
||||
apex_inputs->pedo_step_det_th = 0x2;
|
||||
apex_inputs->pedo_sb_timer_th = APEX_CONFIG4_PEDO_SB_TIMER_TH_150_SAMPLES;
|
||||
apex_inputs->pedo_hi_enrgy_th = APEX_CONFIG4_PEDO_HI_ENRGY_TH_104_MG;
|
||||
apex_inputs->tilt_wait_time = APEX_CONFIG5_TILT_WAIT_TIME_4_S;
|
||||
apex_inputs->power_save_time = APEX_CONFIG2_DMP_POWER_SAVE_TIME_SEL_8_S;
|
||||
apex_inputs->power_save = APEX_CONFIG0_DMP_POWER_SAVE_EN;
|
||||
apex_inputs->sensitivity_mode = APEX_CONFIG9_SENSITIVITY_MODE_NORMAL;
|
||||
apex_inputs->low_energy_amp_th = APEX_CONFIG2_LOW_ENERGY_AMP_TH_SEL_80_MG;
|
||||
apex_inputs->smd_sensitivity = APEX_CONFIG9_SMD_SENSITIVITY_0;
|
||||
apex_inputs->ff_debounce_duration = APEX_CONFIG9_FF_DEBOUNCE_DURATION_2000_MS;
|
||||
apex_inputs->ff_max_duration_cm = APEX_CONFIG12_FF_MAX_DURATION_204_CM;
|
||||
apex_inputs->ff_min_duration_cm = APEX_CONFIG12_FF_MIN_DURATION_10_CM;
|
||||
apex_inputs->lowg_peak_th = APEX_CONFIG10_LOWG_PEAK_TH_563_MG;
|
||||
apex_inputs->lowg_peak_hyst = APEX_CONFIG5_LOWG_PEAK_TH_HYST_156_MG;
|
||||
apex_inputs->lowg_samples_th = APEX_CONFIG10_LOWG_TIME_TH_1_SAMPLE;
|
||||
apex_inputs->highg_peak_th = APEX_CONFIG11_HIGHG_PEAK_TH_2500_MG;
|
||||
apex_inputs->highg_peak_hyst = APEX_CONFIG5_HIGHG_PEAK_TH_HYST_156_MG;
|
||||
apex_inputs->highg_samples_th = APEX_CONFIG11_HIGHG_TIME_TH_1_SAMPLE;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int inv_imu_apex_configure_parameters(struct inv_imu_device *s, const inv_imu_apex_parameters_t *apex_inputs)
|
||||
{
|
||||
int status = 0;
|
||||
uint8_t data;
|
||||
uint8_t apexConfig[7];
|
||||
APEX_CONFIG1_PED_ENABLE_t pedo_state;
|
||||
APEX_CONFIG1_TILT_ENABLE_t tilt_state;
|
||||
APEX_CONFIG1_FF_ENABLE_t ff_state;
|
||||
APEX_CONFIG1_SMD_ENABLE_t smd_state;
|
||||
|
||||
/* DMP cannot be configured if it is running, hence make sure all APEX algorithms are off */
|
||||
status |= inv_imu_read_reg(s, APEX_CONFIG1, 1, &data);
|
||||
pedo_state = (APEX_CONFIG1_PED_ENABLE_t)(data & APEX_CONFIG1_PED_ENABLE_MASK);
|
||||
tilt_state = (APEX_CONFIG1_TILT_ENABLE_t)(data & APEX_CONFIG1_TILT_ENABLE_MASK);
|
||||
ff_state = (APEX_CONFIG1_FF_ENABLE_t)(data & APEX_CONFIG1_FF_ENABLE_MASK);
|
||||
smd_state = (APEX_CONFIG1_SMD_ENABLE_t)(data & APEX_CONFIG1_SMD_ENABLE_MASK);
|
||||
if (pedo_state == APEX_CONFIG1_PED_ENABLE_EN) {
|
||||
return INV_ERROR;
|
||||
}
|
||||
if (tilt_state == APEX_CONFIG1_TILT_ENABLE_EN) {
|
||||
return INV_ERROR;
|
||||
}
|
||||
if (ff_state == APEX_CONFIG1_FF_ENABLE_EN) {
|
||||
return INV_ERROR;
|
||||
}
|
||||
if (smd_state == APEX_CONFIG1_SMD_ENABLE_EN) {
|
||||
return INV_ERROR;
|
||||
}
|
||||
|
||||
|
||||
status |= inv_imu_switch_on_mclk(s);
|
||||
|
||||
/* Power Save mode and low energy amplitude threshold (for Pedometer in Slow Walk mode) */
|
||||
/* APEX_CONFIG2_MREG1 */
|
||||
apexConfig[0] = (uint8_t)apex_inputs->power_save_time
|
||||
| (uint8_t)apex_inputs->low_energy_amp_th;
|
||||
|
||||
/* Pedometer parameters */
|
||||
/* APEX_CONFIG3_MREG1 */
|
||||
apexConfig[1] = (uint8_t)apex_inputs->pedo_amp_th
|
||||
| (apex_inputs->pedo_step_cnt_th & APEX_CONFIG3_PED_STEP_CNT_TH_SEL_MASK);
|
||||
|
||||
/* APEX_CONFIG4_MREG1 */
|
||||
apexConfig[2] = ((apex_inputs->pedo_step_det_th << APEX_CONFIG4_PED_STEP_DET_TH_SEL_POS)
|
||||
& APEX_CONFIG4_PED_STEP_DET_TH_SEL_MASK)
|
||||
| (uint8_t)apex_inputs->pedo_sb_timer_th
|
||||
| (uint8_t)apex_inputs->pedo_hi_enrgy_th;
|
||||
|
||||
/* Tilt, Lowg and highg parameters */
|
||||
/* APEX_CONFIG5_MREG1 */
|
||||
apexConfig[3] = (uint8_t)apex_inputs->tilt_wait_time
|
||||
| (uint8_t)apex_inputs->lowg_peak_hyst
|
||||
| (uint8_t)apex_inputs->highg_peak_hyst;
|
||||
|
||||
status |= inv_imu_write_reg(s, APEX_CONFIG2_MREG1, 4, &apexConfig[0]);
|
||||
|
||||
|
||||
/* APEX_CONFIG0 */
|
||||
status |= inv_imu_read_reg(s, APEX_CONFIG0, 1, &apexConfig[0]);
|
||||
apexConfig[0] &= ~APEX_CONFIG0_DMP_POWER_SAVE_EN_MASK;
|
||||
apexConfig[0] |= apex_inputs->power_save;
|
||||
status |= inv_imu_write_reg(s, APEX_CONFIG0, 1, &apexConfig[0]);
|
||||
|
||||
/* free fall parameter, SMD parameter and parameters for Pedometer in Slow Walk mode */
|
||||
/* APEX_CONFIG9_MREG1 */
|
||||
apexConfig[0] = (uint8_t)apex_inputs->ff_debounce_duration
|
||||
| (uint8_t)apex_inputs->smd_sensitivity
|
||||
| (uint8_t)apex_inputs->sensitivity_mode;
|
||||
|
||||
/* Lowg and highg parameters and free fall parameters */
|
||||
/* APEX_CONFIG10_MREG1 */
|
||||
apexConfig[1] = (uint8_t)apex_inputs->lowg_peak_th
|
||||
| (uint8_t)apex_inputs->lowg_samples_th;
|
||||
|
||||
/* APEX_CONFIG11_MREG1 */
|
||||
apexConfig[2] = (uint8_t)apex_inputs->highg_peak_th
|
||||
| (uint8_t)apex_inputs->highg_samples_th;
|
||||
|
||||
status |= inv_imu_write_reg(s, APEX_CONFIG9_MREG1, 3, &apexConfig[0]);
|
||||
|
||||
|
||||
/* APEX_CONFIG12_MREG1 */
|
||||
apexConfig[0] = (uint8_t)apex_inputs->ff_max_duration_cm
|
||||
| (uint8_t)apex_inputs->ff_min_duration_cm;
|
||||
|
||||
status |= inv_imu_write_reg(s, APEX_CONFIG12_MREG1, 1, &apexConfig[0]);
|
||||
|
||||
status |= inv_imu_switch_off_mclk(s);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int inv_imu_apex_get_parameters(struct inv_imu_device *s, inv_imu_apex_parameters_t *apex_params)
|
||||
{
|
||||
int status = 0;
|
||||
uint8_t data[7];
|
||||
uint8_t value;
|
||||
|
||||
status |= inv_imu_read_reg(s, APEX_CONFIG0, 1, &value);
|
||||
apex_params->power_save = (APEX_CONFIG0_DMP_POWER_SAVE_t)(value & APEX_CONFIG0_DMP_POWER_SAVE_EN_MASK);
|
||||
|
||||
/* Access continuous config registers (CONFIG2-CONFIG11) */
|
||||
status |= inv_imu_read_reg(s, APEX_CONFIG2_MREG1, sizeof(data), &data[0]);
|
||||
|
||||
/* Get params from apex_config2 : dmp_power_save_time and low_energy_amp_th */
|
||||
apex_params->power_save_time = (APEX_CONFIG2_DMP_POWER_SAVE_TIME_t)
|
||||
(data[0] & APEX_CONFIG2_DMP_POWER_SAVE_TIME_SEL_MASK);
|
||||
apex_params->low_energy_amp_th = (APEX_CONFIG2_LOW_ENERGY_AMP_TH_t)
|
||||
(data[0] & APEX_CONFIG2_LOW_ENERGY_AMP_TH_SEL_MASK);
|
||||
|
||||
/* Get params from apex_config3 : pedo_amp_th and pedo_step_cnt_th */
|
||||
apex_params->pedo_amp_th = (APEX_CONFIG3_PEDO_AMP_TH_t)
|
||||
(data[1] & APEX_CONFIG3_PED_AMP_TH_SEL_MASK);
|
||||
apex_params->pedo_step_cnt_th = (data[1] & APEX_CONFIG3_PED_STEP_CNT_TH_SEL_MASK)
|
||||
>> APEX_CONFIG3_PED_STEP_CNT_TH_SEL_POS;
|
||||
|
||||
/* Get params from apex_config4 : pedo_step_det_th, pedo_sb_timer_th and pedo_hi_enrgy_th */
|
||||
apex_params->pedo_step_det_th = (data[2] & APEX_CONFIG4_PED_STEP_DET_TH_SEL_MASK)
|
||||
>> APEX_CONFIG4_PED_STEP_DET_TH_SEL_POS;
|
||||
apex_params->pedo_sb_timer_th = (APEX_CONFIG4_PEDO_SB_TIMER_TH_t)
|
||||
(data[2] & APEX_CONFIG4_PED_SB_TIMER_TH_SEL_MASK);
|
||||
apex_params->pedo_hi_enrgy_th = (APEX_CONFIG4_PEDO_HI_ENRGY_TH_t)
|
||||
(data[2] & APEX_CONFIG4_PED_HI_EN_TH_SEL_MASK);
|
||||
|
||||
/* Get params from apex_config5 : tilt_wait_time, lowg_peak_hyst and highg_peak_hyst */
|
||||
apex_params->tilt_wait_time = (APEX_CONFIG5_TILT_WAIT_TIME_t)
|
||||
(data[3] & APEX_CONFIG5_TILT_WAIT_TIME_SEL_MASK);
|
||||
apex_params->lowg_peak_hyst = (APEX_CONFIG5_LOWG_PEAK_TH_HYST_t)
|
||||
(data[3] & APEX_CONFIG5_LOWG_PEAK_TH_HYST_SEL_MASK);
|
||||
apex_params->highg_peak_hyst = (APEX_CONFIG5_HIGHG_PEAK_TH_HYST_t)
|
||||
(data[3] & APEX_CONFIG5_HIGHG_PEAK_TH_HYST_SEL_MASK);
|
||||
|
||||
/* Get params from apex_config9 : ff_debounce_duration, smd_sensitivity and sensitivity_mode */
|
||||
apex_params->ff_debounce_duration = (APEX_CONFIG9_FF_DEBOUNCE_DURATION_t)
|
||||
(data[4] & APEX_CONFIG9_FF_DEBOUNCE_DURATION_SEL_MASK);
|
||||
apex_params->smd_sensitivity = (APEX_CONFIG9_SMD_SENSITIVITY_t)
|
||||
(data[4] & APEX_CONFIG9_SMD_SENSITIVITY_SEL_MASK);
|
||||
apex_params->sensitivity_mode = (APEX_CONFIG9_SENSITIVITY_MODE_t)
|
||||
(data[4] & APEX_CONFIG9_SENSITIVITY_MODE_MASK);
|
||||
|
||||
/* Get params from apex_config10 : lowg_peak_th and lowg_samples_th */
|
||||
apex_params->lowg_peak_th = (APEX_CONFIG10_LOWG_PEAK_TH_t)
|
||||
(data[5] & APEX_CONFIG10_LOWG_PEAK_TH_SEL_MASK);
|
||||
apex_params->lowg_samples_th = (APEX_CONFIG10_LOWG_TIME_TH_SAMPLES_t)
|
||||
(data[5] & APEX_CONFIG10_LOWG_TIME_TH_SEL_MASK);
|
||||
|
||||
/* Get params from apex_config11 : highg_peak_th and highg_samples_th */
|
||||
apex_params->highg_peak_th = (APEX_CONFIG11_HIGHG_PEAK_TH_t)
|
||||
(data[6] & APEX_CONFIG11_HIGHG_PEAK_TH_SEL_MASK);
|
||||
apex_params->highg_samples_th = (APEX_CONFIG11_HIGHG_TIME_TH_SAMPLES_t)
|
||||
(data[6] & APEX_CONFIG11_HIGHG_TIME_TH_SEL_MASK);
|
||||
|
||||
/* Access apex reg 12 */
|
||||
status |= inv_imu_read_reg(s, APEX_CONFIG12_MREG1, 1, &data[0]);
|
||||
|
||||
/* Get params from apex_config12 : ff_max_duration_cm and ff_min_duration_cm */
|
||||
apex_params->ff_max_duration_cm = (APEX_CONFIG12_FF_MAX_DURATION_t)
|
||||
(data[0] & APEX_CONFIG12_FF_MAX_DURATION_SEL_MASK);
|
||||
apex_params->ff_min_duration_cm = (APEX_CONFIG12_FF_MIN_DURATION_t)
|
||||
(data[0] & APEX_CONFIG12_FF_MIN_DURATION_SEL_MASK);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int inv_imu_apex_set_frequency(struct inv_imu_device *s, const APEX_CONFIG1_DMP_ODR_t frequency)
|
||||
{
|
||||
uint8_t value;
|
||||
int status = 0;
|
||||
|
||||
status |= inv_imu_read_reg(s, APEX_CONFIG1, 1, &value);
|
||||
|
||||
value &= ~APEX_CONFIG1_DMP_ODR_MASK;
|
||||
value |= frequency;
|
||||
|
||||
status |= inv_imu_write_reg(s, APEX_CONFIG1, 1, &value);
|
||||
return status;
|
||||
}
|
||||
|
||||
int inv_imu_apex_enable_pedometer(struct inv_imu_device *s)
|
||||
{
|
||||
int status = 0;
|
||||
uint8_t value;
|
||||
|
||||
status |= inv_imu_start_dmp(s);
|
||||
|
||||
/* Enable Pedometer */
|
||||
status |= inv_imu_read_reg(s, APEX_CONFIG1, 1, &value);
|
||||
value &= ~APEX_CONFIG1_PED_ENABLE_MASK;
|
||||
value |= (uint8_t)APEX_CONFIG1_PED_ENABLE_EN;
|
||||
status |= inv_imu_write_reg(s, APEX_CONFIG1, 1, &value);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int inv_imu_apex_disable_pedometer(struct inv_imu_device *s)
|
||||
{
|
||||
int status = 0;
|
||||
uint8_t value;
|
||||
|
||||
/* Disable Pedometer */
|
||||
status |= inv_imu_read_reg(s, APEX_CONFIG1, 1, &value);
|
||||
value &= ~APEX_CONFIG1_PED_ENABLE_MASK;
|
||||
value |= (uint8_t)APEX_CONFIG1_PED_ENABLE_DIS;
|
||||
status |= inv_imu_write_reg(s, APEX_CONFIG1, 1, &value);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int inv_imu_apex_enable_tilt(struct inv_imu_device *s)
|
||||
{
|
||||
int status = 0;
|
||||
uint8_t value;
|
||||
|
||||
status |= inv_imu_start_dmp(s);
|
||||
|
||||
/* Enable Tilt */
|
||||
status |= inv_imu_read_reg(s, APEX_CONFIG1, 1, &value);
|
||||
value &= ~APEX_CONFIG1_TILT_ENABLE_MASK;
|
||||
value |= (uint8_t)APEX_CONFIG1_TILT_ENABLE_EN;
|
||||
status |= inv_imu_write_reg(s, APEX_CONFIG1, 1, &value);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int inv_imu_apex_disable_tilt(struct inv_imu_device *s)
|
||||
{
|
||||
int status = 0;
|
||||
uint8_t value;
|
||||
|
||||
/* Disable Tilt */
|
||||
status |= inv_imu_read_reg(s, APEX_CONFIG1, 1, &value);
|
||||
value &= ~APEX_CONFIG1_TILT_ENABLE_MASK;
|
||||
value |= (uint8_t)APEX_CONFIG1_TILT_ENABLE_DIS;
|
||||
status |= inv_imu_write_reg(s, APEX_CONFIG1, 1, &value);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int inv_imu_apex_get_data_activity(struct inv_imu_device *s, inv_imu_apex_step_activity_t *apex_activity)
|
||||
{
|
||||
uint8_t data[4];
|
||||
int status = inv_imu_read_reg(s, APEX_DATA0, 4, data);
|
||||
|
||||
apex_activity->step_cnt = data[1] << 8 | data[0];
|
||||
apex_activity->step_cadence = data[2];
|
||||
apex_activity->activity_class = data[3] & APEX_DATA3_ACTIVITY_CLASS_MASK;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int inv_imu_apex_get_data_free_fall(struct inv_imu_device *s, uint16_t *freefall_duration)
|
||||
{
|
||||
uint8_t data[2];
|
||||
int status = inv_imu_read_reg(s, APEX_DATA4, 2, &data[0]);
|
||||
|
||||
*freefall_duration = (data[1] << 8) | data[0];
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
186
apps/common/device/imu_sensor/icm_42670p/inv_imu_apex.h
Normal file
186
apps/common/device/imu_sensor/icm_42670p/inv_imu_apex.h
Normal file
@ -0,0 +1,186 @@
|
||||
/*
|
||||
* ________________________________________________________________________________________________________
|
||||
* Copyright (c) 2017 InvenSense Inc. All rights reserved.
|
||||
*
|
||||
* This software, related documentation and any modifications thereto (collectively "Software") is subject
|
||||
* to InvenSense and its licensors' intellectual property rights under U.S. and international copyright
|
||||
* and other intellectual property rights laws.
|
||||
*
|
||||
* InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software
|
||||
* and any use, reproduction, disclosure or distribution of the Software without an express license agreement
|
||||
* from InvenSense is strictly prohibited.
|
||||
*
|
||||
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, 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 NON-INFRINGEMENT.
|
||||
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, IN NO EVENT SHALL
|
||||
* INVENSENSE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY
|
||||
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
||||
* OF THE SOFTWARE.
|
||||
* ________________________________________________________________________________________________________
|
||||
*/
|
||||
|
||||
/** @defgroup DriverApex IMU driver high level functions related to APEX and the DMP
|
||||
* @brief High-level function to setup an IMU device
|
||||
* @ingroup Driver
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @file inv_imu_apex.h
|
||||
* High-level function to setup an IMU device
|
||||
*/
|
||||
|
||||
#ifndef _INV_IMU_APEX_H_
|
||||
#define _INV_IMU_APEX_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "inv_imu_defs.h"
|
||||
|
||||
#include "InvError.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
/* Forward declarations */
|
||||
struct inv_imu_device;
|
||||
|
||||
/** @brief IMU APEX inputs parameters definition
|
||||
*/
|
||||
typedef struct {
|
||||
APEX_CONFIG3_PEDO_AMP_TH_t pedo_amp_th;
|
||||
uint8_t pedo_step_cnt_th;
|
||||
uint8_t pedo_step_det_th;
|
||||
APEX_CONFIG4_PEDO_SB_TIMER_TH_t pedo_sb_timer_th;
|
||||
APEX_CONFIG4_PEDO_HI_ENRGY_TH_t pedo_hi_enrgy_th;
|
||||
APEX_CONFIG5_TILT_WAIT_TIME_t tilt_wait_time;
|
||||
APEX_CONFIG2_DMP_POWER_SAVE_TIME_t power_save_time;
|
||||
APEX_CONFIG0_DMP_POWER_SAVE_t power_save;
|
||||
APEX_CONFIG9_SENSITIVITY_MODE_t sensitivity_mode;
|
||||
APEX_CONFIG2_LOW_ENERGY_AMP_TH_t low_energy_amp_th;
|
||||
APEX_CONFIG9_SMD_SENSITIVITY_t smd_sensitivity;
|
||||
APEX_CONFIG9_FF_DEBOUNCE_DURATION_t ff_debounce_duration;
|
||||
APEX_CONFIG12_FF_MAX_DURATION_t ff_max_duration_cm;
|
||||
APEX_CONFIG12_FF_MIN_DURATION_t ff_min_duration_cm;
|
||||
APEX_CONFIG10_LOWG_PEAK_TH_t lowg_peak_th;
|
||||
APEX_CONFIG5_LOWG_PEAK_TH_HYST_t lowg_peak_hyst;
|
||||
APEX_CONFIG10_LOWG_TIME_TH_SAMPLES_t lowg_samples_th;
|
||||
APEX_CONFIG11_HIGHG_PEAK_TH_t highg_peak_th;
|
||||
APEX_CONFIG5_HIGHG_PEAK_TH_HYST_t highg_peak_hyst;
|
||||
APEX_CONFIG11_HIGHG_TIME_TH_SAMPLES_t highg_samples_th;
|
||||
} inv_imu_apex_parameters_t;
|
||||
|
||||
/** @brief APEX pedometer outputs
|
||||
*/
|
||||
typedef struct inv_imu_apex_step_activity {
|
||||
uint16_t step_cnt; /**< Number of steps taken */
|
||||
uint8_t step_cadence; /**< Walk/run cadence in number of samples.
|
||||
Format is u6.2. E.g, At 50Hz and 2Hz walk frequency, if the cadency is 25 samples.
|
||||
The register will output 100. */
|
||||
uint8_t activity_class; /**< Detected activity unknown (0), walk (1) or run (2) */
|
||||
} inv_imu_apex_step_activity_t;
|
||||
|
||||
/** @brief Enable Free Fall.
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_apex_enable_ff(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Disable Free Fall.
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_apex_disable_ff(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Enable Significant Motion Detection.
|
||||
* note : SMD requests to have the accelerometer enabled to work.
|
||||
* To have good performance, it's recommended to set accelerometer ODR (Output Data Rate) to 20ms
|
||||
* and the accelerometer in Low Power Mode.
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_apex_enable_smd(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Disable Significant Motion Detection.
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_apex_disable_smd(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Fill the APEX parameters structure with all the default parameters for APEX algorithms (pedometer, tilt)
|
||||
* @param[out] apex_inputs Default input parameters. See @sa inv_imu_apex_parameters_t
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_apex_init_parameters_struct(struct inv_imu_device *s, inv_imu_apex_parameters_t *apex_inputs);
|
||||
|
||||
/** @brief Configures DMP parameters for APEX algorithms (pedometer, tilt, lowg, highg).
|
||||
* This programmable parameters will be decoded and propagate to the SRAM to be executed at DMP start.
|
||||
* @param[in] apex_inputs The requested input parameters. See @sa inv_imu_apex_parameters_t
|
||||
* @warning APEX inputs can't change on the fly, this API should be called before enabling any APEX features.
|
||||
* @warning APEX configuration can't be done too frequently, but only once every 10ms.
|
||||
* Otherwise it can create unknown behavior.
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_apex_configure_parameters(struct inv_imu_device *s, const inv_imu_apex_parameters_t *apex_inputs);
|
||||
|
||||
/** @brief Returns current DMP parameters for APEX algorithms (pedometer, tilt).
|
||||
* @param[out] apex_params The current parameter, fetched from registers. See @sa inv_imu_apex_parameters_t
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_apex_get_parameters(struct inv_imu_device *s, inv_imu_apex_parameters_t *apex_params);
|
||||
|
||||
/** @brief Configure DMP Output Data Rate for APEX algorithms (pedometer, tilt)
|
||||
* @param[in] frequency The requested frequency.
|
||||
* @sa APEX_CONFIG1_DMP_ODR_t
|
||||
* @warning DMP_ODR can change on the fly, and the DMP code will accommodate necessary modifications
|
||||
* @warning The user needs to take care to set Accel frequency >= DMP frequency. This is a hard constraint
|
||||
since HW will not handle incorrect setting.
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_apex_set_frequency(struct inv_imu_device *s, const APEX_CONFIG1_DMP_ODR_t frequency);
|
||||
|
||||
/** @brief Enable APEX algorithm Pedometer.
|
||||
* note : Pedometer request to have the accelerometer enabled to works
|
||||
* with accelerometer frequency less than dmp frequency.
|
||||
* @return 0 on success, negative value on error.
|
||||
* @warning Pedometer must be turned OFF to reconfigure it
|
||||
*/
|
||||
int inv_imu_apex_enable_pedometer(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Disable APEX algorithm Pedometer.
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_apex_disable_pedometer(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Enable APEX algorithm Tilt.
|
||||
* note : Tilt request to have the accelerometer enabled to works
|
||||
* with accelerometer frequency less than dmp frequency.
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_apex_enable_tilt(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Disable APEX algorithm Tilt.
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_apex_disable_tilt(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Retrieve APEX pedometer outputs and format them
|
||||
* @param[out] apex_activity Apex step and activity data value.
|
||||
* @return 0 in case of success, negative value on error. See enum inv_error
|
||||
*/
|
||||
int inv_imu_apex_get_data_activity(struct inv_imu_device *s, inv_imu_apex_step_activity_t *apex_activity);
|
||||
|
||||
/** @brief Retrieve APEX free fall outputs and format them
|
||||
* @param[out] Free fall duration in number of sample.
|
||||
* @return 0 in case of success, negative value on error. See enum inv_error
|
||||
*/
|
||||
int inv_imu_apex_get_data_free_fall(struct inv_imu_device *s, uint16_t *freefall_duration);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _INV_IMU_APEX_H_ */
|
||||
|
||||
/** @} */
|
||||
|
||||
1014
apps/common/device/imu_sensor/icm_42670p/inv_imu_defs.h
Normal file
1014
apps/common/device/imu_sensor/icm_42670p/inv_imu_defs.h
Normal file
File diff suppressed because it is too large
Load Diff
1722
apps/common/device/imu_sensor/icm_42670p/inv_imu_driver.c
Normal file
1722
apps/common/device/imu_sensor/icm_42670p/inv_imu_driver.c
Normal file
File diff suppressed because it is too large
Load Diff
533
apps/common/device/imu_sensor/icm_42670p/inv_imu_driver.h
Normal file
533
apps/common/device/imu_sensor/icm_42670p/inv_imu_driver.h
Normal file
@ -0,0 +1,533 @@
|
||||
/*
|
||||
* ________________________________________________________________________________________________________
|
||||
* Copyright (c) 2017 InvenSense Inc. All rights reserved.
|
||||
*
|
||||
* This software, related documentation and any modifications thereto (collectively "Software") is subject
|
||||
* to InvenSense and its licensors' intellectual property rights under U.S. and international copyright
|
||||
* and other intellectual property rights laws.
|
||||
*
|
||||
* InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software
|
||||
* and any use, reproduction, disclosure or distribution of the Software without an express license agreement
|
||||
* from InvenSense is strictly prohibited.
|
||||
*
|
||||
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, 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 NON-INFRINGEMENT.
|
||||
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, IN NO EVENT SHALL
|
||||
* INVENSENSE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY
|
||||
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
||||
* OF THE SOFTWARE.
|
||||
* ________________________________________________________________________________________________________
|
||||
*/
|
||||
|
||||
/** @defgroup Driver IMU driver high level functions
|
||||
* @brief High-level function to setup an IMU device
|
||||
* @ingroup DriverIcm
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @file inv_imu_driver.h
|
||||
* High-level function to setup an IMU device
|
||||
*/
|
||||
|
||||
#ifndef _INV_IMU_DRIVER_H_
|
||||
#define _INV_IMU_DRIVER_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "inv_imu_defs.h"
|
||||
#include "inv_imu_transport.h"
|
||||
|
||||
#include "InvError.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
/** @brief IMU max FSR values for accel and gyro
|
||||
* Dependent on chip
|
||||
*/
|
||||
#define ACCEL_CONFIG0_FS_SEL_MAX ACCEL_CONFIG0_FS_SEL_16g
|
||||
#define GYRO_CONFIG0_FS_SEL_MAX GYRO_CONFIG0_FS_SEL_2000dps
|
||||
|
||||
#define ACCEL_OFFUSER_MAX_MG 1000
|
||||
#define GYRO_OFFUSER_MAX_DPS 64
|
||||
|
||||
/** @brief IMU maximum buffer size mirrored from FIFO at polling time
|
||||
* @warning fifo_idx type variable must be large enough to parse the FIFO_MIRRORING_SIZE
|
||||
*/
|
||||
#define FIFO_MIRRORING_SIZE 16 * 258 // packet size * max_count = 4kB
|
||||
|
||||
/** @brief IMU Accelerometer start-up time before having correct data
|
||||
*/
|
||||
#define ACC_STARTUP_TIME_US 10000
|
||||
|
||||
/** @brief IMU Gyroscope start-up time before having correct data
|
||||
*/
|
||||
#define GYR_STARTUP_TIME_US 70000
|
||||
|
||||
/** @brief IMU Gyroscope power off to power on duration
|
||||
*/
|
||||
#define GYR_POWER_OFF_DUR_US 20000
|
||||
|
||||
/** @brief Sensor identifier for UI control function
|
||||
*/
|
||||
enum inv_imu_sensor {
|
||||
INV_SENSOR_ACCEL, /**< Accelerometer */
|
||||
INV_SENSOR_GYRO, /**< Gyroscope */
|
||||
INV_SENSOR_FSYNC_EVENT, /**< FSYNC */
|
||||
INV_SENSOR_TEMPERATURE, /**< Chip temperature */
|
||||
INV_SENSOR_DMP_PEDOMETER_EVENT, /**< Pedometer: step detected */
|
||||
INV_SENSOR_DMP_PEDOMETER_COUNT, /**< Pedometer: step counter */
|
||||
INV_SENSOR_DMP_TILT, /**< Tilt */
|
||||
INV_SENSOR_DMP_FF, /**< FreeFall */
|
||||
INV_SENSOR_DMP_LOWG, /**< Low G */
|
||||
INV_SENSOR_DMP_SMD, /**< Significant Motion Detection */
|
||||
INV_SENSOR_MAX
|
||||
};
|
||||
|
||||
/** @brief Configure Fifo usage
|
||||
*/
|
||||
typedef enum {
|
||||
INV_IMU_FIFO_DISABLED = 0, /**< Fifo is disabled and data source is sensors registers */
|
||||
INV_IMU_FIFO_ENABLED = 1, /**< Fifo is used as data source */
|
||||
} INV_IMU_FIFO_CONFIG_t;
|
||||
|
||||
/** @brief Sensor event structure definition
|
||||
*/
|
||||
typedef struct {
|
||||
int sensor_mask;
|
||||
uint16_t timestamp_fsync;
|
||||
int16_t accel[3];
|
||||
int16_t gyro[3];
|
||||
int16_t temperature;
|
||||
int8_t accel_high_res[3];
|
||||
int8_t gyro_high_res[3];
|
||||
} inv_imu_sensor_event_t;
|
||||
|
||||
/** @brief IMU driver states definition
|
||||
*/
|
||||
struct inv_imu_device {
|
||||
struct inv_imu_transport transport; /**< Transport layer
|
||||
Must be the first one of struct inv_imu_device */
|
||||
void (*sensor_event_cb)(inv_imu_sensor_event_t *event); /**< callback executed by:
|
||||
inv_imu_get_data_from_fifo (if FIFO is used)
|
||||
inv_imu_get_data_from_registers (if FIFO isn't used)
|
||||
May be NULL if above API are not used by application */
|
||||
uint8_t fifo_data[FIFO_MIRRORING_SIZE]; /**< FIFO mirroring memory area */
|
||||
uint8_t dmp_is_on; /**< DMP started status */
|
||||
uint8_t endianness_data; /**< Data endianness configuration */
|
||||
uint8_t fifo_highres_enabled; /**< Highres mode configuration */
|
||||
INV_IMU_FIFO_CONFIG_t fifo_is_used; /**< FIFO configuration */
|
||||
uint64_t gyro_start_time_us; /**< Gyro start time used to discard first samples */
|
||||
uint64_t accel_start_time_us; /**< Accel start time used to discard first samples */
|
||||
uint64_t gyro_power_off_tmst; /**< Gyro power off time */
|
||||
};
|
||||
|
||||
|
||||
/* Interrupt enum state for INT1, INT2, and IBI */
|
||||
typedef enum {
|
||||
INV_IMU_DISABLE = 0,
|
||||
INV_IMU_ENABLE
|
||||
} inv_imu_interrupt_value;
|
||||
|
||||
/** @brief Interrupt definition
|
||||
*/
|
||||
typedef struct {
|
||||
inv_imu_interrupt_value INV_UI_FSYNC;
|
||||
inv_imu_interrupt_value INV_UI_DRDY;
|
||||
inv_imu_interrupt_value INV_FIFO_THS;
|
||||
inv_imu_interrupt_value INV_FIFO_FULL;
|
||||
inv_imu_interrupt_value INV_SMD;
|
||||
inv_imu_interrupt_value INV_WOM_X;
|
||||
inv_imu_interrupt_value INV_WOM_Y;
|
||||
inv_imu_interrupt_value INV_WOM_Z;
|
||||
inv_imu_interrupt_value INV_FF;
|
||||
inv_imu_interrupt_value INV_LOWG;
|
||||
inv_imu_interrupt_value INV_STEP_DET;
|
||||
inv_imu_interrupt_value INV_STEP_CNT_OVFL;
|
||||
inv_imu_interrupt_value INV_TILT_DET;
|
||||
} inv_imu_interrupt_parameter_t;
|
||||
|
||||
|
||||
/** @brief Configure the serial interface used to access the device and execute hardware initialization.
|
||||
*
|
||||
* This functions first configures serial interface passed in parameter to make sure device
|
||||
* is accessible both in read and write. Thus no serial access should be done before
|
||||
* successfully executing the present function.
|
||||
*
|
||||
* Then if requested serial interface is a primary interface (aka UI interface or AP
|
||||
* interface), this function initializes the device using the following hardware settings:
|
||||
* - set timestamp resolution to 16us
|
||||
* - enable FIFO mechanism with the following configuration:
|
||||
* - FIFO record mode i.e FIFO count unit is packet
|
||||
* - FIFO snapshot mode i.e drop the data when the FIFO overflows
|
||||
* - Timestamp is logged in FIFO
|
||||
* - Little Endian fifo_count and fifo_data
|
||||
* - generate FIFO threshold interrupt when packet count reaches FIFO watermark
|
||||
* - set FIFO watermark to 1 packet
|
||||
* - enable temperature and timestamp data to go to FIFO
|
||||
*
|
||||
*
|
||||
* @param[in] s driver structure. Note that first field of this structure MUST be a struct
|
||||
* inv_imu_serif.
|
||||
*
|
||||
* @param[in] serif pointer on serial interface structure to be used to access inv_device.
|
||||
*
|
||||
* @param[in] sensor_event_cb callback executed by inv_imu_get_data_from_fifo function
|
||||
* each time it extracts some valid data from fifo. Or inv_imu_get_data_from_registers read data
|
||||
* from register. Thus this parameter is optional as long
|
||||
* as inv_imu_get_data_from_fifo/inv_imu_get_data_from_registers function is not used.
|
||||
*
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_init(struct inv_imu_device *s,
|
||||
struct inv_imu_serif *serif,
|
||||
void (*sensor_event_cb)(inv_imu_sensor_event_t *event));
|
||||
|
||||
/** @brief Perform a soft reset of the device
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_device_reset(struct inv_imu_device *s);
|
||||
|
||||
/** @brief return WHOAMI value
|
||||
* @param[out] who_am_i WHOAMI for device
|
||||
* @return 0 on success, negative value on error
|
||||
*/
|
||||
int inv_imu_get_who_am_i(struct inv_imu_device *s, uint8_t *who_am_i);
|
||||
|
||||
/** @brief Enable/put accel in low power mode
|
||||
* @return 0 on success, negative value on error.
|
||||
* @details
|
||||
* It enables accel and gyro data in the FIFO (so
|
||||
* the packet format is 16 bytes). If called first,
|
||||
* the configuration will be applied, otherwise it
|
||||
* will be ignored if the FIFO is not empty (but since
|
||||
* the new configuration is identical it is not a issue).
|
||||
* @warning inv_device::register_cache::pwr_mgmt0_reg is modified by this function
|
||||
*/
|
||||
int inv_imu_enable_accel_low_power_mode(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Enable/put accel in low noise mode
|
||||
* @return 0 on success, negative value on error.
|
||||
* @details
|
||||
* It enables accel and gyro data in the FIFO (so
|
||||
* the packet format is 16 bytes). If called first,
|
||||
* the configuration will be applied, otherwise it
|
||||
* will be ignored if the FIFO is not empty (but since
|
||||
* the new configuration is identical it is not a issue).
|
||||
* @warning inv_device::register_cache::pwr_mgmt0_reg is modified by this function
|
||||
*/
|
||||
int inv_imu_enable_accel_low_noise_mode(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Disable all 3 axes of accel
|
||||
* @return 0 on success, negative value on error.
|
||||
* @details
|
||||
* If both accel and gyro are turned off as a result of this
|
||||
* function, they will also be removed from the FIFO and a
|
||||
* FIFO reset will be performed (to guarantee no side effects
|
||||
* until the next enable sensor call)
|
||||
* @warning inv_device::register_cache::pwr_mgmt0_reg is modified by this function
|
||||
*/
|
||||
int inv_imu_disable_accel(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Enable/put gyro in low noise mode
|
||||
* @return 0 on success, negative value on error.
|
||||
* @details
|
||||
* It enables gyro and accel data in the FIFO (so
|
||||
* the packet format is 16 bytes). If called first,
|
||||
* the configuration will be applied, otherwise it
|
||||
* will be ignored if the FIFO is not empty (but since
|
||||
* the new configuration is identical it is not a issue).
|
||||
* @warning inv_device::register_cache::pwr_mgmt0_reg is modified by this function
|
||||
*/
|
||||
int inv_imu_enable_gyro_low_noise_mode(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Disable all 3 axes of gyro
|
||||
* @return 0 on success, negative value on error.
|
||||
* @details
|
||||
* If both accel and gyro are turned off as a result of this
|
||||
* function, they will also be removed from the FIFO and a
|
||||
* FIFO reset will be performed (to guarantee no side effects
|
||||
* until the next enable sensor call)
|
||||
* @warning inv_device::register_cache::pwr_mgmt0_reg is modified by this function
|
||||
*/
|
||||
int inv_imu_disable_gyro(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Enable fsync tagging functionality.
|
||||
* In details it:
|
||||
* - enables fsync
|
||||
* - enables timestamp to registers. Once fsync is enabled fsync counter is pushed to
|
||||
* fifo instead of timestamp. So timestamp is made available in registers. Note that
|
||||
* this increase power consumption.
|
||||
* - enables fsync related interrupt
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_enable_fsync(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Disable fsync tagging functionality.
|
||||
* In details it:
|
||||
* - disables fsync
|
||||
* - disables timestamp to registers. Once fsync is disabled timestamp is pushed to fifo
|
||||
* instead of fsync counter. So in order to decrease power consumption, timestamp is no
|
||||
* more available in registers.
|
||||
* - disables fsync related interrupt
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_disable_fsync(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Configure which interrupt source can trigger INT1.
|
||||
* @param[in] interrupt_to_configure structure with the corresponding state to manage INT1.
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_set_config_int1(struct inv_imu_device *s,
|
||||
inv_imu_interrupt_parameter_t *interrupt_to_configure);
|
||||
|
||||
/** @brief Retrieve interrupts configuration.
|
||||
* @param[in] interrupt_to_configure structure with the corresponding state to manage INT1.
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_get_config_int1(struct inv_imu_device *s,
|
||||
inv_imu_interrupt_parameter_t *interrupt_to_configure);
|
||||
|
||||
/** @brief Configure which interrupt source can trigger INT2.
|
||||
* @param[in] interrupt_to_configure structure with the corresponding state to INT2.
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_set_config_int2(struct inv_imu_device *s,
|
||||
inv_imu_interrupt_parameter_t *interrupt_to_configure);
|
||||
|
||||
/** @brief Retrieve interrupts configuration.
|
||||
* @param[in] interrupt_to_configure structure with the corresponding state to manage INT2.
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_get_config_int2(struct inv_imu_device *s,
|
||||
inv_imu_interrupt_parameter_t *interrupt_to_configure);
|
||||
|
||||
/** @brief Read all registers containing data (temperature, accelerometer and gyroscope). Then it calls
|
||||
* sensor_event_cb function passed in parameter of inv_imu_init function for each packet
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_get_data_from_registers(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Read all available packets from the FIFO. For each packet function builds a
|
||||
* sensor event containing packet data and validity information. Then it calls
|
||||
* sensor_event_cb funtion passed in parameter of inv_imu_init function for each
|
||||
* packet.
|
||||
* @return number of valid packets read on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_get_data_from_fifo(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Converts ACCEL_CONFIG0_ODR_t or GYRO_CONFIG0_ODR_t enums to period expressed in us
|
||||
* @param[in] odr_bitfield An ACCEL_CONFIG0_ODR_t or GYRO_CONFIG0_ODR_t enum
|
||||
* @return The corresponding period expressed in us
|
||||
*/
|
||||
uint32_t inv_imu_convert_odr_bitfield_to_us(uint32_t odr_bitfield);
|
||||
|
||||
/** @brief Configure accel Output Data Rate
|
||||
* @param[in] frequency The requested frequency.
|
||||
* @sa ACCEL_CONFIG0_ODR_t
|
||||
* @return 0 on success, negative value on error.
|
||||
* @warning inv_device::register_cache::accel_config0_reg is modified by this function
|
||||
*/
|
||||
int inv_imu_set_accel_frequency(struct inv_imu_device *s,
|
||||
const ACCEL_CONFIG0_ODR_t frequency);
|
||||
|
||||
/** @brief Configure gyro Output Data Rate
|
||||
* @param[in] frequency The requested frequency.
|
||||
* @sa GYRO_CONFIG0_ODR_t
|
||||
* @return 0 on success, negative value on error.
|
||||
* @warning inv_device::register_cache::gyro_config0_reg is modified by this function
|
||||
*/
|
||||
int inv_imu_set_gyro_frequency(struct inv_imu_device *s,
|
||||
const GYRO_CONFIG0_ODR_t frequency);
|
||||
|
||||
/** @brief Set accel full scale range
|
||||
* @param[in] accel_fsr_g requested full scale range.
|
||||
* @sa ACCEL_CONFIG0_FS_SEL_t.
|
||||
* @return 0 on success, negative value on error.
|
||||
* @warning inv_device::register_cache::accel_config0_reg is modified by this function
|
||||
*/
|
||||
int inv_imu_set_accel_fsr(struct inv_imu_device *s,
|
||||
ACCEL_CONFIG0_FS_SEL_t accel_fsr_g);
|
||||
|
||||
/** @brief Access accel full scale range
|
||||
* @param[out] accel_fsr_g current full scale range.
|
||||
* @sa ACCEL_CONFIG0_FS_SEL_t.
|
||||
* @return 0 on success, negative value on error.
|
||||
* @warning inv_device::register_cache::accel_config0_reg is relied upon by this function
|
||||
*/
|
||||
int inv_imu_get_accel_fsr(struct inv_imu_device *s,
|
||||
ACCEL_CONFIG0_FS_SEL_t *accel_fsr_g);
|
||||
|
||||
/** @brief Set gyro full scale range
|
||||
* @param[in] gyro_fsr_dps requested full scale range.
|
||||
* @sa GYRO_CONFIG0_FS_SEL_t.
|
||||
* @return 0 on success, negative value on error.
|
||||
* @warning inv_device::register_cache::gyro_config0_reg is modified by this function
|
||||
*/
|
||||
int inv_imu_set_gyro_fsr(struct inv_imu_device *s,
|
||||
GYRO_CONFIG0_FS_SEL_t gyro_fsr_dps);
|
||||
|
||||
/** @brief Access gyro full scale range
|
||||
* @param[out] gyro_fsr_dps current full scale range.
|
||||
* @sa GYRO_CONFIG0_FS_SEL_t.
|
||||
* @return 0 on success, negative value on error.
|
||||
* @warning inv_device::register_cache::gyro_config0_reg is relied upon by this function
|
||||
*/
|
||||
int inv_imu_get_gyro_fsr(struct inv_imu_device *s,
|
||||
GYRO_CONFIG0_FS_SEL_t *gyro_fsr_dps);
|
||||
|
||||
/** @brief Set accel Low-Power averaging value
|
||||
* @param[in] acc_avg requested averaging value
|
||||
* @sa ACCEL_CONFIG1_ACCEL_FILT_AVG_t
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_set_accel_lp_avg(struct inv_imu_device *s,
|
||||
ACCEL_CONFIG1_ACCEL_FILT_AVG_t acc_avg);
|
||||
|
||||
/** @brief Set accel Low-Noise bandwidth value
|
||||
* @param[in] acc_bw requested averaging value
|
||||
* @sa ACCEL_CONFIG1_ACCEL_FILT_BW_t
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_set_accel_ln_bw(struct inv_imu_device *s,
|
||||
ACCEL_CONFIG1_ACCEL_FILT_BW_t acc_bw);
|
||||
|
||||
/** @brief Set gyro Low-Noise bandwidth value
|
||||
* @param[in] gyr_bw requested averaging value
|
||||
* @sa GYRO_CONFIG1_GYRO_FILT_BW_t
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_set_gyro_ln_bw(struct inv_imu_device *s,
|
||||
GYRO_CONFIG1_GYRO_FILT_BW_t gyr_bw);
|
||||
|
||||
/** @brief Set timestamp resolution
|
||||
* @param[in] timestamp_resol requested timestamp resolution
|
||||
* @sa TMST_CONFIG1_RESOL_t
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_set_timestamp_resolution(struct inv_imu_device *s,
|
||||
const TMST_CONFIG1_RESOL_t timestamp_resol);
|
||||
|
||||
/** @brief reset IMU fifo
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_reset_fifo(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Enable 20 bits raw acc and raw gyr data in fifo.
|
||||
* @return 0 on success, negative return code otherwise
|
||||
*/
|
||||
int inv_imu_enable_high_resolution_fifo(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Disable 20 bits raw acc and raw gyr data in fifo.
|
||||
* @return 0 on success, negative return code otherwise
|
||||
*/
|
||||
int inv_imu_disable_high_resolution_fifo(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Configure Fifo
|
||||
* @param[in] fifo_config Fifo configuration method :
|
||||
* if FIFO is enabled, data are pushed to FIFO and FIFO THS interrupt is set
|
||||
* if FIFO is disabled, data are not pused to FIFO and DRDY interrupt is set
|
||||
* @sa INV_IMU_FIFO_CONFIG_t
|
||||
*/
|
||||
int inv_imu_configure_fifo(struct inv_imu_device *s,
|
||||
INV_IMU_FIFO_CONFIG_t fifo_config);
|
||||
|
||||
/** @brief Get FIFO timestamp resolution
|
||||
* @return the timestamp resolution in us as a q24 or 0 in case of error
|
||||
*/
|
||||
uint32_t inv_imu_get_fifo_timestamp_resolution_us_q24(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Get register timestamp resolution
|
||||
* @return the timestamp resolution in us as a q24 or 0 in case of error
|
||||
*/
|
||||
uint32_t inv_imu_get_reg_timestamp_resolution_us_q24(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Enable Wake On Motion.
|
||||
* @param[in] wom_x_th threshold value for the Wake on Motion Interrupt for X-axis accelerometer.
|
||||
* @param[in] wom_y_th threshold value for the Wake on Motion Interrupt for Y-axis accelerometer.
|
||||
* @param[in] wom_z_th threshold value for the Wake on Motion Interrupt for Z-axis accelerometer.
|
||||
* @param[in] wom_int select which mode between AND/OR is used to generate interrupt.
|
||||
* @param[in] wom_dur select the number of overthreshold event to wait before generating interrupt.
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_configure_wom(struct inv_imu_device *s,
|
||||
const uint8_t wom_x_th,
|
||||
const uint8_t wom_y_th,
|
||||
const uint8_t wom_z_th,
|
||||
WOM_CONFIG_WOM_INT_MODE_t wom_int,
|
||||
WOM_CONFIG_WOM_INT_DUR_t wom_dur);
|
||||
|
||||
/** @brief Enable Wake On Motion.
|
||||
* note : WoM requests to have the accelerometer enabled to work.
|
||||
* As a consequence Fifo water-mark interrupt is disabled to only trigger WoM interrupts.
|
||||
* To have good performance, it's recommended to set accelerometer ODR (Output Data Rate) to 20ms
|
||||
* and the accelerometer in Low Power Mode.
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_enable_wom(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Disable Wake On Motion.
|
||||
* note : Fifo water-mark interrupt is re-enabled when WoM is disabled.
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_disable_wom(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Start DMP for APEX algorithms and selftest
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_start_dmp(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Reset DMP for APEX algorithms and selftest
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_reset_dmp(struct inv_imu_device *s,
|
||||
const APEX_CONFIG0_DMP_MEM_RESET_t sram_reset);
|
||||
|
||||
/** @breif Set the UI endianness and set the inv_device endianness field
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_set_endianness(struct inv_imu_device *s,
|
||||
INTF_CONFIG0_DATA_ENDIAN_t endianness);
|
||||
|
||||
/** @breif Read the UI endianness and set the inv_device endianness field
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_get_endianness(struct inv_imu_device *s);
|
||||
|
||||
//The device powers up in sleep mode.
|
||||
//any time change
|
||||
//Sleep mode, and Accelerometer low power mode with WUOSC do not support MREG1, MREG2 or MREG3 access.
|
||||
//need power on the RC oscillator using register field IDLE from register PWR_MGMT0.
|
||||
int inv_imu_enter_sleep(struct inv_imu_device *s);
|
||||
|
||||
//power on:
|
||||
//After powering the gyroscope off, a period of > 20ms should be allowed to elapse before it is powered back on.
|
||||
//Accelerometer Startup Time From sleep mode to valid data:10ms.
|
||||
//gpro need >45ms
|
||||
int inv_imu_exit_sleep(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Configure Fifo decimation
|
||||
* @param[in] requested decimation factor value from 2 to 256
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_configure_fifo_data_rate(struct inv_imu_device *s,
|
||||
FDR_CONFIG_FDR_SEL_t dec_factor);
|
||||
|
||||
/** @brief Return driver version x.y.z-suffix as a char array
|
||||
* @retval driver version a char array "x.y.z-suffix"
|
||||
*/
|
||||
const char *inv_imu_get_version(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _INV_IMU_DRIVER_H_ */
|
||||
|
||||
/** @} */
|
||||
|
||||
65
apps/common/device/imu_sensor/icm_42670p/inv_imu_extfunc.h
Normal file
65
apps/common/device/imu_sensor/icm_42670p/inv_imu_extfunc.h
Normal file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* ________________________________________________________________________________________________________
|
||||
* Copyright (c) 2017 InvenSense Inc. All rights reserved.
|
||||
*
|
||||
* This software, related documentation and any modifications thereto (collectively "Software") is subject
|
||||
* to InvenSense and its licensors' intellectual property rights under U.S. and international copyright
|
||||
* and other intellectual property rights laws.
|
||||
*
|
||||
* InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software
|
||||
* and any use, reproduction, disclosure or distribution of the Software without an express license agreement
|
||||
* from InvenSense is strictly prohibited.
|
||||
*
|
||||
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, 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 NON-INFRINGEMENT.
|
||||
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, IN NO EVENT SHALL
|
||||
* INVENSENSE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY
|
||||
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
||||
* OF THE SOFTWARE.
|
||||
* ________________________________________________________________________________________________________
|
||||
*/
|
||||
|
||||
/** @defgroup DriverExt IMU driver extern functions
|
||||
* @brief Extern functions for IMU devices
|
||||
* @ingroup Driver
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @file inv_imu_extfunc.h
|
||||
* Extern functions for IMU devices
|
||||
*/
|
||||
|
||||
#ifndef _INV_IMU_EXTFUNC_H_
|
||||
#define _INV_IMU_EXTFUNC_H_
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/** @brief Hook for low-level high res system sleep() function to be implemented by upper layer
|
||||
* ~100us resolution is sufficient
|
||||
* @param[in] us number of us the calling thread should sleep
|
||||
*/
|
||||
extern void inv_imu_sleep_us(uint32_t us);
|
||||
|
||||
/** @brief Hook for low-level high res system get_time() function to be implemented by upper layer
|
||||
* Value shall be on 64bit with a 1 us resolution
|
||||
* @return The current time in us
|
||||
*/
|
||||
extern uint64_t inv_imu_get_time_us(void);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _INV_IMU_EXTFUNC_H_ */
|
||||
|
||||
/** @} */
|
||||
|
||||
3392
apps/common/device/imu_sensor/icm_42670p/inv_imu_regmap.h
Normal file
3392
apps/common/device/imu_sensor/icm_42670p/inv_imu_regmap.h
Normal file
File diff suppressed because it is too large
Load Diff
275
apps/common/device/imu_sensor/icm_42670p/inv_imu_transport.c
Normal file
275
apps/common/device/imu_sensor/icm_42670p/inv_imu_transport.c
Normal file
@ -0,0 +1,275 @@
|
||||
/*
|
||||
* ________________________________________________________________________________________________________
|
||||
* Copyright (c) 2015-2015 InvenSense Inc. All rights reserved.
|
||||
*
|
||||
* This software, related documentation and any modifications thereto (collectively "Software") is subject
|
||||
* to InvenSense and its licensors' intellectual property rights under U.S. and international copyright
|
||||
* and other intellectual property rights laws.
|
||||
*
|
||||
* InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software
|
||||
* and any use, reproduction, disclosure or distribution of the Software without an express license agreement
|
||||
* from InvenSense is strictly prohibited.
|
||||
*
|
||||
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, 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 NON-INFRINGEMENT.
|
||||
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, IN NO EVENT SHALL
|
||||
* INVENSENSE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY
|
||||
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
||||
* OF THE SOFTWARE.
|
||||
* ________________________________________________________________________________________________________
|
||||
*/
|
||||
|
||||
#include "inv_imu_extfunc.h"
|
||||
#include "inv_imu_transport.h"
|
||||
#include "inv_imu_regmap.h"
|
||||
|
||||
#include "InvError.h"
|
||||
|
||||
|
||||
/* Function definition */
|
||||
static uint8_t *get_register_cache_addr(struct inv_imu_device *s, uint32_t reg);
|
||||
static int write_sreg(struct inv_imu_device *s, uint8_t reg, uint32_t len, const uint8_t *buf);
|
||||
static int read_sreg(struct inv_imu_device *s, uint8_t reg, uint32_t len, uint8_t *buf);
|
||||
static int write_mclk_reg(struct inv_imu_device *s, uint16_t regaddr, uint8_t wr_cnt, const uint8_t *buf);
|
||||
static int read_mclk_reg(struct inv_imu_device *s, uint16_t regaddr, uint8_t rd_cnt, uint8_t *buf);
|
||||
|
||||
|
||||
int inv_imu_init_transport(struct inv_imu_device *s)
|
||||
{
|
||||
int status = 0;
|
||||
struct inv_imu_transport *t = (struct inv_imu_transport *)s;
|
||||
|
||||
status |= read_sreg(s, (uint8_t)PWR_MGMT0, 1, &(t->register_cache.pwr_mgmt0_reg));
|
||||
status |= read_sreg(s, (uint8_t)GYRO_CONFIG0, 1, &(t->register_cache.gyro_config0_reg));
|
||||
status |= read_sreg(s, (uint8_t)ACCEL_CONFIG0, 1, &(t->register_cache.accel_config0_reg));
|
||||
|
||||
status |= read_mclk_reg(s, (TMST_CONFIG1_MREG1 & 0xFFFF), 1, &(t->register_cache.tmst_config1_reg));
|
||||
|
||||
t->need_mclk_cnt = 0;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int inv_imu_read_reg(struct inv_imu_device *s, uint32_t reg, uint32_t len, uint8_t *buf)
|
||||
{
|
||||
uint32_t i;
|
||||
int rc = 0;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
uint8_t *cache_addr = get_register_cache_addr(s, reg + i);
|
||||
|
||||
if (cache_addr) {
|
||||
buf[i] = *cache_addr;
|
||||
} else {
|
||||
if (!(reg & 0x10000)) {
|
||||
rc |= read_mclk_reg(s, ((reg + i) & 0xFFFF), 1, &buf[i]);
|
||||
} else {
|
||||
rc |= read_sreg(s, (uint8_t)reg + i, len - i, &buf[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int inv_imu_write_reg(struct inv_imu_device *s, uint32_t reg, uint32_t len, const uint8_t *buf)
|
||||
{
|
||||
uint32_t i;
|
||||
int rc = 0;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
uint8_t *cache_addr = get_register_cache_addr(s, reg + i);
|
||||
|
||||
if (cache_addr) {
|
||||
*cache_addr = buf[i];
|
||||
}
|
||||
|
||||
if (!(reg & 0x10000)) {
|
||||
rc |= write_mclk_reg(s, ((reg + i) & 0xFFFF), 1, &buf[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (reg & 0x10000) {
|
||||
rc |= write_sreg(s, (uint8_t)reg, len, buf);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int inv_imu_switch_on_mclk(struct inv_imu_device *s)
|
||||
{
|
||||
int status = 0;
|
||||
uint8_t data;
|
||||
struct inv_imu_transport *t = (struct inv_imu_transport *)s;
|
||||
|
||||
/* set IDLE bit only if it is not set yet */
|
||||
if (t->need_mclk_cnt == 0) {
|
||||
|
||||
status |= inv_imu_read_reg(s, PWR_MGMT0, 1, &data);
|
||||
data |= PWR_MGMT0_IDLE_MASK;
|
||||
status |= inv_imu_write_reg(s, PWR_MGMT0, 1, &data);
|
||||
|
||||
if (status) {
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Check if MCLK is ready */
|
||||
do {
|
||||
status = inv_imu_read_reg(s, MCLK_RDY, 1, &data);
|
||||
} while ((status != 0) || !(data & MCLK_RDY_MCLK_RDY_MASK));
|
||||
} else {
|
||||
|
||||
/* Make sure it is already on */
|
||||
status |= inv_imu_read_reg(s, PWR_MGMT0, 1, &data);
|
||||
if (0 == (data &= PWR_MGMT0_IDLE_MASK)) {
|
||||
status |= INV_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/* Increment the counter to keep track of number of MCLK requesters */
|
||||
t->need_mclk_cnt++;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int inv_imu_switch_off_mclk(struct inv_imu_device *s)
|
||||
{
|
||||
int status = 0;
|
||||
uint8_t data;
|
||||
struct inv_imu_transport *t = (struct inv_imu_transport *)s;
|
||||
|
||||
/* Reset the IDLE but only if there is one requester left */
|
||||
if (t->need_mclk_cnt == 1) {
|
||||
status |= inv_imu_read_reg(s, PWR_MGMT0, 1, &data);
|
||||
data &= ~PWR_MGMT0_IDLE_MASK;
|
||||
status |= inv_imu_write_reg(s, PWR_MGMT0, 1, &data);
|
||||
} else {
|
||||
/* Make sure it is still on */
|
||||
status |= inv_imu_read_reg(s, PWR_MGMT0, 1, &data);
|
||||
if (0 == (data &= PWR_MGMT0_IDLE_MASK)) {
|
||||
status |= INV_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/* Decrement the counter */
|
||||
t->need_mclk_cnt--;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/* Static function */
|
||||
|
||||
static uint8_t *get_register_cache_addr(struct inv_imu_device *s, uint32_t reg)
|
||||
{
|
||||
struct inv_imu_transport *t = (struct inv_imu_transport *)s;
|
||||
|
||||
switch (reg) {
|
||||
case PWR_MGMT0:
|
||||
return &(t->register_cache.pwr_mgmt0_reg);
|
||||
case GYRO_CONFIG0:
|
||||
return &(t->register_cache.gyro_config0_reg);
|
||||
case ACCEL_CONFIG0:
|
||||
return &(t->register_cache.accel_config0_reg);
|
||||
case TMST_CONFIG1_MREG1:
|
||||
return &(t->register_cache.tmst_config1_reg);
|
||||
default:
|
||||
return (uint8_t *)0; // Not found
|
||||
}
|
||||
}
|
||||
|
||||
static int read_sreg(struct inv_imu_device *s, uint8_t reg, uint32_t len, uint8_t *buf)
|
||||
{
|
||||
struct inv_imu_serif *serif = (struct inv_imu_serif *)s;
|
||||
|
||||
if (len > serif->max_read) {
|
||||
return INV_ERROR_SIZE;
|
||||
}
|
||||
|
||||
if (serif->read_reg(serif, reg, buf, len) != 0) {
|
||||
return INV_ERROR_TRANSPORT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int write_sreg(struct inv_imu_device *s, uint8_t reg, uint32_t len, const uint8_t *buf)
|
||||
{
|
||||
struct inv_imu_serif *serif = (struct inv_imu_serif *)s;
|
||||
|
||||
if (len > serif->max_write) {
|
||||
return INV_ERROR_SIZE;
|
||||
}
|
||||
|
||||
if (serif->write_reg(serif, reg, buf, len) != 0) {
|
||||
return INV_ERROR_TRANSPORT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int read_mclk_reg(struct inv_imu_device *s, uint16_t regaddr, uint8_t rd_cnt, uint8_t *buf)
|
||||
{
|
||||
uint8_t data;
|
||||
uint8_t blk_sel = (regaddr & 0xFF00) >> 8;
|
||||
int status = 0;
|
||||
|
||||
// Have IMU not in IDLE mode to access MCLK domain
|
||||
status |= inv_imu_switch_on_mclk(s);
|
||||
|
||||
// optimize by changing BLK_SEL only if not NULL
|
||||
if (blk_sel) {
|
||||
status |= write_sreg(s, (uint8_t)BLK_SEL_R & 0xff, 1, &blk_sel);
|
||||
}
|
||||
|
||||
data = (regaddr & 0x00FF);
|
||||
status |= write_sreg(s, (uint8_t)MADDR_R, 1, &data);
|
||||
inv_imu_sleep_us(10);
|
||||
status |= read_sreg(s, (uint8_t)M_R, rd_cnt, buf);
|
||||
inv_imu_sleep_us(10);
|
||||
|
||||
if (blk_sel) {
|
||||
data = 0;
|
||||
status |= write_sreg(s, (uint8_t)BLK_SEL_R, 1, &data);
|
||||
}
|
||||
|
||||
// switch OFF MCLK if needed
|
||||
status |= inv_imu_switch_off_mclk(s);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int write_mclk_reg(struct inv_imu_device *s, uint16_t regaddr, uint8_t wr_cnt, const uint8_t *buf)
|
||||
{
|
||||
uint8_t data;
|
||||
uint8_t blk_sel = (regaddr & 0xFF00) >> 8;
|
||||
int status = 0;
|
||||
|
||||
// Have IMU not in IDLE mode to access MCLK domain
|
||||
status |= inv_imu_switch_on_mclk(s);
|
||||
|
||||
// optimize by changing BLK_SEL only if not NULL
|
||||
if (blk_sel) {
|
||||
status |= write_sreg(s, (uint8_t)BLK_SEL_W, 1, &blk_sel);
|
||||
}
|
||||
|
||||
data = (regaddr & 0x00FF);
|
||||
status |= write_sreg(s, (uint8_t)MADDR_W, 1, &data);
|
||||
for (uint8_t i = 0; i < wr_cnt; i++) {
|
||||
status |= write_sreg(s, (uint8_t)M_W, 1, &buf[i]);
|
||||
inv_imu_sleep_us(10);
|
||||
}
|
||||
|
||||
if (blk_sel) {
|
||||
data = 0;
|
||||
status = write_sreg(s, (uint8_t)BLK_SEL_W, 1, &data);
|
||||
}
|
||||
|
||||
status |= inv_imu_switch_off_mclk(s);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
122
apps/common/device/imu_sensor/icm_42670p/inv_imu_transport.h
Normal file
122
apps/common/device/imu_sensor/icm_42670p/inv_imu_transport.h
Normal file
@ -0,0 +1,122 @@
|
||||
/*
|
||||
* ________________________________________________________________________________________________________
|
||||
* Copyright (c) 2015-2015 InvenSense Inc. All rights reserved.
|
||||
*
|
||||
* This software, related documentation and any modifications thereto (collectively "Software") is subject
|
||||
* to InvenSense and its licensors' intellectual property rights under U.S. and international copyright
|
||||
* and other intellectual property rights laws.
|
||||
*
|
||||
* InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software
|
||||
* and any use, reproduction, disclosure or distribution of the Software without an express license agreement
|
||||
* from InvenSense is strictly prohibited.
|
||||
*
|
||||
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, 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 NON-INFRINGEMENT.
|
||||
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, IN NO EVENT SHALL
|
||||
* INVENSENSE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY
|
||||
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
||||
* OF THE SOFTWARE.
|
||||
* ________________________________________________________________________________________________________
|
||||
*/
|
||||
|
||||
/** @defgroup Transport IMU transport
|
||||
* @brief Low-level IMU SCLK register access
|
||||
* @ingroup Driver
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @file inv_imu_transport.h
|
||||
* Low-level IMU SCLK register access
|
||||
*/
|
||||
|
||||
#ifndef _INV_IMU_TRANSPORT_H_
|
||||
#define _INV_IMU_TRANSPORT_H_
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* forward declaration */
|
||||
struct inv_imu_device;
|
||||
|
||||
|
||||
/** @brief enumeration of serial interfaces available on IMU */
|
||||
typedef enum {
|
||||
UI_I2C,
|
||||
UI_SPI4,
|
||||
UI_SPI3
|
||||
} SERIAL_IF_TYPE_t;
|
||||
|
||||
/** @brief basesensor serial interface
|
||||
*/
|
||||
struct inv_imu_serif {
|
||||
void *context;
|
||||
int (*read_reg)(struct inv_imu_serif *serif, uint8_t reg, uint8_t *buf, uint32_t len);
|
||||
int (*write_reg)(struct inv_imu_serif *serif, uint8_t reg, const uint8_t *buf, uint32_t len);
|
||||
int (*configure)(struct inv_imu_serif *serif);
|
||||
uint32_t max_read;
|
||||
uint32_t max_write;
|
||||
SERIAL_IF_TYPE_t serif_type;
|
||||
};
|
||||
|
||||
/** @brief transport interface
|
||||
*/
|
||||
struct inv_imu_transport {
|
||||
struct inv_imu_serif serif; /**< Warning : this field MUST be the first one of struct inv_imu_transport */
|
||||
|
||||
/** @brief Contains mirrored values of some IP registers */
|
||||
struct register_cache {
|
||||
uint8_t pwr_mgmt0_reg; /**< PWR_MGMT0, Bank: 0 */
|
||||
uint8_t gyro_config0_reg; /**< GYRO_CONFIG0, Bank: 0 */
|
||||
uint8_t accel_config0_reg; /**< ACCEL_CONFIG0, Bank: 0 */
|
||||
uint8_t tmst_config1_reg; /**< TMST_CONFIG1, Bank: MREG_TOP1 */
|
||||
} register_cache; /**< Store mostly used register values on SRAM */
|
||||
|
||||
uint8_t need_mclk_cnt; /**< internal counter to keep track of everyone that needs MCLK */
|
||||
|
||||
};
|
||||
|
||||
/** @brief Init cache variable.
|
||||
* @return 0 in case of success, -1 for any error
|
||||
*/
|
||||
int inv_imu_init_transport(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Reads data from a register on IMU.
|
||||
* @param[in] reg register address to be read
|
||||
* @param[in] len number of byte to be read
|
||||
* @param[out] buf output data from the register
|
||||
* @return 0 in case of success, -1 for any error
|
||||
*/
|
||||
int inv_imu_read_reg(struct inv_imu_device *s, uint32_t reg, uint32_t len, uint8_t *buf);
|
||||
|
||||
/** @brief Writes data to a register on IMU.
|
||||
* @param[in] reg register address to be written
|
||||
* @param[in] len number of byte to be written
|
||||
* @param[in] buf input data to write
|
||||
* @return 0 in case of success, -1 for any error
|
||||
*/
|
||||
int inv_imu_write_reg(struct inv_imu_device *s, uint32_t reg, uint32_t len, const uint8_t *buf);
|
||||
|
||||
/** @brief Enable MCLK so that MREG are clocked and system beyond SOI can be safely accessed
|
||||
* @return 0 in case of success, -1 for any error
|
||||
*/
|
||||
int inv_imu_switch_on_mclk(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Disable MCLK so that MREG are not clocked anymore, hence reducing power consumption
|
||||
* @return 0 in case of success, -1 for any error
|
||||
*/
|
||||
int inv_imu_switch_off_mclk(struct inv_imu_device *s);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _INV_IMU_TRANSPORT_H_ */
|
||||
|
||||
/** @} */
|
||||
|
||||
38
apps/common/device/imu_sensor/icm_42670p/inv_imu_version.h
Normal file
38
apps/common/device/imu_sensor/icm_42670p/inv_imu_version.h
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* ________________________________________________________________________________________________________
|
||||
* Copyright (c) 2019 InvenSense Inc. All rights reserved.
|
||||
*
|
||||
* This software, related documentation and any modifications thereto (collectively “Software”) is subject
|
||||
* to InvenSense and its licensors' intellectual property rights under U.S. and international copyright
|
||||
* and other intellectual property rights laws.
|
||||
*
|
||||
* InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software
|
||||
* and any use, reproduction, disclosure or distribution of the Software without an express license agreement
|
||||
* from InvenSense is strictly prohibited.
|
||||
*
|
||||
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, 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 NON-INFRINGEMENT.
|
||||
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, IN NO EVENT SHALL
|
||||
* INVENSENSE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY
|
||||
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
||||
* OF THE SOFTWARE.
|
||||
* ________________________________________________________________________________________________________
|
||||
*/
|
||||
|
||||
#ifndef _INV_IMU_VERSION_H_
|
||||
#define _INV_IMU_VERSION_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define INV_IMU_VERSION_STRING "2.0.4"
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _INV_IMU_VERSION_H_ */
|
||||
|
||||
238
apps/common/device/imu_sensor/imuSensor_manage.c
Normal file
238
apps/common/device/imu_sensor/imuSensor_manage.c
Normal file
@ -0,0 +1,238 @@
|
||||
#include "imuSensor_manage.h"
|
||||
/* #include "asm/iic_hw.h" */
|
||||
/* #include "asm/iic_soft.h" */
|
||||
|
||||
#if TCFG_IMUSENSOR_ENABLE
|
||||
#undef LOG_TAG_CONST
|
||||
#define LOG_TAG "[imu]"
|
||||
#define LOG_ERROR_ENABLE
|
||||
#define LOG_INFO_ENABLE
|
||||
#include "debug.h"
|
||||
|
||||
static struct imusensor_platform_data *platform_data;
|
||||
IMU_SENSOR_INTERFACE *imuSensor_hdl = NULL;
|
||||
u8 imu_sensor_cnt = 0;
|
||||
|
||||
#if 0/*{{{*/
|
||||
u8 imusensor_write_nbyte(u8 w_chip_id, u8 register_address, u8 *buf, u8 data_len)
|
||||
{
|
||||
u8 write_len = 0;
|
||||
u8 i;
|
||||
|
||||
iic_start(imuSensor_info->iic_hdl);
|
||||
if (0 == iic_tx_byte(imuSensor_info->iic_hdl, w_chip_id)) {
|
||||
write_len = 0;
|
||||
r_printf("\n imuSensor iic w err 0\n");
|
||||
goto __wend;
|
||||
}
|
||||
|
||||
delay(imuSensor_info->iic_delay);
|
||||
|
||||
if (0 == iic_tx_byte(imuSensor_info->iic_hdl, register_address)) {
|
||||
write_len = 0;
|
||||
r_printf("\n imuSensor iic w err 1\n");
|
||||
goto __wend;
|
||||
}
|
||||
|
||||
for (i = 0; i < data_len; i++) {
|
||||
delay(imuSensor_info->iic_delay);
|
||||
if (0 == iic_tx_byte(imuSensor_info->iic_hdl, buf[i])) {
|
||||
write_len = 0;
|
||||
r_printf("\n imuSensor iic w err 2\n");
|
||||
goto __wend;
|
||||
}
|
||||
write_len++;
|
||||
}
|
||||
|
||||
__wend:
|
||||
iic_stop(imuSensor_info->iic_hdl);
|
||||
return write_len;
|
||||
}
|
||||
|
||||
u8 imusensor_read_nbyte(u8 r_chip_id, u8 register_address, u8 *buf, u8 data_len)
|
||||
{
|
||||
u8 read_len = 0;
|
||||
|
||||
iic_start(imuSensor_info->iic_hdl);
|
||||
if (0 == iic_tx_byte(imuSensor_info->iic_hdl, r_chip_id - 1)) {
|
||||
r_printf("\n imuSensor iic r err 0\n");
|
||||
read_len = 0;
|
||||
goto __rend;
|
||||
}
|
||||
|
||||
delay(imuSensor_info->iic_delay);
|
||||
if (0 == iic_tx_byte(imuSensor_info->iic_hdl, register_address)) {
|
||||
r_printf("\n imuSensor iic r err 1\n");
|
||||
read_len = 0;
|
||||
goto __rend;
|
||||
}
|
||||
|
||||
iic_start(imuSensor_info->iic_hdl);
|
||||
if (0 == iic_tx_byte(imuSensor_info->iic_hdl, r_chip_id)) {
|
||||
r_printf("\n imuSensor iic r err 2\n");
|
||||
read_len = 0;
|
||||
goto __rend;
|
||||
}
|
||||
|
||||
delay(imuSensor_info->iic_delay);
|
||||
|
||||
for (; data_len > 1; data_len--) {
|
||||
*buf++ = iic_rx_byte(imuSensor_info->iic_hdl, 1);
|
||||
read_len ++;
|
||||
}
|
||||
|
||||
*buf = iic_rx_byte(imuSensor_info->iic_hdl, 0);
|
||||
read_len ++;
|
||||
|
||||
__rend:
|
||||
iic_stop(imuSensor_info->iic_hdl);
|
||||
delay(imuSensor_info->iic_delay);
|
||||
|
||||
return read_len;
|
||||
}
|
||||
#endif/*}}}*/
|
||||
|
||||
extern char *strchrnul(const char *__s, int __c)
|
||||
__THROW __attribute_pure__ __nonnull((1));
|
||||
int imu_sensor_io_ctl(u8 *sensor_name, enum OPERATION_SENSOR cmd, void *arg)
|
||||
{
|
||||
int retval = -1;
|
||||
list_for_each_imusensor(imuSensor_hdl) {
|
||||
/* log_info("%s?=%s", sensor_name, imuSensor_hdl->logo); */
|
||||
if ((sensor_name == NULL) && (cmd == IMU_GET_SENSOR_NAME)) {
|
||||
log_info("get name:%s", imuSensor_hdl->logo);
|
||||
retval = 1;
|
||||
continue;
|
||||
}
|
||||
if (!memcmp(imuSensor_hdl->logo, sensor_name, strlen(imuSensor_hdl->logo))) {
|
||||
/* if (!memcmp(imuSensor_hdl->logo, sensor_name, sizeof(imuSensor_hdl->logo))) { */
|
||||
if ((strchrnul(sensor_name, '\0') - (u32)sensor_name) != (strrchr(imuSensor_hdl->logo, '\0') - (u32)(imuSensor_hdl->logo))) {
|
||||
goto __imu_exit;
|
||||
}
|
||||
retval = imuSensor_hdl->imu_sensor_ctl(cmd, arg);
|
||||
return retval;//1:ok
|
||||
}
|
||||
}
|
||||
__imu_exit:
|
||||
if (retval < 0) {
|
||||
log_e(">>>sensor_name(%s) io_ctl fail: sensor_name err\n", sensor_name);
|
||||
}
|
||||
return retval;//1:ok
|
||||
}
|
||||
|
||||
int imu_sensor_init(void *_data, u16 _data_size)
|
||||
{
|
||||
int retval = -1;
|
||||
u8 data_len = _data_size / sizeof(struct imusensor_platform_data);
|
||||
if (data_len < 1) {
|
||||
log_error("_data_size:%d\n", _data_size);
|
||||
return retval;
|
||||
}
|
||||
platform_data = (const struct imusensor_platform_data *)_data;
|
||||
/* log_info("-----imusensor_dev_begin:0x%x,imusensor_dev_end:0x%x", imusensor_dev_begin, imusensor_dev_end); */
|
||||
for (u8 i = 0; i < data_len; i++) {
|
||||
retval = -1;
|
||||
list_for_each_imusensor(imuSensor_hdl) {
|
||||
/* log_info("%s?=%s", platform_data[i].imu_sensor_name, imuSensor_hdl->logo); */
|
||||
if (!memcmp(imuSensor_hdl->logo, platform_data[i].imu_sensor_name, sizeof(platform_data[i].imu_sensor_name))) {
|
||||
|
||||
retval = -1;
|
||||
if (imuSensor_hdl->imu_sensor_init(&platform_data[i]) == 0) {
|
||||
g_printf(">>>>imuSensor(%s)_Init SUCC\n", platform_data[i].imu_sensor_name);
|
||||
imu_sensor_cnt++;
|
||||
retval = 1;
|
||||
} else {
|
||||
g_printf(">>>>imuSensor(%s)_Init ERROR\n", platform_data[i].imu_sensor_name);
|
||||
retval = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (retval < 0) {
|
||||
log_e(">>>imuSensor(%s) init fail: logo err\n", platform_data[i].imu_sensor_name);
|
||||
}
|
||||
}
|
||||
|
||||
return retval;//1:ok
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**********************test***********************/
|
||||
#if 0
|
||||
u8 test_buf[36 * 20]; //(8+12+12+4)*60=
|
||||
void imu_test()
|
||||
{
|
||||
u8 name_test[20] = "sh3011";
|
||||
u8 arg_data;
|
||||
/* imu_sensor_init(); */
|
||||
imu_sensor_io_ctl(name_test, 0xff, NULL);
|
||||
imu_sensor_io_ctl(NULL, IMU_GET_SENSOR_NAME, name_test);
|
||||
memset(name_test, 0, 20);
|
||||
memcpy(name_test, "sh3001", 6);
|
||||
imu_sensor_io_ctl(name_test, 0xff, NULL);
|
||||
imu_sensor_io_ctl(name_test, IMU_SENSOR_SEARCH, &arg_data);
|
||||
memset(name_test, 0, 20);
|
||||
memcpy(name_test, "mpu9250", 7);
|
||||
imu_sensor_io_ctl(name_test, 0xff, NULL);
|
||||
imu_sensor_io_ctl(name_test, IMU_SENSOR_SEARCH, &arg_data);
|
||||
memset(name_test, 0, 20);
|
||||
memcpy(name_test, "mpu6887p", 8);
|
||||
imu_sensor_io_ctl(name_test, 0xff, NULL);
|
||||
imu_sensor_io_ctl(name_test, IMU_SENSOR_SEARCH, &arg_data);
|
||||
imu_sensor_io_ctl("mpu6887p1", IMU_SENSOR_SEARCH, &arg_data);
|
||||
memset(name_test, 0, 20);
|
||||
memcpy(name_test, "qmi8658", 7);
|
||||
imu_sensor_io_ctl(name_test, 0xff, NULL);
|
||||
imu_sensor_io_ctl(name_test, IMU_SENSOR_SEARCH, &arg_data);
|
||||
memset(name_test, 0, 20);
|
||||
memcpy(name_test, "lsm6dsl", 7);
|
||||
imu_sensor_io_ctl(name_test, IMU_SENSOR_SEARCH, &arg_data);
|
||||
|
||||
memcpy(name_test, "icm42670p", 9);
|
||||
imu_sensor_io_ctl(name_test, 0xff, NULL);
|
||||
imu_sensor_io_ctl(name_test, IMU_SENSOR_SEARCH, &arg_data);
|
||||
imu_axis_data_t raw_acc_xyz;
|
||||
imu_axis_data_t raw_gyro_xyz;
|
||||
imu_sensor_data_t raw_sensor_datas;
|
||||
memset((u8 *)&raw_acc_xyz, 0, sizeof(imu_axis_data_t));
|
||||
memset((u8 *)&raw_gyro_xyz, 0, sizeof(imu_axis_data_t));
|
||||
memset((u8 *)&raw_sensor_datas, 0, sizeof(imu_sensor_data_t));
|
||||
uint64_t timestamp;
|
||||
float accel_g[3];
|
||||
float gyro_dps[3];
|
||||
float temp_degc;
|
||||
int pack_len = 0;
|
||||
while (1) {
|
||||
pack_len = imu_sensor_io_ctl(name_test, IMU_GET_SENSOR_READ_FIFO, test_buf);
|
||||
if (pack_len > 0) {
|
||||
memcpy((u8 *)×tamp, test_buf, 8);
|
||||
memcpy((u8 *)accel_g, test_buf + 8, 12);
|
||||
memcpy((u8 *)gyro_dps, test_buf + 20, 12);
|
||||
memcpy((u8 *)&temp_degc, test_buf + 32, 4);
|
||||
log_info("pack_len:%d first pack:%u: accel_g*10:%d, %d, %d, temp_degc*10:%d, gyro_dps*10:%d, %d, %d", pack_len,
|
||||
(uint32_t)timestamp,
|
||||
(s32)(accel_g[0] * 10), (s32)(accel_g[1] * 10), (s32)(accel_g[2] * 10),
|
||||
(s32)(temp_degc * 10),
|
||||
(s32)(gyro_dps[0] * 10), (s32)(gyro_dps[1] * 10), (s32)(gyro_dps[2] * 10));
|
||||
}
|
||||
|
||||
/* imu_sensor_io_ctl(name_test, IMU_SENSOR_READ_DATA, &raw_sensor_datas); */
|
||||
/* log_info("qmi8658 raw:acc_x:%d acc_y:%d acc_z:%d gyro_x:%d gyro_y:%d gyro_z:%d", raw_sensor_datas.acc.x, raw_sensor_datas.acc.y, raw_sensor_datas.acc.z, raw_sensor_datas.gyro.x, raw_sensor_datas.gyro.y, raw_sensor_datas.gyro.z); */
|
||||
/* log_info("qmi8658 temp:%d.%d\n", (u16)raw_sensor_datas.temp_data, (u16)(((u16)(raw_sensor_datas.temp_data * 100)) % 100)); */
|
||||
/* mdelay(10); */
|
||||
/* imu_sensor_io_ctl(name_test, IMU_GET_ACCEL_DATA, &raw_acc_xyz); */
|
||||
/* log_info("qmi8658 acc: %d %d %d\n", raw_acc_xyz.x, raw_acc_xyz.y, raw_acc_xyz.z); */
|
||||
/* mdelay(10); */
|
||||
/* imu_sensor_io_ctl(name_test, IMU_GET_GYRO_DATA, &raw_gyro_xyz); */
|
||||
/* log_info("qmi8658 gyro: %d %d %d\n", raw_gyro_xyz.x, raw_gyro_xyz.y, raw_gyro_xyz.z); */
|
||||
|
||||
mdelay(50);
|
||||
wdt_clear();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
82
apps/common/device/imu_sensor/imuSensor_manage.h
Normal file
82
apps/common/device/imu_sensor/imuSensor_manage.h
Normal file
@ -0,0 +1,82 @@
|
||||
#ifndef _IMUSENSOR_MANAGE_H
|
||||
#define _IMUSENSOR_MANAGE_H
|
||||
|
||||
#include "app_config.h"
|
||||
#include "system/includes.h"
|
||||
|
||||
#if TCFG_IMUSENSOR_ENABLE
|
||||
enum OPERATION_SENSOR {
|
||||
IMU_SENSOR_SEARCH = 0,//检查传感器id
|
||||
IMU_GET_SENSOR_NAME,//
|
||||
IMU_SENSOR_ENABLE,
|
||||
IMU_SENSOR_DISABLE,
|
||||
IMU_SENSOR_RESET,
|
||||
IMU_SENSOR_SLEEP,
|
||||
IMU_SENSOR_WAKEUP,
|
||||
|
||||
IMU_SENSOR_INT_DET,//传感器中断状态检查
|
||||
IMU_SENSOR_DATA_READY,//传感器数据准备就绪待读
|
||||
IMU_SENSOR_READ_DATA,//默认读传感器所有数据
|
||||
IMU_GET_ACCEL_DATA,//加速度数据
|
||||
IMU_GET_GYRO_DATA,//陀螺仪数据
|
||||
IMU_GET_MAG_DATA,//磁力计数据
|
||||
IMU_SENSOR_CHECK_DATA,//检查传感器缓存buf是否存满
|
||||
IMU_GET_SENSOR_STATUS,//获取传感器状态
|
||||
IMU_SET_SENSOR_FIFO_CONFIG,//配置传感器FIFO
|
||||
IMU_GET_SENSOR_READ_FIFO,//读取传感器FIFO数据
|
||||
IMU_SET_SENSOR_TEMP_DISABLE,//是否关闭温度传感器
|
||||
};
|
||||
typedef struct {
|
||||
char logo[20];
|
||||
s8(*imu_sensor_init)(void *arg);
|
||||
char (*imu_sensor_check)(void);
|
||||
int (*imu_sensor_ctl)(u8 cmd, void *arg);
|
||||
} IMU_SENSOR_INTERFACE;
|
||||
|
||||
typedef struct {
|
||||
u8 iic_hdl;
|
||||
u8 iic_delay; //这个延时并非影响iic的时钟频率,而是2Byte数据之间的延时
|
||||
int init_flag;
|
||||
} IMU_SENSOR_INFO;
|
||||
|
||||
struct imusensor_platform_data {
|
||||
u8 peripheral_hdl; //iic_hdl or spi_hdl
|
||||
u8 peripheral_param0; //iic_delay(iic byte间间隔) or spi_cs_pin
|
||||
u8 peripheral_param1; //spi_mode
|
||||
char imu_sensor_name[20];
|
||||
int imu_sensor_int_io;
|
||||
};
|
||||
typedef struct {
|
||||
short x;
|
||||
short y;
|
||||
short z;
|
||||
} imu_axis_data_t;
|
||||
typedef struct {
|
||||
imu_axis_data_t acc;
|
||||
imu_axis_data_t gyro;
|
||||
float temp_data;
|
||||
} imu_sensor_data_t;
|
||||
|
||||
// u8 imusensor_write_nbyte(u8 w_chip_id, u8 register_address, u8 *buf, u8 data_len);
|
||||
// u8 imusensor_read_nbyte(u8 r_chip_id, u8 register_address, u8 *buf, u8 data_len);
|
||||
int imu_sensor_io_ctl(u8 *sensor_name, enum OPERATION_SENSOR cmd, void *arg);
|
||||
int imu_sensor_init(void *_data, u16 _data_size);
|
||||
|
||||
extern IMU_SENSOR_INTERFACE imusensor_dev_begin[];
|
||||
extern IMU_SENSOR_INTERFACE imusensor_dev_end[];
|
||||
|
||||
#define REGISTER_IMU_SENSOR(imuSensor) \
|
||||
static IMU_SENSOR_INTERFACE imuSensor SEC_USED(.imusensor_dev)
|
||||
|
||||
#define list_for_each_imusensor(c) \
|
||||
for (c=imusensor_dev_begin; c<imusensor_dev_end; c++)
|
||||
|
||||
#define IMU_SENSOR_PLATFORM_DATA_BEGIN(imu_sensor_data) \
|
||||
static const struct imusensor_platform_data imu_sensor_data[] = {
|
||||
|
||||
#define IMU_SENSOR_PLATFORM_DATA_END() \
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
5969
apps/common/device/imu_sensor/lsm6dsl/lsm6dsl.c
Normal file
5969
apps/common/device/imu_sensor/lsm6dsl/lsm6dsl.c
Normal file
File diff suppressed because it is too large
Load Diff
1398
apps/common/device/imu_sensor/lsm6dsl/lsm6dsl.h
Normal file
1398
apps/common/device/imu_sensor/lsm6dsl/lsm6dsl.h
Normal file
File diff suppressed because it is too large
Load Diff
1576
apps/common/device/imu_sensor/mpu6887/mpu6887p.c
Normal file
1576
apps/common/device/imu_sensor/mpu6887/mpu6887p.c
Normal file
File diff suppressed because it is too large
Load Diff
233
apps/common/device/imu_sensor/mpu6887/mpu6887p.h
Normal file
233
apps/common/device/imu_sensor/mpu6887/mpu6887p.h
Normal file
@ -0,0 +1,233 @@
|
||||
#ifndef __MPU6887P_H_
|
||||
#define __MPU6887P_H_
|
||||
|
||||
#include <string.h>
|
||||
/******************************************************************
|
||||
a 6-axis MotionTracking device:
|
||||
a 3-axis gyroscope(±250, ±500, ±1000, and ±2000 degrees/sec.)(16-bit ADCs),
|
||||
a 3-axis accelerometer(±2g, ±4g, ±8g, and ±16g)(16-bit ADCs)
|
||||
|
||||
VDD/VDDIO: 1.71~3.45V
|
||||
FIFO:512-byte. burst read sensor data and then go into a low-power mode.
|
||||
fifo_data:out_data_reg 59~72
|
||||
Host (slave) interface supports I2C(400kHz), and 4-wire SPI(8MHz);
|
||||
no iic master,9 axes are not supported
|
||||
@The device will come up in sleep mode upon power-up
|
||||
******************************************************************/
|
||||
|
||||
#if TCFG_MPU6887P_ENABLE
|
||||
/******************************************************************
|
||||
* user config MPU6887P Macro Definition
|
||||
******************************************************************/
|
||||
#define MPU6887P_USE_I2C 0 /*IIC.(<=400kHz) */
|
||||
#define MPU6887P_USE_SPI 1 /*SPI.(<=8MHz) */
|
||||
#define MPU6887P_USER_INTERFACE TCFG_MPU6887P_INTERFACE_TYPE//MPU6887P_USE_I2C
|
||||
// #define MPU6887P_USER_INTERFACE MPU6887P_USE_SPI
|
||||
#define MPU6887P_SA0_IIC_ADDR 0 //1:iic模式SA0接VCC, 0:iic模式SA0接GND
|
||||
#define MPU6887P_6_Axis_LOW_POWER_MODE 0 //1:6_Axis_LOW_POWER_MODE(1.33ma); 0:6_Axis Low-Noise Mode(2.79ma)
|
||||
//int io config
|
||||
// #define MPU6887P_INT_IO1 IO_PORTB_03//TCFG_IOKEY_POWER_ONE_PORT //
|
||||
// #define MPU6887P_INT_IO1 IO_PORTA_06 //
|
||||
// #define MPU6887P_INT_READ_IO1() gpio_read(MPU6887P_INT_IO1)
|
||||
|
||||
|
||||
#define MPU6887P_USE_FIFO_EN 1 //0:disable fifo 1:enable fifo(fifo size:512 bytes)
|
||||
#define MPU6887P_USE_INT_EN 0 //0:disable //中断方式不成功,疑硬件问题
|
||||
#define MPU6887P_USE_WOM_EN 0 //0:disable
|
||||
#define MPU6887P_USE_FSYNC_EN 0 //0:disable
|
||||
/******************************************************************
|
||||
* MPU6887P I2C address Macro Definition
|
||||
* (7bit): (0x37)011 0111@SDO=1; (0x36)011 0110@SDO=0;
|
||||
******************************************************************/
|
||||
#if MPU6887P_SA0_IIC_ADDR
|
||||
#define MPU6887P_SLAVE_ADDRESS (0x69<<1)//0XD0
|
||||
#else
|
||||
#define MPU6887P_SLAVE_ADDRESS (0x68<<1)//0XD2
|
||||
#endif
|
||||
|
||||
typedef u16(*IMU_read)(unsigned char devAddr,
|
||||
unsigned char regAddr,
|
||||
unsigned char *readBuf,
|
||||
u16 readLen);
|
||||
typedef u16(*IMU_write)(unsigned char devAddr,
|
||||
unsigned char regAddr,
|
||||
unsigned char *writeBuf,
|
||||
u16 writeLen);
|
||||
|
||||
typedef struct {
|
||||
// u8 comms; //0:IIC; 1:SPI //改为宏控制
|
||||
#if (MPU6887P_USER_INTERFACE==MPU6887P_USE_I2C)
|
||||
u8 iic_hdl;
|
||||
u8 iic_delay; //这个延时并非影响iic的时钟频率,而是2Byte数据之间的延时
|
||||
// u8 iic_clk; //iic_clk: <=400kHz
|
||||
#elif (MPU6887P_USER_INTERFACE==MPU6887P_USE_SPI)
|
||||
u8 spi_hdl; //SPIx (role:master)
|
||||
u8 spi_cs_pin; //
|
||||
//u8 spi_work_mode;//mpu6887p only suspport 4wire(SPI_MODE_BIDIR_1BIT) (与spi结构体一样)
|
||||
// u8 port; //SPIx group:A,B,C,D (spi结构体)
|
||||
// U8 spi_clk; //spi_clk: <=8MHz (spi结构体)
|
||||
|
||||
#endif
|
||||
} mpu6887p_param;
|
||||
|
||||
/******************************************************************
|
||||
* Mpu6887p Registers Macro Definitions
|
||||
******************************************************************/
|
||||
enum Mpu6887pRegister {
|
||||
Mpu6887pRegister_XG_OFFS_TC_H = 4, //4
|
||||
Mpu6887pRegister_XG_OFFS_TC_L, //5
|
||||
Mpu6887pRegister_YG_OFFS_TC_H = 7, //7
|
||||
Mpu6887pRegister_YG_OFFS_TC_L, //8
|
||||
Mpu6887pRegister_ZG_OFFS_TC_H = 10, //10
|
||||
Mpu6887pRegister_ZG_OFFS_TC_L, //11
|
||||
Mpu6887pRegister_SELF_TEST_X_ACCEL = 13, //13
|
||||
Mpu6887pRegister_SELF_TEST_Y_ACCEL, //14
|
||||
Mpu6887pRegister_SELF_TEST_Z_ACCEL, //15
|
||||
Mpu6887pRegister_XG_OFFS_USRH = 19, //19
|
||||
Mpu6887pRegister_XG_OFFS_USRL, //20
|
||||
Mpu6887pRegister_YG_OFFS_USRH, //21
|
||||
Mpu6887pRegister_YG_OFFS_USRL, //22
|
||||
Mpu6887pRegister_ZG_OFFS_USRH, //23
|
||||
Mpu6887pRegister_ZG_OFFS_USRL, //24
|
||||
Mpu6887pRegister_SMPLRT_DIV, //25
|
||||
Mpu6887pRegister_CONFIG, //26 ////
|
||||
Mpu6887pRegister_GYRO_CONFIG, //27
|
||||
Mpu6887pRegister_ACCEL_CONFIG, //28
|
||||
Mpu6887pRegister_ACCEL_CONFIG_2, //29
|
||||
Mpu6887pRegister_LP_MODE_CFG, //30
|
||||
Mpu6887pRegister_ACCEL_WOM_X_THR = 32, //32
|
||||
Mpu6887pRegister_ACCEL_WOM_Y_THR, //33
|
||||
Mpu6887pRegister_ACCEL_WOM_Z_THR, //34
|
||||
Mpu6887pRegister_FIFO_EN, //35
|
||||
Mpu6887pRegister_FSYNC_INT = 54, //54
|
||||
Mpu6887pRegister_INT_PIN_CFG, //55
|
||||
Mpu6887pRegister_INT_ENABLE, //56
|
||||
Mpu6887pRegister_FIFO_WM_INT_STATUS,//57
|
||||
Mpu6887pRegister_INT_STATUS, //58
|
||||
Mpu6887pRegister_ACCEL_XOUT_H, //59
|
||||
Mpu6887pRegister_ACCEL_XOUT_L, //60
|
||||
Mpu6887pRegister_ACCEL_YOUT_H, //61
|
||||
Mpu6887pRegister_ACCEL_YOUT_L, //62
|
||||
Mpu6887pRegister_ACCEL_ZOUT_H, //63
|
||||
Mpu6887pRegister_ACCEL_ZOUT_L, //64
|
||||
Mpu6887pRegister_TEMP_OUT_H, //65
|
||||
Mpu6887pRegister_TEMP_OUT_L, //66
|
||||
Mpu6887pRegister_GYRO_XOUT_H, //67
|
||||
Mpu6887pRegister_GYRO_XOUT_L, //68
|
||||
Mpu6887pRegister_GYRO_YOUT_H, //69
|
||||
Mpu6887pRegister_GYRO_YOUT_L, //70
|
||||
Mpu6887pRegister_GYRO_ZOUT_H, //71
|
||||
Mpu6887pRegister_GYRO_ZOUT_L, //72
|
||||
Mpu6887pRegister_SELF_TEST_X_GYRO = 80, //80
|
||||
Mpu6887pRegister_SELF_TEST_Y_GYRO, //81
|
||||
Mpu6887pRegister_SELF_TEST_Z_GYRO, //82
|
||||
Mpu6887pRegister_E_ID0, //83
|
||||
Mpu6887pRegister_E_ID1, //84
|
||||
Mpu6887pRegister_E_ID2, //85
|
||||
Mpu6887pRegister_E_ID3, //86
|
||||
Mpu6887pRegister_E_ID4, //87
|
||||
Mpu6887pRegister_E_ID5, //88
|
||||
Mpu6887pRegister_E_ID6, //89
|
||||
Mpu6887pRegister_FIFO_WM_TH1 = 96, //96
|
||||
Mpu6887pRegister_FIFO_WM_TH2, //97
|
||||
Mpu6887pRegister_SIGNAL_PATH_RESET = 104, //104
|
||||
Mpu6887pRegister_ACCEL_INTEL_CTRL, //105
|
||||
Mpu6887pRegister_USER_CTRL, //106
|
||||
Mpu6887pRegister_PWR_MGMT_1, //107 ////
|
||||
Mpu6887pRegister_PWR_MGMT_2, //108
|
||||
Mpu6887pRegister_I2C_IF = 112, //112
|
||||
Mpu6887pRegister_FIFO_COUNTH = 114, //114
|
||||
Mpu6887pRegister_FIFO_COUNTL, //115
|
||||
Mpu6887pRegister_FIFO_R_W, //116
|
||||
Mpu6887pRegister_WHO_AM_I, //117 ////
|
||||
Mpu6887pRegister_XA_OFFSET_H = 119, //119
|
||||
Mpu6887pRegister_XA_OFFSET_L, //120
|
||||
Mpu6887pRegister_YA_OFFSET_H = 122, //122
|
||||
Mpu6887pRegister_YA_OFFSET_L, //123
|
||||
Mpu6887pRegister_ZA_OFFSET_H = 125, //125
|
||||
Mpu6887pRegister_ZA_OFFSET_L, //126
|
||||
};
|
||||
|
||||
|
||||
|
||||
// #ifndef M_PI
|
||||
// #define M_PI (3.14159265358979323846f)
|
||||
// #endif
|
||||
// #ifndef ONE_G
|
||||
// #define ONE_G (9.807f)
|
||||
// #endif
|
||||
|
||||
typedef enum Mpu6887p_fifo_format {
|
||||
MPU6887P_FORMAT_EMPTY,
|
||||
MPU6887P_FORMAT_ACCEL_8_BYTES,
|
||||
MPU6887P_FORMAT_GYRO_8_BYTES,
|
||||
MPU6887P_FORMAT_ACCEL_GYRO_14_BYTES,
|
||||
|
||||
MPU6887P_FORMAT_UNKNOWN = 0xff,
|
||||
} Mpu6887p_fifo_format;
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
Exported Functions
|
||||
****************************************************************************/
|
||||
|
||||
void mpu6887p_delay(int ms);
|
||||
void mpu6887p_interface_mode_set(u8 spi_en);//1:spi(4wire) ,0:iic
|
||||
void mpu6887p_accel_temp_rst(u8 accel_rst_en, u8 temp_rst_en);//1:rst ,0:dis
|
||||
void mpu6887p_all_reg_rst(u8 all_reg_rst_en);//1:rst ,0:dis
|
||||
void mpu6887p_device_reset();
|
||||
bool mpu6887p_set_sleep_enabled(u8 enable);// 0:唤醒MPU, 1:disable
|
||||
void mpu6887p_power_up_set();
|
||||
// void mpu6887p_clock_select(enum mpu_clock_select clock);
|
||||
void mpu6887p_disable_temp_Sensor(unsigned char temp_disable);//1:temperature disable, 0:temperature enable
|
||||
void mpu6887p_disable_acc_Sensors(u8 acc_x_disable, u8 acc_y_disable, u8 acc_z_disable);//1:disable , 0:enable
|
||||
void mpu6887p_disable_gyro_Sensors(u8 gyro_x_disable, u8 gyro_y_disable, u8 gyro_z_disable);//1:disable , 0:enable
|
||||
u8 mpu6887p_config_acc_range(u8 fsr);//fsr:0,±2g;1,±4g;2,±8g;3,±16g
|
||||
u8 mpu6887p_set_accel_dlpf(u16 lpf);//Low-Noise Mode
|
||||
// u8 mpu6887p_set_accel_low_power(u8 averag);//Low Power Mode
|
||||
u8 mpu6887p_config_gyro_range(u8 fsr);//fsr:0,±250dps;1,±500dps;2,±1000dps;3,±2000dps
|
||||
u8 mpu_set_dlpf(u16 lpf);//Low-Noise Mode
|
||||
// u8 mpu6887p_set_gyro_low_power(u8 gyro_cycle_en,u8 averag);//Low Power Mode
|
||||
u8 mpu_set_rate(u16 rate);// 设置采样速率.
|
||||
unsigned char mpu6887p_read_status(void);
|
||||
unsigned char mpu6887p_read_fsync_status(void);
|
||||
float mpu6887p_readTemp(void);
|
||||
// void mpu6887p_read_raw_acc_xyz(short raw_acc_xyz[3]);
|
||||
// void mpu6887p_read_raw_gyro_xyz(short raw_gyro_xyz[3]);
|
||||
// void mpu6887p_read_raw_acc_gyro_xyz(short raw_acc_xyz[3], short raw_gyro_xyz[3]);
|
||||
void mpu6887p_read_raw_acc_xyz(void *acc_data);
|
||||
void mpu6887p_read_raw_gyro_xyz(void *gyro_data);
|
||||
void mpu6887p_read_raw_acc_gyro_xyz(void *raw_data);
|
||||
|
||||
|
||||
#if (MPU6887P_USE_FIFO_EN)
|
||||
// void mpu6887p_fifo_rst(u8 fifo_rst_en);//1:rst ,0:dis
|
||||
// void mpu6887p_fifo_operation_enable(u8 fifo_en);//1:enable fifo ,0:dis
|
||||
// u8 mpu6887p_set_fifo_data_type(u8 acc_fifo_en, u8 gyro_fifo_en);//1:write data to fifo;0:disable.
|
||||
// u8 mpu6887p_set_fifo_mode(u8 fifo_mode_en);//1:fifo mode ; 0:stream mode.
|
||||
// unsigned char mpu6887p_set_fifo_wm_threshold(u16 watermark_level);//watermark_level:0~1023
|
||||
void mpu6887p_config_fifo(u16 watermark_level, u8 fifo_mode, u8 acc_fifo_en, u8 gyro_fifo_en);
|
||||
u16 mpu6887p_read_fifo_data(u8 *buf);
|
||||
unsigned char mpu6887p_read_fifo_wm_int_status(void);//读FIFO_R_W register清除.如果FIFO没读完,又达到fifo_wm,还会产生中断.
|
||||
#endif
|
||||
|
||||
|
||||
#if (MPU6887P_USE_INT_EN)
|
||||
u8 mpu6887p_interrupt_type_config(u8 fifo_oflow_int_en, u8 Gdrive_int_en, u8 data_RDY_int_en); //int_type_en:1-enable; 0-disable
|
||||
u8 mpu6887p_interrupt_pin_config(u8 int_pin_level, u8 int_pin_open, u8 int_pin_latch_en, u8 int_pin_clear_mode);
|
||||
u8 mpu6887p_interrupt_fsync_pin_config(u8 fsync_int_level, u8 fsync_int_mode_en);
|
||||
#endif
|
||||
|
||||
|
||||
#if (MPU6887P_USE_WOM_EN)
|
||||
// u8 mpu6887p_interrupt_WOM_type_config(u8 WOM_x_int_en, u8 WOM_y_int_en,u8 WOM_z_int_en);//int_type_en:1-enable; 0-disable
|
||||
// u8 mpu6887p_set_WOM_int_threshold(u8 acc_wom_x_thr, u8 acc_wom_y_thr, u8 acc_wom_z_thr);//
|
||||
u8 mpu6887p_WOM_mode_config(u8 acc_wom_x_thr, u8 acc_wom_y_thr, u8 acc_wom_z_thr, u16 sample_rate);//
|
||||
#endif
|
||||
|
||||
u8 mpu6887p_sensor_init(void *priv);
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
1121
apps/common/device/imu_sensor/mpu9250/mpu9250.c
Normal file
1121
apps/common/device/imu_sensor/mpu9250/mpu9250.c
Normal file
File diff suppressed because it is too large
Load Diff
182
apps/common/device/imu_sensor/mpu9250/mpu9250.h
Normal file
182
apps/common/device/imu_sensor/mpu9250/mpu9250.h
Normal file
@ -0,0 +1,182 @@
|
||||
#ifndef _MPU9250_H_
|
||||
#define _MPU9250_H_
|
||||
|
||||
|
||||
|
||||
|
||||
#if TCFG_TP_MPU9250_ENABLE
|
||||
#define SENSORS_MPU6500_BUFF_LEN 14
|
||||
#define SENSORS_MAG_BUFF_LEN 8
|
||||
|
||||
|
||||
#define MPU9250_ADDR 0X68 //器件IIC地址(AD0:GND, AD0:VCC(0X69))
|
||||
#define MPU9250_ADDRESS_W 0xD0 //陀螺地址(AD0:GND, AD0:VCC(0XD2))
|
||||
#define MPU_DEVICE_ID_REG 0X75 //器件ID寄存器
|
||||
|
||||
#define MAG_AK8963_ENABLE 1 //AK8963磁场 enable
|
||||
#define MAG_IIC_ADDRESS 0x0c //AK8963磁场从机地址(旁路直连)
|
||||
#define MAG_IIC_ADDRESS_W (MAG_IIC_ADDRESS<<1) //AK8963磁场从机地址(旁路直连)
|
||||
#define MAG_WHO_AM_I 0x00//IIC地址寄存器(默认数值0x48,只读)
|
||||
|
||||
|
||||
|
||||
// 定义MPU9250内部地址
|
||||
//****************************************
|
||||
#define MPU_SELF_TESTX_REG 0X0D //自检寄存器X
|
||||
#define MPU_SELF_TESTY_REG 0X0E //自检寄存器Y
|
||||
#define MPU_SELF_TESTZ_REG 0X0F //自检寄存器Z
|
||||
#define MPU_SELF_TESTA_REG 0X10 //自检寄存器A
|
||||
#define MPU_SAMPLE_RATE_REG 0X19 //陀螺仪采样频率分频器,典型值:0x07(125Hz)
|
||||
#define MPU_CFG_REG 0X1A //低通滤波频率,典型值:0x06(5Hz)
|
||||
#define MPU_GYRO_CFG_REG 0X1B //陀螺仪自检及测量范围,典型值:0x18(不自检,2000deg/s)
|
||||
#define MPU_ACCEL_CFG_REG 0X1C //加速计自检、测量范围及高通滤波频率,典型值:0x01(不自检,2G,5Hz)
|
||||
#define MPU_ACCEL_CFG_REG_2 0X1D //accel DLPF config
|
||||
#define MPU_MOTION_DET_REG 0X1F //运动检测阀值设置寄存器
|
||||
#define MPU_FIFO_EN_REG 0X23 //FIFO使能寄存器
|
||||
#define MPU_I2CMST_CTRL_REG 0X24 //IIC主机控制寄存器
|
||||
#define MPU_I2CSLV0_ADDR_REG 0X25 //IIC从机0器件地址寄存器
|
||||
#define MPU_I2CSLV0_REG 0X26 //IIC从机0数据地址寄存器
|
||||
#define MPU_I2CSLV0_CTRL_REG 0X27 //IIC从机0控制寄存器
|
||||
#define MPU_I2CSLV1_ADDR_REG 0X28 //IIC从机1器件地址寄存器
|
||||
#define MPU_I2CSLV1_REG 0X29 //IIC从机1数据地址寄存器
|
||||
#define MPU_I2CSLV1_CTRL_REG 0X2A //IIC从机1控制寄存器
|
||||
#define MPU_I2CSLV2_ADDR_REG 0X2B //IIC从机2器件地址寄存器
|
||||
#define MPU_I2CSLV2_REG 0X2C //IIC从机2数据地址寄存器
|
||||
#define MPU_I2CSLV2_CTRL_REG 0X2D //IIC从机2控制寄存器
|
||||
#define MPU_I2CSLV3_ADDR_REG 0X2E //IIC从机3器件地址寄存器
|
||||
#define MPU_I2CSLV3_REG 0X2F //IIC从机3数据地址寄存器
|
||||
#define MPU_I2CSLV3_CTRL_REG 0X30 //IIC从机3控制寄存器
|
||||
#define MPU_I2CSLV4_ADDR_REG 0X31 //IIC从机4器件地址寄存器
|
||||
#define MPU_I2CSLV4_REG 0X32 //IIC从机4数据地址寄存器
|
||||
#define MPU_I2CSLV4_DO_REG 0X33 //IIC从机4写数据寄存器
|
||||
#define MPU_I2CSLV4_CTRL_REG 0X34 //IIC从机4控制寄存器
|
||||
#define MPU_I2CSLV4_DI_REG 0X35 //IIC从机4读数据寄存器
|
||||
|
||||
#define MPU_I2CMST_STA_REG 0X36 //IIC主机状态寄存器
|
||||
#define MPU_INTBP_CFG_REG 0X37 //中断/旁路设置寄存器
|
||||
#define MPU_INT_EN_REG 0X38 //中断使能寄存器
|
||||
#define MPU_INT_STA_REG 0X3A //中断状态寄存器
|
||||
|
||||
#define MPU_ACCEL_XOUTH_REG 0X3B //加速度值,X轴高8位寄存器
|
||||
#define MPU_ACCEL_XOUTL_REG 0X3C //加速度值,X轴低8位寄存器
|
||||
#define MPU_ACCEL_YOUTH_REG 0X3D //加速度值,Y轴高8位寄存器
|
||||
#define MPU_ACCEL_YOUTL_REG 0X3E //加速度值,Y轴低8位寄存器
|
||||
#define MPU_ACCEL_ZOUTH_REG 0X3F //加速度值,Z轴高8位寄存器
|
||||
#define MPU_ACCEL_ZOUTL_REG 0X40 //加速度值,Z轴低8位寄存器
|
||||
|
||||
#define MPU_TEMP_OUTH_REG 0X41 //温度值高八位寄存器
|
||||
#define MPU_TEMP_OUTL_REG 0X42 //温度值低8位寄存器
|
||||
|
||||
#define MPU_GYRO_XOUTH_REG 0X43 //陀螺仪值,X轴高8位寄存器
|
||||
#define MPU_GYRO_XOUTL_REG 0X44 //陀螺仪值,X轴低8位寄存器
|
||||
#define MPU_GYRO_YOUTH_REG 0X45 //陀螺仪值,Y轴高8位寄存器
|
||||
#define MPU_GYRO_YOUTL_REG 0X46 //陀螺仪值,Y轴低8位寄存器
|
||||
#define MPU_GYRO_ZOUTH_REG 0X47 //陀螺仪值,Z轴高8位寄存器
|
||||
#define MPU_GYRO_ZOUTL_REG 0X48 //陀螺仪值,Z轴低8位寄存器
|
||||
|
||||
#define MPU_I2CSLV0_DO_REG 0X63 //IIC从机0数据寄存器
|
||||
#define MPU_I2CSLV1_DO_REG 0X64 //IIC从机1数据寄存器
|
||||
#define MPU_I2CSLV2_DO_REG 0X65 //IIC从机2数据寄存器
|
||||
#define MPU_I2CSLV3_DO_REG 0X66 //IIC从机3数据寄存器
|
||||
|
||||
#define MPU_I2CMST_DELAY_REG 0X67 //IIC主机延时管理寄存器
|
||||
#define MPU_SIGPATH_RST_REG 0X68 //信号通道复位寄存器
|
||||
#define MPU_MDETECT_CTRL_REG 0X69 //运动检测控制寄存器
|
||||
#define MPU_USER_CTRL_REG 0X6A //用户控制寄存器
|
||||
#define MPU_PWR_MGMT1_REG 0X6B //电源管理寄存器1,典型值:0x00(正常启用)
|
||||
#define MPU_PWR_MGMT2_REG 0X6C //电源管理寄存器2
|
||||
#define MPU_FIFO_CNTH_REG 0X72 //FIFO计数寄存器高八位
|
||||
#define MPU_FIFO_CNTL_REG 0X73 //FIFO计数寄存器低八位
|
||||
#define MPU_FIFO_RW_REG 0X74 //FIFO读写寄存器
|
||||
|
||||
#define MPU6500_CLOCK_INTERNAL 0x00
|
||||
#define MPU6500_CLOCK_PLL_XGYRO 0x01
|
||||
#define MPU6500_CLOCK_PLL_YGYRO 0x02
|
||||
#define MPU6500_CLOCK_PLL_ZGYRO 0x03
|
||||
#define MPU6500_CLOCK_PLL_EXT32K 0x04
|
||||
#define MPU6500_CLOCK_PLL_EXT19M 0x05
|
||||
#define MPU6500_CLOCK_KEEP_RESET 0x07
|
||||
|
||||
#define MPU6500_GYRO_FS_250 0x00
|
||||
#define MPU6500_GYRO_FS_500 0x01
|
||||
#define MPU6500_GYRO_FS_1000 0x02
|
||||
#define MPU6500_GYRO_FS_2000 0x03
|
||||
|
||||
#define MPU6500_ACCEL_FS_2 0x00
|
||||
#define MPU6500_ACCEL_FS_4 0x01
|
||||
#define MPU6500_ACCEL_FS_8 0x02
|
||||
#define MPU6500_ACCEL_FS_16 0x03
|
||||
|
||||
#define MPU6500_ACCEL_DLPF_BW_460 0x00
|
||||
#define MPU6500_ACCEL_DLPF_BW_184 0x01
|
||||
#define MPU6500_ACCEL_DLPF_BW_92 0x02
|
||||
#define MPU6500_ACCEL_DLPF_BW_41 0x03
|
||||
#define MPU6500_ACCEL_DLPF_BW_20 0x04
|
||||
#define MPU6500_ACCEL_DLPF_BW_10 0x05
|
||||
#define MPU6500_ACCEL_DLPF_BW_5 0x06
|
||||
|
||||
#define MPU6500_DLPF_BW_256 0x00
|
||||
#define MPU6500_DLPF_BW_188 0x01
|
||||
#define MPU6500_DLPF_BW_98 0x02
|
||||
#define MPU6500_DLPF_BW_42 0x03
|
||||
#define MPU6500_DLPF_BW_20 0x04
|
||||
#define MPU6500_DLPF_BW_10 0x05
|
||||
#define MPU6500_DLPF_BW_5 0x06
|
||||
|
||||
#define MPU6500_DATA_SAMPLE_RATE 100 //HZ
|
||||
/******************mag ak8963 reg*********************/
|
||||
// #define MAG_IIC_ADDRESS 0x0c //AK8963磁场从机地址(旁路直连)
|
||||
// #define MAG_WHO_AM_I 0x00//IIC地址寄存器(默认数值0x48,只读)
|
||||
#define MAG_CNTL_1 0x0A
|
||||
#define MAG_CNTL_2 0x0B
|
||||
#define MAG_STATE_1 0x02
|
||||
#define MAG_XOUT_L 0x03
|
||||
#define MAG_XOUT_H 0x04
|
||||
#define MAG_YOUT_L 0x05
|
||||
#define MAG_YOUT_H 0x06
|
||||
#define MAG_ZOUT_L 0x07
|
||||
#define MAG_ZOUT_H 0x08
|
||||
#define MAG_STATE_2 0x09
|
||||
|
||||
#define AK8963_MODE_POWERDOWN 0x00
|
||||
#define AK8963_MODE_SINGLE 0x01
|
||||
#define AK8963_MODE_CONT1 0x02
|
||||
#define AK8963_MODE_CONT2 0x06
|
||||
#define AK8963_MODE_EXTTRIG 0x04
|
||||
#define AK8963_MODE_SELFTEST 0x08
|
||||
#define AK8963_MODE_FUSEROM 0x0F
|
||||
#define AK8963_MODE_14BIT 0x00
|
||||
#define AK8963_MODE_16BIT 0x10
|
||||
|
||||
|
||||
|
||||
|
||||
// enum power_mode {
|
||||
// POWER_ACTIVE_MODE=0,
|
||||
// POWER_MONITOR_MODE=1,
|
||||
// POWER_HIBERNATE_MODE=3,//100ua.quit:need ft6336 reset
|
||||
// };
|
||||
|
||||
|
||||
typedef struct {
|
||||
u8 comms; //0:IIC; 1:SPI
|
||||
u8 iic_hdl;
|
||||
u8 iic_delay; //这个延时并非影响iic的时钟频率,而是2Byte数据之间的延时
|
||||
} mpu9250_param;
|
||||
|
||||
typedef struct {
|
||||
s16 x_data;
|
||||
s16 y_data;
|
||||
s16 z_data;
|
||||
} axis_data;
|
||||
|
||||
typedef struct {
|
||||
axis_data mag_data;
|
||||
axis_data accel_data;
|
||||
axis_data gyro_data;
|
||||
float temp_data;
|
||||
} mpu9250_data;
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
1846
apps/common/device/imu_sensor/qmi8658/qmi8658c.c
Normal file
1846
apps/common/device/imu_sensor/qmi8658/qmi8658c.c
Normal file
File diff suppressed because it is too large
Load Diff
561
apps/common/device/imu_sensor/qmi8658/qmi8658c.h
Normal file
561
apps/common/device/imu_sensor/qmi8658/qmi8658c.h
Normal file
@ -0,0 +1,561 @@
|
||||
|
||||
#ifndef __QMI8658C_H_
|
||||
#define __QMI8658C_H_
|
||||
|
||||
#include <string.h>
|
||||
/******************************************************************
|
||||
a complete 6D MEMS.
|
||||
The QMI8658C provides an I2C master interface (I2CM)to connect with an external magnetometer.
|
||||
Currently the QMI8658C can support the following magnetometers:
|
||||
AK09915C, AK09918CZ, and QMC6308.
|
||||
Host (slave) interface supports MIPI™ I3C, I2C, and
|
||||
3-wire or 4-wire SPI; auxiliary master I2C interface
|
||||
supports an external magnetometer
|
||||
******************************************************************/
|
||||
|
||||
|
||||
#if TCFG_QMI8658_ENABLE
|
||||
/******************************************************************
|
||||
* user config QMI8658 Macro Definition
|
||||
******************************************************************/
|
||||
// spi模式切换到iic模式, 传感器可能需要重新上电
|
||||
#define QMI8658_USE_I2C 0 /*IIC.(<=400kHz) */
|
||||
#define QMI8658_USE_SPI 1 /*SPI.(<=15MHz) */
|
||||
#define QMI8658_USE_I3C 2 /*I3C. */
|
||||
#define QMI8658_USER_INTERFACE TCFG_QMI8658_INTERFACE_TYPE//QMI8658_USE_I2C
|
||||
// #define QMI8658_USER_INTERFACE QMI8658_USE_SPI
|
||||
|
||||
#define QMI8658_SD0_IIC_ADDR 1 //1:iic模式SD0接VCC, 0:iic模式SD0接GND
|
||||
//int io config
|
||||
// #define QMI8658_INT_IO1 IO_PORTA_06 //高有效 1.CTRL9_protocol 2.WoM
|
||||
// #define QMI8658_INT_READ_IO1() gpio_read(QMI8658_INT_IO1)
|
||||
// #define QMI8658_INT_IO2 IO_PORTA_07 //高有效 1.data ready 2.fifo 3.test 4.AE_mode 5.WoM
|
||||
// #define QMI8658_INT_READ_IO2() gpio_read(QMI8658_INT_IO2)
|
||||
|
||||
|
||||
// 注意: fifo模式切换到寄存器模式, 传感器需要重新上电,反之不需要
|
||||
#define QMI8658_USE_FIFO_EN 1 //0:disable fifo 1:enable fifo(fifo size:1536 bytes)
|
||||
#define QMI8658_USE_INT_EN 0 //0:disable
|
||||
#define QMI8658_USE_ANYMOTION_EN 0
|
||||
#define QMI8658_USE_TAP_EN 0
|
||||
#define QMI8658_USE_STEP_EN 0
|
||||
|
||||
#define QMI8658_UINT_MG_DPS 0
|
||||
#define QMI8658_SYNC_SAMPLE_MODE 0//寄存器中断模式0:disable sync sample, 1:enable
|
||||
|
||||
#define QMI8658_HANDSHAKE_NEW
|
||||
#define QMI8658_HANDSHAKE_TO_STATUS
|
||||
#define QMI8658_NEW_HANDSHAKE 1//另一种qmi8658
|
||||
#if (QMI8658_NEW_HANDSHAKE == 1)
|
||||
#define QMI8658_FIFO_INT_OMAP_INT1 1//1:fifo中断映射到int1; 0:fifo中断映射到int2
|
||||
#endif
|
||||
/******************************************************************
|
||||
* QMI8658 I2C address Macro Definition
|
||||
* (7bit): (0x37)011 0111@SDO=1; (0x36)011 0110@SDO=0;
|
||||
******************************************************************/
|
||||
#if QMI8658_SD0_IIC_ADDR
|
||||
#define QMI8658_SLAVE_ADDRESS (0x6a<<1)//0xd4
|
||||
#else
|
||||
#define QMI8658_SLAVE_ADDRESS (0x6b<<1)//0xd6
|
||||
#endif
|
||||
|
||||
typedef u16(*IMU_read)(unsigned char devAddr,
|
||||
unsigned char regAddr,
|
||||
unsigned char *readBuf,
|
||||
u16 readLen);
|
||||
typedef unsigned char (*IMU_write)(unsigned char devAddr,
|
||||
unsigned char regAddr,
|
||||
unsigned char writebyte);
|
||||
// typedef unsigned char (*IMU_write)( unsigned char devAddr,
|
||||
// unsigned char regAddr,
|
||||
// unsigned char *writeBuf,
|
||||
// unsigned char writeLen);
|
||||
typedef struct {
|
||||
// u8 comms; //0:IIC; 1:SPI //宏控制
|
||||
#if (QMI8658_USER_INTERFACE==QMI8658_USE_I2C)
|
||||
u8 iic_hdl;
|
||||
u8 iic_delay; //这个延时并非影响iic的时钟频率,而是2Byte数据之间的延时
|
||||
// u8 iic_clk; //iic_clk: <=400kHz
|
||||
#elif (QMI8658_USER_INTERFACE==QMI8658_USE_SPI)
|
||||
u8 spi_hdl; //SPIx (role:master)
|
||||
u8 spi_cs_pin; //
|
||||
u8 spi_work_mode;//1:3wire(SPI_MODE_UNIDIR_1BIT) or 0:4wire(SPI_MODE_BIDIR_1BIT) (与spi结构体一样)
|
||||
// u8 port; //SPIx group:A,B,C,D (spi结构体)
|
||||
// U8 spi_clk; //spi_clk: <=15MHz (spi结构体)
|
||||
#else
|
||||
//I3C
|
||||
#endif
|
||||
} qmi8658_param;
|
||||
|
||||
/******************************************************************
|
||||
* QMI8658 Registers Macro Definitions
|
||||
******************************************************************/
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI (3.14159265358979323846f)
|
||||
#endif
|
||||
#ifndef ONE_G
|
||||
#define ONE_G (9.807f)
|
||||
#endif
|
||||
|
||||
#define QMI8658_CTRL7_DISABLE_ALL (0x0)
|
||||
#define QMI8658_CTRL7_ACC_ENABLE (0x1)
|
||||
#define QMI8658_CTRL7_GYR_ENABLE (0x2)
|
||||
#define QMI8658_CTRL7_MAG_ENABLE (0x4)
|
||||
#define QMI8658_CTRL7_AE_ENABLE (0x8)
|
||||
#define QMI8658_CTRL7_GYR_SNOOZE_ENABLE (0x10)
|
||||
#define QMI8658_CTRL7_ENABLE_MASK (0xF)
|
||||
|
||||
#define QMI8658_CONFIG_ACC_ENABLE QMI8658_CTRL7_ACC_ENABLE
|
||||
#define QMI8658_CONFIG_GYR_ENABLE QMI8658_CTRL7_GYR_ENABLE
|
||||
#define QMI8658_CONFIG_MAG_ENABLE QMI8658_CTRL7_MAG_ENABLE
|
||||
#define QMI8658_CONFIG_AE_ENABLE QMI8658_CTRL7_AE_ENABLE
|
||||
#define QMI8658_CONFIG_ACCGYR_ENABLE (QMI8658_CONFIG_ACC_ENABLE | QMI8658_CONFIG_GYR_ENABLE)
|
||||
#define QMI8658_CONFIG_ACCGYRMAG_ENABLE (QMI8658_CONFIG_ACC_ENABLE | QMI8658_CONFIG_GYR_ENABLE | QMI8658_CONFIG_MAG_ENABLE)
|
||||
#define QMI8658_CONFIG_AEMAG_ENABLE (QMI8658_CONFIG_AE_ENABLE | QMI8658_CONFIG_MAG_ENABLE)
|
||||
|
||||
#define QMI8658_STATUS1_CMD_DONE (0x01)
|
||||
#define QMI8658_STATUS1_WAKEUP_EVENT (0x04)
|
||||
|
||||
#if (QMI8658_NEW_HANDSHAKE)
|
||||
#define QMI8658_CTRL8_INT_SEL 0x40 // bit6: 1 int1, 0 int2
|
||||
#define QMI8658_CTRL8_PEDOMETER_EN 0x10
|
||||
#define QMI8658_CTRL8_SIGMOTION_EN 0x08
|
||||
#define QMI8658_CTRL8_NOMOTION_EN 0x04
|
||||
#define QMI8658_CTRL8_ANYMOTION_EN 0x02
|
||||
#define QMI8658_CTRL8_TAP_EN 0x01
|
||||
|
||||
#define QMI8658_INT1_ENABLE 0x08
|
||||
#define QMI8658_INT2_ENABLE 0x10
|
||||
|
||||
#define QMI8658_DRDY_DISABLE 0x20 // ctrl7
|
||||
|
||||
#define QMI8658_FIFO_MAP_INT1 0x04 // ctrl1
|
||||
#define QMI8658_FIFO_MAP_INT2 ~0x04
|
||||
#endif
|
||||
enum Qmi8658Register {
|
||||
Qmi8658Register_WhoAmI = 0, // 0
|
||||
Qmi8658Register_Revision, // 1
|
||||
Qmi8658Register_Ctrl1, // 2
|
||||
Qmi8658Register_Ctrl2, // 3
|
||||
Qmi8658Register_Ctrl3, // 4
|
||||
Qmi8658Register_Ctrl4, // 5
|
||||
Qmi8658Register_Ctrl5, // 6
|
||||
Qmi8658Register_Ctrl6, // 7
|
||||
Qmi8658Register_Ctrl7, // 8
|
||||
Qmi8658Register_Ctrl8, // 9
|
||||
Qmi8658Register_Ctrl9, // 10
|
||||
Qmi8658Register_Cal1_L = 11,
|
||||
Qmi8658Register_Cal1_H,
|
||||
Qmi8658Register_Cal2_L,
|
||||
Qmi8658Register_Cal2_H,
|
||||
Qmi8658Register_Cal3_L,
|
||||
Qmi8658Register_Cal3_H,
|
||||
Qmi8658Register_Cal4_L,
|
||||
Qmi8658Register_Cal4_H,
|
||||
Qmi8658Register_FifoWmkTh = 19,
|
||||
Qmi8658Register_FifoCtrl = 20,
|
||||
Qmi8658Register_FifoCount = 21,
|
||||
Qmi8658Register_FifoStatus = 22,
|
||||
Qmi8658Register_FifoData = 23,
|
||||
Qmi8658Register_StatusI2CM = 44,
|
||||
Qmi8658Register_StatusInt = 45,
|
||||
Qmi8658Register_Status0,
|
||||
Qmi8658Register_Status1,
|
||||
Qmi8658Register_Timestamp_L = 48,
|
||||
Qmi8658Register_Timestamp_M,
|
||||
Qmi8658Register_Timestamp_H,
|
||||
Qmi8658Register_Tempearture_L = 51,
|
||||
Qmi8658Register_Tempearture_H,
|
||||
Qmi8658Register_Ax_L = 53,
|
||||
Qmi8658Register_Ax_H,
|
||||
Qmi8658Register_Ay_L,
|
||||
Qmi8658Register_Ay_H,
|
||||
Qmi8658Register_Az_L,
|
||||
Qmi8658Register_Az_H,
|
||||
Qmi8658Register_Gx_L = 59,
|
||||
Qmi8658Register_Gx_H,
|
||||
Qmi8658Register_Gy_L,
|
||||
Qmi8658Register_Gy_H,
|
||||
Qmi8658Register_Gz_L,
|
||||
Qmi8658Register_Gz_H,
|
||||
Qmi8658Register_Mx_L = 65,
|
||||
Qmi8658Register_Mx_H,
|
||||
Qmi8658Register_My_L,
|
||||
Qmi8658Register_My_H,
|
||||
Qmi8658Register_Mz_L,
|
||||
Qmi8658Register_Mz_H,
|
||||
Qmi8658Register_Q1_L = 73,
|
||||
Qmi8658Register_Q1_H,
|
||||
Qmi8658Register_Q2_L,
|
||||
Qmi8658Register_Q2_H,
|
||||
Qmi8658Register_Q3_L,
|
||||
Qmi8658Register_Q3_H,
|
||||
Qmi8658Register_Q4_L,
|
||||
Qmi8658Register_Q4_H,
|
||||
Qmi8658Register_Dvx_L = 81,
|
||||
Qmi8658Register_Dvx_H,
|
||||
Qmi8658Register_Dvy_L,
|
||||
Qmi8658Register_Dvy_H,
|
||||
Qmi8658Register_Dvz_L,
|
||||
Qmi8658Register_Dvz_H,
|
||||
Qmi8658Register_AeReg1 = 87,
|
||||
Qmi8658Register_AeOverflow,
|
||||
Qmi8658Register_AccEl_X = 90,
|
||||
Qmi8658Register_AccEl_Y,
|
||||
Qmi8658Register_AccEl_Z,
|
||||
|
||||
Qmi8658Register_Reset = 96, //err?????
|
||||
|
||||
Qmi8658Register_I2CM_STATUS = 110, //err???
|
||||
};
|
||||
|
||||
enum Qmi8658_Ois_Register {
|
||||
/*-----------------------------*/
|
||||
/* Setup and Control Registers */
|
||||
/*-----------------------------*/
|
||||
/*! \brief SPI Endian Selection, and SPI 3/4 Wire */
|
||||
Qmi8658_OIS_Reg_Ctrl1 = 0x02, // 2 [0x02] -- Dflt: 0x20
|
||||
/*! \brief Accelerometer control: ODR, Full Scale, Self Test */
|
||||
Qmi8658_OIS_Reg_Ctrl2, // 3 [0x03]
|
||||
/*! \brief Gyroscope control: ODR, Full Scale, Self Test */
|
||||
Qmi8658_OIS_Reg_Ctrl3, // 4 [0x04]
|
||||
/*! \brief Sensor Data Processing Settings */
|
||||
Qmi8658_OIS_Reg_Ctrl5 = 0x06, // 6 [0x06]
|
||||
/*! \brief Sensor enabled status: Enable Sensors */
|
||||
Qmi8658_OIS_Reg_Ctrl7 = 0x08, // 8 [0x08]
|
||||
/*-------------------*/
|
||||
/* Status Registers */
|
||||
/*-------------------*/
|
||||
/*! \brief Sensor Data Availability and Lock Register */
|
||||
Qmi8658_OIS_Reg_StatusInt = 0x2D, // 45 [0x2D]
|
||||
/*! \brief Output data overrun and availability */
|
||||
Qmi8658_OIS_Reg_Status0 = 0x2E, // 46 [0x2E]
|
||||
|
||||
/*-----------------------------------------------------*/
|
||||
/* OIS Sensor Data Output Registers. 16-bit 2's complement */
|
||||
/*-----------------------------------------------------*/
|
||||
/*! \brief Accelerometer X axis least significant byte */
|
||||
Qmi8658_OIS_Reg_Ax_L = 0x33, // 53 [0x35]
|
||||
/*! \brief Accelerometer X axis most significant byte */
|
||||
Qmi8658_OIS_Reg_Ax_H, // 54 [0x36]
|
||||
/*! \brief Accelerometer Y axis least significant byte */
|
||||
Qmi8658_OIS_Reg_Ay_L, // 55 [0x37]
|
||||
/*! \brief Accelerometer Y axis most significant byte */
|
||||
Qmi8658_OIS_Reg_Ay_H, // 56 [0x38]
|
||||
/*! \brief Accelerometer Z axis least significant byte */
|
||||
Qmi8658_OIS_Reg_Az_L, // 57 [0x39]
|
||||
/*! \brief Accelerometer Z axis most significant byte */
|
||||
Qmi8658_OIS_Reg_Az_H, // 58 [0x3A]
|
||||
|
||||
/*! \brief Gyroscope X axis least significant byte */
|
||||
Qmi8658_OIS_Reg_Gx_L = 0x3B, // 59 [0x3B]
|
||||
/*! \brief Gyroscope X axis most significant byte */
|
||||
Qmi8658_OIS_Reg_Gx_H, // 60 [0x3C]
|
||||
/*! \brief Gyroscope Y axis least significant byte */
|
||||
Qmi8658_OIS_Reg_Gy_L, // 61 [0x3D]
|
||||
/*! \brief Gyroscope Y axis most significant byte */
|
||||
Qmi8658_OIS_Reg_Gy_H, // 62 [0x3E]
|
||||
/*! \brief Gyroscope Z axis least significant byte */
|
||||
Qmi8658_OIS_Reg_Gz_L, // 63 [0x3F]
|
||||
/*! \brief Gyroscope Z axis most significant byte */
|
||||
Qmi8658_OIS_Reg_Gz_H, // 64 [0x40]
|
||||
};
|
||||
|
||||
|
||||
enum Qmi8658_Ctrl9Command {
|
||||
Qmi8658_Ctrl9_Cmd_NOP = 0X00,
|
||||
Qmi8658_Ctrl9_Cmd_GyroBias = 0X01,
|
||||
Qmi8658_Ctrl9_Cmd_Rqst_Sdi_Mod = 0X03,
|
||||
Qmi8658_Ctrl9_Cmd_Rst_Fifo = 0X04,
|
||||
Qmi8658_Ctrl9_Cmd_Req_Fifo = 0X05,
|
||||
Qmi8658_Ctrl9_Cmd_I2CM_Write = 0X06,
|
||||
Qmi8658_Ctrl9_Cmd_WoM_Setting = 0x08,
|
||||
Qmi8658_Ctrl9_Cmd_AccelHostDeltaOffset = 0x09,
|
||||
Qmi8658_Ctrl9_Cmd_GyroHostDeltaOffset = 0x0A,
|
||||
Qmi8658_Ctrl9_Cmd_EnableExtReset = 0x0B,
|
||||
Qmi8658_Ctrl9_Cmd_EnableTap = 0x0C,
|
||||
Qmi8658_Ctrl9_Cmd_EnablePedometer = 0x0D,
|
||||
Qmi8658_Ctrl9_Cmd_Reset_Pedometer = 0x0F,
|
||||
|
||||
Qmi8658_Ctrl9_Cmd_Motion = 0x0E,
|
||||
Qmi8658_Ctrl9_Cmd_CopyUsid = 0x10,
|
||||
Qmi8658_Ctrl9_Cmd_SetRpu = 0x11,
|
||||
Qmi8658_Ctrl9_Cmd_AHB_Clock_Gating = 0x12,
|
||||
Qmi8658_Ctrl9_Cmd_On_Demand_Cali = 0xA2,
|
||||
Qmi8658_Ctrl9_Cmd_Dbg_WoM_Data_Enable = 0xF8,
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
enum Qmi8658_LpfConfig {
|
||||
Qmi8658Lpf_Disable, /*!< \brief Disable low pass filter. */
|
||||
Qmi8658Lpf_Enable /*!< \brief Enable low pass filter. */
|
||||
};
|
||||
|
||||
enum Qmi8658_HpfConfig {
|
||||
Qmi8658Hpf_Disable, /*!< \brief Disable high pass filter. */
|
||||
Qmi8658Hpf_Enable /*!< \brief Enable high pass filter. */
|
||||
};
|
||||
|
||||
enum Qmi8658_StConfig {
|
||||
Qmi8658St_Disable, /*!< \brief Disable high pass filter. */
|
||||
Qmi8658St_Enable /*!< \brief Enable high pass filter. */
|
||||
};
|
||||
|
||||
enum Qmi8658_LpfMode {
|
||||
A_LSP_MODE_0 = 0x00 << 1,
|
||||
A_LSP_MODE_1 = 0x01 << 1,
|
||||
A_LSP_MODE_2 = 0x02 << 1,
|
||||
A_LSP_MODE_3 = 0x03 << 1,
|
||||
|
||||
G_LSP_MODE_0 = 0x00 << 5,
|
||||
G_LSP_MODE_1 = 0x01 << 5,
|
||||
G_LSP_MODE_2 = 0x02 << 5,
|
||||
G_LSP_MODE_3 = 0x03 << 5
|
||||
};
|
||||
|
||||
enum Qmi8658_AccRange {
|
||||
Qmi8658AccRange_2g = 0x00 << 4, /*!< \brief +/- 2g range */
|
||||
Qmi8658AccRange_4g = 0x01 << 4, /*!< \brief +/- 4g range */
|
||||
Qmi8658AccRange_8g = 0x02 << 4, /*!< \brief +/- 8g range */
|
||||
Qmi8658AccRange_16g = 0x03 << 4 /*!< \brief +/- 16g range */
|
||||
};
|
||||
|
||||
|
||||
enum Qmi8658_AccOdr {
|
||||
Qmi8658AccOdr_8000Hz = 0x00, /*!< \brief High resolution 8000Hz output rate. */
|
||||
Qmi8658AccOdr_4000Hz = 0x01, /*!< \brief High resolution 4000Hz output rate. */
|
||||
Qmi8658AccOdr_2000Hz = 0x02, /*!< \brief High resolution 2000Hz output rate. */
|
||||
Qmi8658AccOdr_1000Hz = 0x03, /*!< \brief High resolution 1000Hz output rate. */
|
||||
Qmi8658AccOdr_500Hz = 0x04, /*!< \brief High resolution 500Hz output rate. */
|
||||
Qmi8658AccOdr_250Hz = 0x05, /*!< \brief High resolution 250Hz output rate. */
|
||||
Qmi8658AccOdr_125Hz = 0x06, /*!< \brief High resolution 125Hz output rate. */
|
||||
Qmi8658AccOdr_62_5Hz = 0x07, /*!< \brief High resolution 62.5Hz output rate. */
|
||||
Qmi8658AccOdr_31_25Hz = 0x08, /*!< \brief High resolution 31.25Hz output rate. */
|
||||
Qmi8658AccOdr_LowPower_128Hz = 0x0c, /*!< \brief Low power 128Hz output rate. */
|
||||
Qmi8658AccOdr_LowPower_21Hz = 0x0d, /*!< \brief Low power 21Hz output rate. */
|
||||
Qmi8658AccOdr_LowPower_11Hz = 0x0e, /*!< \brief Low power 11Hz output rate. */
|
||||
Qmi8658AccOdr_LowPower_3Hz = 0x0f /*!< \brief Low power 3Hz output rate. */
|
||||
};
|
||||
|
||||
enum Qmi8658_GyrRange {
|
||||
|
||||
Qmi8658GyrRange_16dps = 0 << 4, /*!< \brief +-32 degrees per second. */
|
||||
Qmi8658GyrRange_32dps = 1 << 4, /*!< \brief +-32 degrees per second. */
|
||||
Qmi8658GyrRange_64dps = 2 << 4, /*!< \brief +-64 degrees per second. */
|
||||
Qmi8658GyrRange_128dps = 3 << 4, /*!< \brief +-128 degrees per second. */
|
||||
Qmi8658GyrRange_256dps = 4 << 4, /*!< \brief +-256 degrees per second. */
|
||||
Qmi8658GyrRange_512dps = 5 << 4, /*!< \brief +-512 degrees per second. */
|
||||
Qmi8658GyrRange_1024dps = 6 << 4, /*!< \brief +-1024 degrees per second. */
|
||||
Qmi8658GyrRange_2048dps = 7 << 4, /*!< \brief +-2048 degrees per second. */
|
||||
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Gyroscope output rate configuration.
|
||||
*/
|
||||
enum Qmi8658_GyrOdr {
|
||||
Qmi8658GyrOdr_8000Hz = 0x00, /*!< \brief High resolution 8000Hz output rate. */
|
||||
Qmi8658GyrOdr_4000Hz = 0x01, /*!< \brief High resolution 4000Hz output rate. */
|
||||
Qmi8658GyrOdr_2000Hz = 0x02, /*!< \brief High resolution 2000Hz output rate. */
|
||||
Qmi8658GyrOdr_1000Hz = 0x03, /*!< \brief High resolution 1000Hz output rate. */
|
||||
Qmi8658GyrOdr_500Hz = 0x04, /*!< \brief High resolution 500Hz output rate. */
|
||||
Qmi8658GyrOdr_250Hz = 0x05, /*!< \brief High resolution 250Hz output rate. */
|
||||
Qmi8658GyrOdr_125Hz = 0x06, /*!< \brief High resolution 125Hz output rate. */
|
||||
Qmi8658GyrOdr_62_5Hz = 0x07, /*!< \brief High resolution 62.5Hz output rate. */
|
||||
Qmi8658GyrOdr_31_25Hz = 0x08 /*!< \brief High resolution 31.25Hz output rate. */
|
||||
};
|
||||
|
||||
enum Qmi8658_AeOdr {
|
||||
Qmi8658AeOdr_1Hz = 0x00, /*!< \brief 1Hz output rate. */
|
||||
Qmi8658AeOdr_2Hz = 0x01, /*!< \brief 2Hz output rate. */
|
||||
Qmi8658AeOdr_4Hz = 0x02, /*!< \brief 4Hz output rate. */
|
||||
Qmi8658AeOdr_8Hz = 0x03, /*!< \brief 8Hz output rate. */
|
||||
Qmi8658AeOdr_16Hz = 0x04, /*!< \brief 16Hz output rate. */
|
||||
Qmi8658AeOdr_32Hz = 0x05, /*!< \brief 32Hz output rate. */
|
||||
Qmi8658AeOdr_64Hz = 0x06, /*!< \brief 64Hz output rate. */
|
||||
Qmi8658AeOdr_128Hz = 0x07, /*!< \brief 128Hz output rate. */
|
||||
/*!
|
||||
* \brief Motion on demand mode.
|
||||
*
|
||||
* In motion on demand mode the application can trigger AttitudeEngine
|
||||
* output samples as necessary. This allows the AttitudeEngine to be
|
||||
* synchronized with external data sources.
|
||||
*
|
||||
* When in Motion on Demand mode the application should request new data
|
||||
* by calling the Qmi8658_requestAttitudeEngineData() function. The
|
||||
* AttitudeEngine will respond with a data ready event (INT2) when the
|
||||
* data is available to be read.
|
||||
*/
|
||||
Qmi8658AeOdr_motionOnDemand = 128
|
||||
};
|
||||
|
||||
enum Qmi8658_MagOdr {
|
||||
Qmi8658MagOdr_1000Hz = 0x00, /*!< \brief 1000Hz output rate. */
|
||||
Qmi8658MagOdr_500Hz = 0x01, /*!< \brief 500Hz output rate. */
|
||||
Qmi8658MagOdr_250Hz = 0x02, /*!< \brief 250Hz output rate. */
|
||||
Qmi8658MagOdr_125Hz = 0x03, /*!< \brief 125Hz output rate. */
|
||||
Qmi8658MagOdr_62_5Hz = 0x04, /*!< \brief 62.5Hz output rate. */
|
||||
Qmi8658MagOdr_31_25Hz = 0x05 /*!< \brief 31.25Hz output rate. */
|
||||
};
|
||||
|
||||
enum Qmi8658_MagDev {
|
||||
MagDev_AKM09918 = (0 << 3), /*!< \brief AKM09918. */
|
||||
};
|
||||
|
||||
enum Qmi8658_AccUnit {
|
||||
Qmi8658AccUnit_g, /*!< \brief Accelerometer output in terms of g (9.81m/s^2). */
|
||||
Qmi8658AccUnit_ms2 /*!< \brief Accelerometer output in terms of m/s^2. */
|
||||
};
|
||||
|
||||
enum Qmi8658_GyrUnit {
|
||||
Qmi8658GyrUnit_dps, /*!< \brief Gyroscope output in degrees/s. */
|
||||
Qmi8658GyrUnit_rads /*!< \brief Gyroscope output in rad/s. */
|
||||
};
|
||||
|
||||
enum Qmi8658_fifo_format {
|
||||
QMI8658_FORMAT_EMPTY,
|
||||
QMI8658_FORMAT_ACCEL_6_BYTES,
|
||||
QMI8658_FORMAT_GYRO_6_BYTES,
|
||||
QMI8658_FORMAT_MAG_6_BYTES,
|
||||
QMI8658_FORMAT_12_BYTES, //默认:acc + gyro
|
||||
QMI8658_FORMAT_18_BYTES, //acc + gyro + mag
|
||||
|
||||
QMI8658_FORMAT_UNKNOWN = 0xff,
|
||||
};
|
||||
|
||||
enum Qmi8658_FifoMode {
|
||||
Qmi8658_Fifo_Bypass = 0,
|
||||
Qmi8658_Fifo_Fifo = 1,
|
||||
Qmi8658_Fifo_Stream = 2,
|
||||
Qmi8658_Fifo_StreamToFifo = 3
|
||||
};
|
||||
|
||||
//fifo size:1536 bytes
|
||||
enum Qmi8658_FifoSize {
|
||||
Qmi8658_Fifo_16 = (0 << 2), //support 3 sensor
|
||||
Qmi8658_Fifo_32 = (1 << 2), //support 3 sensor
|
||||
Qmi8658_Fifo_64 = (2 << 2), //support 3 sensor
|
||||
Qmi8658_Fifo_128 = (3 << 2) //support 2 sensor
|
||||
};
|
||||
|
||||
|
||||
// enum Qmi8658_FifoWmkLevel
|
||||
// {
|
||||
// Qmi8658_Fifo_WmkEmpty = (0 << 4),
|
||||
// Qmi8658_Fifo_WmkOneQuarter = (1 << 4),
|
||||
// Qmi8658_Fifo_WmkHalf = (2 << 4),
|
||||
// Qmi8658_Fifo_WmkThreeQuarters = (3 << 4)
|
||||
// };
|
||||
|
||||
|
||||
enum Qmi8658_anymotion_G_TH {
|
||||
Qmi8658_1G = 1 << 5,
|
||||
Qmi8658_2G = 2 << 5,
|
||||
Qmi8658_3G = 3 << 5,
|
||||
Qmi8658_4G = 4 << 5,
|
||||
Qmi8658_5G = 5 << 5,
|
||||
Qmi8658_6G = 6 << 5,
|
||||
Qmi8658_7G = 7 << 5,
|
||||
Qmi8658_8G = 8 << 5,
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
struct Qmi8658_offsetCalibration {
|
||||
enum Qmi8658_AccUnit accUnit;
|
||||
float accOffset[3];
|
||||
enum Qmi8658_GyrUnit gyrUnit;
|
||||
float gyrOffset[3];
|
||||
};
|
||||
|
||||
struct Qmi8658_sensitivityCalibration {
|
||||
float accSensitivity[3];
|
||||
float gyrSensitivity[3];
|
||||
};
|
||||
|
||||
enum Qmi8658_Interrupt {
|
||||
Qmi8658_Int1_low = (0 << 6),
|
||||
Qmi8658_Int2_low = (1 << 6),
|
||||
Qmi8658_Int1_high = (2 << 6),
|
||||
Qmi8658_Int2_high = (3 << 6)
|
||||
};
|
||||
|
||||
enum Qmi8658_InterruptState {
|
||||
Qmi8658State_high = (1 << 7), /*!< Interrupt high. */
|
||||
Qmi8658State_low = (0 << 7) /*!< Interrupt low. */
|
||||
};
|
||||
|
||||
enum Qmi8658_WakeOnMotionThreshold {
|
||||
Qmi8658WomThreshold_off = 0,
|
||||
Qmi8658WomThreshold_low = 32,
|
||||
Qmi8658WomThreshold_mid = 128,
|
||||
Qmi8658WomThreshold_high = 255
|
||||
};
|
||||
|
||||
struct Qmi8658Config {
|
||||
unsigned char inputSelection;
|
||||
enum Qmi8658_AccRange accRange;
|
||||
enum Qmi8658_AccOdr accOdr;
|
||||
enum Qmi8658_GyrRange gyrRange;
|
||||
enum Qmi8658_GyrOdr gyrOdr;
|
||||
enum Qmi8658_AeOdr aeOdr;
|
||||
enum Qmi8658_MagOdr magOdr;
|
||||
enum Qmi8658_MagDev magDev;
|
||||
#if (QMI8658_USE_FIFO_EN)
|
||||
unsigned char fifo_ctrl;
|
||||
unsigned char fifo_fss;
|
||||
enum Qmi8658_fifo_format fifo_format;
|
||||
//unsigned char fifo_status;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
Exported Functions
|
||||
****************************************************************************/
|
||||
extern unsigned char qmi8658_init(u8 demand_cali_en);
|
||||
extern void Qmi8658_Config_apply(struct Qmi8658Config const *config);
|
||||
extern void Qmi8658_enableSensors(unsigned char enableFlags);
|
||||
extern void Qmi8658_read_acc_xyz(float acc_xyz[3]);
|
||||
extern void Qmi8658_read_gyro_xyz(float gyro_xyz[3]);
|
||||
extern void Qmi8658_read_xyz(float acc[3], float gyro[3], unsigned int *tim_count);
|
||||
extern void Qmi8658_read_xyz_raw(short raw_acc_xyz[3], short raw_gyro_xyz[3], unsigned int *tim_count);
|
||||
extern void Qmi8658_read_ae(float quat[4], float velocity[3]);
|
||||
extern float Qmi8658_readTemp(void);
|
||||
// extern unsigned char Qmi8658_readStatusInt(void);//无
|
||||
extern unsigned char Qmi8658_readStatus0(void);
|
||||
extern unsigned char Qmi8658_readStatus1(void);
|
||||
|
||||
extern void Qmi8658_enableWakeOnMotion(enum Qmi8658_Interrupt int_set, enum Qmi8658_WakeOnMotionThreshold threshold, unsigned char blankingTime);
|
||||
extern void Qmi8658_disableWakeOnMotion(void);
|
||||
#if (QMI8658_USE_FIFO_EN)
|
||||
extern void Qmi8658_config_fifo(unsigned char watermark, enum Qmi8658_FifoSize size, enum Qmi8658_FifoMode mode, enum Qmi8658_fifo_format format);
|
||||
// extern void Qmi8658_enable_fifo(void);//无
|
||||
unsigned short Qmi8658_read_fifo(unsigned char *data);
|
||||
void Qmi8658_get_fifo_format(enum Qmi8658_fifo_format *format);
|
||||
#endif
|
||||
#if (QMI8658_USE_STEP_EN)
|
||||
unsigned char stepConfig(unsigned short odr);
|
||||
uint32_t Qmi8658_step_read_stepcounter(uint32_t *step);
|
||||
void step_disable(void);
|
||||
#endif
|
||||
#if (QMI8658_USE_ANYMOTION_EN)
|
||||
// unsigned char anymotion_Config(enum Qmi8658_anymotion_G_TH motion_g_th, unsigned char motion_mg_th );
|
||||
void anymotion_lowpwr_config(void);
|
||||
void anymotion_high_odr_enable(void);
|
||||
void anymotion_disable(void);
|
||||
#endif
|
||||
#if (QMI8658_USE_TAP_EN)
|
||||
// unsigned char tap_Config(void);
|
||||
void tap_enable(void);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
2161
apps/common/device/imu_sensor/sh3001/sh3001.c
Normal file
2161
apps/common/device/imu_sensor/sh3001/sh3001.c
Normal file
File diff suppressed because it is too large
Load Diff
558
apps/common/device/imu_sensor/sh3001/sh3001.h
Normal file
558
apps/common/device/imu_sensor/sh3001/sh3001.h
Normal file
@ -0,0 +1,558 @@
|
||||
#ifndef __SH3001_H
|
||||
#define __SH3001_H
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
||||
#if TCFG_SH3001_ENABLE
|
||||
/******************************************************************
|
||||
* user config SH3001 Macro Definition
|
||||
******************************************************************/
|
||||
|
||||
#define SH3001_USER_INTERFACE TCFG_SH3001_INTERFACE_TYPE //0:I2C(<=400kHz), 1:SPI(<=1MHz)
|
||||
#define SH3001_SD0_IIC_ADDR 1 //1:iic模式SD0接VCC, 0:iic模式SD0接GND
|
||||
//int io config
|
||||
// #define SH3001_INT_IO1 IO_PORTB_03//TCFG_IOKEY_POWER_ONE_PORT //IO_PORTB_01
|
||||
// #define SH3001_INT_READ_IO1() gpio_read(SH3001_INT_IO1)
|
||||
#define SH3001_INT_IO2 IO_PORTA_06
|
||||
#define SH3001_INT_READ_IO2() gpio_read(SH3001_INT_IO2)
|
||||
|
||||
#define TCFG_SH3001_USER_INT_EN 1 //1:中断模式读, 0:定时模式读
|
||||
|
||||
|
||||
|
||||
/******************************************************************
|
||||
* SH3001 I2C address Macro Definition
|
||||
* (7bit): (0x37)011 0111@SDO=1; (0x36)011 0110@SDO=0;
|
||||
******************************************************************/
|
||||
#if SH3001_SD0_IIC_ADDR
|
||||
#define SH3001_ADDRESS (0x37<<1)
|
||||
#else
|
||||
#define SH3001_ADDRESS (0x36<<1)
|
||||
#endif
|
||||
/******************************************************************
|
||||
* SH3001 Registers Macro Definitions
|
||||
******************************************************************/
|
||||
#define SH3001_ACC_XL (0x00)
|
||||
#define SH3001_ACC_XH (0x01)
|
||||
#define SH3001_ACC_YL (0x02)
|
||||
#define SH3001_ACC_YH (0x03)
|
||||
#define SH3001_ACC_ZL (0x04)
|
||||
#define SH3001_ACC_ZH (0x05)
|
||||
#define SH3001_GYRO_XL (0x06)
|
||||
#define SH3001_GYRO_XH (0x07)
|
||||
#define SH3001_GYRO_YL (0x08)
|
||||
#define SH3001_GYRO_YH (0x09)
|
||||
#define SH3001_GYRO_ZL (0x0A)
|
||||
#define SH3001_GYRO_ZH (0x0B)
|
||||
#define SH3001_TEMP_ZL (0x0C)
|
||||
#define SH3001_TEMP_ZH (0x0D)
|
||||
#define SH3001_CHIP_ID (0x0F)
|
||||
#define SH3001_INT_STA0 (0x10)
|
||||
#define SH3001_INT_STA1 (0x11)
|
||||
#define SH3001_INT_STA2 (0x12)
|
||||
#define SH3001_INT_STA3 (0x14)
|
||||
#define SH3001_INT_STA4 (0x15)
|
||||
#define SH3001_FIFO_STA0 (0x16)
|
||||
#define SH3001_FIFO_STA1 (0x17)
|
||||
#define SH3001_FIFO_DATA (0x18)
|
||||
#define SH3001_TEMP_CONF0 (0x20)
|
||||
#define SH3001_TEMP_CONF1 (0x21)
|
||||
|
||||
#define SH3001_ACC_CONF0 (0x22) // accelerometer config 0x22-0x26
|
||||
#define SH3001_ACC_CONF1 (0x23)
|
||||
#define SH3001_ACC_CONF2 (0x25)
|
||||
#define SH3001_ACC_CONF3 (0x26)
|
||||
|
||||
#define SH3001_GYRO_CONF0 (0x28) // gyroscope config 0x28-0x2B
|
||||
#define SH3001_GYRO_CONF1 (0x29)
|
||||
#define SH3001_GYRO_CONF2 (0x2B)
|
||||
|
||||
#define SH3001_SPI_CONF (0x32)
|
||||
#define SH3001_FIFO_CONF0 (0x35)
|
||||
#define SH3001_FIFO_CONF1 (0x36)
|
||||
#define SH3001_FIFO_CONF2 (0x37)
|
||||
#define SH3001_FIFO_CONF3 (0x38)
|
||||
#define SH3001_FIFO_CONF4 (0x39)
|
||||
#define SH3001_MI2C_CONF0 (0x3A)
|
||||
#define SH3001_MI2C_CONF1 (0x3B)
|
||||
#define SH3001_MI2C_CMD0 (0x3C)
|
||||
#define SH3001_MI2C_CMD1 (0x3D)
|
||||
#define SH3001_MI2C_WR (0x3E)
|
||||
#define SH3001_MI2C_RD (0x3F)
|
||||
#define SH3001_INT_ENABLE0 (0x40)
|
||||
#define SH3001_INT_ENABLE1 (0x41)
|
||||
#define SH3001_INT_CONF (0x44)
|
||||
#define SH3001_INT_LIMIT (0x45)
|
||||
#define SH3001_ORIEN_INTCONF0 (0x46)
|
||||
#define SH3001_ORIEN_INTCONF1 (0x47)
|
||||
#define SH3001_ORIEN_INT_LOW (0x48)
|
||||
#define SH3001_ORIEN_INT_HIGH (0x49)
|
||||
#define SH3001_ORIEN_INT_SLOPE_LOW (0x4A)
|
||||
#define SH3001_ORIEN_INT_SLOPE_HIGH (0x4B)
|
||||
#define SH3001_ORIEN_INT_HYST_LOW (0x4C)
|
||||
#define SH3001_ORIEN_INT_HYST_HIGH (0x4D)
|
||||
#define SH3001_FLAT_INT_CONF (0x4E)
|
||||
#define SH3001_ACT_INACT_INT_CONF (0x4F)
|
||||
#define SH3001_ACT_INACT_INT_LINK (0x50)
|
||||
#define SH3001_TAP_INT_THRESHOLD (0x51)
|
||||
#define SH3001_TAP_INT_DURATION (0x52)
|
||||
#define SH3001_TAP_INT_LATENCY (0x53)
|
||||
#define SH3001_DTAP_INT_WINDOW (0x54)
|
||||
#define SH3001_ACT_INT_THRESHOLD (0x55)
|
||||
#define SH3001_ACT_INT_TIME (0x56)
|
||||
#define SH3001_INACT_INT_THRESHOLDL (0x57)
|
||||
#define SH3001_INACT_INT_TIME (0x58)
|
||||
#define SH3001_HIGHLOW_G_INT_CONF (0x59)
|
||||
#define SH3001_HIGHG_INT_THRESHOLD (0x5A)
|
||||
#define SH3001_HIGHG_INT_TIME (0x5B)
|
||||
#define SH3001_LOWG_INT_THRESHOLD (0x5C)
|
||||
#define SH3001_LOWG_INT_TIME (0x5D)
|
||||
#define SH3001_FREEFALL_INT_THRES (0x5E)
|
||||
#define SH3001_FREEFALL_INT_TIME (0x5F)
|
||||
#define SH3001_INT_PIN_MAP0 (0x79)
|
||||
#define SH3001_INT_PIN_MAP1 (0x7A)
|
||||
#define SH3001_INACT_INT_THRESHOLDM (0x7B)
|
||||
#define SH3001_INACT_INT_THRESHOLDH (0x7C)
|
||||
#define SH3001_INACT_INT_1G_REFL (0x7D)
|
||||
#define SH3001_INACT_INT_1G_REFH (0x7E)
|
||||
#define SH3001_SPI_REG_ACCESS (0x7F)
|
||||
#define SH3001_GYRO_CONF3 (0x8F)
|
||||
#define SH3001_GYRO_CONF4 (0x9F)
|
||||
#define SH3001_GYRO_CONF5 (0xAF)
|
||||
#define SH3001_CHIP_ID1 (0xDF)
|
||||
#define SH3001_AUX_I2C_CONF (0xFD)
|
||||
|
||||
|
||||
/******************************************************************
|
||||
* ACC Config Macro Definitions
|
||||
******************************************************************/
|
||||
#define SH3001_ODR_1000HZ (0x00)
|
||||
#define SH3001_ODR_500HZ (0x01)
|
||||
#define SH3001_ODR_250HZ (0x02)
|
||||
#define SH3001_ODR_125HZ (0x03)
|
||||
#define SH3001_ODR_63HZ (0x04)
|
||||
#define SH3001_ODR_31HZ (0x05)
|
||||
#define SH3001_ODR_16HZ (0x06)
|
||||
#define SH3001_ODR_2000HZ (0x08)
|
||||
#define SH3001_ODR_4000HZ (0x09)
|
||||
#define SH3001_ODR_8000HZ (0x0A)
|
||||
#define SH3001_ODR_16000HZ (0x0B)
|
||||
#define SH3001_ODR_32000HZ (0x0C)
|
||||
|
||||
#define SH3001_ACC_RANGE_16G (0x02)
|
||||
#define SH3001_ACC_RANGE_8G (0x03)
|
||||
#define SH3001_ACC_RANGE_4G (0x04)
|
||||
#define SH3001_ACC_RANGE_2G (0x05)
|
||||
|
||||
#define SH3001_ACC_ODRX040 (0x00)
|
||||
#define SH3001_ACC_ODRX025 (0x20)
|
||||
#define SH3001_ACC_ODRX011 (0x40)
|
||||
#define SH3001_ACC_ODRX004 (0x60)
|
||||
#define SH3001_ACC_ODRX002 (0x80)
|
||||
|
||||
#define SH3001_ACC_FILTER_EN (0x00)
|
||||
#define SH3001_ACC_FILTER_DIS (0x08)
|
||||
|
||||
/******************************************************************
|
||||
* GYRO Config Macro Definitions
|
||||
******************************************************************/
|
||||
#define SH3001_GYRO_RANGE_125 (0x02)
|
||||
#define SH3001_GYRO_RANGE_250 (0x03)
|
||||
#define SH3001_GYRO_RANGE_500 (0x04)
|
||||
#define SH3001_GYRO_RANGE_1000 (0x05)
|
||||
#define SH3001_GYRO_RANGE_2000 (0x06)
|
||||
|
||||
#define SH3001_GYRO_ODRX00 (0x00)
|
||||
#define SH3001_GYRO_ODRX01 (0x04)
|
||||
#define SH3001_GYRO_ODRX02 (0x08)
|
||||
#define SH3001_GYRO_ODRX03 (0x0C)
|
||||
|
||||
#define SH3001_GYRO_FILTER_EN (0x00)
|
||||
#define SH3001_GYRO_FILTER_DIS (0x10)
|
||||
|
||||
|
||||
/******************************************************************
|
||||
* Temperature Config Macro Definitions
|
||||
******************************************************************/
|
||||
#define SH3001_TEMP_ODR_500 (0x00)
|
||||
#define SH3001_TEMP_ODR_250 (0x10)
|
||||
#define SH3001_TEMP_ODR_125 (0x20)
|
||||
#define SH3001_TEMP_ODR_63 (0x30)
|
||||
|
||||
#define SH3001_TEMP_EN (0x80)
|
||||
#define SH3001_TEMP_DIS (0x00)
|
||||
|
||||
/******************************************************************
|
||||
* INT Config Macro Definitions
|
||||
******************************************************************/
|
||||
#define SH3001_INT_LOWG (0x8000)
|
||||
#define SH3001_INT_HIGHG (0x4000)
|
||||
#define SH3001_INT_INACT (0x2000)
|
||||
#define SH3001_INT_ACT (0x1000)
|
||||
#define SH3001_INT_DOUBLE_TAP (0x0800)
|
||||
#define SH3001_INT_SINGLE_TAP (0x0400)
|
||||
#define SH3001_INT_FLAT (0x0200)
|
||||
#define SH3001_INT_ORIENTATION (0x0100)
|
||||
#define SH3001_INT_FIFO_GYRO (0x0010)
|
||||
#define SH3001_INT_GYRO_READY (0x0008)
|
||||
#define SH3001_INT_ACC_FIFO (0x0004)
|
||||
#define SH3001_INT_ACC_READY (0x0002)
|
||||
#define SH3001_INT_FREE_FALL (0x0001)
|
||||
#define SH3001_INT_UP_DOWN_Z (0x0040)
|
||||
|
||||
|
||||
#define SH3001_INT_ENABLE (0x01)
|
||||
#define SH3001_INT_DISABLE (0x00)
|
||||
|
||||
#define SH3001_INT_MAP_INT1 (0x01)
|
||||
#define SH3001_INT_MAP_INT (0x00)
|
||||
|
||||
#define SH3001_INT0_LEVEL_LOW (0x80)
|
||||
#define SH3001_INT0_LEVEL_HIGH (0x7F)
|
||||
#define SH3001_INT_NO_LATCH (0x40)
|
||||
#define SH3001_INT_LATCH (0xBF)
|
||||
#define SH3001_INT1_LEVEL_LOW (0x20)
|
||||
#define SH3001_INT1_LEVEL_HIGH (0xDF)
|
||||
#define SH3001_INT_CLEAR_ANY (0x10)
|
||||
#define SH3001_INT_CLEAR_STATUS (0xEF)
|
||||
#define SH3001_INT1_NORMAL (0x04)
|
||||
#define SH3001_INT1_OD (0xFB)
|
||||
#define SH3001_INT0_NORMAL (0x01)
|
||||
#define SH3001_INT0_OD (0xFE)
|
||||
|
||||
/******************************************************************
|
||||
* Orientation Blocking Config Macro Definitions
|
||||
******************************************************************/
|
||||
#define SH3001_ORIENT_BLOCK_MODE0 (0x00)
|
||||
#define SH3001_ORIENT_BLOCK_MODE1 (0x04)
|
||||
#define SH3001_ORIENT_BLOCK_MODE2 (0x08)
|
||||
#define SH3001_ORIENT_BLOCK_MODE3 (0x0C)
|
||||
|
||||
#define SH3001_ORIENT_SYMM (0x00)
|
||||
#define SH3001_ORIENT_HIGH_ASYMM (0x01)
|
||||
#define SH3001_ORIENT_LOW_ASYMM (0x02)
|
||||
|
||||
|
||||
/******************************************************************
|
||||
* Flat Time Config Macro Definitions
|
||||
******************************************************************/
|
||||
#define SH3001_FLAT_TIME_500MS (0x40)
|
||||
#define SH3001_FLAT_TIME_1000MS (0x80)
|
||||
#define SH3001_FLAT_TIME_2000MS (0xC0)
|
||||
|
||||
|
||||
/******************************************************************
|
||||
* ACT and INACT Int Config Macro Definitions
|
||||
******************************************************************/
|
||||
#define SH3001_ACT_AC_MODE (0x80)
|
||||
#define SH3001_ACT_DC_MODE (0x00)
|
||||
#define SH3001_ACT_X_INT_EN (0x40)
|
||||
#define SH3001_ACT_X_INT_DIS (0x00)
|
||||
#define SH3001_ACT_Y_INT_EN (0x20)
|
||||
#define SH3001_ACT_Y_INT_DIS (0x00)
|
||||
#define SH3001_ACT_Z_INT_EN (0x10)
|
||||
#define SH3001_ACT_Z_INT_DIS (0x00)
|
||||
|
||||
|
||||
#define SH3001_INACT_AC_MODE (0x08)
|
||||
#define SH3001_INACT_DC_MODE (0x00)
|
||||
#define SH3001_INACT_X_INT_EN (0x04)
|
||||
#define SH3001_INACT_X_INT_DIS (0x00)
|
||||
#define SH3001_INACT_Y_INT_EN (0x02)
|
||||
#define SH3001_INACT_Y_INT_DIS (0x00)
|
||||
#define SH3001_INACT_Z_INT_EN (0x01)
|
||||
#define SH3001_INACT_Z_INT_DIS (0x00)
|
||||
|
||||
|
||||
#define SH3001_LINK_PRE_STA (0x01)
|
||||
#define SH3001_LINK_PRE_STA_NO (0x00)
|
||||
|
||||
|
||||
/******************************************************************
|
||||
* TAP Int Config Macro Definitions
|
||||
******************************************************************/
|
||||
#define SH3001_TAP_X_INT_EN (0x08)
|
||||
#define SH3001_TAP_X_INT_DIS (0x00)
|
||||
#define SH3001_TAP_Y_INT_EN (0x04)
|
||||
#define SH3001_TAP_Y_INT_DIS (0x00)
|
||||
#define SH3001_TAP_Z_INT_EN (0x02)
|
||||
#define SH3001_TAP_Z_INT_DIS (0x00)
|
||||
|
||||
|
||||
/******************************************************************
|
||||
* HIGHG Int Config Macro Definitions
|
||||
******************************************************************/
|
||||
#define SH3001_HIGHG_ALL_INT_EN (0x80)
|
||||
#define SH3001_HIGHG_ALL_INT_DIS (0x00)
|
||||
#define SH3001_HIGHG_X_INT_EN (0x40)
|
||||
#define SH3001_HIGHG_X_INT_DIS (0x00)
|
||||
#define SH3001_HIGHG_Y_INT_EN (0x20)
|
||||
#define SH3001_HIGHG_Y_INT_DIS (0x00)
|
||||
#define SH3001_HIGHG_Z_INT_EN (0x10)
|
||||
#define SH3001_HIGHG_Z_INT_DIS (0x00)
|
||||
|
||||
|
||||
/******************************************************************
|
||||
* LOWG Int Config Macro Definitions
|
||||
******************************************************************/
|
||||
#define SH3001_LOWG_ALL_INT_EN (0x01)
|
||||
#define SH3001_LOWG_ALL_INT_DIS (0x00)
|
||||
|
||||
|
||||
/******************************************************************
|
||||
* SPI Interface Config Macro Definitions
|
||||
******************************************************************/
|
||||
#define SH3001_SPI_3_WIRE (0x01)
|
||||
#define SH3001_SPI_4_WIRE (0x00)
|
||||
|
||||
|
||||
|
||||
/******************************************************************
|
||||
* FIFO Config Macro Definitions
|
||||
******************************************************************/
|
||||
#define SH3001_FIFO_MODE_DIS (0x00)
|
||||
#define SH3001_FIFO_MODE_FIFO (0x01)
|
||||
#define SH3001_FIFO_MODE_STREAM (0x02)
|
||||
#define SH3001_FIFO_MODE_TRIGGER (0x03)
|
||||
|
||||
#define SH3001_FIFO_ACC_DOWNS_EN (0x80)
|
||||
#define SH3001_FIFO_ACC_DOWNS_DIS (0x00)
|
||||
#define SH3001_FIFO_GYRO_DOWNS_EN (0x08)
|
||||
#define SH3001_FIFO_GYRO_DOWNS_DIS (0x00)
|
||||
|
||||
#define SH3001_FIFO_FREQ_X1_2 (0x00)
|
||||
#define SH3001_FIFO_FREQ_X1_4 (0x01)
|
||||
#define SH3001_FIFO_FREQ_X1_8 (0x02)
|
||||
#define SH3001_FIFO_FREQ_X1_16 (0x03)
|
||||
#define SH3001_FIFO_FREQ_X1_32 (0x04)
|
||||
#define SH3001_FIFO_FREQ_X1_64 (0x05)
|
||||
#define SH3001_FIFO_FREQ_X1_128 (0x06)
|
||||
#define SH3001_FIFO_FREQ_X1_256 (0x07)
|
||||
|
||||
#define SH3001_FIFO_EXT_Z_EN (0x2000)
|
||||
#define SH3001_FIFO_EXT_Y_EN (0x1000)
|
||||
#define SH3001_FIFO_EXT_X_EN (0x0080)
|
||||
#define SH3001_FIFO_TEMPERATURE_EN (0x0040)
|
||||
#define SH3001_FIFO_GYRO_Z_EN (0x0020)
|
||||
#define SH3001_FIFO_GYRO_Y_EN (0x0010)
|
||||
#define SH3001_FIFO_GYRO_X_EN (0x0008)
|
||||
#define SH3001_FIFO_ACC_Z_EN (0x0004)
|
||||
#define SH3001_FIFO_ACC_Y_EN (0x0002)
|
||||
#define SH3001_FIFO_ACC_X_EN (0x0001)
|
||||
#define SH3001_FIFO_ALL_DIS (0x0000)
|
||||
|
||||
/******************************************************************
|
||||
* AUX I2C Config Macro Definitions
|
||||
******************************************************************/
|
||||
#define SH3001_MI2C_NORMAL_MODE (0x00)
|
||||
#define SH3001_MI2C_BYPASS_MODE (0x01)
|
||||
|
||||
#define SH3001_MI2C_READ_ODR_200HZ (0x00)
|
||||
#define SH3001_MI2C_READ_ODR_100HZ (0x10)
|
||||
#define SH3001_MI2C_READ_ODR_50HZ (0x20)
|
||||
#define SH3001_MI2C_READ_ODR_25HZ (0x30)
|
||||
|
||||
#define SH3001_MI2C_FAIL (0x20)
|
||||
#define SH3001_MI2C_SUCCESS (0x10)
|
||||
|
||||
#define SH3001_MI2C_READ_MODE_AUTO (0x40)
|
||||
#define SH3001_MI2C_READ_MODE_MANUAL (0x00)
|
||||
|
||||
|
||||
|
||||
/******************************************************************
|
||||
* Other Macro Definitions
|
||||
******************************************************************/
|
||||
#define SH3001_TRUE (1)
|
||||
#define SH3001_FALSE (0)
|
||||
|
||||
|
||||
#define SH3001_NORMAL_MODE (0x00)
|
||||
#define SH3001_SLEEP_MODE (0x01)
|
||||
#define SH3001_POWERDOWN_MODE (0x02)
|
||||
#define SH3001_ACC_NORMAL_MODE (0x03)
|
||||
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* Type Definitions
|
||||
****************************************************************************/
|
||||
typedef unsigned char (*IMU_read)(unsigned char devAddr,
|
||||
unsigned char regAddr,
|
||||
unsigned char readLen,
|
||||
unsigned char *readBuf);
|
||||
|
||||
typedef unsigned char (*IMU_write)(unsigned char devAddr,
|
||||
unsigned char regAddr,
|
||||
unsigned char writeLen,
|
||||
unsigned char *writeBuf);
|
||||
|
||||
typedef struct {
|
||||
signed char cXY;
|
||||
signed char cXZ;
|
||||
signed char cYX;
|
||||
signed char cYZ;
|
||||
signed char cZX;
|
||||
signed char cZY;
|
||||
signed char jX;
|
||||
signed char jY;
|
||||
signed char jZ;
|
||||
unsigned char xMulti;
|
||||
unsigned char yMulti;
|
||||
unsigned char zMulti;
|
||||
unsigned char paramP0;
|
||||
} compCoefType;
|
||||
|
||||
|
||||
typedef struct {
|
||||
// u8 comms; //0:IIC; 1:SPI //宏控制
|
||||
#if (SH3001_USER_INTERFACE==0)
|
||||
u8 iic_hdl;
|
||||
u8 iic_delay; //这个延时并非影响iic的时钟频率,而是2Byte数据之间的延时
|
||||
// u8 iic_clk; //iic_clk: <=400kHz
|
||||
#else
|
||||
u8 spi_hdl; //SPIx (role:master)
|
||||
u8 spi_cs_pin; //
|
||||
u8 spi_work_mode;//1:3wire(SPI_MODE_UNIDIR_1BIT) or 0:4wire(SPI_MODE_BIDIR_1BIT) (与spi结构体一样)
|
||||
// u8 port; //SPIx group:A,B,C,D (spi结构体)
|
||||
// U8 spi_clk; //spi_clk: <=1MHz (spi结构体)
|
||||
#endif
|
||||
} sh3001_param;
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
Exported Functions
|
||||
****************************************************************************/
|
||||
|
||||
extern unsigned char SH3001_init(void);
|
||||
extern void SH3001_GetImuData(short accData[3], short gyroData[3]);
|
||||
extern void SH3001_GetImuCompData(short accData[3], short gyroData[3]);
|
||||
extern float SH3001_GetTempData(void);
|
||||
extern unsigned char SH3001_SwitchPowerMode(unsigned char powerMode);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// interrupt related fucntions
|
||||
extern void SH3001_INT_Enable(unsigned short int intType,
|
||||
unsigned char intEnable,
|
||||
unsigned char intPinSel);
|
||||
|
||||
extern void SH3001_INT_Config(unsigned char int0Level,
|
||||
unsigned char intLatch,
|
||||
unsigned char int1Level,
|
||||
unsigned char intClear,
|
||||
unsigned char int1Mode,
|
||||
unsigned char int0Mode,
|
||||
unsigned char intTime);
|
||||
|
||||
extern void SH3001_INT_LowG_Config(unsigned char lowGEnDisIntAll,
|
||||
unsigned char lowGThres,
|
||||
unsigned char lowGTimsMs);
|
||||
|
||||
extern void SH3001_INT_HighG_Config(unsigned char highGEnDisIntX,
|
||||
unsigned char highGEnDisIntY,
|
||||
unsigned char highGEnDisIntZ,
|
||||
unsigned char highGEnDisIntAll,
|
||||
unsigned char highGThres,
|
||||
unsigned char highGTimsMs);
|
||||
|
||||
extern void SH3001_INT_Inact_Config(unsigned char inactEnDisIntX,
|
||||
unsigned char inactEnDisIntY,
|
||||
unsigned char inactEnDisIntZ,
|
||||
unsigned char inactIntMode,
|
||||
unsigned char inactLinkStatus,
|
||||
unsigned char inactTimeS,
|
||||
unsigned int inactIntThres,
|
||||
unsigned short int inactG1);
|
||||
|
||||
extern void SH3001_INT_Act_Config(unsigned char actEnDisIntX,
|
||||
unsigned char actEnDisIntY,
|
||||
unsigned char actEnDisIntZ,
|
||||
unsigned char actIntMode,
|
||||
unsigned char actTimeNum,
|
||||
unsigned char actIntThres,
|
||||
unsigned char actLinkStatus);
|
||||
|
||||
extern void SH3001_INT_Tap_Config(unsigned char tapEnDisIntX,
|
||||
unsigned char tapEnDisIntY,
|
||||
unsigned char tapEnDisIntZ,
|
||||
unsigned char tapIntThres,
|
||||
unsigned char tapTimeMs,
|
||||
unsigned char tapWaitTimeMs,
|
||||
unsigned char tapWaitTimeWindowMs);
|
||||
|
||||
extern void SH3001_INT_Flat_Config(unsigned char flatTimeTH,
|
||||
unsigned char flatTanHeta2);
|
||||
|
||||
extern void SH3001_INT_Orient_Config(unsigned char orientBlockMode,
|
||||
unsigned char orientMode,
|
||||
unsigned char orientTheta,
|
||||
unsigned short orientG1point5,
|
||||
unsigned short orientSlope,
|
||||
unsigned short orientHyst);
|
||||
|
||||
extern void SH3001_INT_FreeFall_Config(unsigned char freeFallThres,
|
||||
unsigned char freeFallTimsMs);
|
||||
|
||||
extern unsigned short SH3001_INT_Read_Status0(void);
|
||||
|
||||
extern unsigned char SH3001_INT_Read_Status2(void);
|
||||
|
||||
extern unsigned char SH3001_INT_Read_Status3(void);
|
||||
|
||||
extern unsigned char SH3001_INT_Read_Status4(void);
|
||||
|
||||
extern void SH3001_pre_INT_config(void);
|
||||
|
||||
|
||||
|
||||
|
||||
// Fifo related fucntions
|
||||
extern void SH3001_FIFO_Reset(unsigned char fifoMode);
|
||||
|
||||
extern void SH3001_FIFO_Freq_Config(unsigned char fifoAccDownSampleEnDis,
|
||||
unsigned char fifoAccFreq,
|
||||
unsigned char fifoGyroDownSampleEnDis,
|
||||
unsigned char fifoGyroFreq);
|
||||
|
||||
extern void SH3001_FIFO_Data_Config(unsigned short fifoMode,
|
||||
unsigned short fifoWaterMarkLevel);
|
||||
|
||||
|
||||
extern unsigned char SH3001_FIFO_Read_Status(unsigned short int *fifoEntriesCount);
|
||||
|
||||
extern void SH3001_FIFO_Read_Data(unsigned char *fifoReadData,
|
||||
unsigned short int fifoDataLength);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Master I2C related fucntions
|
||||
extern void SH3001_MI2C_Reset(void);
|
||||
|
||||
extern void SH3001_MI2C_Bus_Config(unsigned char mi2cReadMode,
|
||||
unsigned char mi2cODR,
|
||||
unsigned char mi2cFreq);
|
||||
|
||||
extern void SH3001_MI2C_Cmd_Config(unsigned char mi2cSlaveAddr,
|
||||
unsigned char mi2cSlaveCmd,
|
||||
unsigned char mi2cReadMode);
|
||||
|
||||
extern unsigned char SH3001_MI2C_Write(unsigned char mi2cWriteData);
|
||||
|
||||
extern unsigned char SH3001_MI2C_Read(unsigned char *mi2cReadData);
|
||||
|
||||
|
||||
|
||||
|
||||
// SPI interface related fucntions
|
||||
extern void SH3001_SPI_Config(unsigned char spiInterfaceMode);
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
275
apps/common/device/in_ear_detect/in_ear_detect.c
Normal file
275
apps/common/device/in_ear_detect/in_ear_detect.c
Normal file
@ -0,0 +1,275 @@
|
||||
#include "in_ear_detect/in_ear_manage.h"
|
||||
#include "in_ear_detect/in_ear_detect.h"
|
||||
|
||||
#include "system/includes.h"
|
||||
#include "app_config.h"
|
||||
|
||||
#define LOG_TAG_CONST EAR_DETECT
|
||||
#define LOG_TAG "[EAR_DETECT]"
|
||||
#define LOG_INFO_ENABLE
|
||||
#include "debug.h"
|
||||
|
||||
//#define log_info(format, ...) y_printf("[EAR_DETECT] : " format "\r\n", ## __VA_ARGS__)
|
||||
|
||||
#if TCFG_EAR_DETECT_ENABLE
|
||||
|
||||
static struct ear_detect_t _ear_detect_t = {
|
||||
.is_idle = 1,
|
||||
.in_cnt = 0,
|
||||
.out_cnt = 0,
|
||||
.s_hi_timer = 0,
|
||||
.check_status = DETECT_IDLE,
|
||||
};
|
||||
|
||||
u8 io_key_filter_flag = 0;
|
||||
#define __this (&_ear_detect_t)
|
||||
|
||||
//*********************************************************************************//
|
||||
// IR Detect //
|
||||
//*********************************************************************************//
|
||||
static void __ear_detect_ir_init(void)
|
||||
{
|
||||
log_info("%s\n", __func__);
|
||||
//IR VDD
|
||||
if (TCFG_EAR_DET_IR_POWER_IO != NO_CONFIG_PORT) {
|
||||
gpio_set_pull_up(TCFG_EAR_DET_IR_POWER_IO, 0);
|
||||
gpio_set_pull_down(TCFG_EAR_DET_IR_POWER_IO, 0);
|
||||
gpio_set_die(TCFG_EAR_DET_IR_POWER_IO, 1);
|
||||
gpio_set_direction(TCFG_EAR_DET_IR_POWER_IO, 0);
|
||||
gpio_set_hd0(TCFG_EAR_DET_IR_POWER_IO, 1);
|
||||
gpio_set_hd(TCFG_EAR_DET_IR_POWER_IO, 1);
|
||||
gpio_set_output_value(TCFG_EAR_DET_IR_POWER_IO, 1);
|
||||
}
|
||||
|
||||
|
||||
//ir i01 init
|
||||
gpio_set_pull_up(TCFG_EAR_DETECT_IRO1, 0);
|
||||
gpio_set_pull_down(TCFG_EAR_DETECT_IRO1, 0);
|
||||
gpio_set_direction(TCFG_EAR_DETECT_IRO1, 0);
|
||||
gpio_set_output_value(TCFG_EAR_DETECT_IRO1, !TCFG_EAR_DETECT_IRO1_LEVEL);
|
||||
|
||||
//ir i02 init
|
||||
#if TCFG_EAR_DETECT_IR_MODE
|
||||
log_info("ear_detect_ir_ad_mode\n");
|
||||
adc_add_sample_ch(TCFG_EAR_DETECT_AD_CH);
|
||||
gpio_set_pull_up(TCFG_EAR_DETECT_IRO2, !TCFG_EAR_DETECT_DET_LEVEL);
|
||||
gpio_set_pull_down(TCFG_EAR_DETECT_IRO2, TCFG_EAR_DETECT_DET_LEVEL);
|
||||
gpio_set_die(TCFG_EAR_DETECT_IRO2, 0);
|
||||
gpio_set_direction(TCFG_EAR_DETECT_IRO2, 1);
|
||||
#else
|
||||
log_info("ear_detect_ir_io_mode\n");
|
||||
gpio_set_pull_up(TCFG_EAR_DETECT_IRO2, !TCFG_EAR_DETECT_DET_LEVEL);
|
||||
gpio_set_pull_down(TCFG_EAR_DETECT_IRO2, TCFG_EAR_DETECT_DET_LEVEL);
|
||||
gpio_set_die(TCFG_EAR_DETECT_IRO2, 1);
|
||||
gpio_set_direction(TCFG_EAR_DETECT_IRO2, 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
extern u8 get_charge_online_flag(void);
|
||||
static void __ear_detect_ir_run(void *priv)
|
||||
{
|
||||
if (get_charge_online_flag()) {
|
||||
__this->check_status = DETECT_IDLE;
|
||||
gpio_set_output_value(TCFG_EAR_DETECT_IRO1, !TCFG_EAR_DETECT_IRO1_LEVEL);
|
||||
sys_hi_timer_modify(__this->s_hi_timer, __this->cfg->ear_det_ir_disable_time);
|
||||
//ear_detect_change_state_to_event(!TCFG_EAR_DETECT_DET_LEVEL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (__this->check_status == DETECT_IDLE) {
|
||||
//read det_level without enable power_port,maybe under sun
|
||||
if (__this->cfg->ear_det_ir_compensation_en == 1) {
|
||||
if (gpio_read(TCFG_EAR_DETECT_IRO2) == TCFG_EAR_DETECT_DET_LEVEL) {
|
||||
//putchar('L');
|
||||
if (is_ear_detect_state_in() == 1) {
|
||||
ear_detect_change_state_to_event(!TCFG_EAR_DETECT_DET_LEVEL);
|
||||
__this->in_cnt = 0;
|
||||
__this->is_idle = 1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
__this->check_status = DETECT_CHECKING;
|
||||
gpio_set_output_value(TCFG_EAR_DETECT_IRO1, TCFG_EAR_DETECT_IRO1_LEVEL);
|
||||
|
||||
sys_hi_timer_modify(__this->s_hi_timer, __this->cfg->ear_det_ir_enable_time);
|
||||
return;
|
||||
}
|
||||
#if (!TCFG_EAR_DETECT_IR_MODE)
|
||||
if (gpio_read(TCFG_EAR_DETECT_IRO2) == TCFG_EAR_DETECT_DET_LEVEL) { //入耳
|
||||
#else
|
||||
u32 ear_ad = adc_get_value(TCFG_EAR_DETECT_AD_CH);
|
||||
if (ear_ad >= TCFG_EAR_DETECT_AD_VALUE) {
|
||||
#endif
|
||||
//putchar('i');
|
||||
__this->out_cnt = 0;
|
||||
if (__this->in_cnt < __this->cfg->ear_det_in_cnt) {
|
||||
__this->is_idle = 0; //过滤期间不进入sniff
|
||||
__this->in_cnt++;
|
||||
if (__this->in_cnt == __this->cfg->ear_det_in_cnt) {
|
||||
log_info("earphone ir in\n");
|
||||
#if TCFG_KEY_IN_EAR_FILTER_ENABLE
|
||||
if (gpio_read(IO_PORTB_01) == 0) {
|
||||
io_key_filter_flag = 1;
|
||||
} else {
|
||||
io_key_filter_flag = 0;
|
||||
}
|
||||
#endif
|
||||
__this->is_idle = 1;
|
||||
ear_detect_change_state_to_event(TCFG_EAR_DETECT_DET_LEVEL);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//putchar('o');
|
||||
__this->in_cnt = 0;
|
||||
if (__this->out_cnt < __this->cfg->ear_det_out_cnt) {
|
||||
__this->is_idle = 0; //过滤期间不进入sniff
|
||||
__this->out_cnt++;
|
||||
if (__this->out_cnt == __this->cfg->ear_det_out_cnt) {
|
||||
log_info("earphone ir out\n");
|
||||
__this->is_idle = 1;
|
||||
ear_detect_change_state_to_event(!TCFG_EAR_DETECT_DET_LEVEL);
|
||||
}
|
||||
}
|
||||
}
|
||||
__this->check_status = DETECT_IDLE;
|
||||
gpio_set_output_value(TCFG_EAR_DETECT_IRO1, !TCFG_EAR_DETECT_IRO1_LEVEL);
|
||||
sys_hi_timer_modify(__this->s_hi_timer, __this->cfg->ear_det_ir_disable_time);
|
||||
}
|
||||
|
||||
//*********************************************************************************//
|
||||
// TCH Detect //
|
||||
//*********************************************************************************//
|
||||
void ear_detect_tch_wakeup_init(void)
|
||||
{
|
||||
log_info("%s\n", __func__);
|
||||
|
||||
gpio_set_direction(TCFG_EAR_DETECT_DET_IO, 1);
|
||||
gpio_set_die(TCFG_EAR_DETECT_DET_IO, 1);
|
||||
gpio_set_pull_up(TCFG_EAR_DETECT_DET_IO, 1);
|
||||
gpio_set_pull_down(TCFG_EAR_DETECT_DET_IO, 0);
|
||||
}
|
||||
|
||||
void __ear_detect_tch_run(void *priv)
|
||||
{
|
||||
if (__this->check_status == DETECT_IDLE) {
|
||||
__this->check_status = DETECT_CHECKING;
|
||||
gpio_set_pull_up(TCFG_EAR_DETECT_DET_IO, 1);
|
||||
gpio_set_pull_down(TCFG_EAR_DETECT_DET_IO, 0);
|
||||
gpio_set_die(TCFG_EAR_DETECT_DET_IO, 1);
|
||||
gpio_set_direction(TCFG_EAR_DETECT_DET_IO, 1);
|
||||
sys_hi_timer_modify(__this->s_hi_timer, 2);
|
||||
return;
|
||||
}
|
||||
if (gpio_read(TCFG_EAR_DETECT_DET_IO) == TCFG_EAR_DETECT_DET_LEVEL) { //入耳
|
||||
__this->out_cnt = 0;
|
||||
if (__this->in_cnt < __this->cfg->ear_det_in_cnt) {
|
||||
//putchar('i');
|
||||
__this->is_idle = 0; //过滤期间不进入idle
|
||||
__this->in_cnt++;
|
||||
if (__this->in_cnt == __this->cfg->ear_det_in_cnt) {
|
||||
log_info("earphone touch in\n");
|
||||
#if TCFG_KEY_IN_EAR_FILTER_ENABLE
|
||||
if (gpio_read(IO_PORTB_01) == 0) {
|
||||
io_key_filter_flag = 1;
|
||||
} else {
|
||||
io_key_filter_flag = 0;
|
||||
}
|
||||
#endif
|
||||
__this->is_idle = 1;
|
||||
ear_detect_change_state_to_event(TCFG_EAR_DETECT_DET_LEVEL);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
__this->in_cnt = 0;
|
||||
if (__this->out_cnt < __this->cfg->ear_det_out_cnt) {
|
||||
//putchar('o');
|
||||
__this->is_idle = 0; //过滤期间不进入idle
|
||||
__this->out_cnt++;
|
||||
if (__this->out_cnt == __this->cfg->ear_det_out_cnt) {
|
||||
log_info("earphone touch out\n");
|
||||
__this->is_idle = 1;
|
||||
ear_detect_change_state_to_event(!TCFG_EAR_DETECT_DET_LEVEL);
|
||||
}
|
||||
}
|
||||
}
|
||||
__this->check_status = DETECT_IDLE;
|
||||
gpio_set_pull_up(TCFG_EAR_DETECT_DET_IO, 0);
|
||||
gpio_set_pull_down(TCFG_EAR_DETECT_DET_IO, 0);
|
||||
gpio_set_die(TCFG_EAR_DETECT_DET_IO, 0);
|
||||
gpio_set_direction(TCFG_EAR_DETECT_DET_IO, 1);
|
||||
sys_hi_timer_modify(__this->s_hi_timer, 10);
|
||||
}
|
||||
|
||||
|
||||
//*********************************************************************************//
|
||||
// Detect //
|
||||
//*********************************************************************************//
|
||||
|
||||
static u8 ear_det_idle()
|
||||
{
|
||||
return __this->is_idle;
|
||||
}
|
||||
|
||||
REGISTER_LP_TARGET(ear_detect_lp_target) = {
|
||||
.name = "ear_det",
|
||||
.is_idle = ear_det_idle,
|
||||
};
|
||||
|
||||
#if TCFG_KEY_IN_EAR_FILTER_ENABLE
|
||||
u8 iokey_filter_hook(u8 io_state)
|
||||
{
|
||||
u8 ret = 0;
|
||||
if (io_key_filter_flag) {
|
||||
if (io_state == 1) {
|
||||
io_key_filter_flag = 0;
|
||||
} else {
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if TCFG_EAR_DETECT_CTL_KEY
|
||||
#if TCFG_IOKEY_ENABLE
|
||||
int key_event_remap(struct sys_event *e)
|
||||
#elif TCFG_LP_TOUCH_KEY_ENABLE
|
||||
int lp_touch_key_event_remap(struct sys_event *e)
|
||||
#endif
|
||||
{
|
||||
if (ear_detect_get_key_delay_able() == 0) {
|
||||
log_info("key disable ");
|
||||
return 0;
|
||||
}
|
||||
if (!is_ear_detect_state_in()) { //耳机不在耳朵上,不发
|
||||
log_info("key remap");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
void ear_detect_ir_init(const struct ear_detect_platform_data *cfg)
|
||||
{
|
||||
log_info("%s\n", __func__);
|
||||
ASSERT(cfg);
|
||||
__this->cfg = cfg;
|
||||
__ear_detect_ir_init();
|
||||
__this->s_hi_timer = sys_s_hi_timer_add(NULL, __ear_detect_ir_run, 10);
|
||||
}
|
||||
|
||||
void ear_detect_tch_init(const struct ear_detect_platform_data *cfg)
|
||||
{
|
||||
log_info("%s\n", __func__);
|
||||
ASSERT(cfg);
|
||||
__this->cfg = cfg;
|
||||
#if TCFG_EAR_DETECT_TOUCH_MODE
|
||||
__this->s_hi_timer = sys_s_hi_timer_add(NULL, __ear_detect_tch_run, 10);
|
||||
#else
|
||||
ear_touch_edge_wakeup_handle(0, TCFG_EAR_DETECT_DET_IO); //init first tch sta
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
10
apps/common/device/in_ear_detect/in_ear_detect.h
Normal file
10
apps/common/device/in_ear_detect/in_ear_detect.h
Normal file
@ -0,0 +1,10 @@
|
||||
#ifndef _IN_EAR_DETECT_H
|
||||
#define _IN_EAR_DETECT_H
|
||||
|
||||
//#include "typedef.h"
|
||||
|
||||
|
||||
extern void ear_detect_ir_init(const struct ear_detect_platform_data *cfg);
|
||||
extern void ear_detect_tch_init(const struct ear_detect_platform_data *cfg);
|
||||
|
||||
#endif
|
||||
714
apps/common/device/in_ear_detect/in_ear_manage.c
Normal file
714
apps/common/device/in_ear_detect/in_ear_manage.c
Normal file
@ -0,0 +1,714 @@
|
||||
#include "in_ear_detect/in_ear_manage.h"
|
||||
#include "in_ear_detect/in_ear_detect.h"
|
||||
#include "system/includes.h"
|
||||
#include "app_config.h"
|
||||
#include "btstack/avctp_user.h"
|
||||
#include "tone_player.h"
|
||||
|
||||
#define LOG_TAG_CONST EAR_DETECT
|
||||
#define LOG_TAG "[EAR_DETECT]"
|
||||
#define LOG_INFO_ENABLE
|
||||
#include "debug.h"
|
||||
|
||||
//#define log_info(format, ...) y_printf("[EAR_DETECT] : " format "\r\n", ## __VA_ARGS__)
|
||||
|
||||
|
||||
#if TCFG_USER_TWS_ENABLE
|
||||
#include "bt_tws.h"
|
||||
#endif
|
||||
|
||||
#if TCFG_EAR_DETECT_ENABLE
|
||||
|
||||
#if INEAR_ANC_UI
|
||||
#include "audio_anc.h"
|
||||
u8 inear_tws_ancmode = ANC_OFF;
|
||||
#endif
|
||||
|
||||
static struct ear_detect_d _ear_detect_d = {
|
||||
.toggle = 1,
|
||||
.music_en = 0, //上电开机默认不使能音乐控制
|
||||
.pre_music_sta = MUSIC_STATE_NULL,
|
||||
.pre_state = !TCFG_EAR_DETECT_DET_LEVEL, //默认没有入耳
|
||||
.cur_state = !TCFG_EAR_DETECT_DET_LEVEL, //默认没有入耳
|
||||
.tws_state = !TCFG_EAR_DETECT_DET_LEVEL, //默认没有入耳
|
||||
.bt_init_ok = 1,
|
||||
.music_check_timer = 0,
|
||||
.music_sta_cnt = 0,
|
||||
.change_master_timer = 0,
|
||||
.key_enable_timer = 0,
|
||||
.key_delay_able = 1,
|
||||
//TCFG_EAR_DETECT_MUSIC_CTL_EN
|
||||
.play_cnt = 0,
|
||||
.stop_cnt = 0,
|
||||
.music_ctl_timeout = 0,
|
||||
.a2dp_det_timer = 0,
|
||||
.music_regist_en = 0,
|
||||
};
|
||||
|
||||
#define __this (&_ear_detect_d)
|
||||
|
||||
//入耳检测公共控制
|
||||
u8 is_ear_detect_state_in(void) //入耳返回1
|
||||
{
|
||||
if (0 == __this->toggle) {
|
||||
return 1;
|
||||
}
|
||||
return (__this->cur_state == TCFG_EAR_DETECT_DET_LEVEL);
|
||||
}
|
||||
|
||||
u8 is_ear_detect_tws_state_in(void) //对耳入耳返回1
|
||||
{
|
||||
if (0 == __this->toggle) {
|
||||
return 1;
|
||||
}
|
||||
return (__this->tws_state == TCFG_EAR_DETECT_DET_LEVEL);
|
||||
}
|
||||
|
||||
void ear_detect_music_ctl_delay_deal(void *priv)
|
||||
{
|
||||
//暂停n秒内戴上控制音乐,超过后不能控制
|
||||
log_info("%s", __func__);
|
||||
__this->music_en = 0;
|
||||
__this->music_ctl_timeout = 0;
|
||||
__this->music_regist_en = 0;
|
||||
}
|
||||
|
||||
void ear_detect_music_ctl_timer_del()
|
||||
{
|
||||
log_info("%s", __func__);
|
||||
if (__this->music_ctl_timeout) {
|
||||
sys_timeout_del(__this->music_ctl_timeout);
|
||||
__this->music_ctl_timeout = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void ear_detect_music_ctl_en(u8 en)
|
||||
{
|
||||
log_info("%s, %d, music_en:%d, timeout:%d,regist_en:%d", __func__, en, __this->music_en, __this->music_ctl_timeout, __this->music_regist_en);
|
||||
if (en) {
|
||||
__this->music_en = en;
|
||||
if (__this->music_ctl_timeout) {
|
||||
log_info("del pause timeout deal");
|
||||
sys_timeout_del(__this->music_ctl_timeout);
|
||||
__this->music_ctl_timeout = 0;
|
||||
}
|
||||
} else {
|
||||
if (__this->music_regist_en == 0) {
|
||||
__this->music_en = 0;
|
||||
return;
|
||||
}
|
||||
if (__this->music_en && (0 == __this->music_ctl_timeout)) {
|
||||
log_info("regist pause timeout deal");
|
||||
if (__this->cfg->ear_det_music_ctl_ms) {
|
||||
__this->music_ctl_timeout = sys_timeout_add(NULL, ear_detect_music_ctl_delay_deal, __this->cfg->ear_det_music_ctl_ms);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define A2DP_PLAY_CNT 2
|
||||
#define A2DP_STOP_CNT 2
|
||||
static void ear_detect_a2dp_detech(void *priv)
|
||||
{
|
||||
u8 a2dp_state = 0;
|
||||
if (get_call_status() != BT_CALL_HANGUP) {
|
||||
return;
|
||||
}
|
||||
a2dp_state = a2dp_get_status();
|
||||
//printf("a2dp: %d", a2dp_state);
|
||||
if (a2dp_state == BT_MUSIC_STATUS_STARTING) { //在播歌
|
||||
__this->stop_cnt = 0;
|
||||
if (__this->play_cnt < A2DP_PLAY_CNT) {
|
||||
__this->play_cnt++;
|
||||
if (__this->play_cnt == A2DP_PLAY_CNT) {
|
||||
__this->pre_music_sta = MUSIC_STATE_PLAY;
|
||||
ear_detect_music_ctl_en(1);
|
||||
}
|
||||
}
|
||||
} else { //不在播歌
|
||||
__this->play_cnt = 0;
|
||||
if (__this->stop_cnt < A2DP_STOP_CNT) {
|
||||
__this->stop_cnt++;
|
||||
if (__this->stop_cnt == A2DP_STOP_CNT) {
|
||||
if (__this->music_en) { //入耳检测已经使能
|
||||
__this->pre_music_sta = MUSIC_STATE_PAUSE;
|
||||
ear_detect_music_ctl_en(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ear_detect_a2dp_det_en(u8 en)
|
||||
{
|
||||
if (en) {
|
||||
__this->play_cnt = 0;
|
||||
__this->stop_cnt = 0;
|
||||
if (!__this->a2dp_det_timer) {
|
||||
log_info("ear_detect_a2dp_detech timer add");
|
||||
__this->a2dp_det_timer = sys_timer_add(NULL, ear_detect_a2dp_detech, 500);
|
||||
}
|
||||
} else {
|
||||
if (__this->a2dp_det_timer) {
|
||||
log_info("ear_detect_a2dp_detech timer del");
|
||||
sys_timer_del(__this->a2dp_det_timer);
|
||||
__this->a2dp_det_timer = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void cmd_post_key_msg(u8 user_msg)
|
||||
{
|
||||
struct sys_event e = {0};
|
||||
e.type = SYS_KEY_EVENT;
|
||||
e.u.key.event = KEY_EVENT_USER;
|
||||
e.u.key.value = user_msg;
|
||||
|
||||
sys_event_notify(&e);
|
||||
}
|
||||
|
||||
int cmd_key_msg_handle(struct sys_event *event)
|
||||
{
|
||||
log_info("%s\n", __func__);
|
||||
struct key_event *key = &event->u.key;
|
||||
switch (key->value) {
|
||||
case CMD_EAR_DETECT_MUSIC_PLAY:
|
||||
log_info("CMD_EAR_DETECT_MUSIC_PLAY");
|
||||
user_send_cmd_prepare(USER_CTRL_AVCTP_OPID_PLAY, 0, NULL);
|
||||
break;
|
||||
case CMD_EAR_DETECT_MUSIC_PAUSE:
|
||||
log_info("CMD_EAR_DETECT_MUSIC_PAUSE");
|
||||
user_send_cmd_prepare(USER_CTRL_AVCTP_OPID_PAUSE, 0, NULL);
|
||||
break;
|
||||
case CMD_EAR_DETECT_SCO_CONN:
|
||||
log_info("CMD_EDETECT_SCO_CONN");
|
||||
user_send_cmd_prepare(USER_CTRL_CONN_SCO, 0, NULL);
|
||||
break;
|
||||
case CMD_EAR_DETECT_SCO_DCONN:
|
||||
log_info("CMD_EAR_DETECT_SCO_DCONN");
|
||||
user_send_cmd_prepare(USER_CTRL_DISCONN_SCO, 0, NULL);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static void ear_detect_post_event(u8 event)
|
||||
{
|
||||
struct sys_event e;
|
||||
user_send_cmd_prepare(USER_CTRL_ALL_SNIFF_EXIT, 0, NULL);
|
||||
e.type = SYS_DEVICE_EVENT;
|
||||
e.arg = (void *)DEVICE_EVENT_FROM_EAR_DETECT;
|
||||
e.u.ear.value = event;
|
||||
sys_event_notify(&e);
|
||||
}
|
||||
|
||||
static void cancel_music_state_check()
|
||||
{
|
||||
if (__this->music_check_timer) {
|
||||
sys_timer_del(__this->music_check_timer);
|
||||
__this->music_check_timer = 0;
|
||||
__this->music_sta_cnt = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void music_play_state_check(void *priv)
|
||||
{
|
||||
if (__this->pre_music_sta == MUSIC_STATE_PLAY) {
|
||||
if (__this->cfg->ear_det_in_music_sta == 1) {
|
||||
cancel_music_state_check();
|
||||
} else {
|
||||
if (a2dp_get_status() == BT_MUSIC_STATUS_STARTING) {
|
||||
__this->music_sta_cnt++;
|
||||
log_info("play cnt: %d", __this->music_sta_cnt);
|
||||
} else { //期间变成了暂停
|
||||
cmd_post_key_msg(CMD_EAR_DETECT_MUSIC_PLAY);
|
||||
cancel_music_state_check();
|
||||
}
|
||||
if (__this->music_sta_cnt >= __this->cfg->ear_det_music_play_cnt) {
|
||||
cancel_music_state_check();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (a2dp_get_status() != BT_MUSIC_STATUS_STARTING) {
|
||||
__this->music_sta_cnt++;
|
||||
log_info("pause cnt: %d", __this->music_sta_cnt);
|
||||
} else { //期间变成了暂停
|
||||
cmd_post_key_msg(CMD_EAR_DETECT_MUSIC_PAUSE);
|
||||
cancel_music_state_check();
|
||||
}
|
||||
if (__this->music_sta_cnt >= __this->cfg->ear_det_music_pause_cnt) {
|
||||
cancel_music_state_check();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ear_detect_music_play_ctl(u8 music_state)
|
||||
{
|
||||
log_info("%s", __func__);
|
||||
#if TCFG_USER_TWS_ENABLE
|
||||
if (get_tws_sibling_connect_state() && (__this->pre_music_sta == music_state)) //防止两只耳机陆续入耳,重复操作
|
||||
#endif
|
||||
{
|
||||
log_info("tws same or notws . music_state: %d", music_state);
|
||||
if (__this->cfg->ear_det_music_ctl_en == 1) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
__this->pre_music_sta = music_state;
|
||||
log_info("music state:%d music_en:%d", music_state, __this->music_en);
|
||||
if (__this->music_en) { //入耳检测控制音乐使能
|
||||
if (music_state == MUSIC_STATE_PLAY) { //播放音乐
|
||||
log_info("MUSIC_STATE_PLAY");
|
||||
if (__this->cfg->ear_det_music_ctl_en == 1) {
|
||||
__this->music_regist_en = 0;
|
||||
}
|
||||
if (__this->cfg->ear_det_in_music_sta == 0) {
|
||||
if (a2dp_get_status() != BT_MUSIC_STATUS_STARTING) { //没有播放
|
||||
log_info("-------1");
|
||||
cmd_post_key_msg(CMD_EAR_DETECT_MUSIC_PLAY);
|
||||
} else {
|
||||
log_info("-------2");
|
||||
cancel_music_state_check();
|
||||
__this->music_check_timer = sys_timer_add(NULL, music_play_state_check, 100);
|
||||
}
|
||||
}
|
||||
} else { //暂停音乐
|
||||
log_info("MUSIC_STATE_PAUSE");
|
||||
if (__this->cfg->ear_det_music_ctl_en == 1) {
|
||||
__this->music_regist_en = 1;
|
||||
}
|
||||
if (a2dp_get_status() == BT_MUSIC_STATUS_STARTING) { //正在播放
|
||||
log_info("-------3");
|
||||
cmd_post_key_msg(CMD_EAR_DETECT_MUSIC_PAUSE);
|
||||
} else {
|
||||
log_info("-------4");
|
||||
cancel_music_state_check();
|
||||
__this->music_check_timer = sys_timer_add(NULL, music_play_state_check, 100);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static u8 ear_detect_check_online(u8 check_mode)
|
||||
{
|
||||
if (check_mode == 1) {
|
||||
#if TCFG_USER_TWS_ENABLE
|
||||
if ((get_tws_sibling_connect_state() && (__this->cur_state != TCFG_EAR_DETECT_DET_LEVEL) && (__this->tws_state != TCFG_EAR_DETECT_DET_LEVEL)) //对耳且都不在耳朵上
|
||||
|| (!get_tws_sibling_connect_state() && (__this->cur_state != TCFG_EAR_DETECT_DET_LEVEL))) //单耳且不在耳朵
|
||||
#else
|
||||
if (__this->cur_state != TCFG_EAR_DETECT_DET_LEVEL)
|
||||
#endif
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
} else if (check_mode == 0) {
|
||||
#if TCFG_USER_TWS_ENABLE
|
||||
if ((get_tws_sibling_connect_state() && ((__this->cur_state == TCFG_EAR_DETECT_DET_LEVEL) || (__this->tws_state == TCFG_EAR_DETECT_DET_LEVEL))) //对耳戴上一只
|
||||
|| (!get_tws_sibling_connect_state() && (__this->cur_state == TCFG_EAR_DETECT_DET_LEVEL))) //单耳且入耳
|
||||
#else
|
||||
if (__this->cur_state == TCFG_EAR_DETECT_DET_LEVEL)
|
||||
#endif
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ear_detect_phone_active_deal()
|
||||
{
|
||||
if (0 == __this->toggle) {
|
||||
return;
|
||||
}
|
||||
if (ear_detect_check_online(1) == 1) {
|
||||
cmd_post_key_msg(CMD_EAR_DETECT_SCO_DCONN);
|
||||
}
|
||||
}
|
||||
|
||||
#if (TCFG_EAR_DETECT_AUTO_CHG_MASTER && TCFG_USER_TWS_ENABLE)
|
||||
extern void tws_conn_switch_role();
|
||||
extern void test_esco_role_switch(u8 flag);
|
||||
void ear_detect_change_master_timeout_deal(void *priv) //主从切换
|
||||
{
|
||||
y_printf("%s", __func__);
|
||||
__this->change_master_timer = 0;
|
||||
tws_api_auto_role_switch_disable();
|
||||
test_esco_role_switch(1); //主机调用
|
||||
}
|
||||
|
||||
void ear_detect_change_master_timer_del()
|
||||
{
|
||||
if (__this->change_master_timer) {
|
||||
y_printf("%s", __func__);
|
||||
sys_timeout_del(__this->change_master_timer);
|
||||
__this->change_master_timer = 0;
|
||||
}
|
||||
tws_api_auto_role_switch_enable(); //恢复主从自动切换
|
||||
}
|
||||
|
||||
//开始通话时,判断主机是否在耳朵上,不在切换主从
|
||||
void ear_detect_call_chg_master_deal()
|
||||
{
|
||||
y_printf("self:%d tws:%d\n", __this->cur_state, __this->tws_state);
|
||||
if (0 == __this->toggle) {
|
||||
return;
|
||||
}
|
||||
if (get_tws_sibling_connect_state() && (tws_api_get_role() == TWS_ROLE_MASTER) && (__this->cur_state != TCFG_EAR_DETECT_DET_LEVEL) && (__this->tws_state == TCFG_EAR_DETECT_DET_LEVEL)) { //主机不在耳,从机在耳,切换主从
|
||||
y_printf("%s", __func__);
|
||||
ear_detect_change_master_timeout_deal(NULL);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void ear_detect_in_deal() //主机才会执行
|
||||
{
|
||||
log_info("%s", __func__);
|
||||
u8 call_status = get_call_status();
|
||||
y_printf("[EAR_DETECT] : in self:%d tws:%d call_st:%d\n", __this->cur_state, __this->tws_state, call_status);
|
||||
if (0 == __this->toggle) {
|
||||
return;
|
||||
}
|
||||
if (call_status != BT_CALL_HANGUP) {//通话中
|
||||
#if TCFG_EAR_DETECT_CALL_CTL_SCO
|
||||
if (call_status == BT_CALL_ACTIVE) {//通话中
|
||||
if (ear_detect_check_online(0) == 1) {
|
||||
log_info("CMD_CTRL_CONN_SCO\n");
|
||||
cmd_post_key_msg(CMD_EAR_DETECT_SCO_CONN);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if (TCFG_EAR_DETECT_AUTO_CHG_MASTER && TCFG_USER_TWS_ENABLE)
|
||||
ear_detect_change_master_timer_del();
|
||||
if (get_tws_sibling_connect_state() && (__this->cur_state != TCFG_EAR_DETECT_DET_LEVEL) && (__this->tws_state == TCFG_EAR_DETECT_DET_LEVEL)) { //主机不在耳,从机在耳,切换主从
|
||||
y_printf("master no inside, start change role");
|
||||
__this->change_master_timer = sys_timeout_add(NULL, ear_detect_change_master_timeout_deal, 2000);
|
||||
}
|
||||
#endif
|
||||
} else if (get_total_connect_dev()) { //已连接
|
||||
if ((__this->cur_state == TCFG_EAR_DETECT_DET_LEVEL) || (__this->tws_state == TCFG_EAR_DETECT_DET_LEVEL)) { //可以自定义控制暂停播放的条件
|
||||
ear_detect_music_play_ctl(MUSIC_STATE_PLAY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ear_detect_out_deal() //主机才会执行
|
||||
{
|
||||
log_info("%s", __func__);
|
||||
u8 call_status = get_call_status();
|
||||
y_printf("[EAR_DETECT] : out self:%d tws:%d call_st:%d\n", __this->cur_state, __this->tws_state, call_status);
|
||||
if (0 == __this->toggle) {
|
||||
return;
|
||||
}
|
||||
if (call_status != BT_CALL_HANGUP) {//通话中
|
||||
if (call_status == BT_CALL_ACTIVE) {//通话中
|
||||
if (ear_detect_check_online(1) == 1) {
|
||||
#if (TCFG_EAR_DETECT_AUTO_CHG_MASTER && TCFG_USER_TWS_ENABLE)
|
||||
ear_detect_change_master_timer_del(); //通话中如果主机摘掉,然后从机也摘掉,不切换主从
|
||||
#endif
|
||||
#if TCFG_EAR_DETECT_CALL_CTL_SCO
|
||||
cmd_post_key_msg(CMD_EAR_DETECT_SCO_DCONN);
|
||||
log_info("CMD_CTRL_DISCONN_SCO\n");
|
||||
#endif
|
||||
}
|
||||
#if (TCFG_EAR_DETECT_AUTO_CHG_MASTER && TCFG_USER_TWS_ENABLE)
|
||||
ear_detect_change_master_timer_del();
|
||||
if (get_tws_sibling_connect_state() && (__this->cur_state != TCFG_EAR_DETECT_DET_LEVEL) && (__this->tws_state == TCFG_EAR_DETECT_DET_LEVEL)) { //主机不在耳,从机在耳,切换主从
|
||||
y_printf("master no inside, start change role");
|
||||
__this->change_master_timer = sys_timeout_add(NULL, ear_detect_change_master_timeout_deal, 2000);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
} else if (get_total_connect_dev()) { //已连接
|
||||
if ((__this->cur_state != TCFG_EAR_DETECT_DET_LEVEL) || (__this->tws_state != TCFG_EAR_DETECT_DET_LEVEL)) { //可以自定义控制暂停播放的条件
|
||||
ear_detect_music_play_ctl(MUSIC_STATE_PAUSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if TCFG_USER_TWS_ENABLE
|
||||
void tws_sync_ear_detect_state(u8 need_do)
|
||||
{
|
||||
u8 state = 0;
|
||||
state = need_do ? (BIT(7) | __this->cur_state) : __this->cur_state;
|
||||
if (!need_do) {
|
||||
state |= (__this->music_en << 6);
|
||||
}
|
||||
r_printf("[EAR_DETECT] : %s: %x , %x ", __func__, state, __this->cur_state);
|
||||
tws_api_send_data_to_sibling(&state, 1, TWS_FUNC_ID_EAR_DETECT_SYNC);
|
||||
}
|
||||
|
||||
static void tws_sync_ear_detect_state_deal(void *_data, u16 len, bool rx) //在这个回调里面,不能执行太久,不要调用tws_api_get_role()和user_send_cmd_prepare,会偶尔死机
|
||||
{
|
||||
u8 *data = (u8 *)_data;
|
||||
u8 state = data[0];
|
||||
|
||||
if (rx) {
|
||||
r_printf("[EAR_DETECT] : %s: %x , rx = %x", __func__, state, rx);
|
||||
__this->tws_state = state & BIT(0);
|
||||
if ((state & BIT(7))) { //主机并且需要执行 // && (tws_api_get_role() == TWS_ROLE_MASTER)
|
||||
if (__this->tws_state == TCFG_EAR_DETECT_DET_LEVEL) {
|
||||
ear_detect_post_event(EAR_DETECT_EVENT_IN_DEAL);
|
||||
} else {
|
||||
ear_detect_post_event(EAR_DETECT_EVENT_OUT_DEAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
REGISTER_TWS_FUNC_STUB(ear_detect_sync) = {
|
||||
.func_id = TWS_FUNC_ID_EAR_DETECT_SYNC,
|
||||
.func = tws_sync_ear_detect_state_deal,
|
||||
};
|
||||
#endif
|
||||
|
||||
void ear_detect_change_state_to_event(u8 state)
|
||||
{
|
||||
u8 event = EAR_DETECT_EVENT_NULL;
|
||||
__this->pre_state = __this->cur_state;
|
||||
__this->cur_state = state;
|
||||
if (__this->cur_state == __this->pre_state) {
|
||||
log_info("same state,return");
|
||||
return;
|
||||
}
|
||||
log_info("post event, cur_state:%d, pre_state:%d", __this->cur_state, __this->pre_state);
|
||||
event = (state == TCFG_EAR_DETECT_DET_LEVEL) ? EAR_DETECT_EVENT_IN : EAR_DETECT_EVENT_OUT;
|
||||
ear_detect_post_event(event);
|
||||
}
|
||||
|
||||
static void __ear_detect_in_dealy_deal(void *priv)
|
||||
{
|
||||
static u16 tone_delay_in_deal = 0;
|
||||
if (!tone_get_status()) {
|
||||
sys_timer_del(tone_delay_in_deal);
|
||||
tone_delay_in_deal = 0;
|
||||
ear_detect_in_deal();
|
||||
} else {
|
||||
if (!tone_delay_in_deal) {
|
||||
tone_delay_in_deal = sys_timer_add(NULL, __ear_detect_in_dealy_deal, 100);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ear_detect_set_key_delay_able(void *priv)
|
||||
{
|
||||
u8 able = (u8)priv;
|
||||
__this->key_delay_able = able;
|
||||
}
|
||||
|
||||
u8 ear_detect_get_key_delay_able(void)
|
||||
{
|
||||
return __this->key_delay_able;
|
||||
}
|
||||
#if INEAR_ANC_UI
|
||||
void etch_in_anc(void)
|
||||
{
|
||||
if (get_tws_sibling_connect_state()) {//tws
|
||||
if (__this->tws_state && __this->cur_state) {
|
||||
if (inear_tws_ancmode == ANC_ON) {
|
||||
log_info("switch anc mode\n");
|
||||
anc_mode_switch(inear_tws_ancmode, 0);
|
||||
inear_tws_ancmode = 1;
|
||||
}
|
||||
} else if (__this->cur_state && !__this->tws_state) {
|
||||
if (inear_tws_ancmode == ANC_ON) {
|
||||
anc_mode_switch(ANC_TRANSPARENCY, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void etch_out_anc(void)
|
||||
{
|
||||
if (get_tws_sibling_connect_state()) {//tws
|
||||
if (anc_mode_get() == ANC_ON) {
|
||||
inear_tws_ancmode = ANC_ON;
|
||||
if (!__this->cur_state) {
|
||||
anc_mode_switch(ANC_OFF, 0);
|
||||
} else {
|
||||
anc_mode_switch(ANC_TRANSPARENCY, 0);
|
||||
|
||||
}
|
||||
} else if (anc_mode_get() == ANC_TRANSPARENCY) {
|
||||
if (inear_tws_ancmode == ANC_ON) {
|
||||
anc_mode_switch(ANC_OFF, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
void tone_play_deal(const char *name, u8 preemption, u8 add_en);
|
||||
void ear_detect_event_handle(u8 state)
|
||||
{
|
||||
switch (state) {
|
||||
case EAR_DETECT_EVENT_NULL:
|
||||
log_info("EAR_DETECT_EVENT_NULL");
|
||||
break;
|
||||
case EAR_DETECT_EVENT_IN:
|
||||
log_info("EAR_DETECT_EVENT_IN");
|
||||
#if INEAR_ANC_UI
|
||||
etch_in_anc();
|
||||
#endif
|
||||
log_info("toggle = %d,call_status = %d\n", __this->toggle, get_call_status());
|
||||
if (__this->toggle && __this->bt_init_ok && (get_call_status() == BT_CALL_HANGUP)) {
|
||||
#if TCFG_USER_TWS_ENABLE
|
||||
if (get_tws_sibling_connect_state()) { //对耳链接上了,对耳不在耳时播,第一只播
|
||||
if (__this->tws_state != TCFG_EAR_DETECT_DET_LEVEL) { //对耳已经戴上了,不播放
|
||||
bt_tws_play_tone_at_same_time(SYNC_TONE_EARDET_IN, 400);
|
||||
}
|
||||
} else //对耳没连接上,自己决定
|
||||
|
||||
#endif
|
||||
{
|
||||
tone_play(TONE_EAR_CHECK, 1);
|
||||
}
|
||||
}
|
||||
#if TCFG_USER_TWS_ENABLE
|
||||
if (get_tws_sibling_connect_state()) {
|
||||
tws_sync_ear_detect_state(1);
|
||||
if (tws_api_get_role() == TWS_ROLE_MASTER) {
|
||||
__ear_detect_in_dealy_deal(NULL);
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
__ear_detect_in_dealy_deal(NULL);
|
||||
}
|
||||
if ((__this->key_enable_timer == 0) && (__this->cfg->ear_det_key_delay_time != 0)) {
|
||||
__this->key_enable_timer = sys_timeout_add((void *)1, ear_detect_set_key_delay_able, __this->cfg->ear_det_key_delay_time);
|
||||
}
|
||||
break;
|
||||
case EAR_DETECT_EVENT_OUT:
|
||||
log_info("EAR_DETECT_EVENT_OUT");
|
||||
#if INEAR_ANC_UI
|
||||
etch_out_anc();
|
||||
#endif
|
||||
#if TCFG_USER_TWS_ENABLE
|
||||
if (get_tws_sibling_connect_state()) {
|
||||
tws_sync_ear_detect_state(1);
|
||||
if (tws_api_get_role() == TWS_ROLE_MASTER) {
|
||||
ear_detect_out_deal();
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
ear_detect_out_deal();
|
||||
}
|
||||
if (__this->cfg->ear_det_key_delay_time != 0) {
|
||||
ear_detect_set_key_delay_able(0);
|
||||
if (__this->key_enable_timer) {
|
||||
sys_timeout_del(__this->key_enable_timer);
|
||||
__this->key_enable_timer = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
#if TCFG_USER_TWS_ENABLE
|
||||
case EAR_DETECT_EVENT_IN_DEAL:
|
||||
#if INEAR_ANC_UI
|
||||
etch_in_anc();
|
||||
#endif
|
||||
log_info("EAR_DETECT_EVENT_IN_DEAL");
|
||||
if (tws_api_get_role() == TWS_ROLE_MASTER) {
|
||||
__ear_detect_in_dealy_deal(NULL);
|
||||
}
|
||||
break;
|
||||
case EAR_DETECT_EVENT_OUT_DEAL:
|
||||
log_info("EAR_DETECT_EVENT_OUT_DEAL");
|
||||
#if INEAR_ANC_UI
|
||||
etch_out_anc();
|
||||
#endif
|
||||
if (tws_api_get_role() == TWS_ROLE_MASTER) {
|
||||
ear_detect_out_deal();
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ear_touch_edge_wakeup_handle(u8 index, u8 gpio)
|
||||
{
|
||||
u8 io_state = 0;
|
||||
ASSERT(gpio == TCFG_EAR_DETECT_DET_IO);
|
||||
|
||||
io_state = gpio_read(TCFG_EAR_DETECT_DET_IO);
|
||||
|
||||
if (io_state == TCFG_EAR_DETECT_DET_LEVEL) {
|
||||
log_info("earphone touch in\n");
|
||||
#if TCFG_KEY_IN_EAR_FILTER_ENABLE
|
||||
extern u8 io_key_filter_flag;
|
||||
if (gpio_read(IO_PORTB_01) == 0) {
|
||||
io_key_filter_flag = 1;
|
||||
} else {
|
||||
io_key_filter_flag = 0;
|
||||
}
|
||||
#endif
|
||||
ear_detect_change_state_to_event(TCFG_EAR_DETECT_DET_LEVEL);
|
||||
} else {
|
||||
log_info("earphone touch out\n");
|
||||
ear_detect_change_state_to_event(!TCFG_EAR_DETECT_DET_LEVEL);
|
||||
}
|
||||
|
||||
if (io_state) {
|
||||
//current: High
|
||||
power_wakeup_set_edge(TCFG_EAR_DETECT_DET_IO, FALLING_EDGE);
|
||||
} else {
|
||||
//current: Low
|
||||
power_wakeup_set_edge(TCFG_EAR_DETECT_DET_IO, RISING_EDGE);
|
||||
}
|
||||
}
|
||||
|
||||
static void ear_det_app_event_handler(struct sys_event *event)
|
||||
{
|
||||
//log_info("%s", __func__);
|
||||
struct bt_event *bt = &(event->u.bt);
|
||||
switch (event->type) {
|
||||
case SYS_BT_EVENT:
|
||||
if ((u32)event->arg == SYS_BT_EVENT_TYPE_CON_STATUS) {
|
||||
switch (bt->event) {
|
||||
case BT_STATUS_FIRST_CONNECTED:
|
||||
case BT_STATUS_SECOND_CONNECTED:
|
||||
log_info("BT_STATUS_CONNECTED\n");
|
||||
if (__this->cfg->ear_det_music_ctl_en) {
|
||||
ear_detect_a2dp_det_en(1);
|
||||
}
|
||||
break;
|
||||
case BT_STATUS_FIRST_DISCONNECT:
|
||||
case BT_STATUS_SECOND_DISCONNECT:
|
||||
log_info("BT_STATUS_DISCONNECT\n");
|
||||
if (__this->cfg->ear_det_music_ctl_en) {
|
||||
ear_detect_a2dp_det_en(0);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ear_detect_init(const struct ear_detect_platform_data *cfg)
|
||||
{
|
||||
log_info("%s", __func__);
|
||||
ASSERT(cfg);
|
||||
__this->cfg = cfg;
|
||||
|
||||
if (__this->cfg->ear_det_music_ctl_en) {
|
||||
register_sys_event_handler(SYS_BT_EVENT, 0, 0, ear_det_app_event_handler);
|
||||
}
|
||||
|
||||
#if (TCFG_EAR_DETECT_TYPE == EAR_DETECT_BY_IR)
|
||||
ear_detect_ir_init(cfg);
|
||||
#elif (TCFG_EAR_DETECT_TYPE == EAR_DETECT_BY_TOUCH)
|
||||
ear_detect_tch_init(cfg);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
97
apps/common/device/in_ear_detect/in_ear_manage.h
Normal file
97
apps/common/device/in_ear_detect/in_ear_manage.h
Normal file
@ -0,0 +1,97 @@
|
||||
#ifndef _IN_EAR_MANAGE_H
|
||||
#define _IN_EAR_MANAGE_H
|
||||
|
||||
#include "typedef.h"
|
||||
|
||||
#define INEAR_ANC_UI 0 //switch anc mode when in_out_ear
|
||||
|
||||
enum {
|
||||
EAR_DETECT_EVENT_NULL = 0,
|
||||
EAR_DETECT_EVENT_IN,
|
||||
EAR_DETECT_EVENT_OUT,
|
||||
EAR_DETECT_EVENT_IN_DEAL,
|
||||
EAR_DETECT_EVENT_OUT_DEAL,
|
||||
};
|
||||
|
||||
enum {
|
||||
MUSIC_STATE_NULL = 0,
|
||||
MUSIC_STATE_PLAY, //音乐播放
|
||||
MUSIC_STATE_PAUSE, //音乐暂停
|
||||
};
|
||||
|
||||
enum {
|
||||
CMD_EAR_DETECT_MUSIC_PLAY = 0,
|
||||
CMD_EAR_DETECT_MUSIC_PAUSE,
|
||||
CMD_EAR_DETECT_SCO_CONN,
|
||||
CMD_EAR_DETECT_SCO_DCONN,
|
||||
};
|
||||
|
||||
enum {
|
||||
DETECT_IDLE = 0,
|
||||
DETECT_CHECKING,
|
||||
};
|
||||
|
||||
#define EAR_DETECT_BY_TOUCH 0 //触摸入耳
|
||||
#define EAR_DETECT_BY_IR 1 //光感入耳
|
||||
|
||||
struct ear_detect_platform_data {
|
||||
u8 ear_det_music_ctl_en; //音乐控制使能
|
||||
u16 ear_det_music_ctl_ms; //音乐暂停之后,入耳检测控制暂停播放的时间
|
||||
u8 ear_det_in_music_sta; // 0:入耳播歌 1:入耳不播歌
|
||||
const u16 ear_det_key_delay_time; //入耳后按键起效时间ms ( 0 : OFF )
|
||||
u8 ear_det_in_cnt; //戴上消抖
|
||||
u8 ear_det_out_cnt; //拿下消抖
|
||||
u16 ear_det_ir_enable_time; //使能时长
|
||||
u16 ear_det_ir_disable_time; //休眠时长
|
||||
u8 ear_det_ir_compensation_en; //防太阳光干扰
|
||||
u8 ear_det_music_play_cnt; //音乐播放检测时间
|
||||
u8 ear_det_music_pause_cnt; //音乐暂停检测时间
|
||||
};
|
||||
|
||||
struct ear_detect_d {
|
||||
u8 toggle : 1; //入耳功能开关
|
||||
u8 music_en : 1;
|
||||
u8 pre_music_sta : 2;
|
||||
u8 pre_state : 1;
|
||||
u8 cur_state : 1;
|
||||
u8 tws_state : 1;
|
||||
u8 bt_init_ok : 1;
|
||||
u16 music_check_timer;
|
||||
u16 music_sta_cnt;
|
||||
u16 change_master_timer;
|
||||
u16 key_enable_timer;
|
||||
u8 key_delay_able;
|
||||
//TCFG_EAR_DETECT_MUSIC_CTL_EN
|
||||
u8 play_cnt;
|
||||
u8 stop_cnt;
|
||||
u16 music_ctl_timeout;
|
||||
u16 a2dp_det_timer;
|
||||
u8 music_regist_en;
|
||||
//cfg
|
||||
const struct ear_detect_platform_data *cfg;
|
||||
};
|
||||
|
||||
struct ear_detect_t {
|
||||
//TCFG_EAR_DETECT_TIMER_MODE
|
||||
u8 is_idle;
|
||||
u16 in_cnt;
|
||||
u16 out_cnt;
|
||||
u16 s_hi_timer;
|
||||
volatile u8 check_status;
|
||||
//cfg
|
||||
const struct ear_detect_platform_data *cfg;
|
||||
};
|
||||
|
||||
// ------------------- fun -----------
|
||||
extern void ear_detect_event_handle(u8 state);
|
||||
extern void ear_detect_phone_active_deal();
|
||||
extern void ear_detect_call_chg_master_deal();
|
||||
extern void ear_detect_change_master_timer_del();
|
||||
extern void tws_sync_ear_detect_state(u8 need_do);
|
||||
extern void ear_detect_init(const struct ear_detect_platform_data *cfg);
|
||||
extern void ear_detect_change_state_to_event(u8 state);
|
||||
extern u8 is_ear_detect_state_in(void);
|
||||
extern void ear_touch_edge_wakeup_handle(u8 index, u8 gpio);
|
||||
extern u8 ear_detect_get_key_delay_able(void);
|
||||
|
||||
#endif
|
||||
197
apps/common/device/ir_sensor/ir_manage.c
Normal file
197
apps/common/device/ir_sensor/ir_manage.c
Normal file
@ -0,0 +1,197 @@
|
||||
#include "app_config.h"
|
||||
#include "ir_sensor/ir_manage.h"
|
||||
|
||||
#if(TCFG_IRSENSOR_ENABLE == 1)
|
||||
|
||||
#define LOG_TAG "[IRSENSOR]"
|
||||
#define LOG_ERROR_ENABLE
|
||||
#define LOG_DEBUG_ENABLE
|
||||
#define LOG_INFO_ENABLE
|
||||
/* #define LOG_DUMP_ENABLE */
|
||||
#define LOG_CLI_ENABLE
|
||||
#include "debug.h"
|
||||
|
||||
#if TCFG_SENOR_USER_IIC_TYPE
|
||||
#define iic_init(iic) hw_iic_init(iic)
|
||||
#define iic_uninit(iic) hw_iic_uninit(iic)
|
||||
#define iic_start(iic) hw_iic_start(iic)
|
||||
#define iic_stop(iic) hw_iic_stop(iic)
|
||||
#define iic_tx_byte(iic, byte) hw_iic_tx_byte(iic, byte)
|
||||
#define iic_rx_byte(iic, ack) hw_iic_rx_byte(iic, ack)
|
||||
#define iic_read_buf(iic, buf, len) hw_iic_read_buf(iic, buf, len)
|
||||
#define iic_write_buf(iic, buf, len) hw_iic_write_buf(iic, buf, len)
|
||||
#define iic_suspend(iic) hw_iic_suspend(iic)
|
||||
#define iic_resume(iic) hw_iic_resume(iic)
|
||||
#else
|
||||
#define iic_init(iic) soft_iic_init(iic)
|
||||
#define iic_uninit(iic) soft_iic_uninit(iic)
|
||||
#define iic_start(iic) soft_iic_start(iic)
|
||||
#define iic_stop(iic) soft_iic_stop(iic)
|
||||
#define iic_tx_byte(iic, byte) soft_iic_tx_byte(iic, byte)
|
||||
#define iic_rx_byte(iic, ack) soft_iic_rx_byte(iic, ack)
|
||||
#define iic_read_buf(iic, buf, len) soft_iic_read_buf(iic, buf, len)
|
||||
#define iic_write_buf(iic, buf, len) soft_iic_write_buf(iic, buf, len)
|
||||
#define iic_suspend(iic) soft_iic_suspend(iic)
|
||||
#define iic_resume(iic) soft_iic_resume(iic)
|
||||
#endif
|
||||
|
||||
static const struct irSensor_platform_data *platform_data;
|
||||
IR_SENSOR_INTERFACE *irSensor_hdl = NULL;
|
||||
IR_SENSOR_INFO __irSensor_info = {.iic_delay = 30, .ir_event = IR_SENSOR_EVENT_NULL};
|
||||
#define irSensor_info (&__irSensor_info)
|
||||
|
||||
#define JSA_IIC_DELAY 50
|
||||
|
||||
|
||||
|
||||
u8 irSensor_write(u8 w_chip_id, u8 register_address, u8 function_command)
|
||||
{
|
||||
//spin_lock(&iic_lock);
|
||||
u8 ret = 1;
|
||||
iic_start(irSensor_info->iic_hdl);
|
||||
if (0 == iic_tx_byte(irSensor_info->iic_hdl, w_chip_id)) {
|
||||
ret = 0;
|
||||
log_e("\n JSA iic wr err 0\n");
|
||||
goto __gcend;
|
||||
}
|
||||
|
||||
delay(JSA_IIC_DELAY);
|
||||
|
||||
if (0 == iic_tx_byte(irSensor_info->iic_hdl, register_address)) {
|
||||
ret = 0;
|
||||
log_e("\n JSA iic wr err 1\n");
|
||||
goto __gcend;
|
||||
}
|
||||
|
||||
delay(JSA_IIC_DELAY);
|
||||
|
||||
if (0 == iic_tx_byte(irSensor_info->iic_hdl, function_command)) {
|
||||
ret = 0;
|
||||
log_e("\n JSA iic wr err 2\n");
|
||||
goto __gcend;
|
||||
}
|
||||
|
||||
g_printf("JSA iic wr succ\n");
|
||||
__gcend:
|
||||
iic_stop(irSensor_info->iic_hdl);
|
||||
|
||||
//spin_unlock(&iic_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
u8 irSensor_read(u8 r_chip_id, u8 register_address, u8 *buf, u8 data_len)
|
||||
{
|
||||
u8 read_len = 0;
|
||||
|
||||
//spin_lock(&iic_lock);
|
||||
|
||||
iic_start(irSensor_info->iic_hdl);
|
||||
if (0 == iic_tx_byte(irSensor_info->iic_hdl, r_chip_id - 1)) {
|
||||
log_e("\n JSA iic rd err 0\n");
|
||||
read_len = 0;
|
||||
goto __gdend;
|
||||
}
|
||||
|
||||
|
||||
delay(JSA_IIC_DELAY);
|
||||
if (0 == iic_tx_byte(irSensor_info->iic_hdl, register_address)) {
|
||||
log_e("\n JSA iic rd err 1\n");
|
||||
read_len = 0;
|
||||
goto __gdend;
|
||||
}
|
||||
|
||||
iic_start(irSensor_info->iic_hdl);
|
||||
if (0 == iic_tx_byte(irSensor_info->iic_hdl, r_chip_id)) {
|
||||
log_e("\n JSA iic rd err 2\n");
|
||||
read_len = 0;
|
||||
goto __gdend;
|
||||
}
|
||||
|
||||
delay(JSA_IIC_DELAY);
|
||||
|
||||
for (; data_len > 1; data_len--) {
|
||||
*buf++ = iic_rx_byte(irSensor_info->iic_hdl, 1);
|
||||
read_len ++;
|
||||
}
|
||||
|
||||
*buf = iic_rx_byte(irSensor_info->iic_hdl, 0);
|
||||
read_len ++;
|
||||
|
||||
__gdend:
|
||||
|
||||
iic_stop(irSensor_info->iic_hdl);
|
||||
delay(JSA_IIC_DELAY);
|
||||
|
||||
//spin_unlock(&iic_lock);
|
||||
return read_len;
|
||||
}
|
||||
|
||||
void irSensor_int_io_detect(void *priv)
|
||||
{
|
||||
struct sys_event e;
|
||||
if (gpio_read(irSensor_info->int_io) == 0) {
|
||||
irSensor_info->ir_event = irSensor_hdl->ir_sensor_check();
|
||||
if (irSensor_info->ir_event != IR_SENSOR_EVENT_NULL) {
|
||||
log_info("irSensor event trigger:%d", irSensor_info->ir_event);
|
||||
e.type = SYS_IR_EVENT;
|
||||
e.u.ir.event = irSensor_info->ir_event;
|
||||
sys_event_notify(&e);
|
||||
//Interface: initial state after reboot is near
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum irSensor_event get_irSensor_event(void)
|
||||
{
|
||||
return irSensor_info->ir_event;
|
||||
}
|
||||
|
||||
int ir_sensor_init(void *_data)
|
||||
{
|
||||
int retval = 0;
|
||||
platform_data = (const struct irSensor_platform_data *)_data;
|
||||
irSensor_info->iic_hdl = platform_data->iic;
|
||||
irSensor_info->int_io = platform_data->irSensor_int_io;
|
||||
|
||||
retval = iic_init(irSensor_info->iic_hdl);
|
||||
if (retval < 0) {
|
||||
log_e("\n open iic for gsensor err\n");
|
||||
return retval;
|
||||
} else {
|
||||
log_info("\n iic open succ\n");
|
||||
}
|
||||
|
||||
retval = -EINVAL;
|
||||
list_for_each_irSensor(irSensor_hdl) {
|
||||
if (!memcmp(irSensor_hdl->logo, platform_data->irSensor_name, strlen(platform_data->irSensor_name))) {
|
||||
retval = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (retval < 0) {
|
||||
log_e(">>>irSensor_hdl logo err\n");
|
||||
return retval;
|
||||
} else {
|
||||
|
||||
}
|
||||
|
||||
g_printf("irSensor_init_io:%d", platform_data->irSensor_int_io);
|
||||
gpio_set_pull_up(platform_data->irSensor_int_io, 0);
|
||||
gpio_set_pull_down(platform_data->irSensor_int_io, 0);
|
||||
gpio_set_direction(platform_data->irSensor_int_io, 1);
|
||||
gpio_set_die(platform_data->irSensor_int_io, 1);
|
||||
|
||||
|
||||
if (irSensor_hdl->ir_sensor_init(platform_data->pxs_low_th, platform_data->pxs_high_th)) {
|
||||
log_info(">>>>irSensor_Int SUCC\n");
|
||||
sys_s_hi_timer_add(NULL, irSensor_int_io_detect, 10);
|
||||
} else {
|
||||
log_e(">>>>irSensor_Int ERROR\n");
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
74
apps/common/device/ir_sensor/ir_manage.h
Normal file
74
apps/common/device/ir_sensor/ir_manage.h
Normal file
@ -0,0 +1,74 @@
|
||||
#ifndef _IR_SENSOR_MANAGE_H
|
||||
#define _IR_SENSOR_MANAGE_H
|
||||
|
||||
#include "printf.h"
|
||||
#include "cpu.h"
|
||||
//#include "iic.h"
|
||||
#include "asm/iic_hw.h"
|
||||
#include "asm/iic_soft.h"
|
||||
#include "timer.h"
|
||||
#include "app_config.h"
|
||||
#include "event.h"
|
||||
#include "system/includes.h"
|
||||
|
||||
enum {
|
||||
IR_SENSOR_RESET_INT = 0,
|
||||
IR_SENSOR_RESUME_INT,
|
||||
IR_SENSOR_INT_DET,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
u8 logo[20];
|
||||
u8(*ir_sensor_init)(u16 low_th, u16 high_th);
|
||||
char (*ir_sensor_check)(void);
|
||||
void (*ir_sensor_ctl)(u8 cmd, void *arg);
|
||||
} IR_SENSOR_INTERFACE;
|
||||
|
||||
|
||||
struct irSensor_platform_data {
|
||||
u8 iic;
|
||||
char irSensor_name[20];
|
||||
int irSensor_int_io;
|
||||
u16 pxs_low_th;
|
||||
u16 pxs_high_th;
|
||||
};
|
||||
|
||||
enum irSensor_event {
|
||||
IR_SENSOR_EVENT_NULL = 0,
|
||||
IR_SENSOR_EVENT_FAR,
|
||||
IR_SENSOR_EVENT_NEAR,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
u8 iic_hdl;
|
||||
u8 iic_delay; //这个延时并非影响iic的时钟频率,而是2Byte数据之间的延时
|
||||
int int_io;
|
||||
int check_timer_hdl;
|
||||
enum irSensor_event ir_event;
|
||||
} IR_SENSOR_INFO;
|
||||
|
||||
int ir_sensor_init(void *_data);
|
||||
u8 ir_sensor_command(u8 w_chip_id, u8 register_address, u8 function_command);
|
||||
|
||||
extern IR_SENSOR_INTERFACE irSensor_dev_begin[];
|
||||
extern IR_SENSOR_INTERFACE irSensor_dev_end[];
|
||||
|
||||
#define REGISTER_IR_SENSOR(gSensor) \
|
||||
static IR_SENSOR_INTERFACE irSensor SEC_USED(.irSensor_dev)
|
||||
|
||||
#define list_for_each_irSensor(c) \
|
||||
for (c=irSensor_dev_begin; c<irSensor_dev_end; c++)
|
||||
|
||||
#define IR_SENSOR_PLATFORM_DATA_BEGIN(data) \
|
||||
static const struct irSensor_platform_data data = {
|
||||
|
||||
#define IR_GSENSOR_PLATFORM_DATA_END() \
|
||||
};
|
||||
|
||||
|
||||
int ir_sensor_init(void *_data);
|
||||
u8 irSensor_write(u8 w_chip_id, u8 register_address, u8 function_command);
|
||||
u8 irSensor_read(u8 r_chip_id, u8 register_address, u8 *buf, u8 data_len);
|
||||
enum irSensor_event get_irSensor_event(void);
|
||||
|
||||
#endif
|
||||
75
apps/common/device/ir_sensor/jsa1221.c
Normal file
75
apps/common/device/ir_sensor/jsa1221.c
Normal file
@ -0,0 +1,75 @@
|
||||
#if(TCFG_JSA1221_ENABLE == 1)
|
||||
#include "asm/includes.h"
|
||||
#include "irSensor/jsa1221.h"
|
||||
#include "app_config.h"
|
||||
#include "asm/iic_soft.h"
|
||||
#include "asm/iic_hw.h"
|
||||
#include "system/timer.h"
|
||||
|
||||
#include "system/includes.h"
|
||||
#include "ir_manage.h"
|
||||
|
||||
static u32 jsa_high_th = 0; //红外穿戴中断的触发阈值
|
||||
static u32 jsa_low_th = 0;
|
||||
|
||||
u8 jsa1221_pxs_int_flag(void)
|
||||
{
|
||||
u8 int_flag = 0;
|
||||
irSensor_read(JSA_1221_READ_ADDR, JSA_INT_FLAG, &int_flag, 1);
|
||||
if (int_flag & BIT(1)) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
u16 jsa1221_read_pxs_data(void)
|
||||
{
|
||||
u8 lower_data, upper_data = 0;
|
||||
irSensor_read(JSA_1221_READ_ADDR, JSA_PXS_DATA1, &lower_data, 1);
|
||||
irSensor_read(JSA_1221_READ_ADDR, JSA_PXS_DATA2, &upper_data, 1);
|
||||
return (upper_data * 256 + lower_data);
|
||||
}
|
||||
|
||||
enum irSensor_event jsa1221_check(void *_para)
|
||||
{
|
||||
if (jsa1221_pxs_int_flag()) {
|
||||
u16 pxs_data = jsa1221_read_pxs_data();
|
||||
g_printf("DATA:%d", pxs_data);
|
||||
if (pxs_data < jsa_low_th) {
|
||||
g_printf("FAR");
|
||||
return IR_SENSOR_EVENT_FAR;
|
||||
} else {
|
||||
g_printf("NEAR");
|
||||
return IR_SENSOR_EVENT_NEAR;
|
||||
}
|
||||
} else {
|
||||
return IR_SENSOR_EVENT_NULL;
|
||||
}
|
||||
}
|
||||
|
||||
u8 jsa1221_init(u16 pxs_low_th, u16 pxs_high_th)
|
||||
{
|
||||
u32 ret = 1;
|
||||
jsa_low_th = pxs_low_th;
|
||||
jsa_high_th = pxs_high_th;
|
||||
ret &= irSensor_write(JSA_1221_WRITE_ADDR, JSA_CONFIGURE, PXS_ACTIVE_MODE);
|
||||
ret &= irSensor_write(JSA_1221_WRITE_ADDR, JSA_PXS_LOW_TH1, pxs_low_th & 0xff); // low 8 bit
|
||||
ret &= irSensor_write(JSA_1221_WRITE_ADDR, JSA_PXS_LOW_TH2, pxs_low_th >> 8); // upper 8 bit
|
||||
ret &= irSensor_write(JSA_1221_WRITE_ADDR, JSA_PXS_HIGH_TH1, pxs_high_th & 0xff); // low 8 bit
|
||||
ret &= irSensor_write(JSA_1221_WRITE_ADDR, JSA_PXS_HIGH_TH2, pxs_high_th >> 8); // upper 8 bit
|
||||
ret &= irSensor_write(JSA_1221_WRITE_ADDR, JSA_INT_CTRL, BIT(7)); //enable pxs int
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
REGISTER_IR_SENSOR(irSensor) = {
|
||||
.logo = "jsa1221",
|
||||
.ir_sensor_init = jsa1221_init,
|
||||
.ir_sensor_check = jsa1221_check,
|
||||
.ir_sensor_ctl = NULL,
|
||||
};
|
||||
|
||||
#endif
|
||||
157
apps/common/device/key/adkey.c
Normal file
157
apps/common/device/key/adkey.c
Normal file
@ -0,0 +1,157 @@
|
||||
#include "key_driver.h"
|
||||
#include "adkey.h"
|
||||
#include "gpio.h"
|
||||
#include "system/event.h"
|
||||
#include "app_config.h"
|
||||
|
||||
|
||||
#if TCFG_ADKEY_ENABLE
|
||||
|
||||
static const struct adkey_platform_data *__this = NULL;
|
||||
|
||||
u8 ad_get_key_value(void);
|
||||
//按键驱动扫描参数列表
|
||||
struct key_driver_para adkey_scan_para = {
|
||||
.scan_time = 10, //按键扫描频率, 单位: ms
|
||||
.last_key = NO_KEY, //上一次get_value按键值, 初始化为NO_KEY;
|
||||
.filter_time = 2, //按键消抖延时;
|
||||
.long_time = 75, //按键判定长按数量
|
||||
.hold_time = (75 + 15), //按键判定HOLD数量
|
||||
.click_delay_time = 20, //按键被抬起后等待连击延时数量
|
||||
.key_type = KEY_DRIVER_TYPE_AD,
|
||||
.get_value = ad_get_key_value,
|
||||
};
|
||||
u8 ad_get_key_value(void)
|
||||
{
|
||||
u8 i;
|
||||
u16 ad_data;
|
||||
|
||||
if (!__this->enable) {
|
||||
return NO_KEY;
|
||||
}
|
||||
|
||||
/* ad_data = adc_get_voltage(__this->ad_channel); */
|
||||
ad_data = adc_get_value(__this->ad_channel);
|
||||
/* printf("ad_value = %d \n", ad_data); */
|
||||
for (i = 0; i < ADKEY_MAX_NUM; i++) {
|
||||
if ((ad_data <= __this->ad_value[i]) && (__this->ad_value[i] < 0x3ffL)) {
|
||||
return __this->key_value[i];
|
||||
}
|
||||
}
|
||||
return NO_KEY;
|
||||
}
|
||||
|
||||
int adkey_init(const struct adkey_platform_data *adkey_data)
|
||||
{
|
||||
__this = adkey_data;
|
||||
if (!__this) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!__this->enable) {
|
||||
return KEY_NOT_SUPPORT;
|
||||
}
|
||||
adc_add_sample_ch(__this->ad_channel); //注意:初始化AD_KEY之前,先初始化ADC
|
||||
#if (TCFG_ADKEY_LED_IO_REUSE || TCFG_ADKEY_IR_IO_REUSE || TCFG_ADKEY_LED_SPI_IO_REUSE)
|
||||
#else
|
||||
gpio_set_die(__this->adkey_pin, 0);
|
||||
gpio_set_direction(__this->adkey_pin, 1);
|
||||
gpio_set_pull_down(__this->adkey_pin, 0);
|
||||
if (__this->extern_up_en) {
|
||||
gpio_set_pull_up(__this->adkey_pin, 0);
|
||||
} else {
|
||||
gpio_set_pull_up(__this->adkey_pin, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if (TCFG_ADKEY_LED_IO_REUSE || TCFG_ADKEY_IR_IO_REUSE || TCFG_ADKEY_LED_SPI_IO_REUSE)
|
||||
|
||||
#if TCFG_ADKEY_IR_IO_REUSE
|
||||
static u8 ir_io_sus = 0;
|
||||
extern u8 ir_io_suspend(void);
|
||||
extern u8 ir_io_resume(void);
|
||||
#endif
|
||||
#if TCFG_ADKEY_LED_IO_REUSE
|
||||
static u8 led_io_sus = 0;
|
||||
extern u8 led_io_suspend(void);
|
||||
extern u8 led_io_resume(void);
|
||||
#endif
|
||||
#if TCFG_ADKEY_LED_SPI_IO_REUSE
|
||||
static u8 led_spi_sus = 0;
|
||||
extern u8 led_spi_suspend(void);
|
||||
extern u8 led_spi_resume(void);
|
||||
#endif
|
||||
u8 adc_io_reuse_enter(u32 ch)
|
||||
{
|
||||
if (ch == __this->ad_channel) {
|
||||
#if TCFG_ADKEY_IR_IO_REUSE
|
||||
if (ir_io_suspend()) {
|
||||
return 1;
|
||||
} else {
|
||||
ir_io_sus = 1;
|
||||
}
|
||||
#endif
|
||||
#if TCFG_ADKEY_LED_IO_REUSE
|
||||
if (led_io_suspend()) {
|
||||
return 1;
|
||||
} else {
|
||||
led_io_sus = 1;
|
||||
}
|
||||
#endif
|
||||
#if TCFG_ADKEY_LED_SPI_IO_REUSE
|
||||
if (led_spi_suspend()) {
|
||||
return 1;
|
||||
} else {
|
||||
led_spi_sus = 1;
|
||||
}
|
||||
#endif
|
||||
gpio_set_die(__this->adkey_pin, 0);
|
||||
gpio_set_direction(__this->adkey_pin, 1);
|
||||
gpio_set_pull_down(__this->adkey_pin, 0);
|
||||
if (__this->extern_up_en) {
|
||||
gpio_set_pull_up(__this->adkey_pin, 0);
|
||||
} else {
|
||||
gpio_set_pull_up(__this->adkey_pin, 1);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
u8 adc_io_reuse_exit(u32 ch)
|
||||
{
|
||||
if (ch == __this->ad_channel) {
|
||||
#if TCFG_ADKEY_IR_IO_REUSE
|
||||
if (ir_io_sus) {
|
||||
ir_io_sus = 0;
|
||||
ir_io_resume();
|
||||
}
|
||||
#endif
|
||||
#if TCFG_ADKEY_LED_IO_REUSE
|
||||
if (led_io_sus) {
|
||||
led_io_sus = 0;
|
||||
led_io_resume();
|
||||
}
|
||||
#endif
|
||||
#if TCFG_ADKEY_LED_SPI_IO_REUSE
|
||||
if (led_spi_sus) {
|
||||
led_spi_sus = 0;
|
||||
led_spi_resume();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#endif /* #if TCFG_ADKEY_ENABLE */
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
253
apps/common/device/key/adkey_rtcvdd.c
Normal file
253
apps/common/device/key/adkey_rtcvdd.c
Normal file
@ -0,0 +1,253 @@
|
||||
#include "includes.h"
|
||||
#include "key_driver.h"
|
||||
#include "adkey.h"
|
||||
#include "gpio.h"
|
||||
#include "system/event.h"
|
||||
#include "app_config.h"
|
||||
#include "asm/power/p33.h"
|
||||
|
||||
#if TCFG_ADKEY_RTCVDD_ENABLE
|
||||
|
||||
#define ADKEY_RTCVDD_DEBUG 1
|
||||
#if ADKEY_RTCVDD_DEBUG
|
||||
#define adkey_rtcvdd_debug(fmt, ...) printf("[ADKEY_RTCVDD] "fmt, ##__VA_ARGS__)
|
||||
#else
|
||||
#define adkey_rtcvdd_debug(fmt, ...)
|
||||
#endif
|
||||
|
||||
#define ADC_KEY_NUMBER 10
|
||||
|
||||
#define FULL_ADC 0x3ffL
|
||||
|
||||
#define ADC_FULL(x) (x)
|
||||
#define ADC_VOLTAGE(x,y,z) ((x*y) / (y + z)) //x当前满幅电压,y分压电阻,z上拉电阻
|
||||
#define ADC_ZERRO(x) (0)
|
||||
|
||||
u16 ad_rtcvdd_key_table[ADC_KEY_NUMBER + 1] = {0};
|
||||
|
||||
#define FULL_AD_VOLTAGE 0x3FFF
|
||||
|
||||
volatile u8 adkey_lock_cnt = 0;
|
||||
static u8 rtcvdd_cnt = 10;
|
||||
static u8 rtcvdd_full_cnt = 0xff;
|
||||
u16 rtcvdd_full_value = FULL_AD_VOLTAGE;
|
||||
u16 max_value = 0;
|
||||
u16 min_value = 0xffff;
|
||||
u32 total_value = 0;
|
||||
static u8 check_rtcvdd_cnt = 0;
|
||||
|
||||
static const struct adkey_rtcvdd_platform_data *__this = NULL;
|
||||
|
||||
|
||||
u8 adkey_rtcvdd_get_key_value(void);
|
||||
//按键驱动扫描参数列表
|
||||
struct key_driver_para adkey_rtcvdd_scan_para = {
|
||||
.scan_time = 10, //按键扫描频率, 单位: ms
|
||||
.last_key = NO_KEY, //上一次get_value按键值, 初始化为NO_KEY;
|
||||
.filter_time = 2, //按键消抖延时;
|
||||
.long_time = 75, //按键判定长按数量
|
||||
.hold_time = (75 + 15), //按键判定HOLD数量
|
||||
.click_delay_time = 20, //按键被抬起后等待连击延时数量
|
||||
.key_type = KEY_DRIVER_TYPE_RTCVDD_AD,
|
||||
.get_value = adkey_rtcvdd_get_key_value,
|
||||
};
|
||||
|
||||
static void set_rtcvdd_table(u16 adc_rtcvdd)
|
||||
{
|
||||
u8 i;
|
||||
u32 extern_up_res_value = __this->extern_up_res_value;
|
||||
|
||||
if (extern_up_res_value == 0) { //使用内部上拉
|
||||
extern_up_res_value = 100;
|
||||
}
|
||||
|
||||
for (i = 0; i < __this->adkey_num; i++) {
|
||||
if (i == (__this->adkey_num - 1)) {
|
||||
ad_rtcvdd_key_table[i] = (ADC_VOLTAGE(adc_rtcvdd, __this->res_value[i], extern_up_res_value) + ADC_FULL(adc_rtcvdd)) / 2;
|
||||
//adkey_rtcvdd_debug("recvdd = %d, res_value[%d] = %d", adc_rtcvdd, i, __this->res_value[i]);
|
||||
} else {
|
||||
ad_rtcvdd_key_table[i] = (ADC_VOLTAGE(adc_rtcvdd, __this->res_value[i], extern_up_res_value) + ADC_VOLTAGE(adc_rtcvdd, __this->res_value[i + 1], extern_up_res_value)) / 2;
|
||||
//adkey_rtcvdd_debug("res_value[%d] = %d, res_value[%d] = %d", i, __this->res_value[i], i + 1, __this->res_value[i+1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void SET_ADKEY_LOCK_CNT(u8 cnt)
|
||||
{
|
||||
CPU_SR_ALLOC();
|
||||
OS_ENTER_CRITICAL();
|
||||
|
||||
adkey_lock_cnt = cnt;
|
||||
|
||||
OS_EXIT_CRITICAL();
|
||||
}
|
||||
|
||||
static u8 GET_ADKEY_LOCK_CNT(void)
|
||||
{
|
||||
u8 val;
|
||||
CPU_SR_ALLOC();
|
||||
OS_ENTER_CRITICAL();
|
||||
|
||||
val = adkey_lock_cnt;
|
||||
|
||||
OS_EXIT_CRITICAL();
|
||||
return val;
|
||||
}
|
||||
|
||||
static void POST_ADKEY_LOCK_CNT(void)
|
||||
{
|
||||
CPU_SR_ALLOC();
|
||||
OS_ENTER_CRITICAL();
|
||||
|
||||
adkey_lock_cnt --;
|
||||
|
||||
OS_EXIT_CRITICAL();
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/**@brief ad按键初始化
|
||||
@param void
|
||||
@param void
|
||||
@return void
|
||||
@note void ad_key0_init(void)
|
||||
*/
|
||||
/*----------------------------------------------------------------------------*/
|
||||
int adkey_rtcvdd_init(const struct adkey_rtcvdd_platform_data *adkey_data)
|
||||
{
|
||||
adkey_rtcvdd_debug("ad key init\n");
|
||||
|
||||
__this = adkey_data;
|
||||
if (!__this) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (__this->extern_up_res_value == 0) { //使用内部上拉
|
||||
gpio_set_pull_up(__this->adkey_pin, 1);
|
||||
} else {
|
||||
gpio_set_pull_up(__this->adkey_pin, 0);
|
||||
}
|
||||
gpio_set_direction(__this->adkey_pin, 1);
|
||||
gpio_set_pull_down(__this->adkey_pin, 0);
|
||||
gpio_set_die(__this->adkey_pin, 0);
|
||||
|
||||
adc_add_sample_ch(__this->ad_channel); //注意:初始化AD_KEY之前,先初始化ADC
|
||||
adc_add_sample_ch(AD_CH_RTCVDD);
|
||||
|
||||
set_rtcvdd_table(FULL_ADC);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*把cnt个值里的最大值和最小值去掉,求剩余cnt-2个数的平均值*/
|
||||
static u16 rtcvdd_full_vaule_update(u16 value)
|
||||
{
|
||||
u16 full_value = FULL_ADC;
|
||||
if (rtcvdd_full_cnt == 0xff) {
|
||||
rtcvdd_full_cnt = 0;
|
||||
SET_ADKEY_LOCK_CNT(50);
|
||||
return value; //first time
|
||||
} else {
|
||||
rtcvdd_full_cnt ++;
|
||||
if (value > max_value) {
|
||||
max_value = value;
|
||||
}
|
||||
if (value < min_value) {
|
||||
min_value = value;
|
||||
}
|
||||
total_value += value;
|
||||
|
||||
if (rtcvdd_full_cnt > 10 - 1) { //算10个数
|
||||
full_value = (total_value - max_value - min_value) / (rtcvdd_full_cnt - 2);
|
||||
rtcvdd_full_cnt = 0;
|
||||
max_value = 0;
|
||||
min_value = 0xffff;
|
||||
total_value = 0;
|
||||
} else {
|
||||
return rtcvdd_full_value;
|
||||
}
|
||||
}
|
||||
return full_value;
|
||||
}
|
||||
|
||||
u8 get_rtcvdd_level(void)
|
||||
{
|
||||
u8 level = GET_RTCVDD_VOL();
|
||||
return level;
|
||||
}
|
||||
|
||||
void set_rtcvdd_level(u8 level)
|
||||
{
|
||||
if (level > 7 || level < 0) {
|
||||
return;
|
||||
}
|
||||
RTCVDD_VOL_SEL(level);
|
||||
}
|
||||
/*检测到RTCVDD 比 VDDIO 高的时候自动把RTCVDD降一档*/
|
||||
static u8 rtcvdd_auto_match_vddio_lev(u32 rtcvdd_value)
|
||||
{
|
||||
u8 rtcvdd_lev = 0;
|
||||
if (rtcvdd_value >= FULL_ADC) { //trim rtcvdd < vddio
|
||||
if (rtcvdd_cnt > 10) {
|
||||
rtcvdd_cnt = 0;
|
||||
rtcvdd_lev = get_rtcvdd_level();
|
||||
if (rtcvdd_lev < 8) {
|
||||
rtcvdd_lev++; //降一档
|
||||
/* rtcvdd_lev--; //降一档 */
|
||||
set_rtcvdd_level(rtcvdd_lev);
|
||||
SET_ADKEY_LOCK_CNT(50);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
rtcvdd_cnt ++;
|
||||
}
|
||||
} else {
|
||||
rtcvdd_cnt = 0;
|
||||
rtcvdd_full_value = rtcvdd_full_vaule_update(rtcvdd_value);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/**@brief 获取ad按键值
|
||||
@param void
|
||||
@param void
|
||||
@return key_number
|
||||
@note tu8 adkey_rtcvdd_get_key_value(void)
|
||||
*/
|
||||
/*----------------------------------------------------------------------------*/
|
||||
u8 adkey_rtcvdd_get_key_value(void)
|
||||
{
|
||||
u8 key_number, i;
|
||||
u32 ad_value;
|
||||
u16 rtcvdd_value = 0;
|
||||
|
||||
rtcvdd_value = 2 * adc_get_value(AD_CH_RTCVDD);
|
||||
ad_value = adc_get_value(__this->ad_channel);
|
||||
|
||||
/* printf("rtcvdd_value = %d, ad_value = %d", rtcvdd_value, ad_value); */
|
||||
if (rtcvdd_auto_match_vddio_lev(rtcvdd_value)) {
|
||||
return NO_KEY;
|
||||
}
|
||||
|
||||
if (GET_ADKEY_LOCK_CNT()) {
|
||||
POST_ADKEY_LOCK_CNT();
|
||||
return NO_KEY;
|
||||
}
|
||||
|
||||
set_rtcvdd_table(rtcvdd_full_value);
|
||||
|
||||
for (i = 0; i < __this->adkey_num; i++) {
|
||||
if (ad_value <= ad_rtcvdd_key_table[i] && (ad_rtcvdd_key_table[i] < 0x3FFL)) {
|
||||
return __this->key_value[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NO_KEY;
|
||||
}
|
||||
|
||||
|
||||
#endif /* #if TCFG_ADKEY_RTCVDD_ENABLE */
|
||||
|
||||
61
apps/common/device/key/ctmu_touch_key.c
Normal file
61
apps/common/device/key/ctmu_touch_key.c
Normal file
@ -0,0 +1,61 @@
|
||||
#include "key_driver.h"
|
||||
#include "app_config.h"
|
||||
|
||||
|
||||
|
||||
#if TCFG_CTMU_TOUCH_KEY_ENABLE
|
||||
#include "asm/ctmu.h"
|
||||
|
||||
#define LOG_TAG_CONST CTMU
|
||||
#define LOG_TAG "[ctmu]"
|
||||
#define LOG_ERROR_ENABLE
|
||||
#define LOG_DEBUG_ENABLE
|
||||
#define LOG_INFO_ENABLE
|
||||
/* #define LOG_DUMP_ENABLE */
|
||||
#define LOG_CLI_ENABLE
|
||||
#include "debug.h"
|
||||
|
||||
/* =========== 触摸键使用说明 ============= */
|
||||
//1. 使用ctmu模块作计数;
|
||||
|
||||
static const struct ctmu_touch_key_platform_data *__this = NULL;
|
||||
|
||||
static u8 ctmu_touch_key_get_value(void);
|
||||
//按键驱动扫描参数列表
|
||||
struct key_driver_para ctmu_touch_key_scan_para = {
|
||||
.scan_time = 10, //按键扫描频率, 单位: ms
|
||||
.last_key = NO_KEY, //上一次get_value按键值, 初始化为NO_KEY;
|
||||
.filter_time = 2, //按键消抖延时;
|
||||
.long_time = 55, //按键判定长按数量
|
||||
.hold_time = (55 + 15), //按键判定HOLD数量
|
||||
.click_delay_time = 40, //按键被抬起后等待连击延时数量
|
||||
.key_type = KEY_DRIVER_TYPE_CTMU_TOUCH,
|
||||
.get_value = ctmu_touch_key_get_value,
|
||||
};
|
||||
|
||||
|
||||
|
||||
static u8 ctmu_touch_key_get_value(void)
|
||||
{
|
||||
u8 key = get_ctmu_value();
|
||||
|
||||
if (key != NO_KEY) {
|
||||
log_debug("key = %d %x", key, __this->port_list[key].key_value);
|
||||
return __this->port_list[key].key_value;
|
||||
}
|
||||
|
||||
return NO_KEY;
|
||||
}
|
||||
|
||||
|
||||
int ctmu_touch_key_init(const struct ctmu_touch_key_platform_data *ctmu_touch_key_data)
|
||||
{
|
||||
__this = ctmu_touch_key_data;
|
||||
log_info("ctmu touch_key_init >>>> ");
|
||||
|
||||
return ctmu_init((void *)ctmu_touch_key_data);
|
||||
}
|
||||
|
||||
|
||||
#endif /* #if TCFG_CTMU_TOUCH_KEY_ENABLE */
|
||||
|
||||
277
apps/common/device/key/iokey.c
Normal file
277
apps/common/device/key/iokey.c
Normal file
@ -0,0 +1,277 @@
|
||||
#include "key_driver.h"
|
||||
#include "iokey.h"
|
||||
#include "gpio.h"
|
||||
#include "system/event.h"
|
||||
#include "app_config.h"
|
||||
#include "asm/clock.h"
|
||||
|
||||
#if TCFG_IOKEY_ENABLE
|
||||
|
||||
static const struct iokey_platform_data *__this = NULL;
|
||||
|
||||
u8 io_get_key_value(void);
|
||||
|
||||
#if MOUSE_KEY_SCAN_MODE
|
||||
struct key_driver_para iokey_scan_para = {
|
||||
.scan_time = 5, //按键扫描频率, 单位: ms
|
||||
.last_key = NO_KEY, //上一次get_value按键值, 初始化为NO_KEY;
|
||||
.filter_time = 2, //按键消抖延时;
|
||||
.long_time = 5, //按键判定长按数量
|
||||
.hold_time = (5 + 0), //按键判定HOLD数量
|
||||
.click_delay_time = 20, //按键被抬起后等待连击延时数量
|
||||
.key_type = KEY_DRIVER_TYPE_IO,
|
||||
.get_value = io_get_key_value,
|
||||
};
|
||||
#else
|
||||
//按键驱动扫描参数列表
|
||||
struct key_driver_para iokey_scan_para = {
|
||||
.scan_time = 10, //按键扫描频率, 单位: ms
|
||||
.last_key = NO_KEY, //上一次get_value按键值, 初始化为NO_KEY;
|
||||
.filter_time = 4, //按键消抖延时;
|
||||
.long_time = 75, //按键判定长按数量
|
||||
.hold_time = (75 + 15), //按键判定HOLD数量
|
||||
.click_delay_time = 20, //按键被抬起后等待连击延时数量
|
||||
.key_type = KEY_DRIVER_TYPE_IO,
|
||||
.get_value = io_get_key_value,
|
||||
};
|
||||
#endif
|
||||
|
||||
#define MARK_BIT_VALUE(b, v) do {if ((v & (~BIT(7))) < 7) b |= BIT(v & (~BIT(7)));} while(0)
|
||||
|
||||
static void key_io_pull_down_input(u8 key_io)
|
||||
{
|
||||
gpio_direction_input(key_io);
|
||||
gpio_set_pull_down(key_io, 1);
|
||||
gpio_set_pull_up(key_io, 0);
|
||||
gpio_set_die(key_io, 1);
|
||||
}
|
||||
|
||||
|
||||
static void key_io_pull_up_input(u8 key_io)
|
||||
{
|
||||
gpio_direction_input(key_io);
|
||||
gpio_set_pull_down(key_io, 0);
|
||||
gpio_set_pull_up(key_io, 1);
|
||||
gpio_set_die(key_io, 1);
|
||||
}
|
||||
|
||||
static void key_io_output_high(u8 key_io)
|
||||
{
|
||||
gpio_set_pull_down(key_io, 0);
|
||||
gpio_set_pull_up(key_io, 0);
|
||||
gpio_direction_output(key_io, 1);
|
||||
}
|
||||
|
||||
static void key_io_output_low(u8 key_io)
|
||||
{
|
||||
gpio_set_pull_down(key_io, 0);
|
||||
gpio_set_pull_up(key_io, 0);
|
||||
gpio_direction_output(key_io, 0);
|
||||
}
|
||||
|
||||
static int get_io_key_value(u8 key_io)
|
||||
{
|
||||
return gpio_read(key_io);
|
||||
}
|
||||
|
||||
|
||||
static void key_io_reset(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < __this->num; i++) {
|
||||
switch (__this->port[i].connect_way) {
|
||||
case ONE_PORT_TO_HIGH:
|
||||
key_io_pull_down_input(__this->port[i].key_type.one_io.port);
|
||||
break;
|
||||
|
||||
case ONE_PORT_TO_LOW:
|
||||
#if (TCFG_IO_MULTIPLEX_WITH_SD == ENABLE)
|
||||
if (TCFG_MULTIPLEX_PORT != __this->port[i].key_type.one_io.port) {
|
||||
key_io_pull_up_input(__this->port[i].key_type.one_io.port);
|
||||
}
|
||||
#else
|
||||
|
||||
key_io_pull_up_input(__this->port[i].key_type.one_io.port);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case DOUBLE_PORT_TO_IO:
|
||||
break;
|
||||
|
||||
default:
|
||||
ASSERT(0, "IO KEY CONNECT ERR!!!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if MULT_KEY_ENABLE
|
||||
extern const struct key_remap_data iokey_remap_data;
|
||||
static u8 iokey_value_remap(u8 bit_mark)
|
||||
{
|
||||
for (int i = 0; i < iokey_remap_data.remap_num; i++) {
|
||||
if (iokey_remap_data.table[i].bit_value == bit_mark) {
|
||||
return iokey_remap_data.table[i].remap_value;
|
||||
}
|
||||
}
|
||||
|
||||
return NO_KEY;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if TCFG_IO_MULTIPLEX_WITH_SD == ENABLE
|
||||
static u8 mult_key_value = 1;
|
||||
static void udelay(u32 usec)
|
||||
{
|
||||
JL_TIMER0->CON = BIT(14);
|
||||
JL_TIMER0->CNT = 0;
|
||||
JL_TIMER0->PRD = clk_get("lsb") / 1000000L * usec;
|
||||
JL_TIMER0->CON = BIT(0); //lsb clk
|
||||
while ((JL_TIMER0->CON & BIT(15)) == 0);
|
||||
JL_TIMER0->CON = BIT(14);
|
||||
}
|
||||
extern u8 sd_io_suspend(u8 sdx, u8 sd_io);
|
||||
extern u8 sd_io_resume(u8 sdx, u8 sd_io);
|
||||
void sd_mult_io_detect(void *arg)
|
||||
{
|
||||
static u32 cnt = 0;
|
||||
if (sd_io_suspend(1, 1) == 0) {
|
||||
gpio_set_direction(TCFG_MULTIPLEX_PORT, 0);
|
||||
gpio_write(TCFG_MULTIPLEX_PORT, 0);
|
||||
udelay(10);
|
||||
gpio_set_die(TCFG_MULTIPLEX_PORT, 1);
|
||||
gpio_set_pull_down(TCFG_MULTIPLEX_PORT, 0);
|
||||
gpio_set_pull_up(TCFG_MULTIPLEX_PORT, 1);
|
||||
gpio_set_direction(TCFG_MULTIPLEX_PORT, 1);
|
||||
udelay(10);
|
||||
mult_key_value = gpio_read(TCFG_MULTIPLEX_PORT);
|
||||
sd_io_resume(1, 1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
__attribute__((weak)) u8 iokey_filter_hook(u8 io_state)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
u8 io_get_key_value(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
u8 press_value = 0;
|
||||
u8 read_value = 0;
|
||||
u8 read_io;
|
||||
u8 write_io;
|
||||
u8 connect_way;
|
||||
u8 ret_value = NO_KEY;
|
||||
u8 bit_mark = 0;
|
||||
|
||||
if (!__this->enable) {
|
||||
return NO_KEY;
|
||||
}
|
||||
|
||||
//先扫描单IO接按键方式
|
||||
for (i = 0; i < __this->num; i++) {
|
||||
connect_way = __this->port[i].connect_way;
|
||||
|
||||
if (connect_way == ONE_PORT_TO_HIGH) {
|
||||
press_value = 1;
|
||||
} else if (connect_way == ONE_PORT_TO_LOW) {
|
||||
press_value = 0;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
read_io = __this->port[i].key_type.one_io.port;
|
||||
|
||||
#if (TCFG_IO_MULTIPLEX_WITH_SD == ENABLE)
|
||||
if (read_io == TCFG_MULTIPLEX_PORT) {
|
||||
read_value = mult_key_value;
|
||||
} else {
|
||||
read_value = get_io_key_value(read_io);
|
||||
}
|
||||
#else
|
||||
read_value = get_io_key_value(read_io);
|
||||
#endif
|
||||
if (iokey_filter_hook(read_value)) {
|
||||
#ifdef TCFG_IOKEY_TIME_REDEFINE
|
||||
extern struct key_driver_para iokey_scan_user_para;
|
||||
iokey_scan_user_para.filter_cnt = 0;
|
||||
iokey_scan_user_para.press_cnt = 0;
|
||||
iokey_scan_user_para.click_cnt = 0;
|
||||
iokey_scan_user_para.click_delay_cnt = 0;
|
||||
iokey_scan_user_para.last_key = NO_KEY;
|
||||
#else
|
||||
iokey_scan_para.filter_cnt = 0;
|
||||
iokey_scan_para.press_cnt = 0;
|
||||
iokey_scan_para.click_cnt = 0;
|
||||
iokey_scan_para.click_delay_cnt = 0;
|
||||
iokey_scan_para.last_key = NO_KEY;
|
||||
#endif
|
||||
return NO_KEY;
|
||||
}
|
||||
if (read_value == press_value) {
|
||||
ret_value = __this->port[i].key_value;
|
||||
#if MULT_KEY_ENABLE
|
||||
MARK_BIT_VALUE(bit_mark, ret_value); //标记被按下的按键
|
||||
#else
|
||||
goto _iokey_get_value_end;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
//再扫描两个IO接按键方式, in_port: 上拉输入, out_port: 输出低
|
||||
for (i = 0; i < __this->num; i++) {
|
||||
connect_way = __this->port[i].connect_way;
|
||||
if (connect_way == DOUBLE_PORT_TO_IO) {//标准双io
|
||||
press_value = 0;
|
||||
read_io = __this->port[i].key_type.two_io.in_port;
|
||||
key_io_output_low(__this->port[i].key_type.two_io.out_port); //输出低
|
||||
key_io_pull_up_input(read_io); //上拉
|
||||
read_value = get_io_key_value(read_io);
|
||||
key_io_reset(); //按键初始化为单IO检测状态
|
||||
if (read_value == press_value) {
|
||||
ret_value = __this->port[i].key_value;
|
||||
#if MULT_KEY_ENABLE
|
||||
MARK_BIT_VALUE(bit_mark, ret_value); //标记被按下的按键
|
||||
#else
|
||||
goto _iokey_get_value_end;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if MULT_KEY_ENABLE
|
||||
bit_mark = iokey_value_remap(bit_mark); //组合按键重新映射按键值
|
||||
ret_value = (bit_mark != NO_KEY) ? bit_mark : ret_value;
|
||||
#endif
|
||||
|
||||
_iokey_get_value_end:
|
||||
return ret_value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int iokey_init(const struct iokey_platform_data *iokey_data)
|
||||
{
|
||||
int i;
|
||||
|
||||
__this = iokey_data;
|
||||
if (__this == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!__this->enable) {
|
||||
return KEY_NOT_SUPPORT;
|
||||
}
|
||||
|
||||
key_io_reset();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* #if TCFG_IOKEY_ENABLE */
|
||||
|
||||
78
apps/common/device/key/irkey.c
Normal file
78
apps/common/device/key/irkey.c
Normal file
@ -0,0 +1,78 @@
|
||||
#include "key_driver.h"
|
||||
#include "irkey.h"
|
||||
#include "gpio.h"
|
||||
#include "asm/irflt.h"
|
||||
#include "app_config.h"
|
||||
|
||||
#if TCFG_IRKEY_ENABLE
|
||||
|
||||
u8 ir_get_key_value(void);
|
||||
//按键驱动扫描参数列表
|
||||
struct key_driver_para irkey_scan_para = {
|
||||
.scan_time = 10, //按键扫描频率, 单位: ms
|
||||
.last_key = NO_KEY, //上一次get_value按键值, 初始化为NO_KEY;
|
||||
.filter_time = 2, //按键消抖延时;
|
||||
.long_time = 75, //按键判定长按数量
|
||||
.hold_time = (75 + 15), //按键判定HOLD数量
|
||||
.click_delay_time = 20, //按键被抬起后等待连击延时数量
|
||||
.key_type = KEY_DRIVER_TYPE_IR,
|
||||
.get_value = ir_get_key_value,
|
||||
};
|
||||
|
||||
|
||||
|
||||
const u8 IRTabFF00[] = {
|
||||
NKEY_00, NKEY_01, NKEY_02, NKEY_03, NKEY_04, NKEY_05, NKEY_06, IR_06, IR_15, IR_08, NKEY_0A, NKEY_0B, IR_12, IR_11, NKEY_0E, NKEY_0F,
|
||||
NKEY_10, NKEY_11, NKEY_12, NKEY_13, NKEY_14, IR_07, IR_09, NKEY_17, IR_13, IR_10, NKEY_1A, NKEY_1B, IR_16, NKEY_1D, NKEY_1E, NKEY_1F,
|
||||
NKEY_20, NKEY_21, NKEY_22, NKEY_23, NKEY_24, NKEY_25, NKEY_26, NKEY_27, NKEY_28, NKEY_29, NKEY_2A, NKEY_2B, NKEY_2C, NKEY_2D, NKEY_2E, NKEY_2F,
|
||||
NKEY_30, NKEY_31, NKEY_32, NKEY_33, NKEY_34, NKEY_35, NKEY_36, NKEY_37, NKEY_38, NKEY_39, NKEY_3A, NKEY_3B, NKEY_3C, NKEY_3D, NKEY_3E, NKEY_3F,
|
||||
IR_04, NKEY_41, IR_18, IR_05, IR_03, IR_00, IR_01, IR_02, NKEY_48, NKEY_49, IR_20, NKEY_4B, NKEY_4C, NKEY_4D, NKEY_4E, NKEY_4F,
|
||||
NKEY_50, NKEY_51, IR_19, NKEY_53, NKEY_54, NKEY_55, NKEY_56, NKEY_57, NKEY_58, NKEY_59, IR_17, NKEY_5B, NKEY_5C, NKEY_5D, IR_14, NKEY_5F,
|
||||
};
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/**@brief 获取ir按键值
|
||||
@param void
|
||||
@param void
|
||||
@return void
|
||||
@note void get_irkey_value(void)
|
||||
*/
|
||||
/*----------------------------------------------------------------------------*/
|
||||
u8 ir_get_key_value(void)
|
||||
{
|
||||
u8 tkey = 0xff;
|
||||
tkey = get_irflt_value();
|
||||
if (tkey == 0xff) {
|
||||
return tkey;
|
||||
}
|
||||
tkey = IRTabFF00[tkey];
|
||||
return tkey;
|
||||
}
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/**@brief ir按键初始化
|
||||
@param void
|
||||
@param void
|
||||
@return void
|
||||
@note void ir_key_init(void)
|
||||
*/
|
||||
/*----------------------------------------------------------------------------*/
|
||||
int irkey_init(const struct irkey_platform_data *irkey_data)
|
||||
{
|
||||
printf("irkey_init ");
|
||||
|
||||
ir_input_io_sel(irkey_data->port);
|
||||
|
||||
ir_output_timer_sel();
|
||||
|
||||
irflt_config();
|
||||
|
||||
ir_timeout_set();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
380
apps/common/device/key/key_driver.c
Normal file
380
apps/common/device/key/key_driver.c
Normal file
@ -0,0 +1,380 @@
|
||||
#include "device/key_driver.h"
|
||||
#include "system/event.h"
|
||||
#include "system/init.h"
|
||||
#include "iokey.h"
|
||||
#include "adkey.h"
|
||||
#include "slidekey.h"
|
||||
#include "irkey.h"
|
||||
#include "touch_key.h"
|
||||
#include "system/timer.h"
|
||||
#include "asm/power_interface.h"
|
||||
#include "app_config.h"
|
||||
#include "rdec_key.h"
|
||||
#include "tent600_key.h"
|
||||
#if TCFG_KEY_TONE_EN
|
||||
#include "tone_player.h"
|
||||
#endif
|
||||
|
||||
#if(TCFG_IRSENSOR_ENABLE == 1)
|
||||
#include "irSensor/ir_manage.h"
|
||||
#endif
|
||||
|
||||
#define LOG_TAG_CONST KEY
|
||||
#define LOG_TAG "[KEY]"
|
||||
#define LOG_ERROR_ENABLE
|
||||
#define LOG_DEBUG_ENABLE
|
||||
#define LOG_INFO_ENABLE
|
||||
//#define LOG_DUMP_ENABLE
|
||||
//#define LOG_CLI_ENABLE
|
||||
#include "debug.h"
|
||||
|
||||
#define KEY_EVENT_CLICK_ONLY_SUPPORT 1 //是否支持某些按键只响应单击事件
|
||||
|
||||
|
||||
#if TCFG_SPI_LCD_ENABLE
|
||||
#ifndef ALL_KEY_EVENT_CLICK_ONLY
|
||||
#define ALL_KEY_EVENT_CLICK_ONLY 1 //是否全部按键只响应单击事件
|
||||
#endif
|
||||
#else
|
||||
#ifndef ALL_KEY_EVENT_CLICK_ONLY
|
||||
#define ALL_KEY_EVENT_CLICK_ONLY 0 //是否全部按键只响应单击事件
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static volatile u8 is_key_active = 0;
|
||||
static volatile u8 key_poweron_flag = 0;
|
||||
|
||||
extern u32 timer_get_ms(void);
|
||||
|
||||
//=======================================================//
|
||||
// 按键值重新映射函数:
|
||||
// 用户可以实现该函数把一些按键值重新映射, 可用于组合键的键值重新映射
|
||||
//=======================================================//
|
||||
int __attribute__((weak)) key_event_remap(struct sys_event *e)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//=======================================================//
|
||||
// 设置按键开机标志位
|
||||
//=======================================================//
|
||||
void set_key_poweron_flag(u8 flag)
|
||||
{
|
||||
key_poweron_flag = flag;
|
||||
}
|
||||
|
||||
//=======================================================//
|
||||
// 获取按键开机标志位
|
||||
//=======================================================//
|
||||
u8 get_key_poweron_flag(void)
|
||||
{
|
||||
return key_poweron_flag;
|
||||
}
|
||||
|
||||
//=======================================================//
|
||||
// 清除按键开机标志位
|
||||
//=======================================================//
|
||||
void clear_key_poweron_flag(void)
|
||||
{
|
||||
key_poweron_flag = 0;
|
||||
}
|
||||
|
||||
//=======================================================//
|
||||
// 按键扫描函数: 扫描所有注册的按键驱动
|
||||
//=======================================================//
|
||||
static void key_driver_scan(void *_scan_para)
|
||||
{
|
||||
struct key_driver_para *scan_para = (struct key_driver_para *)_scan_para;
|
||||
|
||||
u8 key_event = 0;
|
||||
u8 cur_key_value = NO_KEY;
|
||||
u8 key_value = 0;
|
||||
struct sys_event e;
|
||||
static u8 poweron_cnt = 0;
|
||||
|
||||
//为了滤掉adkey与mic连在一起时电容充放电导致的开机按键误判,一般用于type-c耳机
|
||||
/* if (poweron_cnt <= 250) { */
|
||||
/* poweron_cnt++; */
|
||||
/* return; */
|
||||
/* } */
|
||||
|
||||
cur_key_value = scan_para->get_value();
|
||||
/* if (cur_key_value != NO_KEY) { */
|
||||
/* printf(">>>cur_key_value: %d\n", cur_key_value); */
|
||||
/* } */
|
||||
|
||||
if (cur_key_value != NO_KEY) {
|
||||
is_key_active = 35; //35*10Ms
|
||||
} else if (is_key_active) {
|
||||
is_key_active --;
|
||||
}
|
||||
//===== 按键消抖处理
|
||||
if (cur_key_value != scan_para->filter_value && scan_para->filter_time) { //当前按键值与上一次按键值如果不相等, 重新消抖处理, 注意filter_time != 0;
|
||||
scan_para->filter_cnt = 0; //消抖次数清0, 重新开始消抖
|
||||
scan_para->filter_value = cur_key_value; //记录上一次的按键值
|
||||
return; //第一次检测, 返回不做处理
|
||||
} //当前按键值与上一次按键值相等, filter_cnt开始累加;
|
||||
if (scan_para->filter_cnt < scan_para->filter_time) {
|
||||
scan_para->filter_cnt++;
|
||||
return;
|
||||
}
|
||||
//为了滤掉adkey与mic连在一起时电容充放电导致的按键误判,一般用于type-c耳机
|
||||
/* if ((cur_key_value != scan_para->last_key) && (scan_para->last_key != NO_KEY) && (cur_key_value != NO_KEY)) { */
|
||||
/* return; */
|
||||
/* } */
|
||||
//===== 按键消抖结束, 开始判断按键类型(单击, 双击, 长按, 多击, HOLD, (长按/HOLD)抬起)
|
||||
if (cur_key_value != scan_para->last_key) {
|
||||
if (cur_key_value == NO_KEY) { //cur_key = NO_KEY; last_key = valid_key -> 按键被抬起
|
||||
|
||||
#if MOUSE_KEY_SCAN_MODE
|
||||
/* if (scan_para->press_cnt >= scan_para->long_time) { //长按/HOLD状态之后被按键抬起; */
|
||||
key_event = KEY_EVENT_UP;
|
||||
key_value = scan_para->last_key;
|
||||
goto _notify; //发送抬起消息
|
||||
/* } */
|
||||
#else
|
||||
if (scan_para->press_cnt >= scan_para->long_time) { //长按/HOLD状态之后被按键抬起;
|
||||
key_event = KEY_EVENT_UP;
|
||||
key_value = scan_para->last_key;
|
||||
goto _notify; //发送抬起消息
|
||||
}
|
||||
#endif
|
||||
|
||||
scan_para->click_delay_cnt = 1; //按键等待下次连击延时开始
|
||||
} else { //cur_key = valid_key, last_key = NO_KEY -> 按键被按下
|
||||
scan_para->press_cnt = 1; //用于判断long和hold事件的计数器重新开始计时;
|
||||
if (cur_key_value != scan_para->notify_value) { //第一次单击/连击时按下的是不同按键, 单击次数重新开始计数
|
||||
scan_para->click_cnt = 1;
|
||||
scan_para->notify_value = cur_key_value;
|
||||
} else {
|
||||
scan_para->click_cnt++; //单击次数累加
|
||||
}
|
||||
}
|
||||
goto _scan_end; //返回, 等待延时时间到
|
||||
} else { //cur_key = last_key -> 没有按键按下/按键长按(HOLD)
|
||||
if (cur_key_value == NO_KEY) { //last_key = NO_KEY; cur_key = NO_KEY -> 没有按键按下
|
||||
if (scan_para->click_cnt > 0) { //有按键需要消息需要处理
|
||||
|
||||
#if ALL_KEY_EVENT_CLICK_ONLY//彩屏方案支持单击
|
||||
key_event = KEY_EVENT_CLICK; //单击
|
||||
key_value = scan_para->notify_value;
|
||||
goto _notify;
|
||||
|
||||
#endif
|
||||
|
||||
#if KEY_EVENT_CLICK_ONLY_SUPPORT //是否支持某些按键只响应单击事件
|
||||
if (scan_para->notify_value & BIT(7)) { //BIT(7)按键特殊处理标志, 只发送单击事件, 也可以用于其它扩展
|
||||
key_event = KEY_EVENT_CLICK; //单击
|
||||
key_value = scan_para->notify_value;
|
||||
goto _notify;
|
||||
}
|
||||
#endif
|
||||
if (scan_para->click_delay_cnt > scan_para->click_delay_time) { //按键被抬起后延时到
|
||||
//TODO: 在此可以添加任意多击事件
|
||||
if (scan_para->click_cnt >= 5) {
|
||||
key_event = KEY_EVENT_FIRTH_CLICK; //五击
|
||||
} else if (scan_para->click_cnt >= 4) {
|
||||
key_event = KEY_EVENT_FOURTH_CLICK; //4击
|
||||
} else if (scan_para->click_cnt >= 3) {
|
||||
key_event = KEY_EVENT_TRIPLE_CLICK; //三击
|
||||
} else if (scan_para->click_cnt >= 2) {
|
||||
key_event = KEY_EVENT_DOUBLE_CLICK; //双击
|
||||
} else {
|
||||
key_event = KEY_EVENT_CLICK; //单击
|
||||
}
|
||||
key_value = scan_para->notify_value;
|
||||
goto _notify;
|
||||
} else { //按键抬起后等待下次延时时间未到
|
||||
scan_para->click_delay_cnt++;
|
||||
goto _scan_end; //按键抬起后延时时间未到, 返回
|
||||
}
|
||||
} else {
|
||||
goto _scan_end; //没有按键需要处理
|
||||
}
|
||||
} else { //last_key = valid_key; cur_key = valid_key, press_cnt累加用于判断long和hold
|
||||
scan_para->press_cnt++;
|
||||
if (scan_para->press_cnt == scan_para->long_time) {
|
||||
key_event = KEY_EVENT_LONG;
|
||||
} else if (scan_para->press_cnt == scan_para->hold_time) {
|
||||
key_event = KEY_EVENT_HOLD;
|
||||
scan_para->press_cnt = scan_para->long_time;
|
||||
} else {
|
||||
goto _scan_end; //press_cnt没到长按和HOLD次数, 返回
|
||||
}
|
||||
//press_cnt没到长按和HOLD次数, 发消息
|
||||
key_value = cur_key_value;
|
||||
goto _notify;
|
||||
}
|
||||
}
|
||||
|
||||
_notify:
|
||||
#if TCFG_IRSENSOR_ENABLE
|
||||
if (get_irSensor_event() == IR_SENSOR_EVENT_FAR) { //未佩戴的耳机不响应按键
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
key_value &= ~BIT(7); //BIT(7) 用作按键特殊处理的标志
|
||||
e.type = SYS_KEY_EVENT;
|
||||
e.u.key.init = 1;
|
||||
e.u.key.type = scan_para->key_type;//区分按键类型
|
||||
e.u.key.event = key_event;
|
||||
e.u.key.value = key_value;
|
||||
e.u.key.tmr = timer_get_ms();
|
||||
|
||||
|
||||
scan_para->click_cnt = 0; //单击次数清0
|
||||
scan_para->notify_value = NO_KEY;
|
||||
|
||||
e.arg = (void *)DEVICE_EVENT_FROM_KEY;
|
||||
/* printf("key_value: 0x%x, event: %d, key_poweron_flag: %d\n", key_value, key_event, key_poweron_flag); */
|
||||
if (key_poweron_flag) {
|
||||
if (key_event == KEY_EVENT_UP) {
|
||||
clear_key_poweron_flag();
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (key_event_remap(&e)) {
|
||||
sys_event_notify(&e);
|
||||
#if TCFG_KEY_TONE_EN
|
||||
audio_key_tone_play();
|
||||
#endif
|
||||
}
|
||||
_scan_end:
|
||||
scan_para->last_key = cur_key_value;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//wakeup callback
|
||||
void key_active_set(u8 port)
|
||||
{
|
||||
is_key_active = 35; //35*10Ms
|
||||
}
|
||||
|
||||
//=======================================================//
|
||||
// 按键初始化函数: 初始化所有注册的按键驱动
|
||||
//=======================================================//
|
||||
int key_driver_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
#if TCFG_IOKEY_ENABLE
|
||||
extern const struct iokey_platform_data iokey_data;
|
||||
extern struct key_driver_para iokey_scan_para;
|
||||
err = iokey_init(&iokey_data);
|
||||
#ifdef TCFG_IOKEY_TIME_REDEFINE
|
||||
extern struct key_driver_para iokey_scan_user_para;
|
||||
if (err == 0) {
|
||||
sys_s_hi_timer_add((void *)&iokey_scan_user_para, key_driver_scan, iokey_scan_user_para.scan_time); //注册按键扫描定时器
|
||||
}
|
||||
#else
|
||||
if (err == 0) {
|
||||
sys_s_hi_timer_add((void *)&iokey_scan_para, key_driver_scan, iokey_scan_para.scan_time); //注册按键扫描定时器
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if TCFG_ADKEY_ENABLE
|
||||
#ifdef CONFIG_ICRECORDER_CASE_ENABLE
|
||||
extern multi_adkey_init(const struct adkey_platform_data * multi_adkey_data);
|
||||
extern const struct adkey_platform_data multi_adkey_data[];
|
||||
extern struct key_driver_para multi_adkey_scan_para;
|
||||
err = multi_adkey_init(multi_adkey_data);
|
||||
if (err == 0) {
|
||||
sys_s_hi_timer_add((void *)&multi_adkey_scan_para, key_driver_scan, multi_adkey_scan_para.scan_time); //注册按键扫描定时器
|
||||
}
|
||||
#else
|
||||
extern const struct adkey_platform_data adkey_data;
|
||||
extern struct key_driver_para adkey_scan_para;
|
||||
err = adkey_init(&adkey_data);
|
||||
if (err == 0) {
|
||||
sys_s_hi_timer_add((void *)&adkey_scan_para, key_driver_scan, adkey_scan_para.scan_time); //注册按键扫描定时器
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if TCFG_IRKEY_ENABLE
|
||||
extern const struct irkey_platform_data irkey_data;
|
||||
extern struct key_driver_para irkey_scan_para;
|
||||
err = irkey_init(&irkey_data);
|
||||
if (err == 0) {
|
||||
sys_s_hi_timer_add((void *)&irkey_scan_para, key_driver_scan, irkey_scan_para.scan_time); //注册按键扫描定时器
|
||||
}
|
||||
#endif
|
||||
|
||||
#if TCFG_TOUCH_KEY_ENABLE
|
||||
extern const struct touch_key_platform_data touch_key_data;
|
||||
extern struct key_driver_para touch_key_scan_para;
|
||||
err = touch_key_init(&touch_key_data);
|
||||
if (err == 0) {
|
||||
sys_s_hi_timer_add((void *)&touch_key_scan_para, key_driver_scan, touch_key_scan_para.scan_time); //注册按键扫描定时器
|
||||
}
|
||||
#endif
|
||||
|
||||
#if TCFG_ADKEY_RTCVDD_ENABLE
|
||||
extern const struct adkey_rtcvdd_platform_data adkey_rtcvdd_data;
|
||||
extern struct key_driver_para adkey_rtcvdd_scan_para;
|
||||
err = adkey_rtcvdd_init(&adkey_rtcvdd_data);
|
||||
if (err == 0) {
|
||||
sys_s_hi_timer_add((void *)&adkey_rtcvdd_scan_para, key_driver_scan, adkey_rtcvdd_scan_para.scan_time); //注册按键扫描定时器
|
||||
}
|
||||
#endif
|
||||
|
||||
#if TCFG_RDEC_KEY_ENABLE
|
||||
extern const struct rdec_platform_data rdec_key_data;
|
||||
extern struct key_driver_para rdec_key_scan_para;
|
||||
err = rdec_key_init(&rdec_key_data);
|
||||
if (err == 0) {
|
||||
sys_s_hi_timer_add((void *)&rdec_key_scan_para, key_driver_scan, rdec_key_scan_para.scan_time); //注册按键扫描定时器
|
||||
}
|
||||
#endif
|
||||
|
||||
#if TCFG_CTMU_TOUCH_KEY_ENABLE
|
||||
#include "asm/ctmu.h"
|
||||
extern const struct ctmu_touch_key_platform_data ctmu_touch_key_data;
|
||||
extern struct key_driver_para ctmu_touch_key_scan_para;
|
||||
extern int ctmu_touch_key_init(const struct ctmu_touch_key_platform_data * ctmu_touch_key_data);
|
||||
err = ctmu_touch_key_init(&ctmu_touch_key_data);
|
||||
if (err == 0) {
|
||||
sys_s_hi_timer_add((void *)&ctmu_touch_key_scan_para, key_driver_scan, ctmu_touch_key_scan_para.scan_time); //注册按键扫描定时器
|
||||
}
|
||||
#endif /* #if TCFG_CTMU_TOUCH_KEY_ENABLE */
|
||||
|
||||
#if TCFG_SLIDE_KEY_ENABLE
|
||||
extern const struct slidekey_platform_data slidekey_data;
|
||||
extern int slidekey_init(const struct slidekey_platform_data * slidekey_data);
|
||||
err = slidekey_init(&slidekey_data);
|
||||
if (err == 0) {
|
||||
}
|
||||
#endif//TCFG_SLIDE_KEY_ENABLE
|
||||
|
||||
#if TCFG_6083_ADKEY_ENABLE
|
||||
extern int adkey_init_6083();
|
||||
err = adkey_init_6083();
|
||||
if (err == 0) {
|
||||
}
|
||||
#endif
|
||||
#if TCFG_TENT600_KEY_ENABLE
|
||||
extern const struct tent600_key_platform_data key_data ;
|
||||
extern struct key_driver_para tent600_key_scan_para;
|
||||
err = tent600_key_init(&key_data);
|
||||
if (err == 0) {
|
||||
sys_s_hi_timer_add((void *)&tent600_key_scan_para, key_driver_scan, tent600_key_scan_para.scan_time); //注册按键扫描定时器
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u8 key_idle_query(void)
|
||||
{
|
||||
return !is_key_active;
|
||||
}
|
||||
#if ((!TCFG_LP_TOUCH_KEY_ENABLE) && (TCFG_IOKEY_ENABLE || TCFG_ADKEY_ENABLE))
|
||||
REGISTER_LP_TARGET(key_lp_target) = {
|
||||
.name = "key",
|
||||
.is_idle = key_idle_query,
|
||||
};
|
||||
#endif /* #if !TCFG_LP_TOUCH_KEY_ENABLE */
|
||||
|
||||
62
apps/common/device/key/touch_key.c
Normal file
62
apps/common/device/key/touch_key.c
Normal file
@ -0,0 +1,62 @@
|
||||
#include "touch_key.h"
|
||||
#include "key_driver.h"
|
||||
#include "app_config.h"
|
||||
|
||||
|
||||
#if TCFG_TOUCH_KEY_ENABLE
|
||||
|
||||
|
||||
/* =========== 触摸键使用说明 ============= */
|
||||
//1. 使用plcnt模块作计数;
|
||||
//2. 配置参数时, 在配置好时钟后, 需要调试no_touch_cnt和touch_cnt的值;
|
||||
|
||||
static const struct touch_key_platform_data *__this = NULL;
|
||||
|
||||
//按键驱动扫描参数列表
|
||||
struct key_driver_para touch_key_scan_para = {
|
||||
.scan_time = 10, //按键扫描频率, 单位: ms
|
||||
.last_key = NO_KEY, //上一次get_value按键值, 初始化为NO_KEY;
|
||||
.filter_time = 1, //按键消抖延时;
|
||||
.long_time = 75, //按键判定长按数量
|
||||
.hold_time = (75 + 15), //按键判定HOLD数量
|
||||
.click_delay_time = 20, //按键被抬起后等待连击延时数量
|
||||
.key_type = KEY_DRIVER_TYPE_TOUCH,
|
||||
.get_value = touch_key_get_value,
|
||||
};
|
||||
|
||||
#define TOUCH_KEY_DEBUG 0
|
||||
|
||||
#if TOUCH_KEY_DEBUG
|
||||
#define touch_key_debug(fmt, ...) printf("[TOUCH] "fmt, ##__VA_ARGS__)
|
||||
#else
|
||||
#define touch_key_debug(fmt, ...)
|
||||
#endif
|
||||
|
||||
|
||||
u8 touch_key_get_value(void)
|
||||
{
|
||||
u8 key = get_plcnt_value();
|
||||
|
||||
if (key != NO_KEY) {
|
||||
touch_key_debug("key = %d", key);
|
||||
return __this->port_list[key].key_value;
|
||||
}
|
||||
|
||||
return NO_KEY;
|
||||
}
|
||||
|
||||
|
||||
int touch_key_init(const struct touch_key_platform_data *touch_key_data)
|
||||
{
|
||||
__this = touch_key_data;
|
||||
printf("touch_key_init >>>> ");
|
||||
|
||||
return plcnt_init((void *)touch_key_data);
|
||||
}
|
||||
|
||||
|
||||
#endif /* #if TCFG_TOUCH_KEY_ENABLE */
|
||||
|
||||
|
||||
|
||||
|
||||
51
apps/common/device/key/uart_key.c
Normal file
51
apps/common/device/key/uart_key.c
Normal file
@ -0,0 +1,51 @@
|
||||
#include "key_driver.h"
|
||||
#include "system/event.h"
|
||||
#include "asm/uart.h"
|
||||
#include "app_config.h"
|
||||
|
||||
extern int getbyte(char *c);
|
||||
|
||||
#if TCFG_UART_KEY_ENABLE
|
||||
|
||||
static int uart_key_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u8 uart_get_key_value(void)
|
||||
{
|
||||
char c;
|
||||
u8 key_value;
|
||||
|
||||
if (getbyte(&c) == 0) {
|
||||
return NO_KEY;
|
||||
}
|
||||
|
||||
switch (c) {
|
||||
case 'm':
|
||||
key_value = KEY_MODE;
|
||||
break;
|
||||
case 'u':
|
||||
key_value = KEY_UP;
|
||||
break;
|
||||
case 'd':
|
||||
key_value = KEY_DOWN;
|
||||
break;
|
||||
case 'o':
|
||||
key_value = KEY_OK;
|
||||
break;
|
||||
case 'e':
|
||||
key_value = KEY_MENU;
|
||||
break;
|
||||
default:
|
||||
key_value = NO_KEY;
|
||||
break;
|
||||
}
|
||||
|
||||
return key_value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif /* #if TCFG_UART_KEY_ENABLE */
|
||||
|
||||
708
apps/common/device/norflash/norflash_sfc.c
Normal file
708
apps/common/device/norflash/norflash_sfc.c
Normal file
@ -0,0 +1,708 @@
|
||||
#include "includes.h"
|
||||
#include "app_config.h"
|
||||
#include "norflash_sfc.h"
|
||||
|
||||
#if (defined(TCFG_NORFLASH_SFC_DEV_ENABLE) && TCFG_NORFLASH_SFC_DEV_ENABLE)
|
||||
|
||||
#undef LOG_TAG_CONST
|
||||
#define LOG_TAG "[FLASH_SFC]"
|
||||
#define LOG_ERROR_ENABLE
|
||||
#define LOG_INFO_ENABLE
|
||||
#include "debug.h"
|
||||
|
||||
|
||||
#define MAX_NORFLASH_PART_NUM 4
|
||||
|
||||
struct norflash_partition {
|
||||
const char *name;
|
||||
u32 start_addr;
|
||||
u32 size;
|
||||
struct device device;
|
||||
};
|
||||
|
||||
static struct norflash_partition nor_part[MAX_NORFLASH_PART_NUM];
|
||||
|
||||
struct norflash_info {
|
||||
u32 flash_id;
|
||||
u32 flash_capacity;
|
||||
int spi_num;
|
||||
int spi_err;
|
||||
u8 spi_cs_io;
|
||||
u8 spi_r_width;
|
||||
u8 part_num;
|
||||
u8 open_cnt;
|
||||
struct norflash_partition *const part_list;
|
||||
OS_MUTEX mutex;
|
||||
u32 max_end_addr;
|
||||
};
|
||||
|
||||
static struct norflash_info _norflash = {
|
||||
.spi_num = (int) - 1,
|
||||
.part_list = nor_part,
|
||||
};
|
||||
|
||||
static int _norflash_read(u32 addr, u8 *buf, u32 len, u8 cache);
|
||||
static int _norflash_eraser(u8 eraser, u32 addr);
|
||||
static void _norflash_cache_sync_timer(void *priv);
|
||||
static int _norflash_write_pages(u32 addr, u8 *buf, u32 len);
|
||||
|
||||
static struct norflash_partition *norflash_find_part(const char *name)
|
||||
{
|
||||
struct norflash_partition *part = NULL;
|
||||
u32 idx;
|
||||
for (idx = 0; idx < MAX_NORFLASH_PART_NUM; idx++) {
|
||||
part = &_norflash.part_list[idx];
|
||||
if (part->name == NULL) {
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(part->name, name)) {
|
||||
return part;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct norflash_partition *norflash_new_part(const char *name, u32 addr, u32 size)
|
||||
{
|
||||
struct norflash_partition *part;
|
||||
u32 idx;
|
||||
for (idx = 0; idx < MAX_NORFLASH_PART_NUM; idx++) {
|
||||
part = &_norflash.part_list[idx];
|
||||
if (part->name == NULL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (part->name != NULL) {
|
||||
log_error("create norflash part fail\n");
|
||||
return NULL;
|
||||
}
|
||||
memset(part, 0, sizeof(*part));
|
||||
part->name = name;
|
||||
part->start_addr = addr;
|
||||
part->size = size;
|
||||
if (part->start_addr + part->size > _norflash.max_end_addr) {
|
||||
_norflash.max_end_addr = part->start_addr + part->size;
|
||||
}
|
||||
_norflash.part_num++;
|
||||
return part;
|
||||
}
|
||||
|
||||
static void norflash_delete_part(const char *name)
|
||||
{
|
||||
struct norflash_partition *part;
|
||||
u32 idx;
|
||||
for (idx = 0; idx < MAX_NORFLASH_PART_NUM; idx++) {
|
||||
part = &_norflash.part_list[idx];
|
||||
if (part->name == NULL) {
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(part->name, name)) {
|
||||
part->name = NULL;
|
||||
_norflash.part_num--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int norflash_verify_part(struct norflash_partition *p)
|
||||
{
|
||||
struct norflash_partition *part = NULL;
|
||||
u32 idx;
|
||||
for (idx = 0; idx < MAX_NORFLASH_PART_NUM; idx++) {
|
||||
part = &_norflash.part_list[idx];
|
||||
if (part->name == NULL) {
|
||||
continue;
|
||||
}
|
||||
if ((p->start_addr >= part->start_addr) && (p->start_addr < part->start_addr + part->size)) {
|
||||
if (strcmp(p->name, part->name) != 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define FLASH_CACHE_ENABLE 1
|
||||
|
||||
#if FLASH_CACHE_ENABLE
|
||||
static u32 flash_cache_addr;
|
||||
static u8 *flash_cache_buf = NULL; //缓存4K的数据,与flash里的数据一样。
|
||||
static u8 flash_cache_is_dirty;
|
||||
static u16 flash_cache_timer;
|
||||
|
||||
#define FLASH_CACHE_SYNC_T_INTERVAL 60
|
||||
|
||||
static int _check_0xff(u8 *buf, u32 len)
|
||||
{
|
||||
for (u32 i = 0; i < len; i ++) {
|
||||
if ((*(buf + i)) != 0xff) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static u32 _pow(u32 num, int n)
|
||||
{
|
||||
u32 powint = 1;
|
||||
int i;
|
||||
for (i = 1; i <= n; i++) {
|
||||
powint *= num;
|
||||
}
|
||||
return powint;
|
||||
}
|
||||
|
||||
static u32 _norflash_read_id()
|
||||
{
|
||||
return sfc_spi_read_id();
|
||||
}
|
||||
|
||||
static int _norflash_init(const char *name, struct norflash_sfc_dev_platform_data *pdata)
|
||||
{
|
||||
log_info("norflash_sfc_init >>>>");
|
||||
|
||||
struct norflash_partition *part;
|
||||
if (_norflash.spi_num == (int) - 1) {
|
||||
//_norflash.spi_num = pdata->spi_hw_num;
|
||||
_norflash.flash_id = 0;
|
||||
_norflash.flash_capacity = 0;
|
||||
os_mutex_create(&_norflash.mutex);
|
||||
_norflash.max_end_addr = 0;
|
||||
_norflash.part_num = 0;
|
||||
sfc_spi_init(pdata->sfc_spi_pdata);
|
||||
}
|
||||
|
||||
part = norflash_find_part(name);
|
||||
|
||||
if (!part) {
|
||||
part = norflash_new_part(name, pdata->start_addr, pdata->size);
|
||||
ASSERT(part, "not enough norflash partition memory in array\n");
|
||||
ASSERT(norflash_verify_part(part) == 0, "norflash partition %s overlaps\n", name);
|
||||
log_info("norflash new partition %s\n", part->name);
|
||||
} else {
|
||||
ASSERT(0, "norflash partition name already exists\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void clock_critical_enter()
|
||||
{
|
||||
|
||||
}
|
||||
static void clock_critical_exit()
|
||||
{
|
||||
/* if (!(_norflash.flash_id == 0 || _norflash.flash_id == 0xffff)) { */
|
||||
/* spi_set_baud(_norflash.spi_num, spi_get_baud(_norflash.spi_num)); */
|
||||
/* } */
|
||||
}
|
||||
CLOCK_CRITICAL_HANDLE_REG(spi_norflash, clock_critical_enter, clock_critical_exit);
|
||||
|
||||
static int _norflash_open(void *arg)
|
||||
{
|
||||
int reg = 0;
|
||||
os_mutex_pend(&_norflash.mutex, 0);
|
||||
log_info("norflash open\n");
|
||||
if (!_norflash.open_cnt) {
|
||||
_norflash.flash_id = _norflash_read_id();
|
||||
|
||||
log_info("norflash_read_id: 0x%x\n", _norflash.flash_id);
|
||||
if ((_norflash.flash_id == 0) || (_norflash.flash_id == 0xffffff)) {
|
||||
log_error("read norflash id error !\n");
|
||||
reg = -ENODEV;
|
||||
goto __exit;
|
||||
}
|
||||
_norflash.flash_capacity = 64 * _pow(2, (_norflash.flash_id & 0xff) - 0x10) * 1024;
|
||||
log_info("norflash_capacity: 0x%x\n", _norflash.flash_capacity);
|
||||
|
||||
#if FLASH_CACHE_ENABLE
|
||||
flash_cache_buf = (u8 *)malloc(4096);
|
||||
ASSERT(flash_cache_buf, "flash_cache_buf is not ok\n");
|
||||
flash_cache_addr = 4096;//先给一个大于4096的数
|
||||
_norflash_read(0, flash_cache_buf, 4096, 1);
|
||||
flash_cache_addr = 0;
|
||||
#endif
|
||||
log_info("norflash open success !\n");
|
||||
}
|
||||
if (_norflash.flash_id == 0 || _norflash.flash_id == 0xffffff) {
|
||||
log_error("re-open norflash id error !\n");
|
||||
reg = -EFAULT;
|
||||
goto __exit;
|
||||
}
|
||||
ASSERT(_norflash.max_end_addr <= _norflash.flash_capacity, "max partition end address is greater than flash capacity\n");
|
||||
_norflash.open_cnt++;
|
||||
|
||||
__exit:
|
||||
os_mutex_post(&_norflash.mutex);
|
||||
return reg;
|
||||
}
|
||||
|
||||
int _norflash_close(void)
|
||||
{
|
||||
os_mutex_pend(&_norflash.mutex, 0);
|
||||
log_info("norflash close\n");
|
||||
if (_norflash.open_cnt) {
|
||||
_norflash.open_cnt--;
|
||||
}
|
||||
if (!_norflash.open_cnt) {
|
||||
#if FLASH_CACHE_ENABLE
|
||||
if (flash_cache_is_dirty) {
|
||||
flash_cache_is_dirty = 0;
|
||||
_norflash_eraser(IOCTL_ERASE_SECTOR, flash_cache_addr);
|
||||
_norflash_write_pages(flash_cache_addr, flash_cache_buf, 4096);
|
||||
}
|
||||
free(flash_cache_buf);
|
||||
flash_cache_buf = NULL;
|
||||
#endif
|
||||
log_info("norflash close done\n");
|
||||
}
|
||||
os_mutex_post(&_norflash.mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _norflash_read(u32 addr, u8 *buf, u32 len, u8 cache)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ret = sfc_spi_read(addr, buf, len);
|
||||
if (ret != len) {
|
||||
ret = -1;
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int _norflash_write_pages(u32 addr, u8 *buf, u32 len)
|
||||
{
|
||||
/* y_printf("flash write addr = %d, num = %d\n", addr, len); */
|
||||
int ret = 0;
|
||||
ret = sfc_spi_write_pages(addr, buf, len);
|
||||
if (ret != len) {
|
||||
ret = -1;
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if FLASH_CACHE_ENABLE
|
||||
static void _norflash_cache_sync_timer(void *priv)
|
||||
{
|
||||
int reg = 0;
|
||||
os_mutex_pend(&_norflash.mutex, 0);
|
||||
if (flash_cache_is_dirty) {
|
||||
flash_cache_is_dirty = 0;
|
||||
reg = _norflash_eraser(IOCTL_ERASE_SECTOR, flash_cache_addr);
|
||||
if (reg) {
|
||||
goto __exit;
|
||||
}
|
||||
reg = _norflash_write_pages(flash_cache_addr, flash_cache_buf, 4096);
|
||||
}
|
||||
if (flash_cache_timer) {
|
||||
sys_timeout_del(flash_cache_timer);
|
||||
flash_cache_timer = 0;
|
||||
}
|
||||
__exit:
|
||||
os_mutex_post(&_norflash.mutex);
|
||||
}
|
||||
#endif
|
||||
|
||||
int _norflash_write(u32 addr, void *buf, u32 len, u8 cache)
|
||||
{
|
||||
int reg = 0;
|
||||
os_mutex_pend(&_norflash.mutex, 0);
|
||||
|
||||
u8 *w_buf = (u8 *)buf;
|
||||
u32 w_len = len;
|
||||
|
||||
/* y_printf("flash write addr = %d, num = %d\n", addr, len); */
|
||||
#if FLASH_CACHE_ENABLE
|
||||
if (!cache) {
|
||||
reg = _norflash_write_pages(addr, w_buf, w_len);
|
||||
goto __exit;
|
||||
}
|
||||
u32 align_addr = addr / 4096 * 4096;
|
||||
u32 align_len = 4096 - (addr - align_addr);
|
||||
align_len = w_len > align_len ? align_len : w_len;
|
||||
if (align_addr != flash_cache_addr) {
|
||||
if (flash_cache_is_dirty) {
|
||||
flash_cache_is_dirty = 0;
|
||||
reg = _norflash_eraser(IOCTL_ERASE_SECTOR, flash_cache_addr);
|
||||
if (reg) {
|
||||
line_inf;
|
||||
goto __exit;
|
||||
}
|
||||
reg = _norflash_write_pages(flash_cache_addr, flash_cache_buf, 4096);
|
||||
if (reg) {
|
||||
line_inf;
|
||||
goto __exit;
|
||||
}
|
||||
}
|
||||
_norflash_read(align_addr, flash_cache_buf, 4096, 0);
|
||||
flash_cache_addr = align_addr;
|
||||
}
|
||||
memcpy(flash_cache_buf + (addr - align_addr), w_buf, align_len);
|
||||
if ((addr + align_len) % 4096) {
|
||||
flash_cache_is_dirty = 1;
|
||||
if (flash_cache_timer) {
|
||||
sys_timer_re_run(flash_cache_timer);
|
||||
} else {
|
||||
flash_cache_timer = sys_timeout_add(0, _norflash_cache_sync_timer, FLASH_CACHE_SYNC_T_INTERVAL);
|
||||
}
|
||||
} else {
|
||||
flash_cache_is_dirty = 0;
|
||||
reg = _norflash_eraser(IOCTL_ERASE_SECTOR, align_addr);
|
||||
if (reg) {
|
||||
line_inf;
|
||||
goto __exit;
|
||||
}
|
||||
reg = _norflash_write_pages(align_addr, flash_cache_buf, 4096);
|
||||
if (reg) {
|
||||
line_inf;
|
||||
goto __exit;
|
||||
}
|
||||
}
|
||||
addr += align_len;
|
||||
w_buf += align_len;
|
||||
w_len -= align_len;
|
||||
while (w_len) {
|
||||
u32 cnt = w_len > 4096 ? 4096 : w_len;
|
||||
_norflash_read(addr, flash_cache_buf, 4096, 0);
|
||||
flash_cache_addr = addr;
|
||||
memcpy(flash_cache_buf, w_buf, cnt);
|
||||
if ((addr + cnt) % 4096) {
|
||||
flash_cache_is_dirty = 1;
|
||||
if (flash_cache_timer) {
|
||||
sys_timer_re_run(flash_cache_timer);
|
||||
} else {
|
||||
flash_cache_timer = sys_timeout_add(0, _norflash_cache_sync_timer, FLASH_CACHE_SYNC_T_INTERVAL);
|
||||
}
|
||||
} else {
|
||||
flash_cache_is_dirty = 0;
|
||||
reg = _norflash_eraser(IOCTL_ERASE_SECTOR, addr);
|
||||
if (reg) {
|
||||
line_inf;
|
||||
goto __exit;
|
||||
}
|
||||
reg = _norflash_write_pages(addr, flash_cache_buf, 4096);
|
||||
if (reg) {
|
||||
line_inf;
|
||||
goto __exit;
|
||||
}
|
||||
}
|
||||
addr += cnt;
|
||||
w_buf += cnt;
|
||||
w_len -= cnt;
|
||||
}
|
||||
#else
|
||||
reg = _norflash_write_pages(addr, w_buf, w_len);
|
||||
#endif
|
||||
__exit:
|
||||
os_mutex_post(&_norflash.mutex);
|
||||
return reg;
|
||||
}
|
||||
|
||||
static int _norflash_eraser(u8 eraser, u32 addr)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ret = sfc_spi_eraser(eraser, addr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int _norflash_ioctl(u32 cmd, u32 arg, u32 unit, void *_part)
|
||||
{
|
||||
int reg = 0;
|
||||
struct norflash_partition *part = _part;
|
||||
os_mutex_pend(&_norflash.mutex, 0);
|
||||
switch (cmd) {
|
||||
case IOCTL_GET_STATUS:
|
||||
*(u32 *)arg = 1;
|
||||
break;
|
||||
case IOCTL_GET_ID:
|
||||
*((u32 *)arg) = _norflash.flash_id;
|
||||
break;
|
||||
case IOCTL_GET_CAPACITY:
|
||||
if (_norflash.flash_capacity == 0) {
|
||||
*(u32 *)arg = 0;
|
||||
} else if (_norflash.part_num == 1 && part->start_addr == 0) {
|
||||
*(u32 *)arg = _norflash.flash_capacity / unit;
|
||||
} else {
|
||||
*(u32 *)arg = part->size / unit;
|
||||
}
|
||||
break;
|
||||
case IOCTL_GET_BLOCK_SIZE:
|
||||
*(u32 *)arg = 512;
|
||||
break;
|
||||
case IOCTL_ERASE_PAGE:
|
||||
reg = _norflash_eraser(IOCTL_ERASE_PAGE, arg * unit + part->start_addr);
|
||||
break;
|
||||
case IOCTL_ERASE_SECTOR:
|
||||
reg = _norflash_eraser(IOCTL_ERASE_SECTOR, arg * unit + part->start_addr);
|
||||
break;
|
||||
case IOCTL_ERASE_BLOCK:
|
||||
reg = _norflash_eraser(IOCTL_ERASE_BLOCK, arg * unit + part->start_addr);
|
||||
break;
|
||||
case IOCTL_ERASE_CHIP:
|
||||
reg = _norflash_eraser(IOCTL_ERASE_CHIP, 0);
|
||||
break;
|
||||
case IOCTL_FLUSH:
|
||||
break;
|
||||
case IOCTL_CMD_RESUME:
|
||||
break;
|
||||
case IOCTL_CMD_SUSPEND:
|
||||
break;
|
||||
case IOCTL_GET_PART_INFO:
|
||||
u32 *info = (u32 *)arg;
|
||||
u32 *start_addr = &info[0];
|
||||
u32 *part_size = &info[1];
|
||||
*start_addr = part->start_addr;
|
||||
*part_size = part->size;
|
||||
break;
|
||||
default:
|
||||
reg = -EINVAL;
|
||||
break;
|
||||
}
|
||||
__exit:
|
||||
os_mutex_post(&_norflash.mutex);
|
||||
return reg;
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************************
|
||||
* 挂钩 device_api
|
||||
************************************************************************************/
|
||||
|
||||
static int norflash_sfc_dev_init(const struct dev_node *node, void *arg)
|
||||
{
|
||||
struct norflash_sfc_dev_platform_data *pdata = arg;
|
||||
|
||||
return _norflash_init(node->name, pdata);
|
||||
}
|
||||
|
||||
static int norflash_sfc_dev_open(const char *name, struct device **device, void *arg)
|
||||
{
|
||||
struct norflash_partition *part;
|
||||
part = norflash_find_part(name);
|
||||
if (!part) {
|
||||
log_error("no norflash partition is found\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
*device = &part->device;
|
||||
(*device)->private_data = part;
|
||||
if (atomic_read(&part->device.ref)) {
|
||||
return 0;
|
||||
}
|
||||
return _norflash_open(arg);
|
||||
}
|
||||
static int norflash_sfc_dev_close(struct device *device)
|
||||
{
|
||||
return _norflash_close();
|
||||
}
|
||||
static int norflash_sfc_dev_read(struct device *device, void *buf, u32 len, u32 offset)
|
||||
{
|
||||
int reg;
|
||||
/* printf("flash read sector = %d, num = %d\n", offset, len); */
|
||||
offset = offset * 512;
|
||||
len = len * 512;
|
||||
struct norflash_partition *part;
|
||||
part = (struct norflash_partition *)device->private_data;
|
||||
if (!part) {
|
||||
log_error("norflash partition invalid\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
offset += part->start_addr;
|
||||
reg = _norflash_read(offset, buf, len, 1);
|
||||
if (reg) {
|
||||
r_printf(">>>[r error]:\n");
|
||||
len = 0;
|
||||
}
|
||||
|
||||
len = len / 512;
|
||||
return len;
|
||||
}
|
||||
static int norflash_sfc_dev_write(struct device *device, void *buf, u32 len, u32 offset)
|
||||
{
|
||||
/* printf("flash write sector = %d, num = %d\n", offset, len); */
|
||||
int reg = 0;
|
||||
offset = offset * 512;
|
||||
len = len * 512;
|
||||
struct norflash_partition *part = device->private_data;
|
||||
if (!part) {
|
||||
log_error("norflash partition invalid\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
offset += part->start_addr;
|
||||
reg = _norflash_write(offset, buf, len, 1);
|
||||
if (reg) {
|
||||
r_printf(">>>[w error]:\n");
|
||||
len = 0;
|
||||
}
|
||||
len = len / 512;
|
||||
return len;
|
||||
}
|
||||
static bool norflash_sfc_dev_online(const struct dev_node *node)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
static int norflash_sfc_dev_ioctl(struct device *device, u32 cmd, u32 arg)
|
||||
{
|
||||
struct norflash_partition *part = device->private_data;
|
||||
if (!part) {
|
||||
log_error("norflash partition invalid\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
return _norflash_ioctl(cmd, arg, 512, part);
|
||||
}
|
||||
|
||||
/*
|
||||
* 1. 外部调用时以512字节为单位的地址和长度,且需要驱动write自己处理擦除,
|
||||
* 请使用norflash_sfc_dev_ops接口,否则使用本文件内的其他ops
|
||||
*
|
||||
* 2. 如果不需要驱动自己处理擦除,可以把宏FLASH_CACHE_ENABLE清零,或者把
|
||||
* norflash_sfc_dev_read()里面调用的_norflash_read()的实参cache填0,
|
||||
* norflash_sfc_dev_write()同理
|
||||
*
|
||||
* 3. norflash_sfc_dev_ops可以被多个设备名注册,每个设备名被认为是不同分区,所以
|
||||
* 需要填不同的分区起始地址和大小,若分区地址有重叠或者最大分区结束地址大于
|
||||
* flash容量,会触发ASSERT()
|
||||
*
|
||||
* 4. 关于IOCTL_GET_CAPACITY,有多个分区注册时返回分区的大小,如果只注册了1
|
||||
* 个分区,分区起始地址 == 0时返回flash容量,起始地址 != 0时返回分区大小,
|
||||
* norflash_sfc_dev_ops返回的长度以512字节为单位
|
||||
*
|
||||
* 5. 本文件内的各个ops可以同时使用
|
||||
*/
|
||||
//按512字节单位读写
|
||||
const struct device_operations norflash_sfc_dev_ops = {
|
||||
.init = norflash_sfc_dev_init,
|
||||
.online = norflash_sfc_dev_online,
|
||||
.open = norflash_sfc_dev_open,
|
||||
.read = norflash_sfc_dev_read,
|
||||
.write = norflash_sfc_dev_write,
|
||||
.ioctl = norflash_sfc_dev_ioctl,
|
||||
.close = norflash_sfc_dev_close,
|
||||
};
|
||||
|
||||
|
||||
static int norflash_sfc_fs_dev_init(const struct dev_node *node, void *arg)
|
||||
{
|
||||
struct norflash_sfc_dev_platform_data *pdata = arg;
|
||||
|
||||
return _norflash_init(node->name, pdata);
|
||||
}
|
||||
|
||||
static int norflash_sfc_fs_dev_open(const char *name, struct device **device, void *arg)
|
||||
{
|
||||
struct norflash_partition *part;
|
||||
part = norflash_find_part(name);
|
||||
if (!part) {
|
||||
log_error("no norflash partition is found\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
*device = &part->device;
|
||||
(*device)->private_data = part;
|
||||
if (atomic_read(&part->device.ref)) {
|
||||
return 0;
|
||||
}
|
||||
return _norflash_open(arg);
|
||||
}
|
||||
static int norflash_sfc_fs_dev_close(struct device *device)
|
||||
{
|
||||
return _norflash_close();
|
||||
}
|
||||
static int norflash_sfc_fs_dev_read(struct device *device, void *buf, u32 len, u32 offset)
|
||||
{
|
||||
int reg;
|
||||
/* printf("flash read sector = %d, num = %d\n", offset, len); */
|
||||
struct norflash_partition *part;
|
||||
part = (struct norflash_partition *)device->private_data;
|
||||
if (!part) {
|
||||
log_error("norflash partition invalid\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
offset += part->start_addr;
|
||||
reg = _norflash_read(offset, buf, len, 0);
|
||||
if (reg) {
|
||||
r_printf(">>>[r error]:\n");
|
||||
len = 0;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int norflash_sfc_fs_dev_write(struct device *device, void *buf, u32 len, u32 offset)
|
||||
{
|
||||
//printf("flash write addr = 0x%x, len = 0x%x\n", offset, len);
|
||||
int reg = 0;
|
||||
struct norflash_partition *part = device->private_data;
|
||||
if (!part) {
|
||||
log_error("norflash partition invalid\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
offset += part->start_addr;
|
||||
reg = _norflash_write(offset, buf, len, 0);
|
||||
if (reg) {
|
||||
r_printf(">>>[w error]:\n");
|
||||
len = 0;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
static bool norflash_sfc_fs_dev_online(const struct dev_node *node)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int norflash_sfc_fs_dev_ioctl(struct device *device, u32 cmd, u32 arg)
|
||||
{
|
||||
struct norflash_partition *part = device->private_data;
|
||||
if (!part) {
|
||||
log_error("norflash partition invalid\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
return _norflash_ioctl(cmd, arg, 1, part);
|
||||
}
|
||||
|
||||
/*
|
||||
* 1. 外部调用时以1字节为单位的地址和长度,且驱动write自己不处理擦除,
|
||||
* 请使用norflash_sfc_fs_dev_ops接口,否则使用本文件内的其他ops。注意:有些文件系
|
||||
* 统需要满足这个条件的驱动,如果期望修改成驱动内部处理擦除,需要测试所
|
||||
* 有关联的文件系统是否支持,或者新建一个符合需求的ops
|
||||
*
|
||||
* 2. 如果需要驱动自己处理擦除,需要把宏FLASH_CACHE_ENABLE置1,且
|
||||
* norflash_sfc_fs_dev_read()里面调用的_norflash_read()的实参cache填1,
|
||||
* norflash_sfc_fs_dev_write()同理
|
||||
*
|
||||
* 3. norflash_sfc_fs_dev_ops可以被多个设备名注册,每个设备名被认为是不同分区,所以
|
||||
* 需要填不同的分区起始地址和大小,若分区地址有重叠或者最大分区结束地址大于
|
||||
* flash容量,会触发ASSERT()
|
||||
*
|
||||
* 4. 关于IOCTL_GET_CAPACITY,有多个分区注册时返回分区的大小,如果只注册了1
|
||||
* 个分区,分区起始地址 == 0时返回flash容量,起始地址 != 0时返回分区大小
|
||||
* norflash_sfc_fs_dev_ops返回的长度以1字节为单位
|
||||
*
|
||||
* 5. 本文件内的各个ops可以同时使用
|
||||
*/
|
||||
//按1字节单位读写
|
||||
const struct device_operations norflash_sfc_fs_dev_ops = {
|
||||
.init = norflash_sfc_fs_dev_init,
|
||||
.online = norflash_sfc_fs_dev_online,
|
||||
.open = norflash_sfc_fs_dev_open,
|
||||
.read = norflash_sfc_fs_dev_read,
|
||||
.write = norflash_sfc_fs_dev_write,
|
||||
.ioctl = norflash_sfc_fs_dev_ioctl,
|
||||
.close = norflash_sfc_fs_dev_close,
|
||||
};
|
||||
|
||||
/*
|
||||
* 对ops的读写单位有另外需求,或者驱动内部是否支持擦除,可以参照上面的ops,
|
||||
* 不同条件自由组合,建立新的ops
|
||||
*/
|
||||
|
||||
#endif /* #if (defined(TCFG_NORFLASH_SFC_DEV_ENABLE) && TCFG_NORFLASH_SFC_DEV_ENABLE) */
|
||||
138
apps/common/device/ntc/ntc_det.c
Normal file
138
apps/common/device/ntc/ntc_det.c
Normal file
@ -0,0 +1,138 @@
|
||||
//*********************************************************************************//
|
||||
// NTC det //
|
||||
//*********************************************************************************//
|
||||
#include "ntc_det_api.h"
|
||||
#include "asm/power/p33.h"
|
||||
#include "system/includes.h"
|
||||
#include "asm/charge.h"
|
||||
|
||||
#if NTC_DET_EN
|
||||
|
||||
#define NTC_DET_BAD_RES 0 //分压电阻损坏关闭检测
|
||||
|
||||
#ifndef NTC_DET_DUTY1
|
||||
#define NTC_DET_DUTY1 5000 //检测周期
|
||||
#endif
|
||||
|
||||
#ifndef NTC_DET_DUTY2
|
||||
#define NTC_DET_DUTY2 10 //检测小周期
|
||||
#endif
|
||||
|
||||
#ifndef NTC_DET_CNT
|
||||
#define NTC_DET_CNT 3 //检测次数
|
||||
#endif
|
||||
|
||||
#ifndef NTC_DET_UPPER
|
||||
#define NTC_DET_UPPER 235 //正常范围AD值上限,0度时
|
||||
#endif
|
||||
|
||||
#ifndef NTC_DET_LOWER
|
||||
#define NTC_DET_LOWER 34 //正常范围AD值下限,45度时
|
||||
#endif
|
||||
|
||||
#define NTC_IS_NORMAL(value, offset) (value >= NTC_DET_LOWER+(offset) && value <= NTC_DET_UPPER-(offset))
|
||||
#define NTC_IS_BAD_RES(value) (value >= 1020 || value <= 5)
|
||||
|
||||
enum {
|
||||
NTC_STATE_NORMAL = 0,
|
||||
NTC_STATE_ABNORMAL,
|
||||
};
|
||||
|
||||
struct ntc_det_t {
|
||||
u16 normal_cnt : 4; //温度正常的次数
|
||||
u16 cnt : 4; //温度检测的次数
|
||||
u16 res_cnt : 4; //分压电阻脱落或损坏
|
||||
u16 state : 1; //是否超出范围
|
||||
u16 timer;
|
||||
};
|
||||
static struct ntc_det_t ntc_det = {0};
|
||||
extern u8 get_charge_full_flag(void);
|
||||
|
||||
u16 ntc_det_working()
|
||||
{
|
||||
return ntc_det.timer;
|
||||
}
|
||||
|
||||
static void ntc_det_timer_deal(void *priv)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
#if NTC_DET_CNT
|
||||
if (ntc_det.cnt == 0) {
|
||||
sys_timer_modify(ntc_det.timer, NTC_DET_DUTY2);
|
||||
}
|
||||
#endif
|
||||
value = adc_get_value(NTC_DET_AD_CH);
|
||||
printf("%d", value);
|
||||
|
||||
ntc_det.cnt++;
|
||||
if (NTC_IS_NORMAL(value, ntc_det.state * 8)) { //温度恢复一定范围后才算正常,防止临界状态
|
||||
ntc_det.normal_cnt++;
|
||||
} else if (NTC_IS_BAD_RES(value)) {
|
||||
ntc_det.res_cnt++;
|
||||
}
|
||||
if (ntc_det.cnt >= NTC_DET_CNT) {
|
||||
if (ntc_det.normal_cnt > NTC_DET_CNT / 2) {
|
||||
if (ntc_det.state == NTC_STATE_ABNORMAL) {
|
||||
printf("temperature recover, start charge");
|
||||
ntc_det.state = NTC_STATE_NORMAL;
|
||||
charge_start();
|
||||
}
|
||||
}
|
||||
#if NTC_DET_BAD_RES
|
||||
else if (ntc_det.res_cnt > NTC_DET_CNT / 2) {
|
||||
printf("bad res, stop det");
|
||||
ntc_det_stop();
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
if (ntc_det.state == NTC_STATE_NORMAL) {
|
||||
printf("temperature is abnormall, stop charge");
|
||||
ntc_det.state = NTC_STATE_ABNORMAL;
|
||||
charge_close();
|
||||
CHARGE_EN(0);
|
||||
}
|
||||
/* power_set_soft_poweroff(); */
|
||||
}
|
||||
ntc_det.cnt = 0;
|
||||
ntc_det.res_cnt = 0;
|
||||
ntc_det.normal_cnt = 0;
|
||||
sys_timer_modify(ntc_det.timer, NTC_DET_DUTY1);
|
||||
}
|
||||
}
|
||||
|
||||
void ntc_det_start(void)
|
||||
{
|
||||
if (ntc_det.timer == 0) {
|
||||
printf("ntc det start");
|
||||
memset(&ntc_det, 0, sizeof(ntc_det));
|
||||
gpio_direction_output(NTC_POWER_IO, 1);
|
||||
|
||||
gpio_set_pull_up(NTC_DETECT_IO, 0);
|
||||
gpio_set_pull_down(NTC_DETECT_IO, 0);
|
||||
gpio_set_die(NTC_DETECT_IO, 0);
|
||||
gpio_set_direction(NTC_DETECT_IO, 1);
|
||||
adc_add_sample_ch(NTC_DET_AD_CH);
|
||||
ntc_det.timer = sys_timer_add(NULL, ntc_det_timer_deal, NTC_DET_DUTY1);
|
||||
}
|
||||
}
|
||||
|
||||
void ntc_det_stop(void)
|
||||
{
|
||||
if (!get_charge_full_flag() && get_charge_online_flag() && ntc_det.state == NTC_STATE_ABNORMAL) {
|
||||
printf("charge protecting, wait recover");
|
||||
return;
|
||||
}
|
||||
if (ntc_det.timer) {
|
||||
printf("ntc det stop");
|
||||
sys_timer_del(ntc_det.timer);
|
||||
ntc_det.timer = 0;
|
||||
adc_remove_sample_ch(NTC_DET_AD_CH);
|
||||
gpio_set_pull_up(NTC_POWER_IO, 0);
|
||||
gpio_set_pull_down(NTC_POWER_IO, 0);
|
||||
gpio_set_die(NTC_POWER_IO, 0);
|
||||
gpio_set_direction(NTC_POWER_IO, 1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
14
apps/common/device/ntc/ntc_det_api.h
Normal file
14
apps/common/device/ntc/ntc_det_api.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef __NTC_DET_API_H__
|
||||
#define __NTC_DET_API_H__
|
||||
|
||||
#include "typedef.h"
|
||||
#include "app_config.h"
|
||||
|
||||
#if NTC_DET_EN
|
||||
extern void ntc_det_start(void);
|
||||
extern void ntc_det_stop(void);
|
||||
extern u16 ntc_det_working();
|
||||
#endif
|
||||
|
||||
#endif //__NTC_DET_API_H__
|
||||
|
||||
490
apps/common/device/usb/device/cdc.c
Normal file
490
apps/common/device/usb/device/cdc.c
Normal file
@ -0,0 +1,490 @@
|
||||
#include "usb/device/usb_stack.h"
|
||||
#include "usb/usb_config.h"
|
||||
#include "usb/device/cdc.h"
|
||||
#include "app_config.h"
|
||||
#include "os/os_api.h"
|
||||
#include "cdc_defs.h" //need redefine __u8, __u16, __u32
|
||||
|
||||
#define LOG_TAG_CONST USB
|
||||
#define LOG_TAG "[USB]"
|
||||
#define LOG_ERROR_ENABLE
|
||||
#define LOG_DEBUG_ENABLE
|
||||
#define LOG_INFO_ENABLE
|
||||
/* #define LOG_DUMP_ENABLE */
|
||||
#define LOG_CLI_ENABLE
|
||||
#include "debug.h"
|
||||
|
||||
#if TCFG_USB_SLAVE_CDC_ENABLE
|
||||
|
||||
|
||||
struct usb_cdc_gadget {
|
||||
u8 *cdc_buffer;
|
||||
u8 *bulk_ep_out_buffer;
|
||||
u8 *bulk_ep_in_buffer;
|
||||
void *priv;
|
||||
int (*output)(void *priv, u8 *obuf, u32 olen);
|
||||
void (*wakeup_handler)(struct usb_device_t *usb_device);
|
||||
OS_MUTEX mutex_data;
|
||||
#if CDC_INTR_EP_ENABLE
|
||||
OS_MUTEX mutex_intr;
|
||||
u8 *intr_ep_in_buffer;
|
||||
#endif
|
||||
u8 bmTransceiver;
|
||||
u8 subtype_data[8];
|
||||
};
|
||||
|
||||
static struct usb_cdc_gadget *cdc_hdl;
|
||||
|
||||
#if USB_MALLOC_ENABLE
|
||||
|
||||
#else
|
||||
static u8 _cdc_buffer[MAXP_SIZE_CDC_BULKOUT] SEC(.cdc_var) __attribute__((aligned(4)));
|
||||
static struct usb_cdc_gadget _cdc_hdl SEC(.cdc_var);
|
||||
#endif
|
||||
|
||||
static const u8 cdc_virtual_comport_desc[] = {
|
||||
//IAD Descriptor
|
||||
0x08, //bLength
|
||||
0x0b, //bDescriptorType
|
||||
0x00, //bFirstInterface
|
||||
0x02, //bInterfaceCount
|
||||
0x02, //bFunctionClass, Comunication and CDC control
|
||||
0x02, //bFunctionSubClass
|
||||
0x01, //bFunctionProtocol
|
||||
0x00, //iFunction
|
||||
//Interface 0, Alt 0
|
||||
0x09, //Length
|
||||
0x04, //DescriptorType:Interface
|
||||
0x00, //InterfaceNum
|
||||
0x00, //AlternateSetting
|
||||
0x01, //NumEndpoint
|
||||
0x02, //InterfaceClass, Communation and CDC control
|
||||
0x02, //InterfaceSubClass, Abstract Control Model
|
||||
0x01, //InterfaceProtocol, AT commands defined by ITU-T V.250 etc
|
||||
0x00, //Interface String
|
||||
//CDC Interface Descriptor
|
||||
0x05, //bLength
|
||||
0x24, //bDescriptorType
|
||||
0x00, //bDescriptorSubType, Header Functional Desc
|
||||
0x10, 0x01, //bcdCDC, version 1.10
|
||||
//CDC Interface Descriptor
|
||||
0x05, //bLength
|
||||
0x24, //bDescriptorType
|
||||
0x01, //bDescriptorSubType, Call Management Functional Descriptor
|
||||
0x03, //bmCapabilities, D7..D2 reversed
|
||||
// D7..D2 reversed
|
||||
// D1 sends/receives call management information only over a Data Class interface
|
||||
// D0 handle call management itself
|
||||
0x01, //bDataInterface
|
||||
//CDC Interface Descriptor
|
||||
0x04, //bLength
|
||||
0x24, //bDescriptorType
|
||||
0x02, //bDescriptorSubType, Abstract Control Management Functional Descriptor
|
||||
0x02, //bmCapabilities, D7..D2 reversed
|
||||
// D7..D4 reversed
|
||||
// D3 supports the notification Network_Connection
|
||||
// D2 not supports the request Send_Break
|
||||
// D1 supports the request combination of Set_Line_Coding, Set_Control_Line_State, Get_Line_Coding, and the notification Serial_State
|
||||
// D0 supports the request combination of Set_Comm_Feature, Clear_Comm_Feature, and Get_Comm_Feature
|
||||
//CDC Interface Descriptor
|
||||
0x05, //bLength
|
||||
0x24, //bDescriptorType
|
||||
0x06, //bDescriptorSubType, Union Functional Descriptor
|
||||
0x00, //bControlInterface
|
||||
0x01, //bSubordinateInterface[0]
|
||||
//Endpoint In
|
||||
0x07, //bLength
|
||||
0x05, //bDescritorType
|
||||
0x82, //bEndpointAddr
|
||||
0x03, //bmAttributes, interrupt
|
||||
0x08, 0x00, //wMaxPacketSize
|
||||
0x01, //bInterval, 1ms
|
||||
//Interface 1, Alt 0
|
||||
0x09, //Length
|
||||
0x04, //DescriptorType:Interface
|
||||
0x01, //InterfaceNum
|
||||
0x00, //AlternateSetting
|
||||
0x02, //NumEndpoint
|
||||
0x0a, //InterfaceClass, CDC Data
|
||||
0x00, //InterfaceSubClass
|
||||
0x00, //InterfaceProtocol
|
||||
0x00, //Interface String
|
||||
//Endpoint Out
|
||||
0x07, //bLength
|
||||
0x05, //bDescriptor
|
||||
0x02, //bEndpointAddr
|
||||
0x02, //bmAttributes, bulk
|
||||
0x40, 0x00, //wMaxPacketSize
|
||||
0x00, //bInterval
|
||||
//Endpoint In
|
||||
0x07, //bLength
|
||||
0x05, //bDescritorType
|
||||
0x83, //bEndpointAddr
|
||||
0x02, //bmAttributes, bulk
|
||||
0x40, 0x00, //wMaxPacketSize
|
||||
0x00, //bInterval
|
||||
};
|
||||
|
||||
static void cdc_endpoint_init(struct usb_device_t *usb_device, u32 itf);
|
||||
static u32 cdc_setup_rx(struct usb_device_t *usb_device, struct usb_ctrlrequest *ctrl_req);
|
||||
|
||||
static void usb_cdc_line_coding_init(struct usb_cdc_line_coding *lc)
|
||||
{
|
||||
lc->dwDTERate = 460800;
|
||||
lc->bCharFormat = USB_CDC_1_STOP_BITS;
|
||||
lc->bParityType = USB_CDC_NO_PARITY;
|
||||
lc->bDataBits = 8;
|
||||
}
|
||||
|
||||
static void dump_line_coding(struct usb_cdc_line_coding *lc)
|
||||
{
|
||||
log_debug("dtw rate : %d", lc->dwDTERate);
|
||||
log_debug("stop bits : %d", lc->bCharFormat);
|
||||
log_debug("verify bits : %d", lc->bParityType);
|
||||
log_debug("data bits : %d", lc->bDataBits);
|
||||
}
|
||||
|
||||
static u32 cdc_setup(struct usb_device_t *usb_device, struct usb_ctrlrequest *ctrl_req)
|
||||
{
|
||||
const usb_dev usb_id = usb_device2id(usb_device);
|
||||
int recip_type;
|
||||
u32 len;
|
||||
|
||||
recip_type = ctrl_req->bRequestType & USB_TYPE_MASK;
|
||||
|
||||
switch (recip_type) {
|
||||
case USB_TYPE_CLASS:
|
||||
switch (ctrl_req->bRequest) {
|
||||
case USB_CDC_REQ_SET_LINE_CODING:
|
||||
log_debug("set line coding");
|
||||
usb_set_setup_recv(usb_device, cdc_setup_rx);
|
||||
break;
|
||||
case USB_CDC_REQ_GET_LINE_CODING:
|
||||
log_debug("get line codling");
|
||||
len = ctrl_req->wLength < sizeof(struct usb_cdc_line_coding) ?
|
||||
ctrl_req->wLength : sizeof(struct usb_cdc_line_coding);
|
||||
if (cdc_hdl == NULL) {
|
||||
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
|
||||
break;
|
||||
}
|
||||
usb_set_data_payload(usb_device, ctrl_req, cdc_hdl->subtype_data, len);
|
||||
dump_line_coding((struct usb_cdc_line_coding *)cdc_hdl->subtype_data);
|
||||
break;
|
||||
case USB_CDC_REQ_SET_CONTROL_LINE_STATE:
|
||||
log_debug("set control line state - %d", ctrl_req->wValue);
|
||||
if (cdc_hdl) {
|
||||
/* if (ctrl_req->wValue & BIT(0)) { //DTR */
|
||||
cdc_hdl->bmTransceiver |= BIT(0);
|
||||
/* } else { */
|
||||
/* usb_slave->cdc->bmTransceiver &= ~BIT(0); */
|
||||
/* } */
|
||||
/* if (ctrl_req->wValue & BIT(1)) { //RTS */
|
||||
cdc_hdl->bmTransceiver |= BIT(1);
|
||||
/* } else { */
|
||||
/* usb_slave->cdc->bmTransceiver &= ~BIT(1); */
|
||||
/* } */
|
||||
cdc_hdl->bmTransceiver |= BIT(4); //cfg done
|
||||
}
|
||||
usb_set_setup_phase(usb_device, USB_EP0_STAGE_SETUP);
|
||||
//cdc_endpoint_init(usb_device, (ctrl_req->wIndex & USB_RECIP_MASK));
|
||||
break;
|
||||
default:
|
||||
log_error("unsupported class req");
|
||||
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
log_error("unsupported req type");
|
||||
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 cdc_setup_rx(struct usb_device_t *usb_device, struct usb_ctrlrequest *ctrl_req)
|
||||
{
|
||||
const usb_dev usb_id = usb_device2id(usb_device);
|
||||
int recip_type;
|
||||
struct usb_cdc_line_coding *lc = 0;
|
||||
u32 len;
|
||||
u8 read_ep[8];
|
||||
|
||||
len = ctrl_req->wLength;
|
||||
usb_read_ep0(usb_id, read_ep, len);
|
||||
recip_type = ctrl_req->bRequestType & USB_TYPE_MASK;
|
||||
switch (recip_type) {
|
||||
case USB_TYPE_CLASS:
|
||||
switch (ctrl_req->bRequest) {
|
||||
case USB_CDC_REQ_SET_LINE_CODING:
|
||||
log_debug("USB_CDC_REQ_SET_LINE_CODING");
|
||||
if (cdc_hdl == NULL) {
|
||||
break;
|
||||
}
|
||||
if (len > sizeof(struct usb_cdc_line_coding)) {
|
||||
len = sizeof(struct usb_cdc_line_coding);
|
||||
}
|
||||
memcpy(cdc_hdl->subtype_data, read_ep, len);
|
||||
lc = (struct usb_cdc_line_coding *)cdc_hdl->subtype_data;
|
||||
dump_line_coding(lc);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return USB_EP0_STAGE_SETUP;
|
||||
}
|
||||
|
||||
static void cdc_reset(struct usb_device_t *usb_device, u32 itf)
|
||||
{
|
||||
log_error("%s()", __func__);
|
||||
const usb_dev usb_id = usb_device2id(usb_device);
|
||||
#if USB_ROOT2
|
||||
usb_disable_ep(usb_id, CDC_DATA_EP_IN);
|
||||
#if CDC_INTR_EP_ENABLE
|
||||
usb_disable_ep(usb_id, CDC_INTR_EP_IN);
|
||||
#endif
|
||||
#else
|
||||
cdc_endpoint_init(usb_device, itf);
|
||||
#endif
|
||||
}
|
||||
|
||||
u32 cdc_desc_config(const usb_dev usb_id, u8 *ptr, u32 *itf)
|
||||
{
|
||||
u8 *tptr;
|
||||
|
||||
tptr = ptr;
|
||||
memcpy(tptr, cdc_virtual_comport_desc, sizeof(cdc_virtual_comport_desc));
|
||||
//iad interface number
|
||||
tptr[2] = *itf;
|
||||
//control interface number
|
||||
tptr[8 + 2] = *itf;
|
||||
tptr[8 + 9 + 5 + 4] = *itf + 1;
|
||||
tptr[8 + 9 + 5 + 5 + 4 + 3] = *itf;
|
||||
tptr[8 + 9 + 5 + 5 + 4 + 4] = *itf + 1;
|
||||
//interrupt in ep
|
||||
tptr[8 + 9 + 5 + 5 + 4 + 5 + 2] = USB_DIR_IN | CDC_INTR_EP_IN;
|
||||
tptr[8 + 9 + 5 + 5 + 4 + 5 + 4] = MAXP_SIZE_CDC_INTRIN & 0xff;
|
||||
tptr[8 + 9 + 5 + 5 + 4 + 5 + 5] = (MAXP_SIZE_CDC_INTRIN >> 8) & 0xff;
|
||||
#if defined(FUSB_MODE) && FUSB_MODE == 0
|
||||
tptr[8 + 9 + 5 + 5 + 4 + 5 + 6] = 4; //high-speed mode, 125x2^(4-1)=1ms
|
||||
#endif
|
||||
//data interface number
|
||||
tptr[8 + 9 + 5 + 5 + 4 + 5 + 7 + 2] = *itf + 1;
|
||||
//bulk out ep
|
||||
tptr[8 + 9 + 5 + 5 + 4 + 5 + 7 + 9 + 2] = CDC_DATA_EP_OUT;
|
||||
tptr[8 + 9 + 5 + 5 + 4 + 5 + 7 + 9 + 4] = MAXP_SIZE_CDC_BULKOUT & 0xff;
|
||||
tptr[8 + 9 + 5 + 5 + 4 + 5 + 7 + 9 + 5] = (MAXP_SIZE_CDC_BULKOUT >> 8) & 0xff;
|
||||
//bulk in ep
|
||||
tptr[8 + 9 + 5 + 5 + 4 + 5 + 7 + 9 + 7 + 2] = USB_DIR_IN | CDC_DATA_EP_IN;
|
||||
tptr[8 + 9 + 5 + 5 + 4 + 5 + 7 + 9 + 7 + 4] = MAXP_SIZE_CDC_BULKIN & 0xff;
|
||||
tptr[8 + 9 + 5 + 5 + 4 + 5 + 7 + 9 + 7 + 5] = (MAXP_SIZE_CDC_BULKIN >> 8) & 0xff;
|
||||
tptr += sizeof(cdc_virtual_comport_desc);
|
||||
|
||||
if (usb_set_interface_hander(usb_id, *itf, cdc_setup) != *itf) {
|
||||
ASSERT(0, "cdc set interface_hander fail");
|
||||
}
|
||||
if (usb_set_reset_hander(usb_id, *itf, cdc_reset) != *itf) {
|
||||
|
||||
}
|
||||
*itf += 2;
|
||||
return (u32)(tptr - ptr);
|
||||
}
|
||||
|
||||
void cdc_set_wakeup_handler(void (*handle)(struct usb_device_t *usb_device))
|
||||
{
|
||||
if (cdc_hdl) {
|
||||
cdc_hdl->wakeup_handler = handle;
|
||||
}
|
||||
}
|
||||
|
||||
static void cdc_wakeup_handler(struct usb_device_t *usb_device, u32 ep)
|
||||
{
|
||||
if (cdc_hdl && cdc_hdl->wakeup_handler) {
|
||||
cdc_hdl->wakeup_handler(usb_device);
|
||||
}
|
||||
}
|
||||
|
||||
void cdc_set_output_handle(void *priv, int (*output_handler)(void *priv, u8 *buf, u32 len))
|
||||
{
|
||||
if (cdc_hdl) {
|
||||
cdc_hdl->output = output_handler;
|
||||
cdc_hdl->priv = priv;
|
||||
}
|
||||
}
|
||||
|
||||
static void cdc_intrrx(struct usb_device_t *usb_device, u32 ep)
|
||||
{
|
||||
const usb_dev usb_id = usb_device2id(usb_device);
|
||||
if (cdc_hdl == NULL) {
|
||||
return;
|
||||
}
|
||||
u8 *cdc_rx_buf = cdc_hdl->cdc_buffer;
|
||||
//由于bulk传输使用双缓冲,无法用usb_get_ep_buffer()知道是哪一个buffer,需要外部buffer接收数据
|
||||
u32 len = usb_g_bulk_read(usb_id, CDC_DATA_EP_OUT, cdc_rx_buf, MAXP_SIZE_CDC_BULKOUT, 0);
|
||||
if (cdc_hdl->output) {
|
||||
cdc_hdl->output(cdc_hdl->priv, cdc_rx_buf, len);
|
||||
}
|
||||
}
|
||||
|
||||
static void cdc_endpoint_init(struct usb_device_t *usb_device, u32 itf)
|
||||
{
|
||||
ASSERT(cdc_hdl, "cdc not register");
|
||||
|
||||
const usb_dev usb_id = usb_device2id(usb_device);
|
||||
|
||||
usb_g_ep_config(usb_id, CDC_DATA_EP_IN | USB_DIR_IN, USB_ENDPOINT_XFER_BULK,
|
||||
0, cdc_hdl->bulk_ep_in_buffer, MAXP_SIZE_CDC_BULKIN);
|
||||
|
||||
usb_g_ep_config(usb_id, CDC_DATA_EP_OUT | USB_DIR_OUT, USB_ENDPOINT_XFER_BULK,
|
||||
1, cdc_hdl->bulk_ep_out_buffer, MAXP_SIZE_CDC_BULKOUT);
|
||||
/* usb_g_set_intr_hander(usb_id, CDC_DATA_EP_OUT | USB_DIR_OUT, cdc_intrrx); */
|
||||
usb_g_set_intr_hander(usb_id, CDC_DATA_EP_OUT | USB_DIR_OUT, cdc_wakeup_handler);
|
||||
usb_enable_ep(usb_id, CDC_DATA_EP_IN);
|
||||
|
||||
#if CDC_INTR_EP_ENABLE
|
||||
usb_g_ep_config(usb_id, CDC_INTR_EP_IN | USB_DIR_IN, USB_ENDPOINT_XFER_INT,
|
||||
0, cdc_hdl->intr_ep_in_buffer, MAXP_SIZE_CDC_INTRIN);
|
||||
usb_enable_ep(usb_id, CDC_INTR_EP_IN);
|
||||
#endif
|
||||
}
|
||||
|
||||
u32 cdc_read_data(const usb_dev usb_id, u8 *buf, u32 len)
|
||||
{
|
||||
u32 rxlen;
|
||||
if (cdc_hdl == NULL) {
|
||||
return 0;
|
||||
}
|
||||
u8 *cdc_rx_buf = cdc_hdl->cdc_buffer;
|
||||
os_mutex_pend(&cdc_hdl->mutex_data, 0);
|
||||
//由于bulk传输使用双缓冲,无法用usb_get_ep_buffer()知道是哪一个buffer,需要外部buffer接收数据
|
||||
rxlen = usb_g_bulk_read(usb_id, CDC_DATA_EP_OUT, cdc_rx_buf, MAXP_SIZE_CDC_BULKOUT, 0);
|
||||
rxlen = rxlen > len ? len : rxlen;
|
||||
if (rxlen > 0) {
|
||||
memcpy(buf, cdc_rx_buf, rxlen);
|
||||
}
|
||||
os_mutex_post(&cdc_hdl->mutex_data);
|
||||
return rxlen;
|
||||
}
|
||||
|
||||
u32 cdc_write_data(const usb_dev usb_id, u8 *buf, u32 len)
|
||||
{
|
||||
u32 txlen, offset;
|
||||
if (cdc_hdl == NULL) {
|
||||
return 0;
|
||||
}
|
||||
if ((cdc_hdl->bmTransceiver & (BIT(1) | BIT(4))) != (BIT(1) | BIT(4))) {
|
||||
return 0;
|
||||
}
|
||||
offset = 0;
|
||||
os_mutex_pend(&cdc_hdl->mutex_data, 0);
|
||||
while (offset < len) {
|
||||
txlen = len - offset > MAXP_SIZE_CDC_BULKIN ?
|
||||
MAXP_SIZE_CDC_BULKIN : len - offset;
|
||||
txlen = usb_g_bulk_write(usb_id, CDC_DATA_EP_IN, buf + offset, txlen);
|
||||
if (txlen == 0) {
|
||||
break;
|
||||
}
|
||||
if ((cdc_hdl->bmTransceiver & (BIT(1) | BIT(4))) != (BIT(1) | BIT(4))) {
|
||||
break;
|
||||
}
|
||||
offset += txlen;
|
||||
}
|
||||
//当最后一包的包长等于maxpktsize,需要发一个0长包表示结束
|
||||
if ((offset % MAXP_SIZE_CDC_BULKIN) == 0) {
|
||||
usb_g_bulk_write(usb_id, CDC_DATA_EP_IN, NULL, 0);
|
||||
}
|
||||
os_mutex_post(&cdc_hdl->mutex_data);
|
||||
return offset;
|
||||
}
|
||||
|
||||
u32 cdc_write_inir(const usb_dev usb_id, u8 *buf, u32 len)
|
||||
{
|
||||
#if CDC_INTR_EP_ENABLE
|
||||
u32 txlen, offset;
|
||||
if (cdc_hdl == NULL) {
|
||||
return 0;
|
||||
}
|
||||
if ((cdc_hdl->bmTransceiver & BIT(4)) == 0) {
|
||||
return 0;
|
||||
}
|
||||
offset = 0;
|
||||
os_mutex_pend(&cdc_hdl->mutex_intr, 0);
|
||||
while (offset < len) {
|
||||
txlen = len - offset > MAXP_SIZE_CDC_INTRIN ?
|
||||
MAXP_SIZE_CDC_INTRIN : len - offset;
|
||||
txlen = usb_g_intr_write(usb_id, CDC_INTR_EP_IN, buf + offset, txlen);
|
||||
if (txlen == 0) {
|
||||
break;
|
||||
}
|
||||
if ((cdc_hdl->bmTransceiver & BIT(4)) == 0) {
|
||||
break;
|
||||
}
|
||||
offset += txlen;
|
||||
}
|
||||
os_mutex_post(&cdc_hdl->mutex_intr);
|
||||
return offset;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void cdc_register(const usb_dev usb_id)
|
||||
{
|
||||
struct usb_cdc_line_coding *lc;
|
||||
/* log_info("%s() %d", __func__, __LINE__); */
|
||||
if (!cdc_hdl) {
|
||||
#if USB_MALLOC_ENABLE
|
||||
cdc_hdl = zalloc(sizeof(struct usb_cdc_gadget));
|
||||
if (!cdc_hdl) {
|
||||
log_error("cdc_register err 1");
|
||||
return;
|
||||
}
|
||||
cdc_hdl->cdc_buffer = malloc(MAXP_SIZE_CDC_BULKOUT);
|
||||
if (!cdc_hdl->cdc_buffer) {
|
||||
log_error("cdc_register err 2");
|
||||
goto __exit_err;
|
||||
}
|
||||
#else
|
||||
memset(&_cdc_hdl, 0, sizeof(struct usb_cdc_gadget));
|
||||
cdc_hdl = &_cdc_hdl;
|
||||
cdc_hdl->cdc_buffer = _cdc_buffer;
|
||||
#endif
|
||||
lc = (struct usb_cdc_line_coding *)cdc_hdl->subtype_data;
|
||||
usb_cdc_line_coding_init(lc);
|
||||
os_mutex_create(&cdc_hdl->mutex_data);
|
||||
|
||||
cdc_hdl->bulk_ep_in_buffer = usb_alloc_ep_dmabuffer(usb_id, CDC_DATA_EP_IN | USB_DIR_IN, MAXP_SIZE_CDC_BULKIN + MAXP_SIZE_CDC_BULKOUT);
|
||||
cdc_hdl->bulk_ep_out_buffer = cdc_hdl->bulk_ep_in_buffer + MAXP_SIZE_CDC_BULKIN;
|
||||
|
||||
#if CDC_INTR_EP_ENABLE
|
||||
os_mutex_create(&cdc_hdl->mutex_intr);
|
||||
cdc_hdl->intr_ep_in_buffer = usb_alloc_ep_dmabuffer(usb_id, CDC_INTR_EP_IN | USB_DIR_IN, MAXP_SIZE_CDC_INTRIN);
|
||||
#endif
|
||||
|
||||
}
|
||||
return;
|
||||
__exit_err:
|
||||
#if USB_MALLOC_ENABLE
|
||||
if (cdc_hdl->cdc_buffer) {
|
||||
free(cdc_hdl->cdc_buffer);
|
||||
}
|
||||
if (cdc_hdl) {
|
||||
free(cdc_hdl);
|
||||
}
|
||||
#endif
|
||||
cdc_hdl = NULL;
|
||||
}
|
||||
|
||||
void cdc_release(const usb_dev usb_id)
|
||||
{
|
||||
/* log_info("%s() %d", __func__, __LINE__); */
|
||||
if (cdc_hdl) {
|
||||
#if USB_MALLOC_ENABLE
|
||||
free(cdc_hdl->cdc_buffer);
|
||||
free(cdc_hdl);
|
||||
#endif
|
||||
cdc_hdl = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
23
apps/common/device/usb/device/cdc.h
Normal file
23
apps/common/device/usb/device/cdc.h
Normal file
@ -0,0 +1,23 @@
|
||||
#ifndef __CDC_H__
|
||||
#define __CDC_H__
|
||||
|
||||
#include "usb/device/usb_stack.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
u32 cdc_desc_config(const usb_dev usb_id, u8 *ptr, u32 *itf);
|
||||
void cdc_set_wakeup_handler(void (*handle)(struct usb_device_t *usb_device));
|
||||
void cdc_set_output_handle(void *priv, int (*output_handler)(void *priv, u8 *buf, u32 len));
|
||||
u32 cdc_read_data(const usb_dev usb_id, u8 *buf, u32 len);
|
||||
u32 cdc_write_data(const usb_dev usb_id, u8 *buf, u32 len);
|
||||
u32 cdc_write_inir(const usb_dev usb_id, u8 *buf, u32 len);
|
||||
void cdc_register(const usb_dev usb_id);
|
||||
void cdc_release(const usb_dev usb_id);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
457
apps/common/device/usb/device/cdc_defs.h
Normal file
457
apps/common/device/usb/device/cdc_defs.h
Normal file
@ -0,0 +1,457 @@
|
||||
|
||||
/*
|
||||
* USB Communications Device Class (CDC) definitions
|
||||
*
|
||||
* CDC says how to talk to lots of different types of network adapters,
|
||||
* notably ethernet adapters and various modems. It's used mostly with
|
||||
* firmware based USB peripherals.
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_USB_CDC_H
|
||||
#define __LINUX_USB_CDC_H
|
||||
|
||||
#include "typedef.h" /* __u8 etc */
|
||||
|
||||
#ifdef __le16
|
||||
#undef __le16
|
||||
#endif
|
||||
typedef unsigned short __le16;
|
||||
#ifdef __le32
|
||||
#undef __le32
|
||||
#endif
|
||||
typedef unsigned int __le32;
|
||||
#ifdef __u8
|
||||
#undef __u8
|
||||
#endif
|
||||
typedef unsigned char __u8;
|
||||
#ifdef __u16
|
||||
#undef __u16
|
||||
#endif
|
||||
typedef unsigned short __u16;
|
||||
#ifdef __u32
|
||||
#undef __u32
|
||||
#endif
|
||||
typedef unsigned int __u32;
|
||||
|
||||
#define USB_CDC_SUBCLASS_ACM 0x02
|
||||
#define USB_CDC_SUBCLASS_ETHERNET 0x06
|
||||
#define USB_CDC_SUBCLASS_WHCM 0x08
|
||||
#define USB_CDC_SUBCLASS_DMM 0x09
|
||||
#define USB_CDC_SUBCLASS_MDLM 0x0a
|
||||
#define USB_CDC_SUBCLASS_OBEX 0x0b
|
||||
#define USB_CDC_SUBCLASS_EEM 0x0c
|
||||
#define USB_CDC_SUBCLASS_NCM 0x0d
|
||||
#define USB_CDC_SUBCLASS_MBIM 0x0e
|
||||
|
||||
#define USB_CDC_PROTO_NONE 0
|
||||
|
||||
#define USB_CDC_ACM_PROTO_AT_V25TER 1
|
||||
#define USB_CDC_ACM_PROTO_AT_PCCA101 2
|
||||
#define USB_CDC_ACM_PROTO_AT_PCCA101_WAKE 3
|
||||
#define USB_CDC_ACM_PROTO_AT_GSM 4
|
||||
#define USB_CDC_ACM_PROTO_AT_3G 5
|
||||
#define USB_CDC_ACM_PROTO_AT_CDMA 6
|
||||
#define USB_CDC_ACM_PROTO_VENDOR 0xff
|
||||
|
||||
#define USB_CDC_PROTO_EEM 7
|
||||
|
||||
#define USB_CDC_NCM_PROTO_NTB 1
|
||||
#define USB_CDC_MBIM_PROTO_NTB 2
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Class-Specific descriptors ... there are a couple dozen of them
|
||||
*/
|
||||
|
||||
#define USB_CDC_HEADER_TYPE 0x00 /* header_desc */
|
||||
#define USB_CDC_CALL_MANAGEMENT_TYPE 0x01 /* call_mgmt_descriptor */
|
||||
#define USB_CDC_ACM_TYPE 0x02 /* acm_descriptor */
|
||||
#define USB_CDC_UNION_TYPE 0x06 /* union_desc */
|
||||
#define USB_CDC_COUNTRY_TYPE 0x07
|
||||
#define USB_CDC_NETWORK_TERMINAL_TYPE 0x0a /* network_terminal_desc */
|
||||
#define USB_CDC_ETHERNET_TYPE 0x0f /* ether_desc */
|
||||
#define USB_CDC_WHCM_TYPE 0x11
|
||||
#define USB_CDC_MDLM_TYPE 0x12 /* mdlm_desc */
|
||||
#define USB_CDC_MDLM_DETAIL_TYPE 0x13 /* mdlm_detail_desc */
|
||||
#define USB_CDC_DMM_TYPE 0x14
|
||||
#define USB_CDC_OBEX_TYPE 0x15
|
||||
#define USB_CDC_NCM_TYPE 0x1a
|
||||
#define USB_CDC_MBIM_TYPE 0x1b
|
||||
|
||||
/* "Header Functional Descriptor" from CDC spec 5.2.3.1 */
|
||||
struct usb_cdc_header_desc {
|
||||
__u8 bLength;
|
||||
__u8 bDescriptorType;
|
||||
__u8 bDescriptorSubType;
|
||||
|
||||
__le16 bcdCDC;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* "Call Management Descriptor" from CDC spec 5.2.3.2 */
|
||||
struct usb_cdc_call_mgmt_descriptor {
|
||||
__u8 bLength;
|
||||
__u8 bDescriptorType;
|
||||
__u8 bDescriptorSubType;
|
||||
|
||||
__u8 bmCapabilities;
|
||||
#define USB_CDC_CALL_MGMT_CAP_CALL_MGMT 0x01
|
||||
#define USB_CDC_CALL_MGMT_CAP_DATA_INTF 0x02
|
||||
|
||||
__u8 bDataInterface;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* "Abstract Control Management Descriptor" from CDC spec 5.2.3.3 */
|
||||
struct usb_cdc_acm_descriptor {
|
||||
__u8 bLength;
|
||||
__u8 bDescriptorType;
|
||||
__u8 bDescriptorSubType;
|
||||
|
||||
__u8 bmCapabilities;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* capabilities from 5.2.3.3 */
|
||||
|
||||
#define USB_CDC_COMM_FEATURE 0x01
|
||||
#define USB_CDC_CAP_LINE 0x02
|
||||
#define USB_CDC_CAP_BRK 0x04
|
||||
#define USB_CDC_CAP_NOTIFY 0x08
|
||||
|
||||
/* "Union Functional Descriptor" from CDC spec 5.2.3.8 */
|
||||
struct usb_cdc_union_desc {
|
||||
__u8 bLength;
|
||||
__u8 bDescriptorType;
|
||||
__u8 bDescriptorSubType;
|
||||
|
||||
__u8 bMasterInterface0;
|
||||
__u8 bSlaveInterface0;
|
||||
/* ... and there could be other slave interfaces */
|
||||
} __attribute__((packed));
|
||||
|
||||
/* "Country Selection Functional Descriptor" from CDC spec 5.2.3.9 */
|
||||
struct usb_cdc_country_functional_desc {
|
||||
__u8 bLength;
|
||||
__u8 bDescriptorType;
|
||||
__u8 bDescriptorSubType;
|
||||
|
||||
__u8 iCountryCodeRelDate;
|
||||
__le16 wCountyCode0;
|
||||
/* ... and there can be a lot of country codes */
|
||||
} __attribute__((packed));
|
||||
|
||||
/* "Network Channel Terminal Functional Descriptor" from CDC spec 5.2.3.11 */
|
||||
struct usb_cdc_network_terminal_desc {
|
||||
__u8 bLength;
|
||||
__u8 bDescriptorType;
|
||||
__u8 bDescriptorSubType;
|
||||
|
||||
__u8 bEntityId;
|
||||
__u8 iName;
|
||||
__u8 bChannelIndex;
|
||||
__u8 bPhysicalInterface;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* "Ethernet Networking Functional Descriptor" from CDC spec 5.2.3.16 */
|
||||
struct usb_cdc_ether_desc {
|
||||
__u8 bLength;
|
||||
__u8 bDescriptorType;
|
||||
__u8 bDescriptorSubType;
|
||||
|
||||
__u8 iMACAddress;
|
||||
__le32 bmEthernetStatistics;
|
||||
__le16 wMaxSegmentSize;
|
||||
__le16 wNumberMCFilters;
|
||||
__u8 bNumberPowerFilters;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* "Telephone Control Model Functional Descriptor" from CDC WMC spec 6.3..3 */
|
||||
struct usb_cdc_dmm_desc {
|
||||
__u8 bFunctionLength;
|
||||
__u8 bDescriptorType;
|
||||
__u8 bDescriptorSubtype;
|
||||
__u16 bcdVersion;
|
||||
__le16 wMaxCommand;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* "MDLM Functional Descriptor" from CDC WMC spec 6.7.2.3 */
|
||||
struct usb_cdc_mdlm_desc {
|
||||
__u8 bLength;
|
||||
__u8 bDescriptorType;
|
||||
__u8 bDescriptorSubType;
|
||||
|
||||
__le16 bcdVersion;
|
||||
__u8 bGUID[16];
|
||||
} __attribute__((packed));
|
||||
|
||||
/* "MDLM Detail Functional Descriptor" from CDC WMC spec 6.7.2.4 */
|
||||
struct usb_cdc_mdlm_detail_desc {
|
||||
__u8 bLength;
|
||||
__u8 bDescriptorType;
|
||||
__u8 bDescriptorSubType;
|
||||
|
||||
/* type is associated with mdlm_desc.bGUID */
|
||||
__u8 bGuidDescriptorType;
|
||||
__u8 bDetailData[0];
|
||||
} __attribute__((packed));
|
||||
|
||||
/* "OBEX Control Model Functional Descriptor" */
|
||||
struct usb_cdc_obex_desc {
|
||||
__u8 bLength;
|
||||
__u8 bDescriptorType;
|
||||
__u8 bDescriptorSubType;
|
||||
|
||||
__le16 bcdVersion;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* "NCM Control Model Functional Descriptor" */
|
||||
struct usb_cdc_ncm_desc {
|
||||
__u8 bLength;
|
||||
__u8 bDescriptorType;
|
||||
__u8 bDescriptorSubType;
|
||||
|
||||
__le16 bcdNcmVersion;
|
||||
__u8 bmNetworkCapabilities;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* "MBIM Control Model Functional Descriptor" */
|
||||
struct usb_cdc_mbim_desc {
|
||||
__u8 bLength;
|
||||
__u8 bDescriptorType;
|
||||
__u8 bDescriptorSubType;
|
||||
|
||||
__le16 bcdMBIMVersion;
|
||||
__le16 wMaxControlMessage;
|
||||
__u8 bNumberFilters;
|
||||
__u8 bMaxFilterSize;
|
||||
__le16 wMaxSegmentSize;
|
||||
__u8 bmNetworkCapabilities;
|
||||
} __attribute__((packed));
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Class-Specific Control Requests (6.2)
|
||||
*
|
||||
* section 3.6.2.1 table 4 has the ACM profile, for modems.
|
||||
* section 3.8.2 table 10 has the ethernet profile.
|
||||
*
|
||||
* Microsoft's RNDIS stack for Ethernet is a vendor-specific CDC ACM variant,
|
||||
* heavily dependent on the encapsulated (proprietary) command mechanism.
|
||||
*/
|
||||
|
||||
#define USB_CDC_SEND_ENCAPSULATED_COMMAND 0x00
|
||||
#define USB_CDC_GET_ENCAPSULATED_RESPONSE 0x01
|
||||
#define USB_CDC_REQ_SET_LINE_CODING 0x20
|
||||
#define USB_CDC_REQ_GET_LINE_CODING 0x21
|
||||
#define USB_CDC_REQ_SET_CONTROL_LINE_STATE 0x22
|
||||
#define USB_CDC_REQ_SEND_BREAK 0x23
|
||||
#define USB_CDC_SET_ETHERNET_MULTICAST_FILTERS 0x40
|
||||
#define USB_CDC_SET_ETHERNET_PM_PATTERN_FILTER 0x41
|
||||
#define USB_CDC_GET_ETHERNET_PM_PATTERN_FILTER 0x42
|
||||
#define USB_CDC_SET_ETHERNET_PACKET_FILTER 0x43
|
||||
#define USB_CDC_GET_ETHERNET_STATISTIC 0x44
|
||||
#define USB_CDC_GET_NTB_PARAMETERS 0x80
|
||||
#define USB_CDC_GET_NET_ADDRESS 0x81
|
||||
#define USB_CDC_SET_NET_ADDRESS 0x82
|
||||
#define USB_CDC_GET_NTB_FORMAT 0x83
|
||||
#define USB_CDC_SET_NTB_FORMAT 0x84
|
||||
#define USB_CDC_GET_NTB_INPUT_SIZE 0x85
|
||||
#define USB_CDC_SET_NTB_INPUT_SIZE 0x86
|
||||
#define USB_CDC_GET_MAX_DATAGRAM_SIZE 0x87
|
||||
#define USB_CDC_SET_MAX_DATAGRAM_SIZE 0x88
|
||||
#define USB_CDC_GET_CRC_MODE 0x89
|
||||
#define USB_CDC_SET_CRC_MODE 0x8a
|
||||
|
||||
/* Line Coding Structure from CDC spec 6.2.13 */
|
||||
struct usb_cdc_line_coding {
|
||||
__le32 dwDTERate;
|
||||
__u8 bCharFormat;
|
||||
#define USB_CDC_1_STOP_BITS 0
|
||||
#define USB_CDC_1_5_STOP_BITS 1
|
||||
#define USB_CDC_2_STOP_BITS 2
|
||||
|
||||
__u8 bParityType;
|
||||
#define USB_CDC_NO_PARITY 0
|
||||
#define USB_CDC_ODD_PARITY 1
|
||||
#define USB_CDC_EVEN_PARITY 2
|
||||
#define USB_CDC_MARK_PARITY 3
|
||||
#define USB_CDC_SPACE_PARITY 4
|
||||
|
||||
__u8 bDataBits;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* table 62; bits in multicast filter */
|
||||
#define USB_CDC_PACKET_TYPE_PROMISCUOUS (1 << 0)
|
||||
#define USB_CDC_PACKET_TYPE_ALL_MULTICAST (1 << 1) /* no filter */
|
||||
#define USB_CDC_PACKET_TYPE_DIRECTED (1 << 2)
|
||||
#define USB_CDC_PACKET_TYPE_BROADCAST (1 << 3)
|
||||
#define USB_CDC_PACKET_TYPE_MULTICAST (1 << 4) /* filtered */
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Class-Specific Notifications (6.3) sent by interrupt transfers
|
||||
*
|
||||
* section 3.8.2 table 11 of the CDC spec lists Ethernet notifications
|
||||
* section 3.6.2.1 table 5 specifies ACM notifications, accepted by RNDIS
|
||||
* RNDIS also defines its own bit-incompatible notifications
|
||||
*/
|
||||
|
||||
#define USB_CDC_NOTIFY_NETWORK_CONNECTION 0x00
|
||||
#define USB_CDC_NOTIFY_RESPONSE_AVAILABLE 0x01
|
||||
#define USB_CDC_NOTIFY_SERIAL_STATE 0x20
|
||||
#define USB_CDC_NOTIFY_SPEED_CHANGE 0x2a
|
||||
|
||||
struct usb_cdc_notification {
|
||||
__u8 bmRequestType;
|
||||
__u8 bNotificationType;
|
||||
__le16 wValue;
|
||||
__le16 wIndex;
|
||||
__le16 wLength;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct usb_cdc_speed_change {
|
||||
__le32 DLBitRRate; /* contains the downlink bit rate (IN pipe) */
|
||||
__le32 ULBitRate; /* contains the uplink bit rate (OUT pipe) */
|
||||
} __attribute__((packed));
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Class Specific structures and constants
|
||||
*
|
||||
* CDC NCM NTB parameters structure, CDC NCM subclass 6.2.1
|
||||
*
|
||||
*/
|
||||
|
||||
struct usb_cdc_ncm_ntb_parameters {
|
||||
__le16 wLength;
|
||||
__le16 bmNtbFormatsSupported;
|
||||
__le32 dwNtbInMaxSize;
|
||||
__le16 wNdpInDivisor;
|
||||
__le16 wNdpInPayloadRemainder;
|
||||
__le16 wNdpInAlignment;
|
||||
__le16 wPadding1;
|
||||
__le32 dwNtbOutMaxSize;
|
||||
__le16 wNdpOutDivisor;
|
||||
__le16 wNdpOutPayloadRemainder;
|
||||
__le16 wNdpOutAlignment;
|
||||
__le16 wNtbOutMaxDatagrams;
|
||||
} __attribute__((packed));
|
||||
|
||||
/*
|
||||
* CDC NCM transfer headers, CDC NCM subclass 3.2
|
||||
*/
|
||||
|
||||
#define USB_CDC_NCM_NTH16_SIGN 0x484D434E /* NCMH */
|
||||
#define USB_CDC_NCM_NTH32_SIGN 0x686D636E /* ncmh */
|
||||
|
||||
struct usb_cdc_ncm_nth16 {
|
||||
__le32 dwSignature;
|
||||
__le16 wHeaderLength;
|
||||
__le16 wSequence;
|
||||
__le16 wBlockLength;
|
||||
__le16 wNdpIndex;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct usb_cdc_ncm_nth32 {
|
||||
__le32 dwSignature;
|
||||
__le16 wHeaderLength;
|
||||
__le16 wSequence;
|
||||
__le32 dwBlockLength;
|
||||
__le32 dwNdpIndex;
|
||||
} __attribute__((packed));
|
||||
|
||||
/*
|
||||
* CDC NCM datagram pointers, CDC NCM subclass 3.3
|
||||
*/
|
||||
|
||||
#define USB_CDC_NCM_NDP16_CRC_SIGN 0x314D434E /* NCM1 */
|
||||
#define USB_CDC_NCM_NDP16_NOCRC_SIGN 0x304D434E /* NCM0 */
|
||||
#define USB_CDC_NCM_NDP32_CRC_SIGN 0x316D636E /* ncm1 */
|
||||
#define USB_CDC_NCM_NDP32_NOCRC_SIGN 0x306D636E /* ncm0 */
|
||||
|
||||
#define USB_CDC_MBIM_NDP16_IPS_SIGN 0x00535049 /* IPS<sessionID> : IPS0 for now */
|
||||
#define USB_CDC_MBIM_NDP32_IPS_SIGN 0x00737069 /* ips<sessionID> : ips0 for now */
|
||||
#define USB_CDC_MBIM_NDP16_DSS_SIGN 0x00535344 /* DSS<sessionID> */
|
||||
#define USB_CDC_MBIM_NDP32_DSS_SIGN 0x00737364 /* dss<sessionID> */
|
||||
|
||||
/* 16-bit NCM Datagram Pointer Entry */
|
||||
struct usb_cdc_ncm_dpe16 {
|
||||
__le16 wDatagramIndex;
|
||||
__le16 wDatagramLength;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
/* 16-bit NCM Datagram Pointer Table */
|
||||
struct usb_cdc_ncm_ndp16 {
|
||||
__le32 dwSignature;
|
||||
__le16 wLength;
|
||||
__le16 wNextNdpIndex;
|
||||
struct usb_cdc_ncm_dpe16 dpe16[0];
|
||||
} __attribute__((packed));
|
||||
|
||||
/* 32-bit NCM Datagram Pointer Entry */
|
||||
struct usb_cdc_ncm_dpe32 {
|
||||
__le32 dwDatagramIndex;
|
||||
__le32 dwDatagramLength;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
/* 32-bit NCM Datagram Pointer Table */
|
||||
struct usb_cdc_ncm_ndp32 {
|
||||
__le32 dwSignature;
|
||||
__le16 wLength;
|
||||
__le16 wReserved6;
|
||||
__le32 dwNextNdpIndex;
|
||||
__le32 dwReserved12;
|
||||
struct usb_cdc_ncm_dpe32 dpe32[0];
|
||||
} __attribute__((packed));
|
||||
|
||||
/* CDC NCM subclass 3.2.1 and 3.2.2 */
|
||||
#define USB_CDC_NCM_NDP16_INDEX_MIN 0x000C
|
||||
#define USB_CDC_NCM_NDP32_INDEX_MIN 0x0010
|
||||
|
||||
/* CDC NCM subclass 3.3.3 Datagram Formatting */
|
||||
#define USB_CDC_NCM_DATAGRAM_FORMAT_CRC 0x30
|
||||
#define USB_CDC_NCM_DATAGRAM_FORMAT_NOCRC 0X31
|
||||
|
||||
/* CDC NCM subclass 4.2 NCM Communications Interface Protocol Code */
|
||||
#define USB_CDC_NCM_PROTO_CODE_NO_ENCAP_COMMANDS 0x00
|
||||
#define USB_CDC_NCM_PROTO_CODE_EXTERN_PROTO 0xFE
|
||||
|
||||
/* CDC NCM subclass 5.2.1 NCM Functional Descriptor, bmNetworkCapabilities */
|
||||
#define USB_CDC_NCM_NCAP_ETH_FILTER (1 << 0)
|
||||
#define USB_CDC_NCM_NCAP_NET_ADDRESS (1 << 1)
|
||||
#define USB_CDC_NCM_NCAP_ENCAP_COMMAND (1 << 2)
|
||||
#define USB_CDC_NCM_NCAP_MAX_DATAGRAM_SIZE (1 << 3)
|
||||
#define USB_CDC_NCM_NCAP_CRC_MODE (1 << 4)
|
||||
#define USB_CDC_NCM_NCAP_NTB_INPUT_SIZE (1 << 5)
|
||||
|
||||
/* CDC NCM subclass Table 6-3: NTB Parameter Structure */
|
||||
#define USB_CDC_NCM_NTB16_SUPPORTED (1 << 0)
|
||||
#define USB_CDC_NCM_NTB32_SUPPORTED (1 << 1)
|
||||
|
||||
/* CDC NCM subclass Table 6-3: NTB Parameter Structure */
|
||||
#define USB_CDC_NCM_NDP_ALIGN_MIN_SIZE 0x04
|
||||
#define USB_CDC_NCM_NTB_MAX_LENGTH 0x1C
|
||||
|
||||
/* CDC NCM subclass 6.2.5 SetNtbFormat */
|
||||
#define USB_CDC_NCM_NTB16_FORMAT 0x00
|
||||
#define USB_CDC_NCM_NTB32_FORMAT 0x01
|
||||
|
||||
/* CDC NCM subclass 6.2.7 SetNtbInputSize */
|
||||
#define USB_CDC_NCM_NTB_MIN_IN_SIZE 2048
|
||||
#define USB_CDC_NCM_NTB_MIN_OUT_SIZE 2048
|
||||
|
||||
/* NTB Input Size Structure */
|
||||
struct usb_cdc_ncm_ndp_input_size {
|
||||
__le32 dwNtbInMaxSize;
|
||||
__le16 wNtbInMaxDatagrams;
|
||||
__le16 wReserved;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* CDC NCM subclass 6.2.11 SetCrcMode */
|
||||
#define USB_CDC_NCM_CRC_NOT_APPENDED 0x00
|
||||
#define USB_CDC_NCM_CRC_APPENDED 0x01
|
||||
|
||||
#endif /* __LINUX_USB_CDC_H */
|
||||
202
apps/common/device/usb/device/descriptor.c
Normal file
202
apps/common/device/usb/device/descriptor.c
Normal file
@ -0,0 +1,202 @@
|
||||
/**
|
||||
* @file descriptor.c
|
||||
* @brief overwrite usb device descriptor
|
||||
* @version 1.00
|
||||
* @date 2019-05-06
|
||||
*/
|
||||
|
||||
#include "usb/device/usb_stack.h"
|
||||
#include "usb/device/descriptor.h"
|
||||
#include "usb/device/uac_audio.h"
|
||||
|
||||
#include "app_config.h"
|
||||
|
||||
#define LOG_TAG_CONST USB
|
||||
#define LOG_TAG "[USB]"
|
||||
#define LOG_ERROR_ENABLE
|
||||
#define LOG_DEBUG_ENABLE
|
||||
#define LOG_INFO_ENABLE
|
||||
/* #define LOG_DUMP_ENABLE */
|
||||
#define LOG_CLI_ENABLE
|
||||
#include "debug.h"
|
||||
|
||||
#if TCFG_USB_SLAVE_ENABLE
|
||||
|
||||
static const u8 sDeviceDescriptor[] = { //<Device Descriptor
|
||||
USB_DT_DEVICE_SIZE, // bLength: Size of descriptor
|
||||
USB_DT_DEVICE, // bDescriptorType: Device
|
||||
#if defined(FUSB_MODE) && FUSB_MODE
|
||||
0x10, 0x01, // bcdUSB: USB 1.1
|
||||
#elif defined(FUSB_MODE) && (FUSB_MODE ==0 )
|
||||
0x00, 0x02, // bcdUSB: USB 2.0
|
||||
#else
|
||||
#error "USB_SPEED_MODE not defined"
|
||||
#endif
|
||||
0x00, // bDeviceClass: none
|
||||
0x00, // bDeviceSubClass: none
|
||||
0x00, // bDeviceProtocol: none
|
||||
EP0_SETUP_LEN,//EP0_LEN, // bMaxPacketSize0: 8/64 bytes
|
||||
'J', 'L', // idVendor: 0x4a4c - JL
|
||||
'U', 'A', // idProduct: chip id
|
||||
0x00, 0x01, // bcdDevice: version 1.0
|
||||
0x01, // iManufacturer: Index to string descriptor that contains the string <Your Name> in Unicode
|
||||
0x02, // iProduct: Index to string descriptor that contains the string <Your Product Name> in Unicode
|
||||
0x03, // iSerialNumber: none
|
||||
0x01 // bNumConfigurations: 1
|
||||
};
|
||||
|
||||
static const u8 LANGUAGE_STR[] = {
|
||||
0x04, 0x03, 0x09, 0x04
|
||||
};
|
||||
|
||||
|
||||
static const u8 product_string[] = {
|
||||
42,
|
||||
0x03,
|
||||
'U', 0x00,
|
||||
'S', 0x00,
|
||||
'B', 0x00,
|
||||
' ', 0x00,
|
||||
'C', 0x00,
|
||||
'o', 0x00,
|
||||
'm', 0x00,
|
||||
'p', 0x00,
|
||||
'o', 0x00,
|
||||
's', 0x00,
|
||||
'i', 0x00,
|
||||
't', 0x00,
|
||||
'e', 0x00,
|
||||
' ', 0x00,
|
||||
'D', 0x00,
|
||||
'e', 0x00,
|
||||
'v', 0x00,
|
||||
'i', 0x00,
|
||||
'c', 0x00,
|
||||
'e', 0x00,
|
||||
};
|
||||
|
||||
static const u8 MANUFACTURE_STR[] = {
|
||||
34, //该描述符的长度为34字节
|
||||
0x03, //字符串描述符的类型编码为0x03
|
||||
0x4a, 0x00, //J
|
||||
0x69, 0x00, //i
|
||||
0x65, 0x00, //e
|
||||
0x6c, 0x00, //l
|
||||
0x69, 0x00, //i
|
||||
0x20, 0x00, //
|
||||
0x54, 0x00, //T
|
||||
0x65, 0x00, //e
|
||||
0x63, 0x00, //c
|
||||
0x68, 0x00, //h
|
||||
0x6e, 0x00, //n
|
||||
0x6f, 0x00, //o
|
||||
0x6c, 0x00, //l
|
||||
0x6f, 0x00, //o
|
||||
0x67, 0x00, //g
|
||||
0x79, 0x00, //y
|
||||
};
|
||||
|
||||
static const u8 sConfigDescriptor[] = { //<Config Descriptor
|
||||
//ConfiguraTIon
|
||||
USB_DT_CONFIG_SIZE, //bLength
|
||||
USB_DT_CONFIG, //DescriptorType : ConfigDescriptor
|
||||
0, 0, //TotalLength
|
||||
0,//bNumInterfaces: 在set_descriptor函数里面计算
|
||||
0x01, //bConfigurationValue - ID of this configuration
|
||||
0x00, //Unused
|
||||
#if USB_ROOT2 || USB_SUSPEND_RESUME || USB_SUSPEND_RESUME_SYSTEM_NO_SLEEP
|
||||
0xA0, //Attributes:Bus Power remotewakeup
|
||||
#else
|
||||
0x80, //Attributes:Bus Power
|
||||
#endif
|
||||
50, //MaxPower * 2ma
|
||||
};
|
||||
|
||||
static const u8 serial_string[] = {
|
||||
0x22, 0x03, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x36, 0x00, 0x46, 0x00, 0x36, 0x00,
|
||||
0x34, 0x00, 0x30, 0x00, 0x39, 0x00, 0x36, 0x00, 0x42, 0x00, 0x32, 0x00, 0x32, 0x00, 0x45, 0x00,
|
||||
0x37, 0x00
|
||||
};
|
||||
|
||||
void get_device_descriptor(u8 *ptr)
|
||||
{
|
||||
memcpy(ptr, sDeviceDescriptor, USB_DT_DEVICE_SIZE);
|
||||
}
|
||||
|
||||
void get_language_str(u8 *ptr)
|
||||
{
|
||||
memcpy(ptr, LANGUAGE_STR, LANGUAGE_STR[0]);
|
||||
}
|
||||
|
||||
void get_manufacture_str(u8 *ptr)
|
||||
{
|
||||
memcpy(ptr, MANUFACTURE_STR, MANUFACTURE_STR[0]);
|
||||
}
|
||||
|
||||
void get_iserialnumber_str(u8 *ptr)
|
||||
{
|
||||
#if USB_ROOT2
|
||||
memcpy(ptr, serial_string, serial_string[0]);
|
||||
#else
|
||||
extern __attribute__((weak)) u8 *get_norflash_uuid(void);
|
||||
u8 flash_id[16] = {0};
|
||||
int i;
|
||||
u8 bcd;
|
||||
if (get_norflash_uuid && get_norflash_uuid()) {
|
||||
ptr[0] = 0x22;
|
||||
ptr[1] = 0x03;
|
||||
memset(&ptr[2], 0, 0x20);
|
||||
memcpy(flash_id, get_norflash_uuid(), 16);
|
||||
//take 8 bytes from flash uuid
|
||||
for (i = 0; i < 8; i++) {
|
||||
bcd = flash_id[i] >> 4;
|
||||
if (bcd > 9) {
|
||||
bcd = bcd - 0xa + 'A';
|
||||
} else {
|
||||
bcd = bcd + '0';
|
||||
}
|
||||
ptr[2 + i * 4] = bcd;
|
||||
bcd = flash_id[i] & 0xf;
|
||||
if (bcd > 9) {
|
||||
bcd = bcd - 0xa + 'A';
|
||||
} else {
|
||||
bcd = bcd + '0';
|
||||
}
|
||||
ptr[2 + i * 4 + 2] = bcd;
|
||||
}
|
||||
} else {
|
||||
memcpy(ptr, serial_string, serial_string[0]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if USB_ROOT2
|
||||
static const u8 ee_string[] = {0x12, 0x03, 0x4D, 0x00, 0x53, 0x00, 0x46, 0x00, 0x54,
|
||||
0x00, 0x31, 0x00, 0x30, 0x00, 0x30, 0x00, 0x90, 0x00
|
||||
};
|
||||
void get_string_ee(u8 *ptr)
|
||||
{
|
||||
memcpy(ptr, ee_string, ee_string[0]);
|
||||
}
|
||||
#endif
|
||||
|
||||
void get_product_str(u8 *ptr)
|
||||
{
|
||||
memcpy(ptr, product_string, product_string[0]);
|
||||
}
|
||||
|
||||
const u8 *usb_get_config_desc()
|
||||
{
|
||||
return sConfigDescriptor;
|
||||
}
|
||||
|
||||
const u8 *usb_get_string_desc(u32 id)
|
||||
{
|
||||
const u8 *pstr = uac_get_string(id);
|
||||
if (pstr != NULL) {
|
||||
return pstr;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
332
apps/common/device/usb/device/hid.c
Normal file
332
apps/common/device/usb/device/hid.c
Normal file
@ -0,0 +1,332 @@
|
||||
#include "os/os_api.h"
|
||||
#include "usb/device/usb_stack.h"
|
||||
#include "usb/device/hid.h"
|
||||
#include "usb_config.h"
|
||||
|
||||
#include "app_config.h"
|
||||
|
||||
#if TCFG_USB_SLAVE_USER_HID
|
||||
#undef TCFG_USB_SLAVE_HID_ENABLE
|
||||
#define TCFG_USB_SLAVE_HID_ENABLE 0
|
||||
#endif
|
||||
|
||||
#if TCFG_USB_SLAVE_HID_ENABLE
|
||||
|
||||
#define LOG_TAG_CONST USB
|
||||
#define LOG_TAG "[USB]"
|
||||
#define LOG_ERROR_ENABLE
|
||||
#define LOG_DEBUG_ENABLE
|
||||
#define LOG_INFO_ENABLE
|
||||
/* #define LOG_DUMP_ENABLE */
|
||||
#define LOG_CLI_ENABLE
|
||||
#include "debug.h"
|
||||
static const u8 sHIDDescriptor[] = {
|
||||
//HID
|
||||
//InterfaceDeszcriptor:
|
||||
USB_DT_INTERFACE_SIZE, // Length
|
||||
USB_DT_INTERFACE, // DescriptorType
|
||||
/* 0x04, // bInterface number */
|
||||
0x00, // bInterface number
|
||||
0x00, // AlternateSetting
|
||||
0x01, // NumEndpoint
|
||||
/* 0x02, // NumEndpoint */
|
||||
USB_CLASS_HID, // Class = Human Interface Device
|
||||
0x00, // Subclass, 0 No subclass, 1 Boot Interface subclass
|
||||
0x00, // Procotol, 0 None, 1 Keyboard, 2 Mouse
|
||||
0x00, // Interface Name
|
||||
|
||||
//HIDDescriptor:
|
||||
0x09, // bLength
|
||||
USB_HID_DT_HID, // bDescriptorType, HID Descriptor
|
||||
0x00, 0x01, // bcdHID, HID Class Specification release NO.
|
||||
0x00, // bCuntryCode, Country localization (=none)
|
||||
0x01, // bNumDescriptors, Number of descriptors to follow
|
||||
0x22, // bDescriptorType, Report Desc. 0x22, Physical Desc. 0x23
|
||||
0,//LOW(ReportLength)
|
||||
0, //HIGH(ReportLength)
|
||||
|
||||
//EndpointDescriptor:
|
||||
USB_DT_ENDPOINT_SIZE, // bLength
|
||||
USB_DT_ENDPOINT, // bDescriptorType, Type
|
||||
USB_DIR_IN | HID_EP_IN, // bEndpointAddress
|
||||
USB_ENDPOINT_XFER_INT, // Interrupt
|
||||
LOBYTE(MAXP_SIZE_HIDIN), HIBYTE(MAXP_SIZE_HIDIN),// Maximum packet size
|
||||
HID_INTR_INTERVAL, // Poll every 10msec seconds
|
||||
|
||||
//@Endpoint Descriptor:
|
||||
/* USB_DT_ENDPOINT_SIZE, // bLength
|
||||
USB_DT_ENDPOINT, // bDescriptorType, Type
|
||||
USB_DIR_OUT | HID_EP_OUT, // bEndpointAddress
|
||||
USB_ENDPOINT_XFER_INT, // Interrupt
|
||||
LOBYTE(MAXP_SIZE_HIDOUT), HIBYTE(MAXP_SIZE_HIDOUT),// Maximum packet size
|
||||
HID_INTR_INTERVAL, // bInterval, for high speed 2^(n-1) * 125us, for full/low speed n * 1ms */
|
||||
};
|
||||
|
||||
static const u8 sHIDReportDesc[] = {
|
||||
USAGE_PAGE(1, CONSUMER_PAGE),
|
||||
USAGE(1, CONSUMER_CONTROL),
|
||||
COLLECTION(1, APPLICATION),
|
||||
|
||||
LOGICAL_MIN(1, 0x00),
|
||||
LOGICAL_MAX(1, 0x01),
|
||||
|
||||
USAGE(1, VOLUME_INC),
|
||||
USAGE(1, VOLUME_DEC),
|
||||
USAGE(1, MUTE),
|
||||
USAGE(1, PLAY_PAUSE),
|
||||
USAGE(1, SCAN_NEXT_TRACK),
|
||||
USAGE(1, SCAN_PREV_TRACK),
|
||||
USAGE(1, FAST_FORWARD),
|
||||
USAGE(1, STOP),
|
||||
|
||||
USAGE(1, TRACKING_INC),
|
||||
USAGE(1, TRACKING_DEC),
|
||||
USAGE(1, STOP_EJECT),
|
||||
USAGE(1, VOLUME),
|
||||
USAGE(2, BALANCE_LEFT),
|
||||
USAGE(2, BALANCE_RIGHT),
|
||||
USAGE(1, PLAY),
|
||||
USAGE(1, PAUSE),
|
||||
|
||||
REPORT_SIZE(1, 0x01),
|
||||
REPORT_COUNT(1, 0x10),
|
||||
INPUT(1, 0x42),
|
||||
END_COLLECTION,
|
||||
|
||||
};
|
||||
|
||||
static u32 get_hid_report_desc_len(u32 index)
|
||||
{
|
||||
u32 len = 0;
|
||||
len = sizeof(sHIDReportDesc);
|
||||
return len;
|
||||
}
|
||||
static void *get_hid_report_desc(u32 index)
|
||||
{
|
||||
u8 *ptr = NULL;
|
||||
ptr = (u8 *)sHIDReportDesc;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
static u8 *hid_ep_in_dma;
|
||||
/* static u8 *hid_ep_out_dma; */
|
||||
|
||||
static u32 hid_tx_data(struct usb_device_t *usb_device, const u8 *buffer, u32 len)
|
||||
{
|
||||
const usb_dev usb_id = usb_device2id(usb_device);
|
||||
return usb_g_intr_write(usb_id, HID_EP_IN, buffer, len);
|
||||
}
|
||||
static void hid_rx_data(struct usb_device_t *usb_device, u32 ep)
|
||||
{
|
||||
/* const usb_dev usb_id = usb_device2id(usb_device); */
|
||||
/* u32 rx_len = usb_g_intr_read(usb_id, ep, NULL, 64, 0); */
|
||||
/* hid_tx_data(usb_device, hid_ep_out_dma, rx_len); */
|
||||
}
|
||||
|
||||
static void hid_endpoint_init(struct usb_device_t *usb_device, u32 itf)
|
||||
{
|
||||
const usb_dev usb_id = usb_device2id(usb_device);
|
||||
usb_g_ep_config(usb_id, HID_EP_IN | USB_DIR_IN, USB_ENDPOINT_XFER_INT, 0, hid_ep_in_dma, MAXP_SIZE_HIDIN);
|
||||
usb_enable_ep(usb_id, HID_EP_IN);
|
||||
|
||||
/* usb_g_set_intr_hander(usb_id, HID_EP_OUT, hid_rx_data); */
|
||||
/* usb_g_ep_config(usb_id, HID_EP_OUT, USB_ENDPOINT_XFER_INT, 1, ep_buffer, MAXP_SIZE_HIDOUT); */
|
||||
}
|
||||
u32 hid_register(const usb_dev usb_id)
|
||||
{
|
||||
hid_ep_in_dma = usb_alloc_ep_dmabuffer(usb_id, HID_EP_IN | USB_DIR_IN, MAXP_SIZE_HIDIN);
|
||||
|
||||
/* hid_ep_out_dma = hid_ep_in_dma + MAXP_SIZE_HIDIN; */
|
||||
return 0;
|
||||
}
|
||||
|
||||
void hid_release(const usb_dev usb_id)
|
||||
{
|
||||
return ;
|
||||
}
|
||||
|
||||
static void hid_reset(struct usb_device_t *usb_device, u32 itf)
|
||||
{
|
||||
const usb_dev usb_id = usb_device2id(usb_device);
|
||||
log_debug("%s", __func__);
|
||||
#if USB_ROOT2
|
||||
usb_disable_ep(usb_id, HID_EP_IN);
|
||||
#else
|
||||
hid_endpoint_init(usb_device, itf);
|
||||
#endif
|
||||
}
|
||||
static u32 hid_recv_output_report(struct usb_device_t *usb_device, struct usb_ctrlrequest *setup)
|
||||
{
|
||||
const usb_dev usb_id = usb_device2id(usb_device);
|
||||
u32 ret = 0;
|
||||
u8 read_ep[8];
|
||||
u8 mute;
|
||||
u16 volume = 0;
|
||||
usb_read_ep0(usb_id, read_ep, MIN(sizeof(read_ep), setup->wLength));
|
||||
ret = USB_EP0_STAGE_SETUP;
|
||||
put_buf(read_ep, 8);
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static u32 hid_itf_hander(struct usb_device_t *usb_device, struct usb_ctrlrequest *req)
|
||||
{
|
||||
const usb_dev usb_id = usb_device2id(usb_device);
|
||||
u32 tx_len;
|
||||
u8 *tx_payload = usb_get_setup_buffer(usb_device);
|
||||
u32 bRequestType = req->bRequestType & USB_TYPE_MASK;
|
||||
switch (bRequestType) {
|
||||
case USB_TYPE_STANDARD:
|
||||
switch (req->bRequest) {
|
||||
case USB_REQ_GET_DESCRIPTOR:
|
||||
switch (HIBYTE(req->wValue)) {
|
||||
case USB_HID_DT_HID:
|
||||
tx_payload = (u8 *)sHIDDescriptor + USB_DT_INTERFACE_SIZE;
|
||||
tx_len = 9;
|
||||
tx_payload = usb_set_data_payload(usb_device, req, tx_payload, tx_len);
|
||||
tx_payload[7] = LOBYTE(get_hid_report_desc_len(req->wIndex));
|
||||
tx_payload[8] = HIBYTE(get_hid_report_desc_len(req->wIndex));
|
||||
break;
|
||||
case USB_HID_DT_REPORT:
|
||||
hid_endpoint_init(usb_device, req->wIndex);
|
||||
tx_len = get_hid_report_desc_len(req->wIndex);
|
||||
tx_payload = get_hid_report_desc(req->wIndex);
|
||||
usb_set_data_payload(usb_device, req, tx_payload, tx_len);
|
||||
break;
|
||||
}// USB_REQ_GET_DESCRIPTOR
|
||||
break;
|
||||
case USB_REQ_SET_DESCRIPTOR:
|
||||
usb_set_setup_phase(usb_device, USB_EP0_STAGE_SETUP);
|
||||
break;
|
||||
case USB_REQ_SET_INTERFACE:
|
||||
if (usb_device->bDeviceStates == USB_DEFAULT) {
|
||||
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
|
||||
} else if (usb_device->bDeviceStates == USB_ADDRESS) {
|
||||
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
|
||||
} else if (usb_device->bDeviceStates == USB_CONFIGURED) {
|
||||
//只有一个interface 没有Alternate
|
||||
if (req->wValue == 0) { //alt 0
|
||||
usb_set_setup_phase(usb_device, USB_EP0_STAGE_SETUP);
|
||||
} else {
|
||||
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case USB_REQ_GET_INTERFACE:
|
||||
if (req->wValue || (req->wLength != 1)) {
|
||||
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
|
||||
} else if (usb_device->bDeviceStates == USB_DEFAULT) {
|
||||
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
|
||||
} else if (usb_device->bDeviceStates == USB_ADDRESS) {
|
||||
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
|
||||
} else if (usb_device->bDeviceStates == USB_CONFIGURED) {
|
||||
tx_len = 1;
|
||||
tx_payload[0] = 0x00;
|
||||
usb_set_data_payload(usb_device, req, tx_payload, tx_len);
|
||||
}
|
||||
break;
|
||||
case USB_REQ_GET_STATUS:
|
||||
if (usb_device->bDeviceStates == USB_DEFAULT) {
|
||||
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
|
||||
} else if (usb_device->bDeviceStates == USB_ADDRESS) {
|
||||
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
|
||||
} else {
|
||||
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
|
||||
}
|
||||
break;
|
||||
}//bRequest @ USB_TYPE_STANDARD
|
||||
break;
|
||||
|
||||
case USB_TYPE_CLASS: {
|
||||
switch (req->bRequest) {
|
||||
case USB_REQ_SET_IDLE:
|
||||
usb_set_setup_phase(usb_device, USB_EP0_STAGE_SETUP);
|
||||
break;
|
||||
case USB_REQ_GET_IDLE:
|
||||
tx_len = 1;
|
||||
tx_payload[0] = 0;
|
||||
usb_set_data_payload(usb_device, req, tx_payload, tx_len);
|
||||
break;
|
||||
case USB_REQ_SET_REPORT:
|
||||
usb_set_setup_recv(usb_device, hid_recv_output_report);
|
||||
break;
|
||||
}//bRequest @ USB_TYPE_CLASS
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 hid_desc_config(const usb_dev usb_id, u8 *ptr, u32 *cur_itf_num)
|
||||
{
|
||||
log_debug("hid interface num:%d\n", *cur_itf_num);
|
||||
u8 *_ptr = ptr;
|
||||
memcpy(ptr, sHIDDescriptor, sizeof(sHIDDescriptor));
|
||||
ptr[2] = *cur_itf_num;
|
||||
if (usb_set_interface_hander(usb_id, *cur_itf_num, hid_itf_hander) != *cur_itf_num) {
|
||||
ASSERT(0, "hid set interface_hander fail");
|
||||
}
|
||||
if (usb_set_reset_hander(usb_id, *cur_itf_num, hid_reset) != *cur_itf_num) {
|
||||
ASSERT(0, "hid set interface_reset_hander fail");
|
||||
}
|
||||
|
||||
ptr[USB_DT_INTERFACE_SIZE + 7] = LOBYTE(get_hid_report_desc_len(0));
|
||||
ptr[USB_DT_INTERFACE_SIZE + 8] = HIBYTE(get_hid_report_desc_len(0));
|
||||
*cur_itf_num = *cur_itf_num + 1;
|
||||
return sizeof(sHIDDescriptor) ;
|
||||
}
|
||||
|
||||
void hid_key_handler(struct usb_device_t *usb_device, u32 hid_key)
|
||||
{
|
||||
const usb_dev usb_id = usb_device2id(usb_device);
|
||||
if (usb_get_ep_status(usb_id, HID_EP_IN)) {
|
||||
return;
|
||||
}
|
||||
|
||||
u16 key_buf = hid_key;
|
||||
hid_tx_data(usb_device, (const u8 *)&key_buf, 2);
|
||||
os_time_dly(2);
|
||||
key_buf = 0;
|
||||
hid_tx_data(usb_device, (const u8 *)&key_buf, 2);
|
||||
}
|
||||
|
||||
void hid_key_handler_send_one_packet(struct usb_device_t *usb_device, u32 hid_key)
|
||||
{
|
||||
const usb_dev usb_id = usb_device2id(usb_device);
|
||||
u16 key_buf = hid_key;
|
||||
hid_tx_data(usb_device, (const u8 *)&key_buf, 2);
|
||||
}
|
||||
|
||||
struct hid_button {
|
||||
u8 report_id;
|
||||
u8 button1: 1;
|
||||
u8 button2: 1;
|
||||
u8 button3: 1;
|
||||
u8 no_button: 5;
|
||||
u8 X_axis;
|
||||
u8 Y_axis;
|
||||
};
|
||||
struct hid_button hid_key;
|
||||
void hid_test(struct usb_device_t *usb_device)
|
||||
{
|
||||
static u32 tx_count = 0;
|
||||
|
||||
hid_key_handler(usb_device, BIT(tx_count));
|
||||
tx_count ++;
|
||||
if (BIT(tx_count) > USB_AUDIO_PAUSE) {
|
||||
tx_count = 0;
|
||||
}
|
||||
}
|
||||
#else
|
||||
void hid_key_handler(struct usb_device_t *usb_device, u32 hid_key)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void hid_key_handler_for_one_packet(struct usb_device_t *usb_device, u32 hid_key)
|
||||
{
|
||||
|
||||
}
|
||||
#endif
|
||||
1126
apps/common/device/usb/device/msd.c
Normal file
1126
apps/common/device/usb/device/msd.c
Normal file
File diff suppressed because it is too large
Load Diff
76
apps/common/device/usb/device/msd_upgrade.c
Normal file
76
apps/common/device/usb/device/msd_upgrade.c
Normal file
@ -0,0 +1,76 @@
|
||||
#include "system/includes.h"
|
||||
#include "usb/device/msd.h"
|
||||
#include "usb/scsi.h"
|
||||
#include "usb_config.h"
|
||||
#include "app_config.h"
|
||||
#include "cpu.h"
|
||||
#include "asm/debug.h"
|
||||
|
||||
#define WRITE_FLASH 0xFB
|
||||
#define READ_FLASH 0xFD
|
||||
#define OTHER_CMD 0xFC
|
||||
typedef enum {
|
||||
UPGRADE_NULL = 0,
|
||||
UPGRADE_USB_HARD_KEY,
|
||||
UPGRADE_USB_SOFT_KEY,
|
||||
UPGRADE_UART_KEY,
|
||||
} UPGRADE_STATE;
|
||||
|
||||
extern void nvram_set_boot_state(u32 state);
|
||||
extern void hw_mmu_disable(void);
|
||||
extern void ram_protect_close(void);
|
||||
|
||||
AT(.volatile_ram_code)
|
||||
void go_mask_usb_updata()
|
||||
{
|
||||
#ifdef CONFIG_CPU_BR18
|
||||
gpio_set_die(IO_PORTD_02, 0);
|
||||
gpio_set_die(IO_PORTB_04, 0);
|
||||
cpu_reset();
|
||||
|
||||
#else
|
||||
local_irq_disable();
|
||||
ram_protect_close();
|
||||
//FIXME
|
||||
/* hw_mmu_disable(); */
|
||||
nvram_set_boot_state(UPGRADE_USB_SOFT_KEY);
|
||||
JL_CLOCK->PWR_CON |= (1 << 4);
|
||||
#endif
|
||||
|
||||
/* chip_reset(); */
|
||||
/* cpu_reset(); */
|
||||
while (1);
|
||||
}
|
||||
#if TCFG_PC_UPDATE
|
||||
|
||||
u32 _usb_bulk_rw_test(const struct usb_device_t *usb_device, struct usb_scsi_cbw *cbw);
|
||||
|
||||
u32 private_scsi_cmd(const struct usb_device_t *usb_device, struct usb_scsi_cbw *cbw)
|
||||
{
|
||||
/* if (_usb_bulk_rw_test(usb_device, cbw)) { */
|
||||
/* return TRUE; */
|
||||
/* } */
|
||||
|
||||
switch (cbw->operationCode) {
|
||||
//////////////////////Boot Loader Custom CMD
|
||||
case WRITE_FLASH:
|
||||
case READ_FLASH:
|
||||
case OTHER_CMD:
|
||||
log_d("goto mask pc mode\n");
|
||||
go_mask_usb_updata();
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
#else
|
||||
u32 private_scsi_cmd(const struct usb_device_t *usb_device, struct usb_scsi_cbw *cbw)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
463
apps/common/device/usb/device/task_pc.c
Normal file
463
apps/common/device/usb/device/task_pc.c
Normal file
@ -0,0 +1,463 @@
|
||||
/**
|
||||
* @file task_pc.c
|
||||
* @brief 从机模式
|
||||
* @author chenrixin@zh-jieli.com
|
||||
* @version 1.0.0
|
||||
* @date 2020-02-29
|
||||
*/
|
||||
|
||||
#include "system/app_core.h"
|
||||
#include "system/includes.h"
|
||||
#include "server/server_core.h"
|
||||
#include "app_config.h"
|
||||
#include "app_action.h"
|
||||
#include "os/os_api.h"
|
||||
#include "device/sdmmc.h"
|
||||
|
||||
#include "app_charge.h"
|
||||
#include "asm/charge.h"
|
||||
|
||||
#if TCFG_USB_SLAVE_ENABLE
|
||||
#if USB_PC_NO_APP_MODE == 0
|
||||
#include "app_task.h"
|
||||
#endif
|
||||
#include "usb/usb_config.h"
|
||||
#include "usb/device/usb_stack.h"
|
||||
|
||||
#if TCFG_USB_SLAVE_HID_ENABLE
|
||||
#include "usb/device/hid.h"
|
||||
#endif
|
||||
|
||||
#if TCFG_USB_SLAVE_MSD_ENABLE
|
||||
#include "usb/device/msd.h"
|
||||
#endif
|
||||
|
||||
#if TCFG_USB_SLAVE_CDC_ENABLE
|
||||
#include "usb/device/cdc.h"
|
||||
#endif
|
||||
|
||||
#if (TCFG_USB_DM_MULTIPLEX_WITH_SD_DAT0)
|
||||
#include "dev_multiplex_api.h"
|
||||
#endif
|
||||
|
||||
#if TCFG_USB_APPLE_DOCK_EN
|
||||
#include "apple_dock/iAP.h"
|
||||
#endif
|
||||
|
||||
#if (TCFG_CFG_TOOL_ENABLE || TCFG_EFFECT_TOOL_ENABLE)
|
||||
#include "cfg_tool.h"
|
||||
#endif
|
||||
|
||||
#if ((TCFG_CHARGESTORE_ENABLE || TCFG_TEST_BOX_ENABLE || TCFG_ANC_BOX_ENABLE) \
|
||||
&& TCFG_CHARGESTORE_PORT == IO_PORT_DP)
|
||||
#include "asm/chargestore.h"
|
||||
#endif
|
||||
|
||||
#define LOG_TAG_CONST USB
|
||||
#define LOG_TAG "[USB_TASK]"
|
||||
#define LOG_ERROR_ENABLE
|
||||
#define LOG_DEBUG_ENABLE
|
||||
#define LOG_INFO_ENABLE
|
||||
/* #define LOG_DUMP_ENABLE */
|
||||
#define LOG_CLI_ENABLE
|
||||
#include "debug.h"
|
||||
|
||||
#define USB_TASK_NAME "usb_msd"
|
||||
|
||||
#define USBSTACK_EVENT 0x80
|
||||
#define USBSTACK_MSD_RUN 0x81
|
||||
#define USBSTACK_MSD_RELASE 0x82
|
||||
#define USBSTACK_HID 0x83
|
||||
#define USBSTACK_MSD_RESET 0x84
|
||||
|
||||
extern int usb_audio_demo_init(void);
|
||||
extern void usb_audio_demo_exit(void);
|
||||
|
||||
static usb_dev usbfd = 0;//SEC(.usb_g_bss);
|
||||
static OS_MUTEX msd_mutex ;//SEC(.usb_g_bss);
|
||||
static u8 msd_in_task;
|
||||
static u8 msd_run_reset;
|
||||
|
||||
|
||||
static void usb_task(void *p)
|
||||
{
|
||||
int ret = 0;
|
||||
int msg[16];
|
||||
while (1) {
|
||||
ret = os_taskq_pend("taskq", msg, ARRAY_SIZE(msg));
|
||||
if (ret != OS_TASKQ) {
|
||||
continue;
|
||||
}
|
||||
if (msg[0] != Q_MSG) {
|
||||
continue;
|
||||
}
|
||||
switch (msg[1]) {
|
||||
#if TCFG_USB_SLAVE_MSD_ENABLE
|
||||
case USBSTACK_MSD_RUN:
|
||||
os_mutex_pend(&msd_mutex, 0);
|
||||
msd_in_task = 1;
|
||||
#if TCFG_USB_APPLE_DOCK_EN
|
||||
apple_mfi_link((void *)msg[2]);
|
||||
#else
|
||||
USB_MassStorage((void *)msg[2]);
|
||||
#endif
|
||||
if (msd_run_reset) {
|
||||
msd_reset((struct usb_device_t *)msg[2], 0);
|
||||
msd_run_reset = 0;
|
||||
}
|
||||
msd_in_task = 0;
|
||||
os_mutex_post(&msd_mutex);
|
||||
break;
|
||||
case USBSTACK_MSD_RELASE:
|
||||
os_sem_post((OS_SEM *)msg[2]);
|
||||
while (1) {
|
||||
os_time_dly(10000);
|
||||
}
|
||||
break;
|
||||
// case USBSTACK_MSD_RESET:
|
||||
// os_mutex_pend(&msd_mutex, 0);
|
||||
// msd_reset((struct usb_device_t *)msg[2], (u32)msg[3]);
|
||||
// os_mutex_post(&msd_mutex);
|
||||
// break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void usb_msd_wakeup(struct usb_device_t *usb_device)
|
||||
{
|
||||
os_taskq_post_msg(USB_TASK_NAME, 2, USBSTACK_MSD_RUN, usb_device);
|
||||
}
|
||||
static void usb_msd_reset_wakeup(struct usb_device_t *usb_device, u32 itf_num)
|
||||
{
|
||||
/* os_taskq_post_msg(USB_TASK_NAME, 3, USBSTACK_MSD_RESET, usb_device, itf_num); */
|
||||
if (msd_in_task) {
|
||||
msd_run_reset = 1;
|
||||
} else {
|
||||
#if TCFG_USB_SLAVE_MSD_ENABLE
|
||||
msd_reset(usb_device, 0);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
static void usb_msd_init()
|
||||
{
|
||||
r_printf("%s()", __func__);
|
||||
int err;
|
||||
os_mutex_create(&msd_mutex);
|
||||
err = task_create(usb_task, NULL, USB_TASK_NAME);
|
||||
if (err != OS_NO_ERR) {
|
||||
r_printf("usb_msd task creat fail %x\n", err);
|
||||
}
|
||||
}
|
||||
static void usb_msd_free()
|
||||
{
|
||||
r_printf("%s()", __func__);
|
||||
|
||||
os_mutex_del(&msd_mutex, 0);
|
||||
|
||||
int err;
|
||||
OS_SEM sem;
|
||||
os_sem_create(&sem, 0);
|
||||
os_taskq_post_msg(USB_TASK_NAME, 2, USBSTACK_MSD_RELASE, (int)&sem);
|
||||
os_sem_pend(&sem, 0);
|
||||
|
||||
|
||||
err = task_kill(USB_TASK_NAME);
|
||||
if (!err) {
|
||||
r_printf("usb_msd_uninit succ!!\n");
|
||||
} else {
|
||||
r_printf("usb_msd_uninit fail!!\n");
|
||||
}
|
||||
}
|
||||
|
||||
#if TCFG_USB_SLAVE_CDC_ENABLE
|
||||
static void usb_cdc_wakeup(struct usb_device_t *usb_device)
|
||||
{
|
||||
//回调函数在中断里,正式使用不要在这里加太多东西阻塞中断,
|
||||
//或者先post到任务,由任务调用cdc_read_data()读取再执行后续工作
|
||||
const usb_dev usb_id = usb_device2id(usb_device);
|
||||
u8 buf[64] = {0};
|
||||
static u8 buf_rx[256] = {0};
|
||||
static u8 rx_len_total = 0;
|
||||
u32 rlen;
|
||||
|
||||
log_debug("cdc rx hook");
|
||||
rlen = cdc_read_data(usb_id, buf, 64);
|
||||
|
||||
/* put_buf(buf, rlen);//固件三部测试使用 */
|
||||
/* cdc_write_data(usb_id, buf, rlen);//固件三部测试使用 */
|
||||
|
||||
if ((buf[0] == 0x5A) && (buf[1] == 0xAA) && (buf[2] == 0xA5)) {
|
||||
memset(buf_rx, 0, 256);
|
||||
memcpy(buf_rx, buf, rlen);
|
||||
/* log_info("need len = %d\n", buf_rx[5] + 6); */
|
||||
/* log_info("rx len = %d\n", rlen); */
|
||||
if ((buf_rx[5] + 6) == rlen) {
|
||||
rx_len_total = 0;
|
||||
#if TCFG_CFG_TOOL_ENABLE || TCFG_EFFECT_TOOL_ENABLE
|
||||
#if (TCFG_COMM_TYPE == TCFG_USB_COMM)
|
||||
/* put_buf(buf_rx, rlen); */
|
||||
online_cfg_tool_data_deal(buf_rx, rlen);
|
||||
#else
|
||||
put_buf(buf, rlen);
|
||||
cdc_write_data(usb_id, buf, rlen);
|
||||
#endif
|
||||
#endif
|
||||
} else {
|
||||
rx_len_total += rlen;
|
||||
}
|
||||
} else {
|
||||
if ((rx_len_total + rlen) > 256) {
|
||||
memset(buf_rx, 0, 256);
|
||||
rx_len_total = 0;
|
||||
return;
|
||||
}
|
||||
memcpy(buf_rx + rx_len_total, buf, rlen);
|
||||
/* log_info("need len = %d\n", buf_rx[5] + 6); */
|
||||
/* log_info("rx len = %d\n", rx_len_total + rlen); */
|
||||
if ((buf_rx[5] + 6) == (rx_len_total + rlen)) {
|
||||
#if TCFG_CFG_TOOL_ENABLE || TCFG_EFFECT_TOOL_ENABLE
|
||||
#if (TCFG_COMM_TYPE == TCFG_USB_COMM)
|
||||
/* put_buf(buf_rx, rx_len_total + rlen); */
|
||||
online_cfg_tool_data_deal(buf_rx, rx_len_total + rlen);
|
||||
#else
|
||||
put_buf(buf, rlen);
|
||||
cdc_write_data(usb_id, buf, rlen);
|
||||
#endif
|
||||
#endif
|
||||
rx_len_total = 0;
|
||||
} else {
|
||||
rx_len_total += rlen;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void usb_start()
|
||||
{
|
||||
|
||||
#if TCFG_USB_SLAVE_AUDIO_ENABLE
|
||||
usb_audio_demo_init();
|
||||
#endif
|
||||
|
||||
#ifdef USB_DEVICE_CLASS_CONFIG
|
||||
g_printf("USB_DEVICE_CLASS_CONFIG:%x", USB_DEVICE_CLASS_CONFIG);
|
||||
#if TCFG_USB_CDC_BACKGROUND_RUN
|
||||
usb_device_mode(usbfd, USB_DEVICE_CLASS_CONFIG | CDC_CLASS);
|
||||
#else
|
||||
usb_device_mode(usbfd, USB_DEVICE_CLASS_CONFIG);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if TCFG_USB_SLAVE_MSD_ENABLE
|
||||
//没有复用时候判断 sd开关
|
||||
//复用时候判断是否参与复用
|
||||
#if (!TCFG_USB_DM_MULTIPLEX_WITH_SD_DAT0 && TCFG_SD0_ENABLE)\
|
||||
||(TCFG_SD0_ENABLE && TCFG_USB_DM_MULTIPLEX_WITH_SD_DAT0 && TCFG_DM_MULTIPLEX_WITH_SD_PORT != 0)
|
||||
msd_register_disk("sd0", NULL);
|
||||
#endif
|
||||
|
||||
#if (!TCFG_USB_DM_MULTIPLEX_WITH_SD_DAT0 && TCFG_SD1_ENABLE)\
|
||||
||(TCFG_SD1_ENABLE && TCFG_USB_DM_MULTIPLEX_WITH_SD_DAT0 && TCFG_DM_MULTIPLEX_WITH_SD_PORT != 1)
|
||||
msd_register_disk("sd1", NULL);
|
||||
#endif
|
||||
|
||||
#if TCFG_NOR_FAT
|
||||
msd_register_disk("fat_nor", NULL);
|
||||
#endif
|
||||
|
||||
#if TCFG_VIR_UDISK_ENABLE
|
||||
msd_register_disk("vir_udisk0", NULL);
|
||||
#endif
|
||||
|
||||
msd_set_wakeup_handle(usb_msd_wakeup);
|
||||
msd_set_reset_wakeup_handle(usb_msd_reset_wakeup);
|
||||
usb_msd_init();
|
||||
#endif
|
||||
|
||||
#if TCFG_USB_SLAVE_CDC_ENABLE
|
||||
cdc_set_wakeup_handler(usb_cdc_wakeup);
|
||||
#endif
|
||||
}
|
||||
static void usb_remove_disk()
|
||||
{
|
||||
#if TCFG_USB_SLAVE_MSD_ENABLE
|
||||
os_mutex_pend(&msd_mutex, 0);
|
||||
msd_unregister_all();
|
||||
os_mutex_post(&msd_mutex);
|
||||
#endif
|
||||
}
|
||||
void usb_pause()
|
||||
{
|
||||
log_info("usb pause");
|
||||
|
||||
usb_sie_disable(usbfd);
|
||||
|
||||
#if TCFG_USB_SLAVE_MSD_ENABLE
|
||||
if (msd_set_wakeup_handle(NULL)) {
|
||||
usb_remove_disk();
|
||||
usb_msd_free();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if TCFG_USB_SLAVE_AUDIO_ENABLE
|
||||
usb_audio_demo_exit();
|
||||
#endif
|
||||
|
||||
usb_device_mode(usbfd, 0);
|
||||
}
|
||||
|
||||
void usb_stop()
|
||||
{
|
||||
log_info("App Stop - usb");
|
||||
|
||||
usb_pause();
|
||||
|
||||
usb_sie_close(usbfd);
|
||||
}
|
||||
|
||||
#if TCFG_USB_CDC_BACKGROUND_RUN
|
||||
void usb_cdc_background_run()
|
||||
{
|
||||
g_printf("CDC is running in the background");
|
||||
usb_device_mode(0, CDC_CLASS);
|
||||
cdc_set_wakeup_handler(usb_cdc_wakeup);
|
||||
}
|
||||
#endif
|
||||
|
||||
int pc_device_event_handler(struct sys_event *event)
|
||||
{
|
||||
if ((int)event->arg != DEVICE_EVENT_FROM_OTG) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int switch_app_case = false;
|
||||
const char *usb_msg = (const char *)event->u.dev.value;
|
||||
log_debug("usb event : %d DEVICE_EVENT_FROM_OTG %s", event->u.dev.event, usb_msg);
|
||||
|
||||
if (usb_msg[0] == 's') {
|
||||
if (event->u.dev.event == DEVICE_EVENT_IN) {
|
||||
log_info("usb %c online", usb_msg[2]);
|
||||
usbfd = usb_msg[2] - '0';
|
||||
#if USB_PC_NO_APP_MODE
|
||||
usb_start();
|
||||
#elif TCFG_USB_DM_MULTIPLEX_WITH_SD_DAT0
|
||||
|
||||
#if TCFG_USB_CDC_BACKGROUND_RUN
|
||||
mult_sdio_suspend();
|
||||
usb_cdc_background_run();
|
||||
switch_app_case = 0;
|
||||
#else
|
||||
usb_otg_suspend(0, OTG_KEEP_STATE);
|
||||
mult_sdio_suspend();
|
||||
usb_pause();
|
||||
mult_sdio_resume();
|
||||
switch_app_case = 0;
|
||||
#endif//TCFG_USB_CDC_BACKGROUND_RUN
|
||||
|
||||
#else
|
||||
|
||||
|
||||
#if (TWFG_APP_POWERON_IGNORE_DEV && TCFG_USB_CDC_BACKGROUND_RUN && TCFG_PC_ENABLE)
|
||||
if (jiffies_to_msecs(jiffies) < TWFG_APP_POWERON_IGNORE_DEV) {
|
||||
usb_cdc_background_run();
|
||||
switch_app_case = 0;
|
||||
} else {
|
||||
usb_pause();
|
||||
switch_app_case = 1;
|
||||
}
|
||||
#elif (TCFG_USB_CDC_BACKGROUND_RUN)
|
||||
usb_cdc_background_run();
|
||||
switch_app_case = 0;
|
||||
|
||||
#elif (TWFG_APP_POWERON_IGNORE_DEV == 0)
|
||||
usb_pause();
|
||||
switch_app_case = 1;
|
||||
|
||||
#else
|
||||
usb_pause();
|
||||
switch_app_case = 1;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
} else if (event->u.dev.event == DEVICE_EVENT_OUT) {
|
||||
log_info("usb %c offline", usb_msg[2]);
|
||||
#if USB_PC_NO_APP_MODE
|
||||
usb_stop();
|
||||
#else
|
||||
|
||||
#ifdef CONFIG_SOUNDBOX
|
||||
if (true == app_check_curr_task(APP_PC_TASK)) {
|
||||
#else
|
||||
if (app_get_curr_task() == APP_PC_TASK) {
|
||||
#endif
|
||||
switch_app_case = 2;
|
||||
} else {
|
||||
/* 此处的模式限制会在USB已连接,蓝牙播歌切换到蓝牙模式后再拔出USB的情况下,
|
||||
无法检测到再次插入USB */
|
||||
#if TCFG_USB_DM_MULTIPLEX_WITH_SD_DAT0
|
||||
mult_sdio_suspend();
|
||||
#endif
|
||||
usb_stop();
|
||||
#if TCFG_USB_DM_MULTIPLEX_WITH_SD_DAT0
|
||||
mult_sdio_resume();
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return switch_app_case;
|
||||
}
|
||||
|
||||
#if USB_PC_NO_APP_MODE
|
||||
void usbstack_init()
|
||||
{
|
||||
register_sys_event_handler(SYS_DEVICE_EVENT, DEVICE_EVENT_FROM_OTG, 2,
|
||||
(void (*)(struct sys_event *))pc_device_event_handler);
|
||||
}
|
||||
|
||||
void usbstack_exit()
|
||||
{
|
||||
unregister_sys_event_handler((void (*)(struct sys_event *))pc_device_event_handler);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (TCFG_OTG_MODE & OTG_DET_DM_ONLY)
|
||||
static void otg_sof_check_before_hook()
|
||||
{
|
||||
log_debug("sof_check_before");
|
||||
#if ((TCFG_CHARGESTORE_ENABLE || TCFG_TEST_BOX_ENABLE || TCFG_ANC_BOX_ENABLE) \
|
||||
&& TCFG_CHARGESTORE_PORT == IO_PORT_DP)
|
||||
power_wakeup_index_enable(2, 0);
|
||||
chargestore_api_stop();
|
||||
#endif
|
||||
}
|
||||
|
||||
static void otg_sof_check_after_hook()
|
||||
{
|
||||
log_debug("sof_check_after");
|
||||
#if ((TCFG_CHARGESTORE_ENABLE || TCFG_TEST_BOX_ENABLE || TCFG_ANC_BOX_ENABLE) \
|
||||
&& TCFG_CHARGESTORE_PORT == IO_PORT_DP)
|
||||
chargestore_api_restart();
|
||||
power_wakeup_index_enable(2, 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int otg_sof_check_hook_register()
|
||||
{
|
||||
//需要在otg定时器启动之前(即devices_init()之前)注册钩子函数
|
||||
usb_otg_sof_check_register_hooks(otg_sof_check_before_hook,
|
||||
otg_sof_check_after_hook);
|
||||
return 0;
|
||||
}
|
||||
early_initcall(otg_sof_check_hook_register);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
1401
apps/common/device/usb/device/uac1.c
Normal file
1401
apps/common/device/usb/device/uac1.c
Normal file
File diff suppressed because it is too large
Load Diff
514
apps/common/device/usb/device/uac_stream.c
Normal file
514
apps/common/device/usb/device/uac_stream.c
Normal file
@ -0,0 +1,514 @@
|
||||
#include "app_config.h"
|
||||
#include "system/includes.h"
|
||||
#include "printf.h"
|
||||
#include "usb/usb_config.h"
|
||||
#include "usb/device/usb_stack.h"
|
||||
|
||||
#if TCFG_USB_SLAVE_AUDIO_ENABLE
|
||||
#include "usb/device/uac_audio.h"
|
||||
#include "uac_stream.h"
|
||||
#include "audio_config.h"
|
||||
|
||||
/* #ifdef CONFIG_MEDIA_DEVELOP_ENABLE */
|
||||
#include "audio_track.h"
|
||||
/* #endif */
|
||||
|
||||
|
||||
#define LOG_TAG_CONST USB
|
||||
#define LOG_TAG "[UAC]"
|
||||
#define LOG_ERROR_ENABLE
|
||||
#define LOG_DEBUG_ENABLE
|
||||
#define LOG_INFO_ENABLE
|
||||
/* #define LOG_DUMP_ENABLE */
|
||||
#define LOG_CLI_ENABLE
|
||||
#include "debug.h"
|
||||
|
||||
#define UAC_DEBUG_ECHO_MODE 0
|
||||
|
||||
static volatile u8 speaker_stream_is_open = 0;
|
||||
struct uac_speaker_handle {
|
||||
cbuffer_t cbuf;
|
||||
volatile u8 need_resume;
|
||||
u8 channel;
|
||||
u8 alive;
|
||||
void *buffer;
|
||||
void *audio_track;
|
||||
//void (*rx_handler)(int, void *, int);
|
||||
};
|
||||
|
||||
static void (*uac_rx_handler)(int, void *, int) = NULL;
|
||||
|
||||
#if (SOUNDCARD_ENABLE)
|
||||
#define UAC_BUFFER_SIZE (4 * 1024)
|
||||
#else
|
||||
#define UAC_BUFFER_SIZE (1 * 1024)
|
||||
#endif
|
||||
|
||||
#define UAC_BUFFER_MAX (UAC_BUFFER_SIZE * 50 / 100)
|
||||
|
||||
static struct uac_speaker_handle *uac_speaker = NULL;
|
||||
|
||||
#if USB_MALLOC_ENABLE
|
||||
#else
|
||||
static struct uac_speaker_handle uac_speaker_handle SEC(.uac_var);
|
||||
static u8 uac_rx_buffer[UAC_BUFFER_SIZE] ALIGNED(4) SEC(.uac_rx);
|
||||
#endif
|
||||
u32 uac_speaker_stream_length()
|
||||
{
|
||||
return UAC_BUFFER_SIZE;
|
||||
}
|
||||
u32 uac_speaker_stream_size()
|
||||
{
|
||||
if (!speaker_stream_is_open) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (uac_speaker) {
|
||||
return cbuf_get_data_size(&uac_speaker->cbuf);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 uac_speaker_get_alive()
|
||||
{
|
||||
if (uac_speaker) {
|
||||
return uac_speaker->alive;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
void uac_speaker_set_alive(u8 alive)
|
||||
{
|
||||
local_irq_disable();
|
||||
if (uac_speaker) {
|
||||
uac_speaker->alive = alive;
|
||||
}
|
||||
local_irq_enable();
|
||||
}
|
||||
|
||||
void uac_speaker_stream_buf_clear(void)
|
||||
{
|
||||
if (speaker_stream_is_open) {
|
||||
cbuf_clear(&uac_speaker->cbuf);
|
||||
}
|
||||
}
|
||||
|
||||
void set_uac_speaker_rx_handler(void *priv, void (*rx_handler)(int, void *, int))
|
||||
{
|
||||
uac_rx_handler = rx_handler;
|
||||
/* if (uac_speaker) { */
|
||||
/* uac_speaker->rx_handler = rx_handler; */
|
||||
/* } */
|
||||
}
|
||||
|
||||
int uac_speaker_stream_sample_rate(void)
|
||||
{
|
||||
/* #ifdef CONFIG_MEDIA_DEVELOP_ENABLE */
|
||||
if (uac_speaker && uac_speaker->audio_track) {
|
||||
int sr = audio_local_sample_track_rate(uac_speaker->audio_track);
|
||||
if ((sr < (SPK_AUDIO_RATE + 100)) && (sr > (SPK_AUDIO_RATE - 100))) {
|
||||
return sr;
|
||||
}
|
||||
/* printf("uac audio_track reset \n"); */
|
||||
/* local_irq_disable(); */
|
||||
/* audio_local_sample_track_close(uac_speaker->audio_track); */
|
||||
/* uac_speaker->audio_track = audio_local_sample_track_open(SPK_CHANNEL, SPK_AUDIO_RATE, 1000); */
|
||||
/* local_irq_enable(); */
|
||||
}
|
||||
/* #endif */
|
||||
return SPK_AUDIO_RATE;
|
||||
}
|
||||
|
||||
void uac_speaker_stream_write(const u8 *obuf, u32 len)
|
||||
{
|
||||
if (speaker_stream_is_open) {
|
||||
//write dac
|
||||
/* #ifdef CONFIG_MEDIA_DEVELOP_ENABLE */
|
||||
if (uac_speaker->audio_track) {
|
||||
audio_local_sample_track_in_period(uac_speaker->audio_track, (len >> 1) / uac_speaker->channel);
|
||||
}
|
||||
/* #endif */
|
||||
int wlen = cbuf_write(&uac_speaker->cbuf, (void *)obuf, len);
|
||||
if (wlen != len) {
|
||||
//putchar('W');
|
||||
}
|
||||
//if (uac_speaker->rx_handler) {
|
||||
if (uac_rx_handler) {
|
||||
/* if (uac_speaker->cbuf.data_len >= UAC_BUFFER_MAX) { */
|
||||
// 马上就要满了,赶紧取走
|
||||
uac_speaker->need_resume = 1; //2020-12-22注:无需唤醒
|
||||
/* } */
|
||||
if (uac_speaker->need_resume) {
|
||||
uac_speaker->need_resume = 0;
|
||||
uac_rx_handler(0, (void *)obuf, len);
|
||||
//uac_speaker->rx_handler(0, (void *)obuf, len);
|
||||
}
|
||||
}
|
||||
uac_speaker->alive = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int uac_speaker_read(void *priv, void *data, u32 len)
|
||||
{
|
||||
int r_len;
|
||||
int err = 0;
|
||||
|
||||
local_irq_disable();
|
||||
if (!speaker_stream_is_open) {
|
||||
local_irq_enable();
|
||||
return 0;
|
||||
}
|
||||
|
||||
r_len = cbuf_get_data_size(&uac_speaker->cbuf);
|
||||
if (r_len) {
|
||||
r_len = r_len > len ? len : r_len;
|
||||
r_len = cbuf_read(&uac_speaker->cbuf, data, r_len);
|
||||
if (!r_len) {
|
||||
putchar('U');
|
||||
}
|
||||
}
|
||||
|
||||
if (r_len == 0) {
|
||||
uac_speaker->need_resume = 1;
|
||||
}
|
||||
local_irq_enable();
|
||||
return r_len;
|
||||
}
|
||||
|
||||
void uac_speaker_stream_open(u32 samplerate, u32 ch)
|
||||
{
|
||||
if (speaker_stream_is_open) {
|
||||
return;
|
||||
}
|
||||
log_info("%s", __func__);
|
||||
|
||||
if (!uac_speaker) {
|
||||
#if USB_MALLOC_ENABLE
|
||||
|
||||
uac_speaker = zalloc(sizeof(struct uac_speaker_handle));
|
||||
if (!uac_speaker) {
|
||||
return;
|
||||
}
|
||||
|
||||
uac_speaker->buffer = malloc(UAC_BUFFER_SIZE);
|
||||
if (!uac_speaker->buffer) {
|
||||
free(uac_speaker);
|
||||
uac_speaker = NULL;
|
||||
goto __err;
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
|
||||
uac_speaker = &uac_speaker_handle;
|
||||
|
||||
memset(uac_speaker, 0, sizeof(struct uac_speaker_handle));
|
||||
|
||||
uac_speaker->buffer = uac_rx_buffer;
|
||||
#endif
|
||||
uac_speaker->channel = ch;
|
||||
/* #ifdef CONFIG_MEDIA_DEVELOP_ENABLE */
|
||||
uac_speaker->audio_track = audio_local_sample_track_open(ch, samplerate, 1000);
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
|
||||
//uac_speaker->rx_handler = NULL;
|
||||
|
||||
cbuf_init(&uac_speaker->cbuf, uac_speaker->buffer, UAC_BUFFER_SIZE);
|
||||
speaker_stream_is_open = 1;
|
||||
struct sys_event event;
|
||||
event.type = SYS_DEVICE_EVENT;
|
||||
event.arg = (void *)DEVICE_EVENT_FROM_UAC;
|
||||
event.u.dev.event = USB_AUDIO_PLAY_OPEN;
|
||||
event.u.dev.value = (int)((ch << 24) | samplerate);
|
||||
|
||||
#if !UAC_DEBUG_ECHO_MODE
|
||||
sys_event_notify(&event);
|
||||
#endif
|
||||
|
||||
return;
|
||||
|
||||
__err:
|
||||
return;
|
||||
}
|
||||
|
||||
void uac_speaker_stream_close()
|
||||
{
|
||||
if (speaker_stream_is_open == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
log_info("%s", __func__);
|
||||
speaker_stream_is_open = 0;
|
||||
|
||||
if (uac_speaker) {
|
||||
/* #ifdef CONFIG_MEDIA_DEVELOP_ENABLE */
|
||||
audio_local_sample_track_close(uac_speaker->audio_track);
|
||||
/* #endif */
|
||||
uac_speaker->audio_track = NULL;
|
||||
#if USB_MALLOC_ENABLE
|
||||
if (uac_speaker->buffer) {
|
||||
free(uac_speaker->buffer);
|
||||
}
|
||||
free(uac_speaker);
|
||||
#endif
|
||||
uac_speaker = NULL;
|
||||
}
|
||||
struct sys_event event;
|
||||
event.type = SYS_DEVICE_EVENT;
|
||||
event.arg = (void *)DEVICE_EVENT_FROM_UAC;
|
||||
event.u.dev.event = USB_AUDIO_PLAY_CLOSE;
|
||||
event.u.dev.value = (int)0;
|
||||
|
||||
#if !UAC_DEBUG_ECHO_MODE
|
||||
sys_event_notify(&event);
|
||||
#endif
|
||||
}
|
||||
|
||||
int uac_get_spk_vol()
|
||||
{
|
||||
int max_vol = get_max_sys_vol();
|
||||
int vol = app_audio_get_volume(APP_AUDIO_STATE_MUSIC);
|
||||
if (vol * 100 / max_vol < 100) {
|
||||
return vol * 100 / max_vol;
|
||||
} else {
|
||||
return 99;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static u8 flag_uac_event_enable = 1;
|
||||
void set_uac_event_flag(u8 en)
|
||||
{
|
||||
flag_uac_event_enable = en;
|
||||
}
|
||||
u8 get_uac_event_flag(void)
|
||||
{
|
||||
return flag_uac_event_enable;
|
||||
}
|
||||
static volatile u32 mic_stream_is_open;
|
||||
|
||||
u8 uac_get_mic_stream_status(void)
|
||||
{
|
||||
return mic_stream_is_open;
|
||||
}
|
||||
|
||||
void uac_mute_volume(u32 type, u32 l_vol, u32 r_vol)
|
||||
{
|
||||
struct sys_event event;
|
||||
event.type = SYS_DEVICE_EVENT;
|
||||
event.arg = (void *)DEVICE_EVENT_FROM_UAC;
|
||||
|
||||
static u32 last_spk_l_vol = (u32) - 1, last_spk_r_vol = (u32) - 1;
|
||||
static u32 last_mic_vol = (u32) - 1;
|
||||
|
||||
if (!get_uac_event_flag()) {
|
||||
return;
|
||||
}
|
||||
switch (type) {
|
||||
case MIC_FEATURE_UNIT_ID: //MIC
|
||||
if (mic_stream_is_open == 0) {
|
||||
return ;
|
||||
}
|
||||
if (l_vol == last_mic_vol) {
|
||||
return;
|
||||
}
|
||||
last_mic_vol = l_vol;
|
||||
event.u.dev.event = USB_AUDIO_SET_MIC_VOL;
|
||||
break;
|
||||
case SPK_FEATURE_UNIT_ID: //SPK
|
||||
if (speaker_stream_is_open == 0) {
|
||||
return;
|
||||
}
|
||||
if (l_vol == last_spk_l_vol && r_vol == last_spk_r_vol) {
|
||||
return;
|
||||
}
|
||||
last_spk_l_vol = l_vol;
|
||||
last_spk_r_vol = r_vol;
|
||||
event.u.dev.event = USB_AUDIO_SET_PLAY_VOL;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
event.u.dev.value = (int)(r_vol << 16 | l_vol);
|
||||
#if !UAC_DEBUG_ECHO_MODE
|
||||
sys_event_notify(&event);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static int (*mic_tx_handler)(int, void *, int) = NULL;
|
||||
int uac_mic_stream_read(u8 *buf, u32 len)
|
||||
{
|
||||
if (mic_stream_is_open == 0) {
|
||||
return 0;
|
||||
}
|
||||
#if 0//48K 1ksin
|
||||
const s16 sin_48k[] = {
|
||||
0, 2139, 4240, 6270, 8192, 9974, 11585, 12998,
|
||||
14189, 15137, 15826, 16244, 16384, 16244, 15826, 15137,
|
||||
14189, 12998, 11585, 9974, 8192, 6270, 4240, 2139,
|
||||
0, -2139, -4240, -6270, -8192, -9974, -11585, -12998,
|
||||
-14189, -15137, -15826, -16244, -16384, -16244, -15826, -15137,
|
||||
-14189, -12998, -11585, -9974, -8192, -6270, -4240, -2139
|
||||
};
|
||||
u16 *l_ch = (u16 *)buf;
|
||||
u16 *r_ch = (u16 *)buf;
|
||||
r_ch++;
|
||||
for (int i = 0; i < len / 2; i++) {
|
||||
*l_ch = sin_48k[i];
|
||||
*r_ch = sin_48k[i];
|
||||
l_ch += 1;
|
||||
r_ch += 1;
|
||||
}
|
||||
return len;
|
||||
#elif UAC_DEBUG_ECHO_MODE
|
||||
#if MIC_CHANNEL == 2
|
||||
uac_speaker_read(NULL, buf, len);
|
||||
const s16 sin_48k[] = {
|
||||
0, 2139, 4240, 6270, 8192, 9974, 11585, 12998,
|
||||
14189, 15137, 15826, 16244, 16384, 16244, 15826, 15137,
|
||||
14189, 12998, 11585, 9974, 8192, 6270, 4240, 2139,
|
||||
0, -2139, -4240, -6270, -8192, -9974, -11585, -12998,
|
||||
-14189, -15137, -15826, -16244, -16384, -16244, -15826, -15137,
|
||||
-14189, -12998, -11585, -9974, -8192, -6270, -4240, -2139
|
||||
};
|
||||
u16 *r_ch = (u16 *)buf;
|
||||
r_ch++;
|
||||
for (int i = 0; i < len / 4; i++) {
|
||||
*r_ch = sin_48k[i];
|
||||
r_ch += 2;
|
||||
}
|
||||
#else
|
||||
uac_speaker_read(NULL, buf, len * 2);
|
||||
u16 *r_ch = (u16 *)buf;
|
||||
for (int i = 0; i < len / 2; i++) {
|
||||
r_ch[i] = r_ch[i * 2];
|
||||
}
|
||||
|
||||
#endif
|
||||
return len;
|
||||
#else
|
||||
if (mic_tx_handler) {
|
||||
#if 1
|
||||
return mic_tx_handler(0, buf, len);
|
||||
#else
|
||||
//16bit ---> 24bit
|
||||
int rlen = mic_tx_handler(0, tmp_buf, len / 3 * 2);
|
||||
rlen /= 2; //sampe point
|
||||
for (int i = 0 ; i < rlen ; i++) {
|
||||
buf[i * 3] = 0;
|
||||
buf[i * 3 + 1] = tmp_buf[i * 2];
|
||||
buf[i * 3 + 2] = tmp_buf[i * 2 + 1];
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
//putchar('N');
|
||||
}
|
||||
return 0;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
void set_uac_mic_tx_handler(void *priv, int (*tx_handler)(int, void *, int))
|
||||
{
|
||||
mic_tx_handler = tx_handler;
|
||||
}
|
||||
static u32 mic_close_tid = 0;
|
||||
static u8 mic_sw;
|
||||
u32 uac_mic_stream_open(u32 samplerate, u32 frame_len, u32 ch)
|
||||
{
|
||||
mic_sw = 1;
|
||||
if (mic_stream_is_open) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* mic_tx_handler = NULL; */
|
||||
log_info("%s", __func__);
|
||||
|
||||
struct sys_event event;
|
||||
event.type = SYS_DEVICE_EVENT;
|
||||
event.arg = (void *)DEVICE_EVENT_FROM_UAC;
|
||||
event.u.dev.event = USB_AUDIO_MIC_OPEN;
|
||||
event.u.dev.value = (int)((ch << 24) | samplerate);
|
||||
mic_stream_is_open = 1;
|
||||
|
||||
#if !UAC_DEBUG_ECHO_MODE
|
||||
sys_event_notify(&event);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void uac_mic_stream_close_delay()
|
||||
{
|
||||
mic_close_tid = 0;
|
||||
if (!mic_sw) {
|
||||
|
||||
} else {
|
||||
return ;
|
||||
}
|
||||
log_info("%s", __func__);
|
||||
struct sys_event event;
|
||||
event.type = SYS_DEVICE_EVENT;
|
||||
event.arg = (void *)DEVICE_EVENT_FROM_UAC;
|
||||
event.u.dev.event = USB_AUDIO_MIC_CLOSE;
|
||||
event.u.dev.value = (int)0;
|
||||
mic_stream_is_open = 0;
|
||||
|
||||
#if !UAC_DEBUG_ECHO_MODE
|
||||
sys_event_notify(&event);
|
||||
#endif
|
||||
}
|
||||
void uac_mic_stream_close()
|
||||
{
|
||||
mic_sw = 0;
|
||||
if (mic_stream_is_open == 0) {
|
||||
return ;
|
||||
}
|
||||
//FIXME:
|
||||
//未知原因出现频繁开关mic,导致出现audio或者蓝牙工作异常,
|
||||
//收到mic关闭命令后延时1s再发消息通知audio模块执行关闭动作
|
||||
//如果在1s之内继续收到usb下发的关闭命令,则继续推迟1s。
|
||||
if (mic_close_tid == 0) {
|
||||
mic_close_tid = sys_hi_timeout_add(NULL, uac_mic_stream_close_delay, 1000);
|
||||
} else {
|
||||
sys_hi_timeout_modify(mic_close_tid, 1000);
|
||||
}
|
||||
}
|
||||
|
||||
_WEAK_
|
||||
s8 app_audio_get_volume(u8 state)
|
||||
{
|
||||
return 88;
|
||||
}
|
||||
_WEAK_
|
||||
void usb_audio_demo_exit(void)
|
||||
{
|
||||
|
||||
}
|
||||
_WEAK_
|
||||
int usb_audio_demo_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
_WEAK_
|
||||
u8 get_max_sys_vol(void)
|
||||
{
|
||||
return 100;
|
||||
}
|
||||
_WEAK_
|
||||
void *audio_local_sample_track_open(u8 channel, int sample_rate, int period)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
_WEAK_
|
||||
int audio_local_sample_track_in_period(void *c, int samples)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
_WEAK_
|
||||
void audio_local_sample_track_close(void *c)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
31
apps/common/device/usb/device/uac_stream.h
Normal file
31
apps/common/device/usb/device/uac_stream.h
Normal file
@ -0,0 +1,31 @@
|
||||
/*****************************************************************
|
||||
>file name : usb_audio.h
|
||||
>author : lichao
|
||||
>create time : Wed 22 May 2019 10:39:35 AM CST
|
||||
*****************************************************************/
|
||||
#ifndef _UAC_STREAM_H_
|
||||
#define _UAC_STREAM_H_
|
||||
#include "typedef.h"
|
||||
|
||||
enum uac_event {
|
||||
USB_AUDIO_PLAY_OPEN = 0x0,
|
||||
USB_AUDIO_PLAY_CLOSE,
|
||||
USB_AUDIO_MIC_OPEN,
|
||||
USB_AUDIO_MIC_CLOSE,
|
||||
// USB_AUDIO_MUTE,
|
||||
USB_AUDIO_SET_PLAY_VOL,
|
||||
USB_AUDIO_SET_MIC_VOL,
|
||||
};
|
||||
|
||||
|
||||
void uac_speaker_stream_buf_clear(void);
|
||||
u32 uac_speaker_stream_length();
|
||||
u32 uac_speaker_stream_size();
|
||||
void set_uac_speaker_rx_handler(void *priv, void (*rx_handler)(int, void *, int));
|
||||
void set_uac_mic_tx_handler(void *priv, int (*tx_handler)(int, void *, int));
|
||||
int uac_speaker_stream_sample_rate(void);
|
||||
|
||||
int uac_speaker_read(void *priv, void *data, u32 len);
|
||||
u32 uac_speaker_get_alive();
|
||||
void uac_speaker_set_alive(u8 alive);
|
||||
#endif
|
||||
258
apps/common/device/usb/device/usb_device.c
Normal file
258
apps/common/device/usb/device/usb_device.c
Normal file
@ -0,0 +1,258 @@
|
||||
#include "usb/device/usb_stack.h"
|
||||
#include "usb_config.h"
|
||||
#include "usb/device/msd.h"
|
||||
#include "usb/scsi.h"
|
||||
#include "usb/device/hid.h"
|
||||
#include "usb/device/uac_audio.h"
|
||||
#include "usb/device/cdc.h"
|
||||
#include "irq.h"
|
||||
#include "init.h"
|
||||
#include "gpio.h"
|
||||
#include "app_config.h"
|
||||
|
||||
#define LOG_TAG_CONST USB
|
||||
#define LOG_TAG "[USB]"
|
||||
#define LOG_ERROR_ENABLE
|
||||
#define LOG_DEBUG_ENABLE
|
||||
#define LOG_INFO_ENABLE
|
||||
/* #define LOG_DUMP_ENABLE */
|
||||
#define LOG_CLI_ENABLE
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
#if TCFG_USB_SLAVE_ENABLE
|
||||
|
||||
static void usb_device_init(const usb_dev usb_id)
|
||||
{
|
||||
|
||||
usb_config(usb_id);
|
||||
usb_g_sie_init(usb_id);
|
||||
#if defined(FUSB_MODE) && FUSB_MODE
|
||||
usb_write_power(usb_id, 0x40);
|
||||
#elif defined(FUSB_MODE) && (FUSB_MODE == 0)
|
||||
usb_write_power(usb_id, 0x60);
|
||||
#endif
|
||||
usb_slave_init(usb_id);
|
||||
u8 *ep0_dma_buffer = usb_alloc_ep_dmabuffer(usb_id, 0, 64);
|
||||
|
||||
usb_set_dma_raddr(usb_id, 0, ep0_dma_buffer);
|
||||
usb_set_dma_raddr(usb_id, 1, ep0_dma_buffer);
|
||||
usb_set_dma_raddr(usb_id, 2, ep0_dma_buffer);
|
||||
usb_set_dma_raddr(usb_id, 3, ep0_dma_buffer);
|
||||
usb_set_dma_raddr(usb_id, 4, ep0_dma_buffer);
|
||||
|
||||
usb_write_intr_usbe(usb_id, INTRUSB_RESET_BABBLE | INTRUSB_SUSPEND);
|
||||
usb_clr_intr_txe(usb_id, -1);
|
||||
usb_clr_intr_rxe(usb_id, -1);
|
||||
usb_set_intr_txe(usb_id, 0);
|
||||
usb_set_intr_rxe(usb_id, 0);
|
||||
usb_g_isr_reg(usb_id, 3, 0);
|
||||
/* usb_sof_isr_reg(usb_id,3,0); */
|
||||
/* usb_sofie_enable(usb_id); */
|
||||
/* USB_DEBUG_PRINTF("ep0 addr %x %x\n", usb_get_dma_taddr(0), ep0_dma_buffer); */
|
||||
}
|
||||
static void usb_device_hold(const usb_dev usb_id)
|
||||
{
|
||||
|
||||
usb_g_hold(usb_id);
|
||||
usb_release(usb_id);
|
||||
}
|
||||
|
||||
|
||||
static int usb_ep_conflict_check(const usb_dev usb_id);
|
||||
int usb_device_mode(const usb_dev usb_id, const u32 class)
|
||||
{
|
||||
|
||||
/* usb_device_set_class(CLASS_CONFIG); */
|
||||
u8 class_index = 0;
|
||||
if (class == 0) {
|
||||
gpio_direction_input(IO_PORT_DM + 2 * usb_id);
|
||||
gpio_set_pull_up(IO_PORT_DM + 2 * usb_id, 0);
|
||||
gpio_set_pull_down(IO_PORT_DM + 2 * usb_id, 0);
|
||||
gpio_set_die(IO_PORT_DM + 2 * usb_id, 0);
|
||||
|
||||
gpio_direction_input(IO_PORT_DP + 2 * usb_id);
|
||||
gpio_set_pull_up(IO_PORT_DP + 2 * usb_id, 0);
|
||||
gpio_set_pull_down(IO_PORT_DP + 2 * usb_id, 0);
|
||||
gpio_set_die(IO_PORT_DP + 2 * usb_id, 0);
|
||||
|
||||
os_time_dly(15);
|
||||
|
||||
gpio_set_die(IO_PORT_DM + 2 * usb_id, 1);
|
||||
gpio_set_die(IO_PORT_DP + 2 * usb_id, 1);
|
||||
|
||||
#if TCFG_USB_SLAVE_MSD_ENABLE
|
||||
msd_release(usb_id);
|
||||
#endif
|
||||
|
||||
#if TCFG_USB_SLAVE_AUDIO_ENABLE
|
||||
uac_release(usb_id);
|
||||
#endif
|
||||
|
||||
#if TCFG_USB_SLAVE_CDC_ENABLE
|
||||
cdc_release(usb_id);
|
||||
#endif
|
||||
#if TCFG_USB_SLAVE_HID_ENABLE
|
||||
hid_release(usb_id);
|
||||
#endif
|
||||
usb_device_hold(usb_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* int ret = usb_ep_conflict_check(usb_id); */
|
||||
/* if (ret) { */
|
||||
/* return ret; */
|
||||
/* } */
|
||||
|
||||
usb_memory_init();
|
||||
|
||||
usb_add_desc_config(usb_id, MAX_INTERFACE_NUM, NULL);
|
||||
|
||||
#if TCFG_USB_SLAVE_MSD_ENABLE
|
||||
if ((class & MASSSTORAGE_CLASS) == MASSSTORAGE_CLASS) {
|
||||
log_info("add desc msd");
|
||||
usb_add_desc_config(usb_id, class_index++, msd_desc_config);
|
||||
msd_register(usb_id);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if TCFG_USB_SLAVE_AUDIO_ENABLE
|
||||
if ((class & AUDIO_CLASS) == AUDIO_CLASS) {
|
||||
log_info("add audio desc");
|
||||
usb_add_desc_config(usb_id, class_index++, uac_audio_desc_config);
|
||||
uac_register(usb_id, AUDIO_CLASS);
|
||||
} else if ((class & SPEAKER_CLASS) == SPEAKER_CLASS) {
|
||||
log_info("add desc speaker");
|
||||
usb_add_desc_config(usb_id, class_index++, uac_spk_desc_config);
|
||||
uac_register(usb_id, SPEAKER_CLASS);
|
||||
} else if ((class & MIC_CLASS) == MIC_CLASS) {
|
||||
log_info("add desc mic");
|
||||
usb_add_desc_config(usb_id, class_index++, uac_mic_desc_config);
|
||||
uac_register(usb_id, MIC_CLASS);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if TCFG_USB_SLAVE_HID_ENABLE
|
||||
if ((class & HID_CLASS) == HID_CLASS) {
|
||||
log_info("add desc std hid");
|
||||
usb_add_desc_config(usb_id, class_index++, hid_desc_config);
|
||||
hid_register(usb_id);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if TCFG_USB_SLAVE_CDC_ENABLE
|
||||
if ((class & CDC_CLASS) == CDC_CLASS) {
|
||||
log_info("add desc cdc");
|
||||
usb_add_desc_config(usb_id, class_index++, cdc_desc_config);
|
||||
cdc_register(usb_id);
|
||||
}
|
||||
#endif
|
||||
|
||||
usb_device_init(usb_id);
|
||||
user_setup_filter_install(usb_id2device(usb_id));
|
||||
return 0;
|
||||
}
|
||||
/* module_initcall(usb_device_mode); */
|
||||
|
||||
static int usb_ep_conflict_check(const usb_dev usb_id)
|
||||
{
|
||||
u8 usb_ep_tx_list[] = {
|
||||
#if TCFG_USB_SLAVE_MSD_ENABLE
|
||||
MSD_BULK_EP_IN,
|
||||
#endif
|
||||
#if TCFG_USB_SLAVE_HID_ENABLE
|
||||
HID_EP_IN,
|
||||
#endif
|
||||
#if TCFG_USB_SLAVE_AUDIO_ENABLE
|
||||
MIC_ISO_EP_IN,
|
||||
#endif
|
||||
#if TCFG_USB_SLAVE_CDC_ENABLE
|
||||
CDC_DATA_EP_IN,
|
||||
#if CDC_INTR_EP_ENABLE
|
||||
CDC_INTR_EP_IN,
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
u8 usb_ep_rx_list[] = {
|
||||
#if TCFG_USB_SLAVE_MSD_ENABLE
|
||||
MSD_BULK_EP_OUT,
|
||||
#endif
|
||||
#if TCFG_USB_SLAVE_HID_ENABLE
|
||||
HID_EP_OUT,
|
||||
#endif
|
||||
#if TCFG_USB_SLAVE_AUDIO_ENABLE
|
||||
SPK_ISO_EP_OUT,
|
||||
#endif
|
||||
#if TCFG_USB_SLAVE_CDC_ENABLE
|
||||
CDC_DATA_EP_OUT,
|
||||
#endif
|
||||
};
|
||||
int ret = 0;
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < sizeof(usb_ep_tx_list) - 1; i++) {
|
||||
for (j = i + 1; j < sizeof(usb_ep_tx_list); j++) {
|
||||
if (usb_ep_tx_list[i] == usb_ep_tx_list[j]) {
|
||||
ret = -1;
|
||||
ASSERT(0, "ep%d conflict, dir in\n", usb_ep_tx_list[i]);
|
||||
goto __exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i = 0; i < sizeof(usb_ep_rx_list) - 1; i++) {
|
||||
for (j = i + 1; j < sizeof(usb_ep_rx_list); j++) {
|
||||
if (usb_ep_rx_list[i] == usb_ep_rx_list[j]) {
|
||||
ret = -1;
|
||||
ASSERT(0, "ep%d conflict, dir out\n", usb_ep_rx_list[i]);
|
||||
goto __exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
__exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* @brief otg检测中sof初始化,不要放在TCFG_USB_SLAVE_ENABLE里
|
||||
* @parm id usb设备号
|
||||
* @return 0 ,忽略sof检查,1 等待sof信号
|
||||
*/
|
||||
u32 usb_otg_sof_check_init(const usb_dev id)
|
||||
{
|
||||
/* return 0;// */
|
||||
u8 *ep0_dma_buffer = usb_alloc_ep_dmabuffer(id, 0, 64);
|
||||
|
||||
usb_g_sie_init(id);
|
||||
|
||||
#ifdef USB_HW_20
|
||||
//husb调用完usb_g_sie_init(),或者收到usb reset中断,intrusbe,intrtxe,
|
||||
//intrrxe会复位成默认值,不手动清零以及关中断,会收到usb reset中断,由于
|
||||
//空指针问题导致异常
|
||||
usb_write_intr_usbe(id, 0);
|
||||
usb_clr_intr_txe(id, -1);
|
||||
usb_clr_intr_rxe(id, -1);
|
||||
if (id == 0) {
|
||||
unrequest_irq(IRQ_USB_CTRL_IDX);
|
||||
#if USB_MAX_HW_NUM > 1
|
||||
} else {
|
||||
unrequest_irq(IRQ_USB1_CTRL_IDX);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(FUSB_MODE) && FUSB_MODE
|
||||
usb_write_power(id, 0x40);
|
||||
#elif defined(FUSB_MODE) && (FUSB_MODE == 0)
|
||||
usb_write_power(id, 0x60);
|
||||
#endif
|
||||
|
||||
usb_set_dma_raddr(id, 0, ep0_dma_buffer);
|
||||
|
||||
for (int ep = 1; ep < USB_MAX_HW_EPNUM; ep++) {
|
||||
usb_disable_ep(id, ep);
|
||||
}
|
||||
usb_sof_clr_pnd(id);
|
||||
return 1;
|
||||
}
|
||||
223
apps/common/device/usb/device/user_setup.c
Normal file
223
apps/common/device/usb/device/user_setup.c
Normal file
@ -0,0 +1,223 @@
|
||||
#include "usb/device/usb_stack.h"
|
||||
#include "usb_config.h"
|
||||
#include "usb/device/msd.h"
|
||||
#include "usb/scsi.h"
|
||||
#include "usb/device/hid.h"
|
||||
#include "usb/device/uac_audio.h"
|
||||
#include "irq.h"
|
||||
#include "init.h"
|
||||
#include "gpio.h"
|
||||
#include "app_config.h"
|
||||
|
||||
#if TCFG_USB_APPLE_DOCK_EN
|
||||
#include "apple_dock/iAP.h"
|
||||
#endif
|
||||
|
||||
#define LOG_TAG_CONST USB
|
||||
#define LOG_TAG "[USB]"
|
||||
#define LOG_ERROR_ENABLE
|
||||
#define LOG_DEBUG_ENABLE
|
||||
#define LOG_INFO_ENABLE
|
||||
/* #define LOG_DUMP_ENABLE */
|
||||
#define LOG_CLI_ENABLE
|
||||
#include "debug.h"
|
||||
|
||||
#if TCFG_USB_SLAVE_ENABLE
|
||||
|
||||
static const u8 user_stirng[] = {
|
||||
24,
|
||||
0x03,
|
||||
'U', 0x00,
|
||||
'S', 0x00,
|
||||
'B', 0x00,
|
||||
'A', 0x00,
|
||||
'u', 0x00,
|
||||
'd', 0x00,
|
||||
'i', 0x00,
|
||||
'o', 0x00,
|
||||
'1', 0x00,
|
||||
'.', 0x00,
|
||||
'0', 0x00,
|
||||
};
|
||||
|
||||
#if TCFG_USB_APPLE_DOCK_EN
|
||||
static const u8 IAP_interface_string[] = {
|
||||
0x1c, 0x03,
|
||||
//iAP Interface
|
||||
0x69, 0x00, 0x41, 0x00, 0x50, 0x00, 0x20, 0x00, 0x49, 0x00, 0x6e, 0x00, 0x74, 0x00,
|
||||
0x65, 0x00, 0x72, 0x00, 0x66, 0x00, 0x61, 0x00, 0x63, 0x00, 0x65, 0x00
|
||||
};
|
||||
#endif
|
||||
|
||||
static u8 root2_testing;
|
||||
u32 usb_root2_testing()
|
||||
{
|
||||
#if USB_ROOT2
|
||||
return root2_testing;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
u32 check_ep_vaild(u32 ep)
|
||||
{
|
||||
u32 en = 0;
|
||||
switch (ep) {
|
||||
case 0:
|
||||
en = 1;
|
||||
break;
|
||||
#if TCFG_USB_SLAVE_MSD_ENABLE
|
||||
case 1:
|
||||
en = 1;
|
||||
break;
|
||||
#endif
|
||||
#if TCFG_USB_SLAVE_HID_ENABLE
|
||||
case 2:
|
||||
en = 1;
|
||||
break;
|
||||
#endif
|
||||
#if TCFG_USB_SLAVE_AUDIO_ENABLE
|
||||
case 3:
|
||||
en = 1;
|
||||
break;
|
||||
#endif
|
||||
case 4:
|
||||
break;
|
||||
}
|
||||
return en;
|
||||
}
|
||||
static u32 setup_endpoint(struct usb_device_t *usb_device, struct usb_ctrlrequest *req)
|
||||
{
|
||||
const usb_dev usb_id = usb_device2id(usb_device);
|
||||
u32 tx_len = 0;
|
||||
u8 *tx_payload = usb_get_setup_buffer(usb_device);
|
||||
|
||||
#if TCFG_USB_SLAVE_AUDIO_ENABLE
|
||||
if (uac_setup_endpoint(usb_device, req)) {
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
u32 ep = LOBYTE(req->wIndex) & 0x0f;
|
||||
if (check_ep_vaild(ep) == 0) {
|
||||
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
|
||||
return 1;// not zero user handle this request
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
static u32 setup_device(struct usb_device_t *usb_device, struct usb_ctrlrequest *req)
|
||||
{
|
||||
const usb_dev usb_id = usb_device2id(usb_device);
|
||||
u32 ret = 0;
|
||||
switch (req->bRequest) {
|
||||
case USB_REQ_GET_DESCRIPTOR:
|
||||
switch (HIBYTE(req->wValue)) {
|
||||
case USB_DT_STRING:
|
||||
switch (LOBYTE(req->wValue)) {
|
||||
#if TCFG_USB_SLAVE_AUDIO_ENABLE
|
||||
case SPEAKER_STR_INDEX:
|
||||
case MIC_STR_INDEX:
|
||||
if (usb_device->bDeviceStates == USB_DEFAULT) {
|
||||
ret = 0;
|
||||
} else {
|
||||
usb_set_data_payload(usb_device, req, user_stirng, sizeof(user_stirng));
|
||||
ret = 1;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#if TCFG_USB_APPLE_DOCK_EN
|
||||
case MSD_STR_INDEX:
|
||||
if (apple_mfi_chip_online_lib()) {
|
||||
y_printf("MSD_STR_INDEX \n");
|
||||
usb_set_data_payload(usb_device, req, IAP_interface_string, sizeof(IAP_interface_string));
|
||||
apple_mfi_pass_ready_set_api();
|
||||
extern void apple_usb_msd_wakeup(struct usb_device_t *usb_device);
|
||||
apple_usb_msd_wakeup(usb_device);
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case USB_DT_DEVICE:
|
||||
#if USB_ROOT2
|
||||
if (req->wLength == 0xffff) {
|
||||
root2_testing = 1;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case USB_REQ_SET_CONFIGURATION:
|
||||
break;
|
||||
case USB_REQ_SET_ADDRESS:
|
||||
/* if(req->wLength || req->wIndex){ */
|
||||
/* ret = 1; */
|
||||
/* usb_set_setup_phase(usb_device, USB_EP0_SET_STALL); */
|
||||
/* dump_setup_request(req); */
|
||||
/* log_debug_hexdump((u8 *)req, 8); */
|
||||
/* } */
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static u32 setup_other(struct usb_device_t *usb_device, struct usb_ctrlrequest *req)
|
||||
{
|
||||
u32 ret = 0;
|
||||
u32 tx_len;
|
||||
u8 *tx_payload = usb_get_setup_buffer(usb_device);
|
||||
switch (req->bRequest) {
|
||||
case USB_REQ_GET_STATUS:
|
||||
#if TCFG_TYPEC_EARPHONE_TEST_FILTER
|
||||
tx_len = 1;
|
||||
tx_payload[0] = 0xfe;
|
||||
usb_set_data_payload(usb_device, req, tx_payload, tx_len);
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
ret = 1 ;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
static u32 user_setup_filter(struct usb_device_t *usb_device, struct usb_ctrlrequest *request)
|
||||
{
|
||||
// dump_setup_request(request);
|
||||
// log_debug_hexdump((u8 *)request, 8);
|
||||
u32 ret = 0;
|
||||
u32 recip = request->bRequestType & USB_RECIP_MASK;
|
||||
switch (recip) {
|
||||
case USB_RECIP_DEVICE:
|
||||
ret = setup_device(usb_device, request);
|
||||
break;
|
||||
case USB_RECIP_INTERFACE:
|
||||
break;
|
||||
case USB_RECIP_ENDPOINT:
|
||||
ret = setup_endpoint(usb_device, request);
|
||||
break;
|
||||
case USB_RECIP_OTHER:
|
||||
ret = setup_other(usb_device, request);
|
||||
break;
|
||||
}
|
||||
#if 0
|
||||
const char *statas[] = {"USB_ATTACHED", "USB_POWERED", "USB_DEFAULT",
|
||||
"USB_ADDRESS", "USB_CONFIGURED", "USB_SUSPENDED"
|
||||
};
|
||||
|
||||
const char *phases[] = {"SETUP", "IN", "OUT",
|
||||
"STALL",
|
||||
};
|
||||
|
||||
printf("state:%s phase: %s", statas[usb_device->bDeviceStates],
|
||||
phases[usb_device->bsetup_phase]);
|
||||
#endif
|
||||
return ret;// not zero user handle this request
|
||||
}
|
||||
void user_setup_filter_install(struct usb_device_t *usb_device)
|
||||
{
|
||||
usb_set_setup_hook(usb_device, user_setup_filter);
|
||||
}
|
||||
#endif
|
||||
459
apps/common/device/usb/host/adb.c
Normal file
459
apps/common/device/usb/host/adb.c
Normal file
@ -0,0 +1,459 @@
|
||||
#include "includes.h"
|
||||
#include "asm/includes.h"
|
||||
#include "system/timer.h"
|
||||
#include "device/ioctl_cmds.h"
|
||||
#include "usb/host/usb_host.h"
|
||||
#include "usb_ctrl_transfer.h"
|
||||
#include "usb_bulk_transfer.h"
|
||||
#include "device_drive.h"
|
||||
#include "adb.h"
|
||||
#include "usb_config.h"
|
||||
#include "app_config.h"
|
||||
#if TCFG_ADB_ENABLE
|
||||
#define LOG_TAG_CONST USB
|
||||
#define LOG_TAG "[adb]"
|
||||
#define LOG_ERROR_ENABLE
|
||||
#define LOG_DEBUG_ENABLE
|
||||
#define LOG_INFO_ENABLE
|
||||
/* #define LOG_DUMP_ENABLE */
|
||||
#define LOG_CLI_ENABLE
|
||||
#include "debug.h"
|
||||
|
||||
|
||||
#include "adb_rsa_key.c"
|
||||
|
||||
struct adb_device_t adb;
|
||||
|
||||
struct device adb_device;
|
||||
void aoa_switch(struct usb_host_device *host_dev);
|
||||
|
||||
static int set_adb_power(struct usb_host_device *host_dev, u32 value)
|
||||
{
|
||||
return DEV_ERR_NONE;
|
||||
}
|
||||
|
||||
static int get_adb_power(struct usb_host_device *host_dev, u32 value)
|
||||
{
|
||||
return DEV_ERR_NONE;
|
||||
}
|
||||
|
||||
static const struct interface_ctrl adb_ops = {
|
||||
.interface_class = USB_CLASS_ADB,
|
||||
.set_power = set_adb_power,
|
||||
.get_power = get_adb_power,
|
||||
.ioctl = NULL,
|
||||
};
|
||||
|
||||
static const struct usb_interface_info adb_inf = {
|
||||
.ctrl = (struct interface_ctrl *) &adb_ops,
|
||||
.dev.adb = &adb,
|
||||
};
|
||||
|
||||
u32 usb_adb_interface_ptp_mtp_parse(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf)
|
||||
{
|
||||
struct usb_interface_descriptor *interface = (struct usb_interface_descriptor *)pBuf;
|
||||
pBuf += sizeof(struct usb_interface_descriptor);
|
||||
int len = 0;
|
||||
const usb_dev usb_id = host_device2id(host_dev);
|
||||
|
||||
for (int i = 0; i < interface->bNumEndpoints; i++) {
|
||||
struct usb_endpoint_descriptor *endpoint = (struct usb_endpoint_descriptor *)pBuf;
|
||||
if (endpoint->bDescriptorType == USB_DT_ENDPOINT) {
|
||||
if (endpoint->bmAttributes == USB_ENDPOINT_XFER_BULK) {
|
||||
if (endpoint->bEndpointAddress & USB_DIR_IN) {
|
||||
adb.extr_in = endpoint->bEndpointAddress & 0xf;
|
||||
} else {
|
||||
adb.extr_out = endpoint->bEndpointAddress;
|
||||
}
|
||||
}
|
||||
pBuf += USB_DT_ENDPOINT_SIZE;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
printf("%s() %x %x\n", __func__, adb.extr_in, adb.extr_out);
|
||||
return pBuf - (u8 *)interface ;
|
||||
}
|
||||
|
||||
int usb_adb_parser(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf)
|
||||
{
|
||||
struct usb_interface_descriptor *interface = (struct usb_interface_descriptor *)pBuf;
|
||||
pBuf += sizeof(struct usb_interface_descriptor);
|
||||
int len = 0;
|
||||
const usb_dev usb_id = host_device2id(host_dev);
|
||||
|
||||
adb_device.private_data = host_dev;
|
||||
|
||||
host_dev->interface_info[interface_num] = &adb_inf;
|
||||
|
||||
for (int endnum = 0; endnum < interface->bNumEndpoints; endnum++) {
|
||||
struct usb_endpoint_descriptor *end_desc = (struct usb_endpoint_descriptor *)pBuf;
|
||||
|
||||
if (end_desc->bDescriptorType != USB_DT_ENDPOINT ||
|
||||
end_desc->bLength != USB_DT_ENDPOINT_SIZE) {
|
||||
log_error("ep bDescriptorType = %d bLength = %d", end_desc->bDescriptorType, end_desc->bLength);
|
||||
return -USB_DT_ENDPOINT;
|
||||
}
|
||||
|
||||
len += USB_DT_ENDPOINT_SIZE;
|
||||
pBuf += USB_DT_ENDPOINT_SIZE;
|
||||
|
||||
if ((end_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) {
|
||||
if (end_desc->bEndpointAddress & USB_DIR_IN) {
|
||||
adb.host_epin = usb_get_ep_num(usb_id, USB_DIR_IN, USB_ENDPOINT_XFER_BULK);
|
||||
adb.target_epin = end_desc->bEndpointAddress & 0x0f;
|
||||
#if defined(FUSB_MODE) && FUSB_MODE == 0
|
||||
adb.rxmaxp = end_desc->wMaxPacketSize;
|
||||
#endif
|
||||
log_debug("D(%d)->H(%d)", adb.target_epin, adb.host_epin);
|
||||
} else {
|
||||
adb.host_epout = usb_get_ep_num(usb_id, USB_DIR_OUT, USB_ENDPOINT_XFER_BULK);
|
||||
adb.target_epout = end_desc->bEndpointAddress & 0x0f;
|
||||
#if defined(FUSB_MODE) && FUSB_MODE == 0
|
||||
adb.txmaxp = end_desc->wMaxPacketSize;
|
||||
#endif
|
||||
log_debug("H(%d)->D(%d)", adb.host_epout, adb.target_epout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u8 *ep_buffer = usb_h_get_ep_buffer(usb_id, adb.host_epin | USB_DIR_IN);
|
||||
usb_h_ep_config(usb_id, adb.host_epin | USB_DIR_IN, USB_ENDPOINT_XFER_BULK, 0, 0, ep_buffer, 64);
|
||||
|
||||
|
||||
ep_buffer = usb_h_get_ep_buffer(usb_id, adb.host_epout | USB_DIR_OUT);
|
||||
usb_h_ep_config(usb_id, adb.host_epout | USB_DIR_OUT, USB_ENDPOINT_XFER_BULK, 0, 0, ep_buffer, 64);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int adb_send_packet(struct amessage *msg, const u8 *data_ptr)
|
||||
{
|
||||
if (msg == NULL) {
|
||||
return usb_bulk_only_send(&adb_device, adb.host_epout, 64, adb.target_epout, NULL, 0);
|
||||
}
|
||||
u32 cnt;
|
||||
u32 count = msg->data_length;
|
||||
|
||||
msg->magic = msg->command ^ 0xffffffff;
|
||||
const u8 *_data_ptr = data_ptr;
|
||||
msg->data_check = 0;
|
||||
while (count--) {
|
||||
msg->data_check += *_data_ptr++;
|
||||
}
|
||||
int ret = usb_bulk_only_send(&adb_device, adb.host_epout, 64, adb.target_epout, (u8 *)msg, sizeof(*msg));
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
if (data_ptr != NULL) {
|
||||
return usb_bulk_only_send(&adb_device, adb.host_epout, 64, adb.target_epout, data_ptr, msg->data_length);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
static int adb_recv(u8 *buffer, u32 len, u32 timeout)
|
||||
{
|
||||
return usb_bulk_only_receive(&adb_device, adb.host_epin, 64, adb.target_epin, buffer, len);
|
||||
}
|
||||
#define check_usb_status(ret) do{\
|
||||
if(ret < 0){\
|
||||
log_info("%s() @ %d %d\n", __func__, __LINE__, ret);\
|
||||
return ret;\
|
||||
}\
|
||||
}while(0);
|
||||
|
||||
static u8 adb_signatrue_data_index ;
|
||||
|
||||
u32 adb_auth()
|
||||
{
|
||||
log_info("%s() %d\n", __func__, __LINE__);
|
||||
struct amessage msg;
|
||||
int ret = 0;
|
||||
u8 *cmd_string;
|
||||
adb.local_id = 0x58525047;
|
||||
adb.remote_id = 0;
|
||||
msg.command = A_CNXN;
|
||||
msg.arg0 = A_VERSION;
|
||||
msg.arg1 = 0x00001000;
|
||||
cmd_string = (u8 *)"host::";
|
||||
msg.data_length = strlen((const char *)cmd_string) + 1;
|
||||
ret = adb_send_packet(&msg, cmd_string);
|
||||
check_usb_status(ret);
|
||||
memset(&msg, 0, 24);
|
||||
ret = adb_recv((u8 *)&msg, 24, 5);
|
||||
check_usb_status(ret);
|
||||
|
||||
if (msg.command == A_CNXN) {
|
||||
if (adb_recv(adb.buffer, msg.data_length, 1 * 100)) {
|
||||
log_error("auth error 0\n");
|
||||
return 0;
|
||||
}
|
||||
log_info("auth not send rsa pub key\n");
|
||||
return 0;
|
||||
} else if (msg.command == A_AUTH) {
|
||||
|
||||
} else {
|
||||
log_error("auth error 1\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
ret = adb_recv(adb.buffer, msg.data_length, 1 * 100);
|
||||
check_usb_status(ret);
|
||||
msg.command = A_AUTH;
|
||||
msg.arg0 = ADB_AUTH_SIGNATURE;
|
||||
msg.data_length = sizeof(adb_signatrue_data[0]);
|
||||
if (adb_signatrue_data_index > 2) {
|
||||
adb_signatrue_data_index = 0;
|
||||
}
|
||||
|
||||
adb_signatrue_data_index ++;
|
||||
cmd_string = (u8 *)&adb_signatrue_data[adb_signatrue_data_index][0];
|
||||
ret = adb_send_packet(&msg, cmd_string);
|
||||
check_usb_status(ret);
|
||||
|
||||
ret = adb_send_packet(NULL, NULL);//zero packet
|
||||
check_usb_status(ret);
|
||||
|
||||
memset(&msg, 0, 24);
|
||||
ret = adb_recv((u8 *)&msg, 24, 1 * 100);
|
||||
check_usb_status(ret);
|
||||
if (msg.command != A_AUTH) {
|
||||
log_error("auth error 2\n");
|
||||
return 1;
|
||||
}
|
||||
ret = adb_recv(adb.buffer, msg.data_length, 1 * 100);
|
||||
check_usb_status(ret);
|
||||
|
||||
|
||||
__RETRY:
|
||||
msg.command = A_AUTH;
|
||||
msg.arg0 = ADB_AUTH_RSAPUBLICKEY;
|
||||
msg.arg1 = 0;
|
||||
msg.data_length = sizeof(adb_rsa_pub_key);
|
||||
ret = adb_send_packet(&msg, (u8 *)adb_rsa_pub_key);
|
||||
check_usb_status(ret);
|
||||
|
||||
ret = adb_recv((u8 *)&msg, 24, 30 * 100);
|
||||
|
||||
if (ret < 0) {
|
||||
if (ret == -DEV_ERR_TIMEOUT) {
|
||||
goto __RETRY;
|
||||
}
|
||||
check_usb_status(ret);
|
||||
}
|
||||
|
||||
ret = adb_recv(adb.buffer, msg.data_length, 1 * 100);//最长等待30s,等手机点击确认授权adb
|
||||
if (ret < 0) {
|
||||
if (ret == -DEV_ERR_TIMEOUT) {
|
||||
goto __RETRY;
|
||||
}
|
||||
check_usb_status(ret);
|
||||
}
|
||||
|
||||
if (msg.command == A_AUTH) {
|
||||
goto __RETRY;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 adb_shell_login()
|
||||
{
|
||||
log_info("%s() %d\n", __func__, __LINE__);
|
||||
struct amessage msg;
|
||||
u8 *cmd_string;
|
||||
/* __AUTH_SUCCESS: */
|
||||
|
||||
cmd_string = (u8 *)"shell:";
|
||||
msg.command = A_OPEN;
|
||||
msg.arg0 = adb.local_id;
|
||||
msg.arg1 = 0;
|
||||
msg.data_length = strlen((char const *)cmd_string) + 1;
|
||||
int ret = adb_send_packet(&msg, cmd_string);
|
||||
check_usb_status(ret);
|
||||
|
||||
memset(&msg, 0, 24);
|
||||
ret = adb_recv((u8 *)&msg, 24, 1 * 100);
|
||||
check_usb_status(ret);
|
||||
|
||||
if (msg.command != A_OKAY) {
|
||||
log_error("A_OKAY error\n");
|
||||
return 4;
|
||||
}
|
||||
|
||||
ret = adb_recv((u8 *)&msg, 24, 1 * 100);
|
||||
check_usb_status(ret);
|
||||
if (msg.command != A_WRTE) {
|
||||
log_error("A_WRTE error\n");
|
||||
return 5;
|
||||
}
|
||||
adb.remote_id = msg.arg0;
|
||||
|
||||
ret = adb_recv(adb.buffer, msg.data_length, 1 * 100);
|
||||
check_usb_status(ret);
|
||||
|
||||
msg.command = A_OKAY;
|
||||
msg.arg0 = adb.local_id;
|
||||
msg.arg1 = adb.remote_id;
|
||||
msg.data_length = 0;
|
||||
ret = adb_send_packet(&msg, NULL);
|
||||
check_usb_status(ret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 adb_ex_cmd(const char *cmd_string, u8 *echo_buffer, u32 max_len)
|
||||
{
|
||||
log_info("%s\n", cmd_string);
|
||||
int ret;
|
||||
struct amessage msg;
|
||||
msg.command = A_WRTE;
|
||||
msg.arg0 = adb.local_id;
|
||||
msg.arg1 = adb.remote_id;
|
||||
msg.data_length = strlen(cmd_string);
|
||||
ret = adb_send_packet(&msg, (u8 *)cmd_string);
|
||||
check_usb_status(ret);
|
||||
memset(&msg, 0, 24);
|
||||
memset(echo_buffer, 0, max_len);
|
||||
ret = adb_recv((u8 *)&msg, sizeof(msg), 3 * 100);
|
||||
check_usb_status(ret);
|
||||
|
||||
if (msg.command != A_OKAY) {
|
||||
return true;
|
||||
}
|
||||
u32 offset = 0;
|
||||
do {
|
||||
ret = adb_recv((u8 *)&msg, sizeof(msg), 3 * 100);
|
||||
check_usb_status(ret);
|
||||
if (msg.command != A_WRTE) {
|
||||
log_info("command %x\n", msg.command);
|
||||
return true;
|
||||
}
|
||||
if ((offset + msg.data_length) > max_len) {
|
||||
log_info("%s", echo_buffer);
|
||||
echo_buffer[offset] = 0;
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
ret = adb_recv(&echo_buffer[offset], msg.data_length, 3 * 100);
|
||||
check_usb_status(ret);
|
||||
offset += msg.data_length;
|
||||
|
||||
if (msg.data_length == 0) {
|
||||
log_info("no data_length\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (offset >= max_len) {
|
||||
|
||||
}
|
||||
/* echo_buffer[offset] = '\n'; */
|
||||
echo_buffer[offset] = 0;
|
||||
|
||||
if (echo_buffer[offset - 2] == 0x24 && echo_buffer[offset - 1] == 0x20) {
|
||||
/* puts("end\n"); */
|
||||
break;
|
||||
} else if (echo_buffer[offset - 2] == 0x23 && echo_buffer[offset - 1] == 0x20) {
|
||||
/* puts("end 1\n"); */
|
||||
break;
|
||||
}
|
||||
msg.command = A_OKAY;
|
||||
msg.arg0 = adb.local_id;
|
||||
msg.arg1 = adb.remote_id;
|
||||
msg.data_length = 0;
|
||||
ret = adb_send_packet(&msg, NULL);
|
||||
check_usb_status(ret);
|
||||
|
||||
} while (1);
|
||||
|
||||
msg.command = A_OKAY;
|
||||
msg.arg0 = adb.local_id;
|
||||
msg.arg1 = adb.remote_id;
|
||||
msg.data_length = 0;
|
||||
/* puts("exit\n"); */
|
||||
return adb_send_packet(&msg, NULL);
|
||||
|
||||
}
|
||||
#define APP_ACTIVITY_PATH "com.zh-jieli.gmaeCenter/com.zh-jieli.gameCenter.activity.guide.SplashActivity\n"
|
||||
#define APP_WEBSITE "http://www.zh-jieli.com\n"
|
||||
#define APP_BASH_IN_PATH "/sdcard/jilei/active.bash"
|
||||
#define APP_BASH_OUT_PATH "/data/local/tmp/active.bash"
|
||||
|
||||
u32 adb_game_active()
|
||||
{
|
||||
log_info("%s() %d\n", __func__, __LINE__);
|
||||
u32 max_len = adb.max_len;;
|
||||
u8 *adb_buffer = adb.buffer;
|
||||
//1,启动app
|
||||
adb_ex_cmd("am start -n " APP_ACTIVITY_PATH, adb_buffer, max_len);
|
||||
puts((char *)adb_buffer);
|
||||
//查找Error字符串,如果找到跳转网页下载app,否则执行adb指令
|
||||
if (strstr((const char *)adb_buffer, "Error") != NULL) {
|
||||
adb_ex_cmd("am start -a android.intent.action.VIEW -d " APP_WEBSITE, adb_buffer, max_len);
|
||||
puts((char *)adb_buffer);
|
||||
} else {
|
||||
adb_ex_cmd("dd if=" APP_BASH_IN_PATH " of=" APP_BASH_OUT_PATH "\n", adb_buffer, max_len);
|
||||
puts((char *)adb_buffer);
|
||||
adb_ex_cmd("chown shell " APP_BASH_OUT_PATH";chmod 777 "APP_BASH_OUT_PATH "\n", adb_buffer, max_len);
|
||||
puts((char *)adb_buffer);
|
||||
adb_ex_cmd("trap \"\" HUP;sh "APP_BASH_OUT_PATH "&\n", adb_buffer, max_len);
|
||||
puts((char *)adb_buffer);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
static void mtp_ptp_open_session(u32 is_mtp)
|
||||
{
|
||||
/* usbh_bulk_send_blocking(ADB_HOST_EP, adb_device.extr_out, (u8 *)_open_session, 16); */
|
||||
/* usbh_request_bulk_blocking(ADB_HOST_EP, adb_device.extr_in, get_data_buffer(), 12, 3); */
|
||||
|
||||
/* usbh_bulk_send_blocking(ADB_HOST_EP, adb_device.extr_out, (u8 *)get_device_info, sizeof(get_device_info)); */
|
||||
/* usbh_request_bulk_blocking(ADB_HOST_EP, adb_device.extr_in, get_data_buffer(), 512, 3); */
|
||||
|
||||
/* usbh_request_bulk_blocking(ADB_HOST_EP, adb_device.extr_in, get_data_buffer(), 12, 3); */
|
||||
}
|
||||
|
||||
static void adb_open_session()
|
||||
{
|
||||
struct usb_host_device *host_dev = adb_device.private_data;
|
||||
if (adb.extr_in && adb.extr_out) {
|
||||
get_ms_extended_compat_id(host_dev, adb.buffer);
|
||||
get_device_status(host_dev);
|
||||
get_config_descriptor(host_dev, adb.buffer, 0xff);
|
||||
/* mtp_ptp_open_session(ac6921_data_buffer[0x12] == 0x4d); */
|
||||
}
|
||||
}
|
||||
u32 adb_process()
|
||||
{
|
||||
adb.max_len = 1024;
|
||||
adb.buffer = malloc(adb.max_len);
|
||||
os_time_dly(20);
|
||||
do {
|
||||
|
||||
adb_open_session();
|
||||
|
||||
if (adb_auth()) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (adb_shell_login()) {
|
||||
break;
|
||||
}
|
||||
|
||||
adb_game_active();
|
||||
log_info("adb active succ");
|
||||
return 0;
|
||||
|
||||
} while (0);
|
||||
|
||||
free(adb.buffer);
|
||||
|
||||
|
||||
log_info("adb active error");
|
||||
return 1;
|
||||
}
|
||||
void adb_switch_aoa(u32 id)
|
||||
{
|
||||
struct usb_host_device *host_dev = adb_device.private_data;
|
||||
aoa_switch(host_dev);
|
||||
/* usb_host_remount(id, 3, 30, 50, 1); */
|
||||
}
|
||||
#endif //TCFG_ADB_ENABLE
|
||||
73
apps/common/device/usb/host/adb.h
Normal file
73
apps/common/device/usb/host/adb.h
Normal file
@ -0,0 +1,73 @@
|
||||
#ifndef __ADB_H__
|
||||
#define __ADB_H__
|
||||
|
||||
#include "system/task.h"
|
||||
#include "device/device.h"
|
||||
#include "usb/scsi.h"
|
||||
#include "usb_bulk_transfer.h"
|
||||
#include "usb/host/usb_host.h"
|
||||
struct adb_device_t {
|
||||
u32 local_id;
|
||||
u32 remote_id;
|
||||
void *buffer;
|
||||
u32 max_len;
|
||||
|
||||
u8 target_epin;
|
||||
u8 target_epout;
|
||||
u8 host_epin;
|
||||
u8 host_epout;
|
||||
|
||||
u8 extr_in;
|
||||
u8 extr_out;
|
||||
};
|
||||
u32 usb_adb_interface_ptp_mtp_parse(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf);
|
||||
int usb_adb_parser(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf);
|
||||
u32 adb_process();
|
||||
void adb_switch_aoa(u32 id);
|
||||
|
||||
#if 1
|
||||
#define A_SYNC 0x434e5953
|
||||
#define A_CNXN 0x4e584e43
|
||||
#define A_OPEN 0x4e45504f
|
||||
#define A_OKAY 0x59414b4f
|
||||
#define A_CLSE 0x45534c43
|
||||
#define A_WRTE 0x45545257
|
||||
#define A_AUTH 0x48545541
|
||||
//#define S_ID_LOCAL 0x00003456
|
||||
/* AUTH packets first argument */
|
||||
/* Request */
|
||||
#define ADB_AUTH_TOKEN 1
|
||||
/* Response */
|
||||
#define ADB_AUTH_SIGNATURE 2
|
||||
#define ADB_AUTH_RSAPUBLICKEY 3
|
||||
|
||||
#define A_VERSION 0x01000000 // ADB protocol version
|
||||
|
||||
#define ADB_VERSION_MAJOR 1 // Used for help/version information
|
||||
#define ADB_VERSION_MINOR 0 // Used for help/version information
|
||||
|
||||
#else
|
||||
#define A_SYNC 0x53594e43
|
||||
#define A_CNXN 0x434e584e
|
||||
#define A_OPEN 0x4f50454e
|
||||
#define A_OKAY 0x4f4b4159
|
||||
#define A_CLSE 0x434c5345
|
||||
#define A_WRTE 0x57525445
|
||||
|
||||
#define A_VERSION 0x00000001 // ADB protocol version
|
||||
|
||||
#define ADB_VERSION_MAJOR 1 // Used for help/version information
|
||||
#define ADB_VERSION_MINOR 0 // Used for help/version information
|
||||
|
||||
#endif
|
||||
|
||||
struct amessage {
|
||||
unsigned long int command; /* command identifier constant */
|
||||
unsigned long int arg0; /* first argument */
|
||||
unsigned long int arg1; /* second argument */
|
||||
unsigned long int data_length; /* length of payload (0 is allowed) */
|
||||
unsigned long int data_check; /* checksum of data payload */
|
||||
unsigned long int magic; /* command ^ 0xffffffff */
|
||||
};
|
||||
|
||||
#endif /*ADB_H*/
|
||||
115
apps/common/device/usb/host/adb_rsa_key.c
Normal file
115
apps/common/device/usb/host/adb_rsa_key.c
Normal file
@ -0,0 +1,115 @@
|
||||
#include "typedef.h"
|
||||
#include "app_config.h"
|
||||
#if TCFG_ADB_ENABLE
|
||||
static const u8 _open_session[] = {
|
||||
0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00
|
||||
};
|
||||
static const u8 get_device_info[] = {
|
||||
0x0C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
|
||||
static const u8 adb_signatrue_data[][256] = {
|
||||
{
|
||||
0xFA, 0xA6, 0xE3, 0x50, 0x3C, 0xC4, 0x95, 0xFE, 0xBB, 0x46, 0xE0, 0x9F, 0xD9, 0x9A, 0x18, 0xC1,
|
||||
0x28, 0x67, 0xA9, 0x46, 0xF8, 0x20, 0xBF, 0xDB, 0xFE, 0x6B, 0xC8, 0xC4, 0x0A, 0x09, 0xFA, 0x9A,
|
||||
0xCD, 0x51, 0xE3, 0x67, 0xD1, 0xDF, 0xD2, 0x92, 0xD3, 0x9E, 0xFA, 0x17, 0x76, 0x01, 0xF5, 0xE2,
|
||||
0xBD, 0x64, 0x9C, 0x92, 0x82, 0x4B, 0xE4, 0x27, 0x21, 0x22, 0x1A, 0x70, 0x99, 0x8F, 0xC5, 0xD5,
|
||||
0xE2, 0x02, 0x2C, 0xA4, 0x13, 0x08, 0x1E, 0x42, 0x83, 0x5C, 0x7E, 0x3C, 0x1F, 0x97, 0x1B, 0xAF,
|
||||
0x6F, 0x7E, 0x4F, 0xAB, 0xDA, 0x6A, 0x61, 0x56, 0x03, 0x79, 0xB5, 0xF0, 0x97, 0xEE, 0xEC, 0x88,
|
||||
0x6F, 0x9E, 0x8D, 0x41, 0xE2, 0x13, 0x9B, 0x21, 0xEE, 0x6F, 0x09, 0x81, 0x62, 0xC1, 0xB5, 0xE7,
|
||||
0xC2, 0x5C, 0x4A, 0x8C, 0x39, 0xAA, 0x50, 0x08, 0x48, 0xB5, 0x1D, 0xF6, 0x7C, 0x67, 0xD6, 0x39,
|
||||
0x63, 0x7E, 0x5E, 0x49, 0x3D, 0x9B, 0x49, 0x4B, 0x67, 0x8E, 0x06, 0x31, 0x07, 0x4E, 0x56, 0x8A,
|
||||
0xC4, 0x9D, 0x84, 0xA9, 0xF4, 0xFC, 0xE3, 0x2D, 0x1D, 0x2A, 0x98, 0x52, 0x40, 0x49, 0x93, 0x71,
|
||||
0xA7, 0x43, 0x0D, 0x78, 0xEB, 0xFA, 0x49, 0x7A, 0x39, 0xBF, 0xE4, 0x06, 0x08, 0x1B, 0x20, 0x84,
|
||||
0xDC, 0x64, 0xBB, 0xDE, 0x1A, 0x5E, 0x4B, 0xF8, 0x57, 0xBF, 0x9C, 0x8C, 0xB9, 0x1D, 0xEE, 0xB3,
|
||||
0x90, 0x17, 0x03, 0x8B, 0x3E, 0x9F, 0x8A, 0x23, 0xEC, 0x30, 0xA7, 0x24, 0x5E, 0x5B, 0x58, 0xAA,
|
||||
0x5A, 0xAE, 0xE2, 0x14, 0xC1, 0xAE, 0xA3, 0xF9, 0xAF, 0x70, 0xE0, 0x14, 0x7D, 0x73, 0x3B, 0x6D,
|
||||
0x9B, 0x06, 0x2F, 0xAA, 0xFF, 0x7A, 0x2A, 0x56, 0x6F, 0x91, 0x70, 0x6D, 0x4A, 0x18, 0x35, 0x51,
|
||||
0xD5, 0x5D, 0xFB, 0xA1, 0x8B, 0x03, 0xF2, 0x0C, 0x56, 0xF0, 0x5A, 0x4A, 0x08, 0x89, 0xFE, 0x86
|
||||
},
|
||||
{
|
||||
0x60, 0xE6, 0x4A, 0x3D, 0x12, 0xD1, 0x48, 0x25, 0x7D, 0x6E, 0x8E, 0x03, 0xE2, 0xC8, 0xE7, 0x66,
|
||||
0x96, 0xD7, 0xD3, 0xBF, 0xE6, 0x97, 0x13, 0x3A, 0x2D, 0x2B, 0x85, 0xE7, 0xDA, 0x5C, 0x87, 0xD8,
|
||||
0xDC, 0x88, 0xAC, 0xF7, 0xC3, 0xF0, 0x5A, 0xE8, 0x95, 0x66, 0x19, 0xA1, 0xA8, 0x2A, 0xE1, 0x70,
|
||||
0x13, 0xF0, 0x05, 0x59, 0x3D, 0x89, 0x04, 0x65, 0x08, 0x03, 0x9C, 0xDC, 0x71, 0x24, 0xC5, 0x9E,
|
||||
0x4D, 0x82, 0xD8, 0x72, 0x07, 0xFD, 0x8F, 0xD3, 0x37, 0x56, 0x8C, 0xB6, 0x01, 0xDB, 0x08, 0x5B,
|
||||
0xA3, 0x42, 0x8F, 0xF0, 0xCA, 0xDC, 0x80, 0xEB, 0x32, 0xC4, 0x67, 0x1F, 0x73, 0xAF, 0xF0, 0x56,
|
||||
0xBC, 0x89, 0x72, 0xB1, 0x7D, 0xDA, 0xA4, 0x79, 0x7D, 0x02, 0x35, 0x38, 0xBA, 0xA0, 0x36, 0xFE,
|
||||
0x5A, 0x70, 0x93, 0xF5, 0x10, 0x7A, 0x92, 0xE9, 0xD4, 0xB0, 0xED, 0xF3, 0x00, 0xD0, 0x27, 0x79,
|
||||
0x51, 0x54, 0x38, 0x2D, 0x4C, 0xAA, 0x27, 0xEF, 0xA7, 0x8A, 0x34, 0x4E, 0x4B, 0x29, 0x90, 0xC4,
|
||||
0x3E, 0xA8, 0x8D, 0x3D, 0x00, 0xD6, 0x84, 0x11, 0x17, 0x32, 0xD6, 0xE9, 0x33, 0x02, 0xCD, 0x04,
|
||||
0x35, 0x3F, 0x1A, 0xC3, 0x05, 0xCF, 0x6F, 0xF4, 0x39, 0x65, 0xE5, 0x6B, 0x88, 0x1E, 0x25, 0xA1,
|
||||
0xD7, 0xC0, 0x30, 0xE4, 0x0B, 0x2A, 0x61, 0x6D, 0x61, 0xF1, 0x93, 0xAE, 0xC3, 0x42, 0xDC, 0x15,
|
||||
0x1D, 0x87, 0x60, 0x09, 0x92, 0x64, 0xC1, 0x63, 0xAD, 0xCA, 0x36, 0x63, 0x0E, 0x69, 0x51, 0x45,
|
||||
0xD0, 0x18, 0x5E, 0x10, 0x88, 0x7B, 0xD9, 0xDE, 0xA3, 0x12, 0x85, 0xF9, 0x30, 0x01, 0x0A, 0xE1,
|
||||
0x82, 0xD1, 0x49, 0x44, 0xD9, 0x97, 0xE4, 0xF1, 0x55, 0x2D, 0xE2, 0xF3, 0x32, 0xC8, 0xA0, 0xC8,
|
||||
0x81, 0xB9, 0x02, 0x87, 0x5C, 0x19, 0xB7, 0x21, 0x6A, 0xB9, 0xB0, 0x81, 0x61, 0x8C, 0x35, 0x78
|
||||
},
|
||||
{
|
||||
0x0C, 0x7E, 0xDC, 0x78, 0x60, 0x1A, 0xC8, 0x9B, 0x3A, 0x23, 0x0B, 0x1D, 0x6F, 0xAE, 0x71, 0x6D,
|
||||
0xD8, 0x3C, 0xE9, 0xA3, 0x51, 0x90, 0xAA, 0x7B, 0x7E, 0x2F, 0x2B, 0xBD, 0x34, 0xF4, 0x43, 0x3F,
|
||||
0x77, 0xC4, 0x0E, 0x41, 0x04, 0xD9, 0xD4, 0x9C, 0xB3, 0xD2, 0x6B, 0xE1, 0xC6, 0xA8, 0xEF, 0x50,
|
||||
0x00, 0x11, 0xE1, 0x08, 0x8B, 0xB4, 0xF1, 0xE3, 0x3D, 0x56, 0x83, 0x07, 0x7F, 0xB8, 0x47, 0xF2,
|
||||
0x84, 0xD2, 0xA1, 0x50, 0x64, 0x5A, 0x08, 0x42, 0x36, 0x23, 0x09, 0x31, 0x9A, 0x6B, 0x61, 0x6F,
|
||||
0x60, 0x2C, 0xF2, 0x75, 0x4E, 0x6B, 0xB9, 0x15, 0xEE, 0x3C, 0x5E, 0xA2, 0x7F, 0xA0, 0x41, 0xFE,
|
||||
0x00, 0x6A, 0x30, 0x49, 0x2C, 0xEC, 0x17, 0x8B, 0x04, 0x32, 0xE9, 0x7A, 0x68, 0xA0, 0xF4, 0xDF,
|
||||
0x34, 0xF7, 0x1E, 0x6F, 0x19, 0x09, 0x37, 0x87, 0x99, 0xAA, 0x81, 0x1A, 0xCD, 0xF3, 0x1F, 0x89,
|
||||
0x50, 0xB2, 0x17, 0x52, 0x6D, 0x8E, 0xA6, 0x02, 0xC4, 0x2A, 0xAB, 0x3E, 0x5B, 0x38, 0x0C, 0x3F,
|
||||
0x50, 0xAA, 0x5F, 0xFE, 0x47, 0x04, 0xED, 0xCD, 0xEE, 0x7C, 0xD5, 0xED, 0x5F, 0x0E, 0xC6, 0x9C,
|
||||
0x79, 0x10, 0x11, 0x6F, 0x65, 0x58, 0x37, 0x95, 0x54, 0x50, 0x59, 0x68, 0x4C, 0x8E, 0xE7, 0x35,
|
||||
0xF0, 0x96, 0x5A, 0x21, 0x48, 0xB4, 0x53, 0x52, 0xFC, 0xA4, 0x7C, 0x2B, 0xB1, 0xE1, 0x54, 0x2C,
|
||||
0x42, 0x3B, 0x68, 0xBF, 0xBB, 0x68, 0x0D, 0x62, 0x16, 0x2F, 0xF5, 0xC8, 0x5F, 0x95, 0x11, 0xF2,
|
||||
0xDF, 0x03, 0x1E, 0xCB, 0x7C, 0xD0, 0x9C, 0xE9, 0x89, 0x62, 0xEA, 0xC5, 0x4B, 0xA9, 0xD5, 0xCC,
|
||||
0xD2, 0x42, 0x33, 0xA8, 0x7B, 0x2C, 0x56, 0xCF, 0xCE, 0x0D, 0x09, 0x64, 0x62, 0x3F, 0x58, 0x41,
|
||||
0x71, 0x79, 0x5D, 0x1D, 0xDF, 0x08, 0x0B, 0x36, 0x97, 0x16, 0x24, 0x20, 0x76, 0x9C, 0x9E, 0xEA
|
||||
}
|
||||
};
|
||||
static const u8 adb_rsa_pub_key[] = {
|
||||
0x51, 0x41, 0x41, 0x41, 0x41, 0x46, 0x4F, 0x56, 0x4F, 0x6E, 0x49, 0x6C, 0x69, 0x51, 0x58, 0x44,
|
||||
0x73, 0x42, 0x43, 0x42, 0x31, 0x75, 0x6F, 0x68, 0x70, 0x2B, 0x52, 0x71, 0x6E, 0x6E, 0x59, 0x48,
|
||||
0x2F, 0x75, 0x45, 0x58, 0x34, 0x59, 0x6A, 0x50, 0x71, 0x52, 0x4D, 0x35, 0x4B, 0x75, 0x62, 0x56,
|
||||
0x50, 0x71, 0x66, 0x57, 0x35, 0x64, 0x56, 0x46, 0x33, 0x2B, 0x76, 0x57, 0x6B, 0x53, 0x4B, 0x71,
|
||||
0x35, 0x4C, 0x31, 0x42, 0x4F, 0x4E, 0x4D, 0x36, 0x4B, 0x4F, 0x31, 0x69, 0x31, 0x73, 0x69, 0x4F,
|
||||
0x54, 0x69, 0x34, 0x6C, 0x45, 0x30, 0x6F, 0x54, 0x6F, 0x74, 0x30, 0x41, 0x4B, 0x6E, 0x4D, 0x67,
|
||||
0x4E, 0x6A, 0x6F, 0x33, 0x45, 0x4D, 0x65, 0x72, 0x30, 0x6C, 0x57, 0x56, 0x54, 0x54, 0x43, 0x39,
|
||||
0x68, 0x52, 0x66, 0x67, 0x46, 0x65, 0x56, 0x73, 0x43, 0x32, 0x44, 0x74, 0x71, 0x62, 0x61, 0x6D,
|
||||
0x4A, 0x48, 0x63, 0x41, 0x66, 0x59, 0x77, 0x36, 0x54, 0x62, 0x4C, 0x44, 0x6C, 0x4B, 0x70, 0x6A,
|
||||
0x38, 0x34, 0x33, 0x63, 0x31, 0x59, 0x5A, 0x65, 0x59, 0x6D, 0x52, 0x56, 0x4D, 0x7A, 0x4D, 0x34,
|
||||
0x6E, 0x74, 0x49, 0x78, 0x64, 0x56, 0x33, 0x33, 0x76, 0x4B, 0x75, 0x39, 0x38, 0x34, 0x6A, 0x72,
|
||||
0x43, 0x41, 0x47, 0x68, 0x77, 0x4A, 0x41, 0x67, 0x4A, 0x46, 0x53, 0x41, 0x4B, 0x56, 0x59, 0x51,
|
||||
0x55, 0x33, 0x6A, 0x4C, 0x76, 0x41, 0x76, 0x57, 0x45, 0x6C, 0x59, 0x47, 0x37, 0x2F, 0x4B, 0x59,
|
||||
0x6D, 0x55, 0x34, 0x54, 0x71, 0x73, 0x70, 0x64, 0x76, 0x4C, 0x42, 0x6F, 0x65, 0x36, 0x68, 0x64,
|
||||
0x46, 0x44, 0x65, 0x76, 0x4D, 0x4D, 0x43, 0x63, 0x72, 0x6C, 0x44, 0x49, 0x66, 0x65, 0x45, 0x53,
|
||||
0x57, 0x68, 0x42, 0x56, 0x35, 0x67, 0x78, 0x6A, 0x57, 0x41, 0x70, 0x4D, 0x47, 0x67, 0x53, 0x71,
|
||||
0x53, 0x45, 0x6A, 0x70, 0x36, 0x79, 0x62, 0x6A, 0x33, 0x38, 0x50, 0x4C, 0x72, 0x76, 0x49, 0x51,
|
||||
0x48, 0x77, 0x2B, 0x66, 0x70, 0x6F, 0x51, 0x74, 0x6F, 0x4F, 0x4E, 0x65, 0x37, 0x6F, 0x68, 0x66,
|
||||
0x42, 0x77, 0x45, 0x66, 0x47, 0x46, 0x4E, 0x63, 0x33, 0x61, 0x70, 0x48, 0x50, 0x6E, 0x59, 0x53,
|
||||
0x47, 0x4F, 0x67, 0x70, 0x54, 0x78, 0x70, 0x57, 0x57, 0x75, 0x49, 0x42, 0x79, 0x2F, 0x67, 0x38,
|
||||
0x35, 0x2B, 0x65, 0x54, 0x30, 0x44, 0x61, 0x36, 0x53, 0x65, 0x71, 0x33, 0x67, 0x62, 0x4A, 0x59,
|
||||
0x64, 0x75, 0x52, 0x44, 0x65, 0x36, 0x5A, 0x39, 0x63, 0x4A, 0x77, 0x48, 0x79, 0x38, 0x43, 0x34,
|
||||
0x59, 0x79, 0x6B, 0x44, 0x56, 0x45, 0x4B, 0x6A, 0x39, 0x75, 0x52, 0x41, 0x41, 0x45, 0x59, 0x70,
|
||||
0x52, 0x6B, 0x74, 0x39, 0x66, 0x34, 0x79, 0x51, 0x4A, 0x31, 0x73, 0x4D, 0x48, 0x31, 0x5A, 0x75,
|
||||
0x4F, 0x55, 0x46, 0x4A, 0x46, 0x65, 0x74, 0x6B, 0x72, 0x67, 0x32, 0x44, 0x46, 0x61, 0x35, 0x30,
|
||||
0x50, 0x39, 0x48, 0x61, 0x78, 0x6F, 0x4D, 0x59, 0x30, 0x41, 0x79, 0x78, 0x7A, 0x51, 0x72, 0x53,
|
||||
0x77, 0x4D, 0x44, 0x79, 0x6E, 0x36, 0x64, 0x49, 0x65, 0x38, 0x65, 0x58, 0x46, 0x78, 0x51, 0x62,
|
||||
0x56, 0x4D, 0x4F, 0x6C, 0x4B, 0x36, 0x79, 0x33, 0x70, 0x6F, 0x2B, 0x4A, 0x4D, 0x42, 0x34, 0x79,
|
||||
0x4D, 0x42, 0x36, 0x51, 0x77, 0x30, 0x7A, 0x31, 0x35, 0x62, 0x6F, 0x58, 0x4C, 0x78, 0x4D, 0x4B,
|
||||
0x76, 0x4E, 0x59, 0x6E, 0x4B, 0x4E, 0x70, 0x69, 0x6F, 0x33, 0x67, 0x45, 0x78, 0x5A, 0x2B, 0x48,
|
||||
0x68, 0x57, 0x62, 0x43, 0x47, 0x69, 0x37, 0x64, 0x4A, 0x6C, 0x56, 0x47, 0x50, 0x6F, 0x74, 0x34,
|
||||
0x4D, 0x42, 0x45, 0x4C, 0x7A, 0x43, 0x38, 0x66, 0x4C, 0x55, 0x44, 0x69, 0x41, 0x43, 0x49, 0x54,
|
||||
0x37, 0x75, 0x31, 0x58, 0x31, 0x62, 0x68, 0x65, 0x71, 0x6C, 0x35, 0x59, 0x7A, 0x43, 0x30, 0x6C,
|
||||
0x67, 0x2F, 0x4B, 0x48, 0x5A, 0x7A, 0x62, 0x36, 0x6D, 0x63, 0x74, 0x4E, 0x2B, 0x34, 0x62, 0x52,
|
||||
0x74, 0x79, 0x4B, 0x35, 0x75, 0x52, 0x52, 0x4A, 0x70, 0x48, 0x45, 0x56, 0x63, 0x4B, 0x58, 0x57,
|
||||
0x50, 0x34, 0x30, 0x73, 0x31, 0x79, 0x38, 0x37, 0x75, 0x30, 0x6D, 0x49, 0x50, 0x4A, 0x6E, 0x73,
|
||||
0x39, 0x6D, 0x4F, 0x2F, 0x2F, 0x44, 0x41, 0x35, 0x4C, 0x32, 0x6D, 0x64, 0x77, 0x56, 0x79, 0x73,
|
||||
0x72, 0x74, 0x4B, 0x51, 0x69, 0x51, 0x37, 0x36, 0x57, 0x6A, 0x74, 0x59, 0x51, 0x63, 0x41, 0x73,
|
||||
0x46, 0x2B, 0x42, 0x54, 0x4E, 0x56, 0x48, 0x62, 0x41, 0x6E, 0x7A, 0x7A, 0x52, 0x75, 0x6C, 0x52,
|
||||
0x61, 0x43, 0x45, 0x78, 0x2B, 0x6E, 0x30, 0x49, 0x6A, 0x35, 0x34, 0x49, 0x45, 0x41, 0x4F, 0x75,
|
||||
0x55, 0x4B, 0x70, 0x6F, 0x61, 0x48, 0x71, 0x6F, 0x56, 0x4F, 0x33, 0x51, 0x42, 0x36, 0x52, 0x41,
|
||||
0x51, 0x7A, 0x4D, 0x67, 0x70, 0x44, 0x73, 0x41, 0x30, 0x58, 0x34, 0x4C, 0x6A, 0x4F, 0x32, 0x52,
|
||||
0x2B, 0x4D, 0x4B, 0x6F, 0x6D, 0x6F, 0x6C, 0x52, 0x5A, 0x6F, 0x32, 0x34, 0x57, 0x32, 0x41, 0x35,
|
||||
0x57, 0x2B, 0x30, 0x56, 0x4A, 0x77, 0x45, 0x41, 0x41, 0x51, 0x41, 0x3D, 0x20, 0x75, 0x6E, 0x6B,
|
||||
0x6E, 0x6F, 0x77, 0x6E, 0x40, 0x75, 0x6E, 0x6B, 0x6E, 0x6F, 0x77, 0x6E, 0x00
|
||||
};
|
||||
#endif
|
||||
232
apps/common/device/usb/host/aoa.c
Normal file
232
apps/common/device/usb/host/aoa.c
Normal file
@ -0,0 +1,232 @@
|
||||
/**
|
||||
* @file aoa.c
|
||||
* @brief https://source.android.com/devices/accessories/aoa
|
||||
* http://www.hackermi.com/2015-04/aoa-analyse/
|
||||
* Android 开放配件协议 1.0
|
||||
* @author chenrixin@zh-jieli.com
|
||||
* @version 1
|
||||
* @date 2020-03-25
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "app_config.h"
|
||||
|
||||
#include "usb_config.h"
|
||||
#include "usb/host/usb_host.h"
|
||||
#include "usb/usb_phy.h"
|
||||
#include "device_drive.h"
|
||||
#include "usb_ctrl_transfer.h"
|
||||
#include "usb_bulk_transfer.h"
|
||||
#include "usb_storage.h"
|
||||
#include "adb.h"
|
||||
#include "aoa.h"
|
||||
#include "usb_hid_keys.h"
|
||||
#if TCFG_AOA_ENABLE
|
||||
#include "gamebox.h"
|
||||
|
||||
#define LOG_TAG_CONST USB
|
||||
#define LOG_TAG "[AOA]"
|
||||
#define LOG_ERROR_ENABLE
|
||||
#define LOG_DEBUG_ENABLE
|
||||
#define LOG_INFO_ENABLE
|
||||
/* #define LOG_DUMP_ENABLE */
|
||||
#define LOG_CLI_ENABLE
|
||||
#include "debug.h"
|
||||
|
||||
//0x2D00 有一个接口,该接口有两个批量端点,用于输入和输出通信。
|
||||
//0x2D01 有两个接口,每个接口有两个批量端点,用于输入和输出通信。
|
||||
//第一个接口处理标准通信,
|
||||
//第二个接口则处理 ADB 通信。
|
||||
//要使用接口,请找到第一个批量输入和输出端点,
|
||||
//使用 SET_CONFIGURATION (0x09) 设备请求将设备配置的值设为 1,然后使用端点进行通信
|
||||
//
|
||||
|
||||
|
||||
static void aoa_timer_handler(void *priv);
|
||||
static u32 aoa_timer_id;
|
||||
static struct aoa_device_t aoa;
|
||||
static struct device aoa_device;
|
||||
|
||||
static int set_power(struct usb_host_device *host_dev, u32 value)
|
||||
{
|
||||
if (aoa_timer_id) {
|
||||
usr_timer_del(aoa_timer_id);
|
||||
aoa_timer_id = 0;
|
||||
}
|
||||
return DEV_ERR_NONE;
|
||||
}
|
||||
|
||||
static int get_power(struct usb_host_device *host_dev, u32 value)
|
||||
{
|
||||
return DEV_ERR_NONE;
|
||||
}
|
||||
static const struct interface_ctrl aoa_ctrl = {
|
||||
.interface_class = USB_CLASS_AOA,
|
||||
.set_power = set_power,
|
||||
.get_power = get_power,
|
||||
.ioctl = NULL,
|
||||
};
|
||||
|
||||
static const struct usb_interface_info aoa_inf = {
|
||||
.ctrl = (struct interface_ctrl *) &aoa_ctrl,
|
||||
.dev.aoa = &aoa,
|
||||
};
|
||||
|
||||
static const char *credetials[] = {"JieLiTec",
|
||||
"GameBox",
|
||||
"Android accessories devcie !",
|
||||
"1.0.0",
|
||||
"http://www.zh-jieli.com",
|
||||
"1234567890ABCDEF",
|
||||
};
|
||||
|
||||
void aoa_switch(struct usb_host_device *host_dev)
|
||||
{
|
||||
u16 version;
|
||||
log_info("aoa_switch");
|
||||
usb_get_aoa_version(host_dev, &version);
|
||||
log_info("AOA version: %x", version);
|
||||
for (int i = 0; i < 5; i++) {
|
||||
log_info("send string [%d] %s", i, credetials[i]);
|
||||
int r = usb_set_credentials(host_dev, credetials[i], i);
|
||||
if (r < 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
usb_switch2aoa(host_dev);
|
||||
}
|
||||
|
||||
int usb_aoa_parser(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf)
|
||||
{
|
||||
struct usb_interface_descriptor *interface = (struct usb_interface_descriptor *)pBuf;
|
||||
pBuf += sizeof(struct usb_interface_descriptor);
|
||||
int len = 0;
|
||||
const usb_dev usb_id = host_device2id(host_dev);
|
||||
aoa_device.private_data = host_dev;
|
||||
host_dev->interface_info[interface_num] = &aoa_inf;
|
||||
|
||||
for (int endnum = 0; endnum < interface->bNumEndpoints; endnum++) {
|
||||
struct usb_endpoint_descriptor *end_desc = (struct usb_endpoint_descriptor *)pBuf;
|
||||
|
||||
if (end_desc->bDescriptorType != USB_DT_ENDPOINT ||
|
||||
end_desc->bLength != USB_DT_ENDPOINT_SIZE) {
|
||||
log_error("ep bDescriptorType = %d bLength = %d", end_desc->bDescriptorType, end_desc->bLength);
|
||||
return -USB_DT_ENDPOINT;
|
||||
}
|
||||
|
||||
len += USB_DT_ENDPOINT_SIZE;
|
||||
pBuf += USB_DT_ENDPOINT_SIZE;
|
||||
|
||||
if ((end_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) {
|
||||
if (end_desc->bEndpointAddress & USB_DIR_IN) {
|
||||
aoa.target_epin = end_desc->bEndpointAddress & 0x0f;
|
||||
#if defined(FUSB_MODE) && FUSB_MODE == 0
|
||||
aoa.rxmaxp = end_desc->wMaxPacketSize;
|
||||
#endif
|
||||
} else {
|
||||
aoa.target_epout = end_desc->bEndpointAddress & 0x0f;
|
||||
#if defined(FUSB_MODE) && FUSB_MODE == 0
|
||||
aoa.txmaxp = end_desc->wMaxPacketSize;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int aoa_tx_data(const u8 *pbuf, u32 len)
|
||||
{
|
||||
struct usb_host_device *host_dev = aoa_device.private_data;
|
||||
usb_dev usb_id = host_device2id(host_dev);
|
||||
g_printf("TX:");
|
||||
printf_buf(pbuf, len);
|
||||
return usb_h_ep_write_async(usb_id, aoa.host_epout, 64, aoa.target_epout, pbuf, len, USB_ENDPOINT_XFER_BULK, 1);
|
||||
}
|
||||
static void aoa_epin_isr(struct usb_host_device *host_dev, u32 ep)
|
||||
{
|
||||
u8 buffer[64] = {0};
|
||||
usb_dev usb_id = host_device2id(host_dev);
|
||||
u32 rx_len = usb_h_ep_read_async(usb_id, ep, aoa.target_epin, buffer, sizeof(buffer), USB_ENDPOINT_XFER_BULK, 0);
|
||||
g_printf("RX:");
|
||||
printf_buf(buffer, rx_len);
|
||||
|
||||
usb_h_ep_read_async(usb_id, ep, aoa.target_epin, NULL, 0, USB_ENDPOINT_XFER_BULK, 1);
|
||||
}
|
||||
|
||||
#define Accessory_assigned_ID 0x0001
|
||||
|
||||
u32 aoa_process(u32 mode, u32 id)
|
||||
{
|
||||
struct usb_host_device *host_dev = aoa_device.private_data;
|
||||
struct usb_device_descriptor device_desc;
|
||||
usb_get_device_descriptor(host_dev, &device_desc);
|
||||
|
||||
if ((device_desc.idVendor == 0x18d1) &&
|
||||
((device_desc.idProduct & 0x2d00) == 0x2d00)) {
|
||||
log_info("aoa mode ready idVendor:%x idProduct: %x",
|
||||
device_desc.idVendor, device_desc.idProduct);
|
||||
} else {
|
||||
log_info("aoa switch idVendor:%x idProduct: %x",
|
||||
device_desc.idVendor, device_desc.idProduct);
|
||||
|
||||
aoa_switch(host_dev);
|
||||
|
||||
usb_host_remount(id, 3, 30, 50, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
usb_aoa_register_hid(host_dev, Accessory_assigned_ID, sizeof(hid_report_desc));
|
||||
|
||||
u32 offset = 0;
|
||||
while (offset < sizeof(hid_report_desc)) {
|
||||
u32 cnt = min(sizeof(hid_report_desc) - offset, 63);
|
||||
usb_aoa_set_hid_report_desc(host_dev, Accessory_assigned_ID, offset, &hid_report_desc[offset], cnt);
|
||||
offset += cnt;
|
||||
}
|
||||
|
||||
aoa.host_epout = usb_get_ep_num(id, USB_DIR_OUT, USB_ENDPOINT_XFER_BULK);
|
||||
aoa.host_epin = usb_get_ep_num(id, USB_DIR_IN, USB_ENDPOINT_XFER_BULK);
|
||||
log_debug("D(%d)->H(%d)", aoa.target_epin, aoa.host_epin);
|
||||
log_debug("H(%d)->D(%d)", aoa.host_epout, aoa.target_epout);
|
||||
|
||||
usb_h_set_ep_isr(host_dev, aoa.host_epin | USB_DIR_IN, aoa_epin_isr, host_dev);
|
||||
u8 *ep_buffer = usb_h_get_ep_buffer(id, aoa.host_epin | USB_DIR_IN);
|
||||
usb_h_ep_config(id, aoa.host_epin | USB_DIR_IN, USB_ENDPOINT_XFER_BULK, 1, 0, ep_buffer, 64);
|
||||
int r = usb_h_ep_read_async(id, aoa.host_epin, aoa.target_epin, NULL, 0, USB_ENDPOINT_XFER_BULK, 1);
|
||||
|
||||
ep_buffer = usb_h_get_ep_buffer(id, aoa.host_epout | USB_DIR_OUT);
|
||||
usb_h_ep_config(id, aoa.host_epout | USB_DIR_OUT, USB_ENDPOINT_XFER_BULK, 0, 0, ep_buffer, 64);
|
||||
|
||||
aoa_timer_id = usr_timer_add((void *)0, aoa_timer_handler, 4, 0);
|
||||
g_printf("aoa succ");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static void aoa_timer_handler(void *priv)
|
||||
{
|
||||
struct usb_host_device *host_dev = aoa_device.private_data;
|
||||
|
||||
u8 tx_buffer[32];
|
||||
if (mouse_data_send == 1) {
|
||||
tx_buffer[0] = MOUSE_POINT_ID;
|
||||
memcpy(&tx_buffer[1], &mouse_data, sizeof(mouse_data));
|
||||
usb_aoa_send_hid_event(host_dev, Accessory_assigned_ID, tx_buffer, sizeof(mouse_data) + 1);
|
||||
memset(&mouse_data, 0, sizeof(mouse_data)) ;
|
||||
mouse_data_send = 0;
|
||||
}
|
||||
|
||||
tx_buffer[0] = TOUCH_SCREEN_ID;
|
||||
struct touch_screen_t t;
|
||||
memset(&t, 0, sizeof(t));
|
||||
if (point_list_pop(&t)) {
|
||||
memcpy(&tx_buffer[1], &t, sizeof(t));
|
||||
usb_aoa_send_hid_event(host_dev, Accessory_assigned_ID, tx_buffer, sizeof(t) + 1);
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
20
apps/common/device/usb/host/aoa.h
Normal file
20
apps/common/device/usb/host/aoa.h
Normal file
@ -0,0 +1,20 @@
|
||||
#ifndef __AOA_H__
|
||||
#define __AOA_H__
|
||||
|
||||
struct aoa_device_t {
|
||||
u16 version;
|
||||
|
||||
u8 target_epin;
|
||||
u8 target_epout;
|
||||
|
||||
u8 host_epin;
|
||||
u8 host_epout;
|
||||
|
||||
struct adb_device_t *adb;
|
||||
};
|
||||
u32 aoa_process(u32 mode, u32 id);
|
||||
int usb_aoa_parser(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf);
|
||||
|
||||
|
||||
|
||||
#endif /*AOA_H*/
|
||||
8
apps/common/device/usb/host/apple_mfi.h
Normal file
8
apps/common/device/usb/host/apple_mfi.h
Normal file
@ -0,0 +1,8 @@
|
||||
#ifndef _APPLE_MFI_H_
|
||||
#define _APPLE_MFI_H_
|
||||
|
||||
int usb_apple_mfi_parser(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
820
apps/common/device/usb/host/audio.c
Normal file
820
apps/common/device/usb/host/audio.c
Normal file
@ -0,0 +1,820 @@
|
||||
#include "includes.h"
|
||||
#include "asm/includes.h"
|
||||
#include "app_config.h"
|
||||
#include "system/timer.h"
|
||||
#include "device/ioctl_cmds.h"
|
||||
#include "device_drive.h"
|
||||
#if TCFG_HOST_AUDIO_ENABLE
|
||||
#include "usb/host/usb_host.h"
|
||||
#include "usb_ctrl_transfer.h"
|
||||
#include "usb_bulk_transfer.h"
|
||||
#include "audio.h"
|
||||
#include "usb_config.h"
|
||||
|
||||
#define LOG_TAG_CONST USB
|
||||
#define LOG_TAG "[AUDIO]"
|
||||
#define LOG_ERROR_ENABLE
|
||||
#define LOG_DEBUG_ENABLE
|
||||
#define LOG_INFO_ENABLE
|
||||
/* #define LOG_DUMP_ENABLE */
|
||||
#define LOG_CLI_ENABLE
|
||||
#include "debug.h"
|
||||
|
||||
|
||||
/* #define USB_AUDIO_PLAY_TEST */
|
||||
|
||||
struct usb_audio_play {
|
||||
u32 sample_rate;
|
||||
u8 Cur_AlternateSetting;
|
||||
u8 src_channel;
|
||||
u8 play_state;
|
||||
u8 mute;
|
||||
u8 *send_buf;
|
||||
u8 *usb_audio_play_buf;
|
||||
u8 *usb_audio_play_buf2;
|
||||
cbuffer_t usb_audio_play_cbuf;
|
||||
u32 usb_audio_remain_len;
|
||||
OS_SEM sem;
|
||||
int (*put_buf)(void *ptr, u32 len);
|
||||
};
|
||||
struct usb_audio_mic {
|
||||
u8 Cur_AlternateSetting;
|
||||
u32 sample_rate;
|
||||
u8 record_state;
|
||||
u8 *usb_audio_record_buf;
|
||||
u8 *usb_audio_record_buf2;
|
||||
cbuffer_t usb_audio_record_cbuf;
|
||||
int *(*get_buf)(void *ptr, u32 len);
|
||||
};
|
||||
struct usb_audio_info {
|
||||
usb_dev usb_id;
|
||||
struct usb_audio_play player;
|
||||
struct usb_audio_mic microphone;
|
||||
};
|
||||
|
||||
enum {
|
||||
AUDIO_PLAY_IDLE = 0,
|
||||
AUDIO_PLAY_START,
|
||||
AUDIO_PLAY_STOP,
|
||||
AUDIO_PLAY_PAUSE,
|
||||
};
|
||||
enum {
|
||||
AUDIO_RECORD_IDLE = 0,
|
||||
AUDIO_RECORD_START,
|
||||
AUDIO_RECORD_STOP,
|
||||
AUDIO_RECORD_PAUSE,
|
||||
};
|
||||
|
||||
#define EP_MAX_PACKET_SIZE (192)
|
||||
|
||||
struct usb_audio_info _usb_audio_info = {0};
|
||||
#define __this (&_usb_audio_info)
|
||||
|
||||
struct audio_device_t audio_device[USB_MAX_HW_NUM][MAX_HOST_INTERFACE];
|
||||
|
||||
static u8 ep_in_dma_buf[256] __attribute__((aligned(4)));
|
||||
static u8 ep_out_dma_buf[256] __attribute__((aligned(4)));
|
||||
|
||||
static int set_power(struct usb_host_device *host_dev, u32 value)
|
||||
{
|
||||
const usb_dev usb_id = host_device2id(host_dev);
|
||||
return DEV_ERR_NONE;
|
||||
}
|
||||
|
||||
static int get_power(struct usb_host_device *host_dev, u32 value)
|
||||
{
|
||||
return DEV_ERR_NONE;
|
||||
}
|
||||
|
||||
static const struct interface_ctrl uac_ctrl = {
|
||||
.interface_class = USB_CLASS_AUDIO,
|
||||
.set_power = set_power,
|
||||
.get_power = get_power,
|
||||
.ioctl = NULL,
|
||||
};
|
||||
|
||||
static const struct usb_interface_info _uac_if[USB_MAX_HW_NUM][MAX_HOST_INTERFACE] = {
|
||||
{
|
||||
{
|
||||
.ctrl = (struct interface_ctrl *) &uac_ctrl,
|
||||
.dev.audio = &audio_device[0][0],
|
||||
},
|
||||
{
|
||||
.ctrl = (struct interface_ctrl *) &uac_ctrl,
|
||||
.dev.audio = &audio_device[0][1],
|
||||
},
|
||||
{
|
||||
.ctrl = (struct interface_ctrl *) &uac_ctrl,
|
||||
.dev.audio = &audio_device[0][2],
|
||||
},
|
||||
{
|
||||
.ctrl = (struct interface_ctrl *) &uac_ctrl,
|
||||
.dev.audio = &audio_device[0][3],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
int usb_audio_parser(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf)
|
||||
{
|
||||
struct usb_interface_descriptor *interface = (struct usb_interface_descriptor *)pBuf;
|
||||
const usb_dev usb_id = host_device2id(host_dev);
|
||||
|
||||
const struct usb_interface_info *usb_if = &_uac_if[usb_id][interface_num];
|
||||
struct audio_streaming_t *as_t = NULL;
|
||||
memset(usb_if->dev.p, 0, sizeof(struct audio_device_t));
|
||||
host_dev->interface_info[interface_num] = usb_if;
|
||||
usb_if->dev.audio->parent = host_dev;
|
||||
|
||||
if (interface->bInterfaceSubClass == USB_SUBCLASS_AUDIOCONTROL) {
|
||||
log_info("audio control interface : %d\n", interface_num);
|
||||
pBuf += sizeof(struct usb_interface_descriptor);
|
||||
usb_if->dev.audio->subclass = interface->bInterfaceSubClass;
|
||||
usb_if->dev.audio->interface_num = interface_num;
|
||||
|
||||
return sizeof(struct usb_interface_descriptor);
|
||||
}
|
||||
|
||||
if (interface->bInterfaceSubClass == USB_SUBCLASS_AUDIOSTREAMING) {
|
||||
usb_if->dev.audio->subclass = interface->bInterfaceSubClass;
|
||||
usb_if->dev.audio->interface_num = interface_num;
|
||||
if (interface->bNumEndpoints == 0) {
|
||||
pBuf += sizeof(struct usb_interface_descriptor);
|
||||
do {
|
||||
struct usb_interface_descriptor *as_interface = (struct usb_interface_descriptor *)pBuf;
|
||||
if (as_interface->bNumEndpoints == 0 || as_interface->bInterfaceClass != USB_CLASS_AUDIO) {
|
||||
break;
|
||||
}
|
||||
log_info("audio streaming interface : %d ep_num:%d Altersetting:%d", interface_num, as_interface->bNumEndpoints, as_interface->bAlternateSetting);
|
||||
as_t = &usb_if->dev.audio->as[as_interface->bAlternateSetting - 1];
|
||||
as_t->bNumEndpoints = as_interface->bNumEndpoints;
|
||||
pBuf += (USB_DT_INTERFACE_SIZE + UAC_DT_AS_HEADER_SIZE);
|
||||
//解析format
|
||||
struct uac_format_type_i_discrete_descriptor *uac_format_desc = (struct uac_format_type_i_discrete_descriptor *)pBuf;
|
||||
if (uac_format_desc->bDescriptorSubtype == UAC_FORMAT_TYPE) {
|
||||
as_t->bFormatType = uac_format_desc->bFormatType;
|
||||
as_t->bNrChannels = uac_format_desc->bNrChannels;
|
||||
as_t->bSubframeSize = uac_format_desc->bSubframeSize;
|
||||
as_t->bBitResolution = uac_format_desc->bBitResolution;
|
||||
as_t->bSamFreqType = uac_format_desc->bSamFreqType;
|
||||
for (u8 i = 0; i < as_t->bSamFreqType; i++) {
|
||||
memcpy(&as_t->tSamFreq[i], &uac_format_desc->tSamFreq[i], 3);
|
||||
log_info("as bNrChannels:%d bBitResolution:%d tSamFreq : %d", as_t->bNrChannels, as_t->bBitResolution, as_t->tSamFreq[i]);
|
||||
}
|
||||
//Endpointdescriptor
|
||||
pBuf += uac_format_desc->bLength;
|
||||
/* for (int i = 0; i < as_t->bNumEndpoints; i++) { */
|
||||
struct usb_endpoint_descriptor *endpoint = (struct usb_endpoint_descriptor *)pBuf;
|
||||
if (endpoint->bDescriptorType == USB_DT_ENDPOINT) {
|
||||
as_t->ep_Interval = endpoint->bInterval;
|
||||
as_t->ep_max_packet_size = endpoint->wMaxPacketSize;
|
||||
if (endpoint->bEndpointAddress & USB_DIR_IN) {
|
||||
as_t->ep = endpoint->bEndpointAddress & 0xf;
|
||||
log_info("ep in : %x\n", as_t->ep);
|
||||
usb_if->dev.audio->support = MICROPHONE_SUPPORTED;
|
||||
} else {
|
||||
as_t->ep = endpoint->bEndpointAddress;
|
||||
log_info("ep out : %x\n", as_t->ep);
|
||||
usb_if->dev.audio->support = HEADPHONE_SUPPORTED;
|
||||
}
|
||||
pBuf += (USB_DT_ENDPOINT_AUDIO_SIZE + UAC_ISO_ENDPOINT_DESC_SIZE);
|
||||
}
|
||||
/* } */
|
||||
} else {
|
||||
log_error("uac_format_desc->bDescriptorSubtype err!!\n");
|
||||
goto __exit;
|
||||
}
|
||||
|
||||
} while (1);
|
||||
/* log_info("lennnn:%d\n",pBuf - (u8 *)interface); */
|
||||
return pBuf - (u8 *)interface ;
|
||||
} else {
|
||||
log_info("audio streaming interface : %d ep_num:%d Altersetting:%d\n", interface_num, interface->bNumEndpoints, interface->bAlternateSetting);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
__exit:
|
||||
return USB_DT_INTERFACE_SIZE;
|
||||
|
||||
}
|
||||
|
||||
static struct audio_device_t *__find_microphone_interface(const struct usb_host_device *host_dev)
|
||||
{
|
||||
struct audio_device_t *audio = NULL;
|
||||
for (u8 i = 0; i < MAX_HOST_INTERFACE; i++) {
|
||||
const struct usb_interface_info *usb_if = host_dev->interface_info[i];
|
||||
if (usb_if &&
|
||||
(usb_if->ctrl->interface_class == USB_CLASS_AUDIO)) {
|
||||
audio = usb_if->dev.audio;
|
||||
if (audio->subclass == USB_SUBCLASS_AUDIOSTREAMING &&
|
||||
audio->support == MICROPHONE_SUPPORTED) {
|
||||
// find microphone
|
||||
return audio;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
static struct audio_device_t *__find_headphone_interface(const struct usb_host_device *host_dev)
|
||||
{
|
||||
struct audio_device_t *audio = NULL;
|
||||
for (u8 i = 0; i < MAX_HOST_INTERFACE; i++) {
|
||||
const struct usb_interface_info *usb_if = host_dev->interface_info[i];
|
||||
if (usb_if &&
|
||||
(usb_if->ctrl->interface_class == USB_CLASS_AUDIO)) {
|
||||
audio = usb_if->dev.audio;
|
||||
if (audio->subclass == USB_SUBCLASS_AUDIOSTREAMING &&
|
||||
audio->support == HEADPHONE_SUPPORTED) {
|
||||
// find headphone
|
||||
return audio;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
static u32 play_vol_convert(u16 v)
|
||||
{
|
||||
//固定音量表,更换声卡需要修改音量表
|
||||
const u16 vol_table[] = {
|
||||
//0-100
|
||||
0xd300, //0
|
||||
0xd58f, 0xd7bf, 0xd9a8, 0xdb5b, 0xdce1, 0xde45, 0xdf8a, 0xe0b6, 0xe1cd, 0xe2d1,
|
||||
0xe3c5, 0xe4ab, 0xe583, 0xe651, 0xe714, 0xe7cd, 0xe87f, 0xe928, 0xe9ca, 0xea66,
|
||||
0xeafc, 0xeb8d, 0xec18, 0xec9e, 0xed20, 0xed9e, 0xee18, 0xee8e, 0xef00, 0xef6f,
|
||||
0xefdc, 0xf045, 0xf0ab, 0xf10f, 0xf171, 0xf1d0, 0xf22c, 0xf287, 0xf2e0, 0xf336,
|
||||
0xf38b, 0xf3de, 0xf42f, 0xf47e, 0xf4cc, 0xf518, 0xf563, 0xf5ad, 0xf5f5, 0xf63c,
|
||||
0xf681, 0xf6c6, 0xf709, 0xf74b, 0xf78c, 0xf7cb, 0xf80a, 0xf848, 0xf885, 0xf8c1,
|
||||
0xf8fc, 0xf936, 0xf96f, 0xf9a8, 0xf9df, 0xfa16, 0xfa4c, 0xfa81, 0xfab6, 0xfaea,
|
||||
0xfb1d, 0xfb50, 0xfb82, 0xfbb3, 0xfbe4, 0xfc14, 0xfc43, 0xfc72, 0xfca0, 0xfcce,
|
||||
0xfcfc, 0xfd28, 0xfd55, 0xfd80, 0xfdab, 0xfdd6, 0xfe01, 0xfe2a, 0xfe54, 0xfe7d,
|
||||
0xfea5, 0xfece, 0xfef5, 0xff1d, 0xff43, 0xff6a, 0xff90, 0xffb6, 0xffdb, 0x0000,
|
||||
};
|
||||
|
||||
if (v <= 100) {
|
||||
return vol_table[v];
|
||||
}
|
||||
|
||||
for (int i = 0; i < sizeof(vol_table) / 2; i++) {
|
||||
if (v <= vol_table[i]) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void set_usb_audio_play_volume(u16 vol)
|
||||
{
|
||||
const struct usb_host_device *host_dev = host_id2device(__this->usb_id);
|
||||
u8 featureUnitID = 6;
|
||||
usb_audio_volume_control(host_dev, featureUnitID, 1, play_vol_convert(vol));
|
||||
usb_audio_volume_control(host_dev, featureUnitID, 2, play_vol_convert(vol));
|
||||
if (vol == 0) {
|
||||
__this->player.mute = 1;
|
||||
usb_audio_mute_control(host_dev, featureUnitID, __this->player.mute); //mute
|
||||
} else {
|
||||
if (__this->player.mute == 1) {
|
||||
__this->player.mute = 0;
|
||||
usb_audio_mute_control(host_dev, featureUnitID, __this->player.mute);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USB_AUDIO_PLAY_TEST
|
||||
static const s16 sin_48k[] = {
|
||||
0, 2139, 4240, 6270, 8192, 9974, 11585, 12998,
|
||||
14189, 15137, 15826, 16244, 16384, 16244, 15826, 15137,
|
||||
14189, 12998, 11585, 9974, 8192, 6270, 4240, 2139,
|
||||
0, -2139, -4240, -6270, -8192, -9974, -11585, -12998,
|
||||
-14189, -15137, -15826, -16244, -16384, -16244, -15826, -15137,
|
||||
-14189, -12998, -11585, -9974, -8192, -6270, -4240, -2139
|
||||
};
|
||||
#endif
|
||||
static void usb_audio_tx_isr(struct usb_host_device *host_dev, u32 ep)
|
||||
{
|
||||
const usb_dev usb_id = host_device2id(host_dev);
|
||||
struct audio_device_t *audio = NULL;
|
||||
struct audio_streaming_t *as_t = NULL;
|
||||
u16 ep_max_packet_size = 0;
|
||||
u8 channel = 0;
|
||||
u32 rlen = 0;
|
||||
static u32 usb_audio_tx_len = 0;
|
||||
|
||||
if (__this->player.play_state != AUDIO_PLAY_START) {
|
||||
return;
|
||||
}
|
||||
|
||||
audio = __find_headphone_interface(host_dev);
|
||||
if (!audio) {
|
||||
log_error("no find headphone interface!");
|
||||
return;
|
||||
}
|
||||
|
||||
as_t = &audio->as[__this->player.Cur_AlternateSetting - 1];
|
||||
/* ep_max_packet_size = as_t->ep_max_packet_size; */
|
||||
ep_max_packet_size = EP_MAX_PACKET_SIZE;
|
||||
channel = as_t->bNrChannels;
|
||||
|
||||
//iso send
|
||||
#ifdef USB_AUDIO_PLAY_TEST
|
||||
//For Test
|
||||
int tx_len = 0;
|
||||
#if 1 // 单声道双声道输出
|
||||
s16 buf[240 / 2];
|
||||
for (u8 i = 0, j = 0; i < 240 / 2; i += 2) {
|
||||
buf[i] = sin_48k[j];
|
||||
buf[i + 1] = sin_48k[j];
|
||||
j++;
|
||||
if (j >= sizeof(sin_48k) / sizeof(sin_48k[0])) {
|
||||
j = 0;
|
||||
}
|
||||
}
|
||||
#else
|
||||
//单声道直接输出
|
||||
u8 buf[248];
|
||||
do {
|
||||
memcpy(&buf[tx_len], sin_48k, sizeof(sin_48k));
|
||||
tx_len += sizeof(sin_48k);
|
||||
} while (tx_len < ep_max_packet_size);
|
||||
#endif
|
||||
usb_h_ep_write_async(usb_id, ep, ep_max_packet_size, as_t->ep, buf, ep_max_packet_size, USB_ENDPOINT_XFER_ISOC, 0);
|
||||
#else
|
||||
if (__this->player.usb_audio_remain_len == 0) {
|
||||
cbuf_read_alloc(&__this->player.usb_audio_play_cbuf, &__this->player.usb_audio_remain_len);
|
||||
usb_audio_tx_len = 0;
|
||||
}
|
||||
if (__this->player.usb_audio_remain_len) {
|
||||
if (usb_audio_tx_len == 0) {
|
||||
rlen = cbuf_read(&__this->player.usb_audio_play_cbuf, __this->player.usb_audio_play_buf2, __this->player.usb_audio_remain_len);
|
||||
if (!rlen) {
|
||||
__this->player.usb_audio_remain_len = 0;
|
||||
usb_audio_tx_len = 0;
|
||||
putchar('C');
|
||||
usb_h_ep_write_async(usb_id, ep, ep_max_packet_size, as_t->ep, NULL, ep_max_packet_size, USB_ENDPOINT_XFER_ISOC, 1);
|
||||
os_sem_post(&__this->player.sem);
|
||||
return;
|
||||
}
|
||||
os_sem_post(&__this->player.sem);
|
||||
|
||||
}
|
||||
u8 *send_buf = __this->player.send_buf;
|
||||
u8 *play_buf = __this->player.usb_audio_play_buf2;
|
||||
if (channel == 2) {
|
||||
if (__this->player.src_channel == 1) {
|
||||
//源数据是单声道数据,转双声道输出
|
||||
int j = 0;
|
||||
for (u8 i = 0; i < ep_max_packet_size; i += 4) {
|
||||
//left
|
||||
*(send_buf + i) = *(play_buf + (usb_audio_tx_len + j));
|
||||
*(send_buf + i + 1) = *(play_buf + (usb_audio_tx_len + j + 1));
|
||||
//right
|
||||
|
||||
*(send_buf + i + 2) = *(play_buf + (usb_audio_tx_len + j));
|
||||
*(send_buf + i + 3) = *(play_buf + (usb_audio_tx_len + j + 1));
|
||||
j += 2;
|
||||
}
|
||||
usb_audio_tx_len += j;
|
||||
usb_h_ep_write_async(usb_id, ep, ep_max_packet_size, as_t->ep, send_buf, ep_max_packet_size, USB_ENDPOINT_XFER_ISOC, 0);
|
||||
} else if (__this->player.src_channel == 2) {
|
||||
//源数据是双声道数据,直接双声道输出
|
||||
usb_h_ep_write_async(usb_id, ep, ep_max_packet_size, as_t->ep, play_buf + usb_audio_tx_len, ep_max_packet_size, USB_ENDPOINT_XFER_ISOC, 0);
|
||||
usb_audio_tx_len += ep_max_packet_size;
|
||||
}
|
||||
} else if (channel == 1) {
|
||||
}
|
||||
if (usb_audio_tx_len >= __this->player.usb_audio_remain_len) {
|
||||
__this->player.usb_audio_remain_len = 0;
|
||||
usb_audio_tx_len = 0;
|
||||
}
|
||||
} else {
|
||||
//audio buf null ,send null packet
|
||||
putchar('E');
|
||||
usb_h_ep_write_async(usb_id, ep, ep_max_packet_size, as_t->ep, NULL, ep_max_packet_size, USB_ENDPOINT_XFER_ISOC, 1);
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
void set_vol_test(void *p)
|
||||
{
|
||||
struct usb_host_device *host_dev = (struct usb_host_device *)p;
|
||||
static u16 vol = 100;
|
||||
set_usb_audio_play_volume(vol);
|
||||
/* static u8 f = 0; */
|
||||
/* void usb_audio_pause_play(void); */
|
||||
/* void usb_audio_resume_play(void); */
|
||||
/* if (!f) { */
|
||||
/* usb_audio_pause_play(); */
|
||||
/* } else { */
|
||||
/* usb_audio_resume_play(); */
|
||||
/* } */
|
||||
/* f = !f; */
|
||||
vol -= 10;
|
||||
}
|
||||
void audio_play_task(void *p)
|
||||
{
|
||||
log_info(">>> Enter usb audio play task");
|
||||
struct usb_host_device *host_dev = (struct usb_host_device *)p;
|
||||
const usb_dev usb_id = host_device2id(host_dev);
|
||||
u8 *ptr = NULL;
|
||||
u32 wlen = 0;
|
||||
u32 ret = 0;
|
||||
struct audio_device_t *audio = NULL;
|
||||
audio = __find_headphone_interface(host_dev);
|
||||
struct audio_streaming_t *as_t = &audio->as[__this->player.Cur_AlternateSetting - 1];
|
||||
/* u32 ep_max_packet_size = as_t->ep_max_packet_size; */
|
||||
u32 ep_max_packet_size = EP_MAX_PACKET_SIZE;
|
||||
log_info("ep max packet : %d\n", ep_max_packet_size);
|
||||
if (__this->player.send_buf) {
|
||||
free(__this->player.send_buf);
|
||||
__this->player.send_buf = NULL;
|
||||
}
|
||||
__this->player.send_buf = zalloc(ep_max_packet_size);
|
||||
u32 usb_audio_buf_size = ep_max_packet_size * 5; //预留5个包的缓存
|
||||
|
||||
/* sys_timer_add(host_dev,set_vol_test,5000); */
|
||||
os_sem_create(&__this->player.sem, 0);
|
||||
u32 host_ep = as_t->host_ep;
|
||||
__this->player.play_state = AUDIO_PLAY_START;
|
||||
//分配双缓存
|
||||
// 一个缓存保存读卡的数据,一个用于usb发送
|
||||
if (!__this->player.usb_audio_play_buf) {
|
||||
__this->player.usb_audio_play_buf = zalloc(usb_audio_buf_size);
|
||||
cbuf_init(&__this->player.usb_audio_play_cbuf, __this->player.usb_audio_play_buf, usb_audio_buf_size);
|
||||
usb_h_ep_write_async(usb_id, host_ep, ep_max_packet_size, as_t->ep, NULL, ep_max_packet_size, USB_ENDPOINT_XFER_ISOC, 1); //启动iso传输
|
||||
}
|
||||
if (!__this->player.usb_audio_play_buf2) {
|
||||
__this->player.usb_audio_play_buf2 = zalloc(usb_audio_buf_size);
|
||||
}
|
||||
while (1) {
|
||||
if (__this->player.Cur_AlternateSetting == 0 || __this->player.play_state != AUDIO_PLAY_START) {
|
||||
putchar('C');
|
||||
os_time_dly(50);
|
||||
continue;
|
||||
}
|
||||
ptr = cbuf_write_alloc(&__this->player.usb_audio_play_cbuf, &wlen);
|
||||
if (wlen) {
|
||||
putchar('R');
|
||||
ret = __this->player.put_buf(ptr, wlen);
|
||||
if (ret != wlen) {
|
||||
__this->player.play_state = AUDIO_PLAY_STOP;
|
||||
goto __task_exit;
|
||||
|
||||
}
|
||||
cbuf_write_updata(&__this->player.usb_audio_play_cbuf, wlen);
|
||||
} else {
|
||||
log_w("usb audio play buf not enough!\n");
|
||||
}
|
||||
__task_exit:
|
||||
os_sem_pend(&__this->player.sem, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void usb_audio_start_play(const usb_dev usb_id, u8 channel, u8 bit_reso, u32 sample_rate)
|
||||
{
|
||||
log_info(" usb audio play\n");
|
||||
const struct usb_host_device *host_dev = host_id2device(usb_id);
|
||||
struct audio_device_t *audio = NULL;
|
||||
struct audio_streaming_t *as_t = NULL;
|
||||
u8 *ep_buffer = ep_out_dma_buf;
|
||||
u8 find_alternatesetting = 0;
|
||||
audio = __find_headphone_interface(host_dev);
|
||||
if (!audio) {
|
||||
log_error("no find headphone interface!");
|
||||
return;
|
||||
}
|
||||
for (u8 i = 0; i < ARRAY_SIZE(audio->as); i++) {
|
||||
as_t = &audio->as[i];
|
||||
if (as_t->bBitResolution == bit_reso) {
|
||||
for (u8 j = 0; j < as_t->bSamFreqType; j++) {
|
||||
if (as_t->tSamFreq[j] == sample_rate) {
|
||||
find_alternatesetting = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!find_alternatesetting) {
|
||||
log_e("can not find Alternatesetting,please check bit_reso and sample_rate\n");
|
||||
return;
|
||||
}
|
||||
|
||||
__this->usb_id = usb_id;
|
||||
//端点分配
|
||||
u32 host_ep = usb_get_ep_num(usb_id, USB_DIR_OUT, USB_ENDPOINT_XFER_ISOC);
|
||||
ASSERT(host_ep != -1, "ep not enough");
|
||||
|
||||
__this->player.Cur_AlternateSetting = find_alternatesetting; //选择Alternatesetting
|
||||
__this->player.sample_rate = sample_rate; //选择采样率
|
||||
__this->player.src_channel = channel;
|
||||
as_t = &audio->as[find_alternatesetting - 1];
|
||||
u8 target_ep = as_t->ep;
|
||||
u8 ep_interval = as_t->ep_Interval;
|
||||
as_t->host_ep = host_ep;
|
||||
|
||||
usb_set_interface(host_dev, audio->interface_num, find_alternatesetting); //interface Alternatesetting
|
||||
usb_audio_sampling_frequency_control(host_dev, target_ep, sample_rate);//设置采样率
|
||||
//设置音量
|
||||
/* usb_audio_volume_control(host_dev, 6, 1, vol_convert(5)); */
|
||||
/* usb_audio_volume_control(host_dev, 6, 2, vol_convert(5)); */
|
||||
|
||||
log_info("H2D ep: %x --> %x interval: %d", host_ep, target_ep, ep_interval);
|
||||
usb_h_set_ep_isr(host_dev, host_ep, usb_audio_tx_isr, host_dev);
|
||||
usb_h_ep_config(usb_id, host_ep, USB_ENDPOINT_XFER_ISOC, 1, ep_interval, ep_buffer, sizeof(ep_out_dma_buf));
|
||||
task_create(audio_play_task, host_dev, "uac_play");
|
||||
}
|
||||
|
||||
void usb_audio_stop_play(const usb_dev usb_id)
|
||||
{
|
||||
const struct usb_host_device *host_dev = host_id2device(usb_id);
|
||||
usb_h_set_ep_isr(NULL, 0, NULL, NULL);
|
||||
__this->player.put_buf(NULL, 0);
|
||||
__this->player.Cur_AlternateSetting = 0;
|
||||
__this->player.sample_rate = 0;
|
||||
__this->player.src_channel = 0;
|
||||
if (__this->player.usb_audio_play_buf) {
|
||||
free(__this->player.usb_audio_play_buf);
|
||||
__this->player.usb_audio_play_buf = NULL;
|
||||
}
|
||||
if (__this->player.usb_audio_play_buf2) {
|
||||
free(__this->player.usb_audio_play_buf2);
|
||||
__this->player.usb_audio_play_buf2 = NULL;
|
||||
}
|
||||
if (__this->player.send_buf) {
|
||||
free(__this->player.send_buf);
|
||||
__this->player.send_buf = NULL;
|
||||
}
|
||||
printf("\n[ debug ]--func=%s line=%d\n", __func__, __LINE__);
|
||||
task_kill("uac_play");
|
||||
printf("\n[ debug ]--func=%s line=%d\n", __func__, __LINE__);
|
||||
}
|
||||
void usb_audio_pause_play(void)
|
||||
{
|
||||
__this->player.play_state = AUDIO_PLAY_PAUSE;
|
||||
}
|
||||
void usb_audio_resume_play(void)
|
||||
{
|
||||
const struct usb_host_device *host_dev = host_id2device(__this->usb_id);
|
||||
struct audio_device_t *audio = __find_headphone_interface(host_dev);
|
||||
struct audio_streaming_t *as_t = &audio->as[__this->player.Cur_AlternateSetting - 1];
|
||||
__this->player.play_state = AUDIO_PLAY_START;
|
||||
usb_h_ep_write_async(__this->usb_id, as_t->host_ep, as_t->ep_max_packet_size, as_t->ep, NULL, as_t->ep_max_packet_size, USB_ENDPOINT_XFER_ISOC, 1); //重新启动传输
|
||||
}
|
||||
|
||||
|
||||
static u32 record_vol_convert(u16 v)
|
||||
{
|
||||
//固定音量表,更换声卡需要修改音量表
|
||||
const u16 vol_table[] = {
|
||||
//0-100
|
||||
0xf400,
|
||||
0xf479, 0xf4ee, 0xf560, 0xf5cf, 0xf63a, 0xf6a3, 0xf709, 0xf76c, 0xf7cd, 0xf82b,
|
||||
0xf887, 0xf8e1, 0xf939, 0xf98f, 0xf9e4, 0xfa36, 0xfa87, 0xfad6, 0xfb23, 0xfb6f,
|
||||
0xfbba, 0xfc03, 0xfc4b, 0xfc91, 0xfcd6, 0xfd1a, 0xfd5d, 0xfd9f, 0xfde0, 0xfe1f,
|
||||
0xfe5e, 0xfe9b, 0xfed8, 0xff14, 0xff4e, 0xff88, 0xffc1, 0xfff9, 0x0003, 0x0069,
|
||||
0x00a3, 0x00de, 0x0119, 0x0155, 0x0193, 0x01d1, 0x0210, 0x0251, 0x0292, 0x02d5,
|
||||
0x0318, 0x035d, 0x03a3, 0x03eb, 0x0434, 0x047e, 0x04c9, 0x0517, 0x0565, 0x05b5,
|
||||
0x0607, 0x065b, 0x06b1, 0x0708, 0x0762, 0x07bd, 0x081b, 0x087c, 0x08de, 0x0943,
|
||||
0x09ab, 0x0a16, 0x0a84, 0x0af4, 0x0b69, 0x0be1, 0x0c5c, 0x0cdc, 0x0d60, 0x0de9,
|
||||
0x0e77, 0x0f0a, 0x0fa2, 0x1041, 0x10e7, 0x1195, 0x124a, 0x1308, 0x13d0, 0x14a3,
|
||||
0x1582, 0x166e, 0x176a, 0x1877, 0x1998, 0x1ad0, 0x1c24, 0x1d98, 0x1f33, 0x2100,
|
||||
};
|
||||
|
||||
if (v <= 100) {
|
||||
return vol_table[v];
|
||||
}
|
||||
|
||||
for (int i = 0; i < sizeof(vol_table) / 2; i++) {
|
||||
if (v <= vol_table[i]) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void set_usb_audio_record_volume(u16 vol)
|
||||
{
|
||||
const struct usb_host_device *host_dev = host_id2device(__this->usb_id);
|
||||
u8 featureUnitID = 5;
|
||||
usb_audio_volume_control(host_dev, featureUnitID, 0, record_vol_convert(vol));
|
||||
}
|
||||
|
||||
static u32 write_file_len = 0;
|
||||
static void usb_audio_rx_isr(struct usb_host_device *host_dev, u32 ep)
|
||||
{
|
||||
u8 buffer[192] = {0};
|
||||
u8 *ptr = NULL;
|
||||
int rlen, wlen = 0;
|
||||
usb_dev usb_id = host_device2id(host_dev);
|
||||
struct audio_device_t *audio = NULL;
|
||||
struct audio_streaming_t *as_t = NULL;
|
||||
audio = __find_microphone_interface(host_dev);
|
||||
if (!audio) {
|
||||
log_error("no find microphone interface!");
|
||||
return;
|
||||
}
|
||||
if (__this->microphone.record_state != AUDIO_RECORD_START) {
|
||||
return;
|
||||
}
|
||||
as_t = &audio->as[__this->microphone.Cur_AlternateSetting - 1];
|
||||
u8 channel = as_t->bNrChannels;
|
||||
|
||||
u32 rx_len = usb_h_ep_read_async(usb_id, ep, as_t->ep, buffer, sizeof(buffer), USB_ENDPOINT_XFER_ISOC, 0);
|
||||
/* g_printf("RX:%d\n",rx_len); */
|
||||
/* printf_buf(buffer, rx_len); */
|
||||
cbuf_write(&__this->microphone.usb_audio_record_cbuf, buffer, rx_len);
|
||||
cbuf_write_alloc(&__this->microphone.usb_audio_record_cbuf, &wlen);
|
||||
if (wlen == 0) {
|
||||
putchar('O');
|
||||
if (write_file_len) {
|
||||
log_w("write againnnnn\n");
|
||||
}
|
||||
/* [> printf("R:%d W:%d\n", rx_len,wlen); <] */
|
||||
cbuf_read_alloc(&__this->microphone.usb_audio_record_cbuf, &rlen);
|
||||
cbuf_read(&__this->microphone.usb_audio_record_cbuf, __this->microphone.usb_audio_record_buf2, rlen);
|
||||
write_file_len = rlen;
|
||||
os_taskq_post_msg("uac_record", 2, 0x01, rlen);
|
||||
/* return; */
|
||||
}
|
||||
|
||||
usb_h_ep_read_async(usb_id, ep, as_t->ep, NULL, 0, USB_ENDPOINT_XFER_ISOC, 1); //触发下一个接收中断
|
||||
}
|
||||
void audio_record_task(void *p)
|
||||
{
|
||||
log_info(">>> Enter usb audio record task");
|
||||
struct usb_host_device *host_dev = (struct usb_host_device *)p;
|
||||
const usb_dev usb_id = host_device2id(host_dev);
|
||||
u8 *ptr = NULL;
|
||||
u32 rlen = 0;
|
||||
u32 ret = 0;
|
||||
int msg[16];
|
||||
struct audio_device_t *audio = NULL;
|
||||
audio = __find_microphone_interface(host_dev);
|
||||
struct audio_streaming_t *as_t = &audio->as[__this->microphone.Cur_AlternateSetting - 1];
|
||||
/* u32 ep_max_packet_size = as_t->ep_max_packet_size; */
|
||||
u32 ep_max_packet_size = EP_MAX_PACKET_SIZE;
|
||||
log_info("ep max packet : %d\n", ep_max_packet_size);
|
||||
u32 usb_audio_buf_size = ep_max_packet_size * 50;
|
||||
|
||||
u32 host_ep = as_t->host_ep;
|
||||
u8 target_ep = as_t->ep;
|
||||
//分配双缓存
|
||||
// 一个缓存写卡的数据,一个用于usb接收
|
||||
if (!__this->microphone.usb_audio_record_buf) {
|
||||
__this->microphone.usb_audio_record_buf = zalloc(usb_audio_buf_size);
|
||||
cbuf_init(&__this->microphone.usb_audio_record_cbuf, __this->microphone.usb_audio_record_buf, usb_audio_buf_size);
|
||||
|
||||
}
|
||||
if (!__this->microphone.usb_audio_record_buf2) {
|
||||
__this->microphone.usb_audio_record_buf2 = zalloc(usb_audio_buf_size);
|
||||
}
|
||||
|
||||
usb_h_ep_read_async(usb_id, host_ep, target_ep, NULL, 0, USB_ENDPOINT_XFER_ISOC, 1); //启动iso
|
||||
while (1) {
|
||||
ret = os_taskq_pend(NULL, msg, ARRAY_SIZE(msg));
|
||||
if (ret == OS_TASKQ) {
|
||||
switch (msg[1]) {
|
||||
case 0x01:
|
||||
ptr = __this->microphone.usb_audio_record_buf2;
|
||||
rlen = msg[2];
|
||||
putchar('W');
|
||||
__this->microphone.get_buf(ptr, rlen);
|
||||
write_file_len = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void usb_audio_start_record(const usb_dev usb_id, u8 bit_reso, u32 sample_rate)
|
||||
{
|
||||
log_info(" usb audio record\n");
|
||||
const struct usb_host_device *host_dev = host_id2device(usb_id);
|
||||
struct audio_device_t *audio = NULL;
|
||||
struct audio_streaming_t *as_t = NULL;
|
||||
u8 *ep_buffer = ep_in_dma_buf;
|
||||
u8 find_alternatesetting = 0;
|
||||
audio = __find_microphone_interface(host_dev);
|
||||
if (!audio) {
|
||||
log_error("no find microphone interface!");
|
||||
return;
|
||||
}
|
||||
for (u8 i = 0; i < ARRAY_SIZE(audio->as); i++) {
|
||||
as_t = &audio->as[i];
|
||||
if (as_t->bBitResolution == bit_reso) {
|
||||
for (u8 j = 0; j < as_t->bSamFreqType; j++) {
|
||||
if (as_t->tSamFreq[j] == sample_rate) {
|
||||
find_alternatesetting = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!find_alternatesetting) {
|
||||
log_e("can not find Alternatesetting,please check bit_reso and sample_rate\n");
|
||||
return;
|
||||
}
|
||||
//端点分配
|
||||
u32 host_ep = usb_get_ep_num(usb_id, USB_DIR_IN, USB_ENDPOINT_XFER_ISOC);
|
||||
ASSERT(host_ep != -1, "ep not enough");
|
||||
__this->usb_id = usb_id;
|
||||
host_ep = host_ep | USB_DIR_IN;
|
||||
|
||||
__this->microphone.Cur_AlternateSetting = find_alternatesetting; //选择Alternatesetting
|
||||
__this->microphone.sample_rate = sample_rate; //选择采样率
|
||||
as_t = &audio->as[find_alternatesetting - 1];
|
||||
u8 target_ep = as_t->ep;
|
||||
u8 ep_interval = as_t->ep_Interval;
|
||||
as_t->host_ep = host_ep;
|
||||
|
||||
usb_set_interface(host_dev, audio->interface_num, find_alternatesetting); //interface 1 Alternatesetting 1
|
||||
usb_audio_sampling_frequency_control(host_dev, target_ep, sample_rate);//设置采样率
|
||||
//设置音量
|
||||
/* usb_audio_volume_control(host_dev, 6, 1, vol_convert(5)); */
|
||||
/* usb_audio_volume_control(host_dev, 6, 2, vol_convert(5)); */
|
||||
log_info("D2H ep: %x --> %x", target_ep, host_ep);
|
||||
usb_h_set_ep_isr(host_dev, host_ep, usb_audio_rx_isr, host_dev);
|
||||
usb_h_ep_config(usb_id, host_ep, USB_ENDPOINT_XFER_ISOC, 1, ep_interval, ep_buffer, sizeof(ep_in_dma_buf));
|
||||
task_create(audio_record_task, host_dev, "uac_record");
|
||||
__this->microphone.record_state = AUDIO_RECORD_START;
|
||||
}
|
||||
void usb_audio_stop_record(const usb_dev usb_id)
|
||||
{
|
||||
const struct usb_host_device *host_dev = host_id2device(usb_id);
|
||||
usb_h_set_ep_isr(NULL, 0, NULL, NULL);
|
||||
__this->microphone.get_buf(NULL, 0);
|
||||
__this->microphone.Cur_AlternateSetting = 0;
|
||||
__this->microphone.sample_rate = 0;
|
||||
if (__this->microphone.usb_audio_record_buf) {
|
||||
free(__this->microphone.usb_audio_record_buf);
|
||||
__this->microphone.usb_audio_record_buf = NULL;
|
||||
}
|
||||
if (__this->microphone.usb_audio_record_buf2) {
|
||||
free(__this->microphone.usb_audio_record_buf2);
|
||||
__this->microphone.usb_audio_record_buf2 = NULL;
|
||||
}
|
||||
printf("\n[ debug ]--func=%s line=%d\n", __func__, __LINE__);
|
||||
task_kill("uac_record");
|
||||
printf("\n[ debug ]--func=%s line=%d\n", __func__, __LINE__);
|
||||
}
|
||||
void usb_audio_pause_record(void)
|
||||
{
|
||||
__this->microphone.record_state = AUDIO_RECORD_PAUSE;
|
||||
}
|
||||
void usb_audio_resume_record(void)
|
||||
{
|
||||
const struct usb_host_device *host_dev = host_id2device(__this->usb_id);
|
||||
struct audio_device_t *audio = __find_microphone_interface(host_dev);
|
||||
struct audio_streaming_t *as_t = &audio->as[__this->microphone.Cur_AlternateSetting - 1];
|
||||
__this->microphone.record_state = AUDIO_RECORD_START;
|
||||
usb_h_ep_read_async(__this->usb_id, as_t->host_ep, as_t->ep, NULL, 0, USB_ENDPOINT_XFER_ISOC, 1); //重新启动接收
|
||||
}
|
||||
|
||||
void usb_audio_start_process(u32 id)
|
||||
{
|
||||
usb_audio_start_play(id, 1, 16, 48000); //开启headphone
|
||||
usb_audio_start_record(id, 16, 48000); //开启microphone
|
||||
}
|
||||
void usb_audio_stop_process(u32 id)
|
||||
{
|
||||
usb_audio_stop_play(id);
|
||||
usb_audio_stop_record(id);
|
||||
}
|
||||
|
||||
|
||||
static void usb_audio_event_handler(struct sys_event *event, void *priv)
|
||||
{
|
||||
const char *audio = NULL;
|
||||
switch (event->type) {
|
||||
case SYS_DEVICE_EVENT:
|
||||
if ((u32)event->arg == DEVICE_EVENT_FROM_USB_HOST) {
|
||||
if ((event->u.dev.event == DEVICE_EVENT_IN) ||
|
||||
(event->u.dev.event == DEVICE_EVENT_CHANGE)) {
|
||||
audio = (const char *)event->u.dev.value;
|
||||
usb_audio_start_process(audio[5] - '0');
|
||||
|
||||
} else if (event->u.dev.event == DEVICE_EVENT_OUT) {
|
||||
log_error("device out %x", event->u.dev.value);
|
||||
usb_audio_stop_process(audio[5] - '0');
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
void usb_host_audio_init(int (*put_buf)(void *ptr, u32 len), int *(*get_buf)(void *ptr, u32 len))
|
||||
{
|
||||
memset(__this, 0, sizeof(struct usb_audio_info));
|
||||
__this->player.put_buf = put_buf;
|
||||
__this->microphone.get_buf = get_buf;
|
||||
register_sys_event_handler(SYS_DEVICE_EVENT, DEVICE_EVENT_FROM_USB_HOST, 2,
|
||||
usb_audio_event_handler);
|
||||
}
|
||||
void usb_host_audio_exit()
|
||||
{
|
||||
unregister_sys_event_handler(usb_audio_event_handler);
|
||||
__this->player.put_buf = NULL;
|
||||
__this->microphone.get_buf = NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
56
apps/common/device/usb/host/audio.h
Normal file
56
apps/common/device/usb/host/audio.h
Normal file
@ -0,0 +1,56 @@
|
||||
#ifndef __AUDIO_H__
|
||||
#define __AUDIO_H__
|
||||
|
||||
#include "system/task.h"
|
||||
#include "device/device.h"
|
||||
#include "usb_bulk_transfer.h"
|
||||
#include "usb/host/usb_host.h"
|
||||
#include "usb/device/uac_audio.h"
|
||||
|
||||
|
||||
#define HEADPHONE_SUPPORTED 0x01
|
||||
#define MICROPHONE_SUPPORTED 0x02
|
||||
#define HEADSET_SUPPORTED 0x03
|
||||
|
||||
struct audio_streaming_t {
|
||||
u8 bNumEndpoints;
|
||||
u8 bFormatType; /** FORMAT_TYPE_1 */
|
||||
u8 bNrChannels; /** physical channels in the stream */
|
||||
u8 bSubframeSize;
|
||||
u8 bBitResolution;
|
||||
u8 bSamFreqType;
|
||||
u32 tSamFreq[8];
|
||||
u8 host_ep; //主机传输端点
|
||||
u8 ep; //从机端点(由描述符中指定)
|
||||
u8 ep_Interval;
|
||||
u16 ep_max_packet_size;
|
||||
};
|
||||
|
||||
struct audio_device_t {
|
||||
u8 interface_num; //接口号
|
||||
u8 subclass;
|
||||
u8 support;
|
||||
void *parent;
|
||||
struct audio_streaming_t as[8];
|
||||
};
|
||||
|
||||
int usb_audio_parser(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf);
|
||||
|
||||
// API
|
||||
int usb_audio_play_put_buf(void *ptr, u32 len);
|
||||
int usb_audio_record_get_buf(void *ptr, u32 len);
|
||||
|
||||
//headphone api
|
||||
void set_usb_audio_play_volume(u16 vol);
|
||||
void usb_audio_start_play(const usb_dev usb_id, u8 channel, u8 bit_reso, u32 sample_rate); //指定播放数据的声道数,位数,采样率
|
||||
void usb_audio_stop_play(const usb_dev usb_id);
|
||||
void usb_audio_pause_play(void);
|
||||
void usb_audio_resume_play(void);
|
||||
|
||||
//microphone api
|
||||
void set_usb_audio_record_volume(u16 vol);
|
||||
void usb_audio_start_record(const usb_dev usb_id, u8 bit_reso, u32 sample_rate); //指定录制数据的位数,采样率
|
||||
void usb_audio_stop_record(const usb_dev usb_id);
|
||||
void usb_audio_pause_record(void);
|
||||
void usb_audio_resume_record(void);
|
||||
#endif
|
||||
111
apps/common/device/usb/host/audio_demo.c
Normal file
111
apps/common/device/usb/host/audio_demo.c
Normal file
@ -0,0 +1,111 @@
|
||||
#include "includes.h"
|
||||
#include "asm/includes.h"
|
||||
#include "app_config.h"
|
||||
#include "system/timer.h"
|
||||
#include "device/ioctl_cmds.h"
|
||||
#include "device_drive.h"
|
||||
#if TCFG_HOST_AUDIO_ENABLE
|
||||
#include "usb/host/usb_host.h"
|
||||
#include "usb_ctrl_transfer.h"
|
||||
#include "usb_bulk_transfer.h"
|
||||
#include "audio.h"
|
||||
#include "usb_config.h"
|
||||
|
||||
#define LOG_TAG_CONST USB
|
||||
#define LOG_TAG "[AUDIO]"
|
||||
#define LOG_ERROR_ENABLE
|
||||
#define LOG_DEBUG_ENABLE
|
||||
#define LOG_INFO_ENABLE
|
||||
/* #define LOG_DUMP_ENABLE */
|
||||
#define LOG_CLI_ENABLE
|
||||
#include "debug.h"
|
||||
|
||||
|
||||
#define TEST_FILE_ENABLE (0) //从sd卡读数据; 录制数据至sd卡
|
||||
#if (TEST_FILE_ENABLE)
|
||||
static FILE *play_file = NULL;
|
||||
int usb_audio_play_put_buf(void *ptr, u32 len)
|
||||
{
|
||||
int ret = 0;
|
||||
if (ptr == NULL && len == 0) {
|
||||
//err
|
||||
if (play_file) {
|
||||
fclose(play_file);
|
||||
play_file = NULL;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (!play_file) {
|
||||
play_file = fopen("storage/sd0/C/raw.pcm", "r"); //单声道
|
||||
/* play_file = fopen("storage/sd0/C/raw2.pcm", "r"); //双声道 */
|
||||
if (!play_file) {
|
||||
log_e("fopen play file faild!\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
//读sd卡数据到播放缓存中
|
||||
ret = fread(play_file, ptr, len);
|
||||
if (ret != len) {
|
||||
log_e(" file read buf err %d\n", ret);
|
||||
fclose(play_file);
|
||||
play_file = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
static FILE *record_file = NULL;
|
||||
int usb_audio_record_get_buf(void *ptr, u32 len)
|
||||
{
|
||||
#if (TEST_FILE_ENABLE)
|
||||
int ret = 0;
|
||||
static u32 cnt = 0;
|
||||
if (!record_file) {
|
||||
record_file = fopen("storage/sd0/C/record01.pcm", "w+");
|
||||
cnt = 0;
|
||||
if (!record_file) {
|
||||
log_e("fopen play file faild!\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
putchar('W');
|
||||
ret = fwrite(record_file, ptr, len);
|
||||
if (ret != len) {
|
||||
log_e(" file write buf err %d\n", ret);
|
||||
fclose(record_file);
|
||||
record_file = NULL;
|
||||
return -1;
|
||||
}
|
||||
//test
|
||||
if (cnt++ >= 800) {
|
||||
cnt = 0;
|
||||
log_info("stop record....\n");
|
||||
fclose(record_file);
|
||||
record_file = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
return len;
|
||||
}
|
||||
#else
|
||||
|
||||
//将数据传入usb
|
||||
//ptr:usb数据指针
|
||||
//len:需要传入的数据长度
|
||||
int usb_audio_play_put_buf(void *ptr, u32 len)
|
||||
{
|
||||
return len;
|
||||
}
|
||||
|
||||
//从usb读取数据
|
||||
//ptr:usb数据指针
|
||||
//len:读取的数据长度
|
||||
int usb_audio_record_get_buf(void *ptr, u32 len)
|
||||
{
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
657
apps/common/device/usb/host/hid.c
Normal file
657
apps/common/device/usb/host/hid.c
Normal file
@ -0,0 +1,657 @@
|
||||
#include "includes.h"
|
||||
#include "asm/includes.h"
|
||||
#include "app_config.h"
|
||||
#include "system/timer.h"
|
||||
#include "device/ioctl_cmds.h"
|
||||
#include "device_drive.h"
|
||||
#if TCFG_HID_HOST_ENABLE
|
||||
#include "usb/host/usb_host.h"
|
||||
#include "usb_ctrl_transfer.h"
|
||||
#include "usb_bulk_transfer.h"
|
||||
#include "hid.h"
|
||||
#include "usb_config.h"
|
||||
#include "usb_hid_keys.h"
|
||||
|
||||
#define MAIN_ITEM 0
|
||||
#define GLOBAL_ITEM 1
|
||||
#define LOCAL_ITEM 2
|
||||
|
||||
#define LOG_TAG_CONST USB
|
||||
#define LOG_TAG "[HID]"
|
||||
#define LOG_ERROR_ENABLE
|
||||
#define LOG_DEBUG_ENABLE
|
||||
#define LOG_INFO_ENABLE
|
||||
/* #define LOG_DUMP_ENABLE */
|
||||
#define LOG_CLI_ENABLE
|
||||
#include "debug.h"
|
||||
|
||||
|
||||
struct hid_device_t hid_device[USB_MAX_HW_NUM][MAX_HOST_INTERFACE];
|
||||
|
||||
static int set_power(struct usb_host_device *host_dev, u32 value)
|
||||
{
|
||||
const usb_dev usb_id = host_device2id(host_dev);
|
||||
memset(hid_device[usb_id], 0, sizeof(hid_device[usb_id]));
|
||||
return DEV_ERR_NONE;
|
||||
}
|
||||
|
||||
static int get_power(struct usb_host_device *host_dev, u32 value)
|
||||
{
|
||||
return DEV_ERR_NONE;
|
||||
}
|
||||
|
||||
static const struct interface_ctrl hid_ctrl = {
|
||||
.interface_class = USB_CLASS_HID,
|
||||
.set_power = set_power,
|
||||
.get_power = get_power,
|
||||
.ioctl = NULL,
|
||||
};
|
||||
|
||||
static const struct usb_interface_info _usb_if[USB_MAX_HW_NUM][MAX_HOST_INTERFACE] = {
|
||||
{
|
||||
{
|
||||
.ctrl = (struct interface_ctrl *) &hid_ctrl,
|
||||
.dev.hid = &hid_device[0][0],
|
||||
},
|
||||
{
|
||||
.ctrl = (struct interface_ctrl *) &hid_ctrl,
|
||||
.dev.hid = &hid_device[0][1],
|
||||
},
|
||||
{
|
||||
.ctrl = (struct interface_ctrl *) &hid_ctrl,
|
||||
.dev.hid = &hid_device[0][2],
|
||||
},
|
||||
{
|
||||
.ctrl = (struct interface_ctrl *) &hid_ctrl,
|
||||
.dev.hid = &hid_device[0][3],
|
||||
},
|
||||
},
|
||||
#if USB_MAX_HW_NUM > 1
|
||||
{
|
||||
{
|
||||
.ctrl = (struct interface_ctrl *) &hid_ctrl,
|
||||
.dev.hid = &hid_device[1][0],
|
||||
},
|
||||
{
|
||||
.ctrl = (struct interface_ctrl *) &hid_ctrl,
|
||||
.dev.hid = &hid_device[1][1],
|
||||
},
|
||||
{
|
||||
.ctrl = (struct interface_ctrl *) &hid_ctrl,
|
||||
.dev.hid = &hid_device[1][2],
|
||||
},
|
||||
{
|
||||
.ctrl = (struct interface_ctrl *) &hid_ctrl,
|
||||
.dev.hid = &hid_device[1][3],
|
||||
},
|
||||
},
|
||||
#endif
|
||||
};
|
||||
|
||||
static u8 interval[USB_MAX_HW_NUM][16];
|
||||
|
||||
int usb_hid_parser(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf)
|
||||
{
|
||||
struct usb_interface_descriptor *interface = (struct usb_interface_descriptor *)pBuf;
|
||||
pBuf += sizeof(struct usb_interface_descriptor);
|
||||
int len = 0;
|
||||
const usb_dev usb_id = host_device2id(host_dev);
|
||||
|
||||
struct usb_endpoint_descriptor *endpoint;
|
||||
|
||||
pBuf += 9;//hid desc;
|
||||
|
||||
const struct usb_interface_info *usb_if = &_usb_if[usb_id][interface_num];
|
||||
|
||||
memset(usb_if->dev.p, 0, sizeof(struct hid_device_t));
|
||||
|
||||
host_dev->interface_info[interface_num] = usb_if;
|
||||
usb_if->dev.hid->parent = host_dev;
|
||||
|
||||
log_info("hid eps %d %d %x %x", interface->bNumEndpoints, interface_num, usb_if, usb_if->dev.p);
|
||||
|
||||
log_info("parent %x hid @ interface %d usb_if %x hid %x",
|
||||
host_dev, interface_num, usb_if, usb_if->dev.hid);
|
||||
|
||||
if ((interface->bInterfaceProtocol == 0x02) ||
|
||||
(interface->bInterfaceProtocol == 0x01)) { //mouse & keyboard
|
||||
|
||||
usb_if->dev.hid->bNumEndpoints = interface->bNumEndpoints;
|
||||
usb_if->dev.hid->report_list[0].usage = interface->bInterfaceProtocol;
|
||||
for (int i = 0 ; i < interface->bNumEndpoints; i++) {
|
||||
endpoint = (struct usb_endpoint_descriptor *)pBuf;
|
||||
if (USB_DIR_IN & endpoint->bEndpointAddress) {
|
||||
const u8 ep = endpoint->bEndpointAddress & 0x0f;
|
||||
usb_if->dev.hid->ep_pair[i] = ep;
|
||||
interval[usb_id][ep] = endpoint->bInterval;
|
||||
log_info("interfacenum = %d,endpoint = %x interval = %x",
|
||||
interface->bInterfaceNumber, endpoint->bEndpointAddress, endpoint->bInterval);
|
||||
}
|
||||
pBuf += endpoint->bLength;
|
||||
}
|
||||
} else {
|
||||
log_info("vendor");
|
||||
host_dev->interface_info[interface_num] = NULL; //???
|
||||
for (int i = 0 ; i < interface->bNumEndpoints; i++) {
|
||||
endpoint = (struct usb_endpoint_descriptor *)pBuf;
|
||||
if (USB_DIR_IN & endpoint->bEndpointAddress) {
|
||||
/* interface_endpoint[interface->bInterfaceNumber] = endpoint->bEndpointAddress & 0x0f; */
|
||||
log_info("interfacenum = %d,endpoint = %x interval = %x",
|
||||
interface->bInterfaceNumber, endpoint->bEndpointAddress, endpoint->bInterval);
|
||||
}
|
||||
pBuf += endpoint->bLength;
|
||||
}
|
||||
return sizeof(struct usb_interface_descriptor);
|
||||
}
|
||||
|
||||
return pBuf - (u8 *)interface;
|
||||
}
|
||||
|
||||
static u32 _hid_report_parse(struct hid_device_t *hid, const u8 *report, u32 len)
|
||||
{
|
||||
hid->report_count = 0;
|
||||
struct report_info_t null_rpt;
|
||||
struct report_info_t *const rpt = &null_rpt;
|
||||
|
||||
memset(rpt, 0, sizeof(*rpt));
|
||||
|
||||
unsigned char ops;
|
||||
int index = 0;
|
||||
u8 report_size = 0;
|
||||
u8 report_count = 0;
|
||||
u8 cur_ops_is_report_size_count = 0;
|
||||
u8 old_ops_is_report_size_count = 0;
|
||||
s8 cur_section_bit = 0;
|
||||
u8 input_bit_index = 0;
|
||||
u8 total_bits = 0;
|
||||
u8 output_bit_index = 0;
|
||||
u8 cur_usage = 0;
|
||||
u32 undef_type = 0;
|
||||
u8 undef_usage = 0;
|
||||
u8 collection_deep = 0;
|
||||
|
||||
while (index < len) {
|
||||
ops = (char)report[index++];
|
||||
char bSize = ops & 0x03;
|
||||
bSize = bSize == 3 ? 4 : bSize; // size is 4 when bSize is 3
|
||||
char bType = (ops >> 2) & 0x03;
|
||||
char bTag = (ops >> 4) & 0x0F;
|
||||
|
||||
cur_ops_is_report_size_count = 0;
|
||||
char bSizeActual = 0;
|
||||
int itemVal = 0;
|
||||
for (int j = 0; j < bSize; j++) {
|
||||
if (index + j < len) {
|
||||
itemVal += report[index + j] << (8 * j);
|
||||
bSizeActual++;
|
||||
}
|
||||
}
|
||||
if (undef_type) {
|
||||
undef_type ++;
|
||||
if (bTag == 0x0A) {
|
||||
undef_usage ++;
|
||||
} else if (bTag == 0x0C) {
|
||||
undef_usage --;
|
||||
}
|
||||
if (undef_usage == 0 && undef_type > 2) {
|
||||
undef_type = 0;
|
||||
}
|
||||
index += bSize;
|
||||
continue;
|
||||
}
|
||||
if (undef_type) {
|
||||
index += bSize;
|
||||
continue;
|
||||
}
|
||||
if (itemVal == 0xffb5) {
|
||||
undef_type = 1;
|
||||
index += bSize;
|
||||
continue;
|
||||
} else {
|
||||
undef_type = 0;
|
||||
}
|
||||
if (bType == MAIN_ITEM) {
|
||||
if (old_ops_is_report_size_count) {
|
||||
cur_section_bit += report_size * report_count;
|
||||
}
|
||||
if (bTag == 0x08) {
|
||||
/* log_info("input %X", itemVal); */
|
||||
/* log_info("\tusage %x", cur_usage); */
|
||||
/* log_info("\t\tcur_section_bit %d", cur_section_bit); */
|
||||
if (rpt->usage == 0x02) { //mouse
|
||||
if (cur_usage == 1) {
|
||||
if (rpt->btn_start_bit == 0) {
|
||||
rpt->btn_start_bit = total_bits ;
|
||||
}
|
||||
rpt->btn_width += cur_section_bit ;
|
||||
/* log_info("btn_width %d-%d", rpt->btn_start_bit, rpt->btn_width); */
|
||||
} else if ((cur_usage == 0x30) || (cur_usage == 0x31)) {
|
||||
|
||||
if (rpt->xy_start_bit == 0) {
|
||||
rpt->xy_start_bit = total_bits;
|
||||
}
|
||||
rpt->xy_width = cur_section_bit;
|
||||
/* log_info("xy_width %d-%d", rpt->xy_start_bit, rpt->xy_width); */
|
||||
} else if (cur_usage == 0x38) {
|
||||
if (rpt->wheel_start_bit == 0) {
|
||||
rpt->wheel_start_bit = total_bits;
|
||||
}
|
||||
if (rpt->xy_width || cur_section_bit < 24) {
|
||||
rpt->wheel_width = cur_section_bit;
|
||||
/* log_info("wheel_width %d-%d", rpt->wheel_start_bit, rpt->wheel_width); */
|
||||
} else {
|
||||
rpt->wheel_width = rpt->xy_width = cur_section_bit / 3;
|
||||
|
||||
rpt->xy_start_bit = total_bits;
|
||||
rpt->wheel_start_bit = rpt->xy_start_bit + rpt->xy_width * 2;
|
||||
/* log_info("wheel_width %d-%d", rpt->wheel_start_bit, rpt->wheel_width); */
|
||||
/* log_info("xy_width %d-%d", rpt->xy_start_bit, rpt->xy_width); */
|
||||
}
|
||||
} else if (cur_usage == 0xb8) {
|
||||
rpt->wheel_width = rpt->xy_width = cur_section_bit / 4;
|
||||
rpt->xy_start_bit = total_bits;
|
||||
rpt->wheel_start_bit = rpt->xy_start_bit + rpt->xy_width * 2;
|
||||
}
|
||||
}
|
||||
total_bits += cur_section_bit;
|
||||
/* input_bit[input_bit_index++] = cur_section_bit; */
|
||||
cur_section_bit = -1;
|
||||
} else if (bTag == 0x09) {
|
||||
/* log_info("OUTPUT %X", itemVal); */
|
||||
/* log_info("\tusage %x", cur_usage); */
|
||||
/* log_info("\t\tcur_section_bit %d", cur_section_bit); */
|
||||
/* output_bit[output_bit_index++] = cur_section_bit; */
|
||||
cur_section_bit = -1;
|
||||
} else if (bTag == 0x0B) {
|
||||
/* log_info("Feature %X", itemVal); */
|
||||
/* log_info("\tusage %x", cur_usage); */
|
||||
/* log_info("\t\tcur_section_bit %d", cur_section_bit); */
|
||||
/* output_bit[output_bit_index++] = cur_section_bit; */
|
||||
cur_section_bit = -1;
|
||||
} else if (bTag == 0x0A) {
|
||||
collection_deep ++ ;
|
||||
log_info("Collection %d %x", collection_deep, rpt->usage);
|
||||
} else if (bTag == 0x0C) {
|
||||
collection_deep --;
|
||||
log_info("End Collection %d %x", collection_deep, rpt->usage);
|
||||
if (collection_deep == 0) {
|
||||
if (rpt->usage == 0x02 ||
|
||||
rpt->usage == 0x06 ||
|
||||
rpt->usage == 0x07) {
|
||||
|
||||
memcpy(&hid->report_list[hid->report_count], rpt, sizeof(*rpt));
|
||||
memset(rpt, 0, sizeof(*rpt));
|
||||
|
||||
hid->report_count ++;
|
||||
}
|
||||
}
|
||||
if (index < len) {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
log_info("MAIN_ITEM Unknown btag :%x", bTag);
|
||||
return 1;
|
||||
}
|
||||
} else if (bType == GLOBAL_ITEM) {
|
||||
/* log_info("GLOBAL_ITEM"); */
|
||||
if (bTag == 0x00) {
|
||||
/* log_info("Usage Page %x", itemVal); */
|
||||
|
||||
if (rpt->usage == 0x06) {
|
||||
if (itemVal == 0x07) {
|
||||
rpt->usage = 0x07;
|
||||
log_info("re set type %x", 0x07);
|
||||
}
|
||||
}
|
||||
if (itemVal == 0x02) {
|
||||
rpt->usage = 0x02;
|
||||
log_info("re set type %x", 0x02);
|
||||
}
|
||||
|
||||
} else if (bTag == 0x01) {
|
||||
//log_info("Logical Minimum %x", itemVal);
|
||||
} else if (bTag == 0x02) {
|
||||
//log_info("Logical Maximum %x", itemVal);
|
||||
} else if (bTag == 0x03) {
|
||||
/* log_info("Physical Minimum %x", itemVal); */
|
||||
} else if (bTag == 0x04) {
|
||||
/* log_info("Physical Maximum %x", itemVal); */
|
||||
} else if (bTag == 0x05) {
|
||||
/* log_info("Unit Exponent %x", itemVal); */
|
||||
} else if (bTag == 0x06) {
|
||||
/* log_info("Unit %x", itemVal); */
|
||||
} else if (bTag == 0x07) {
|
||||
/* log_info("Report Size %x", itemVal); */
|
||||
report_size = itemVal;
|
||||
cur_ops_is_report_size_count = 1;
|
||||
} else if (bTag == 0x08) {
|
||||
log_info("Report ID %x", itemVal, rpt->usage);
|
||||
rpt->report_id = itemVal;
|
||||
} else if (bTag == 0x09) {
|
||||
/* log_info("Report Count %x", itemVal); */
|
||||
report_count = itemVal;
|
||||
cur_ops_is_report_size_count = 1;
|
||||
} else if (bTag == 0x0A) {
|
||||
/* log_info("Push %x", bSizeActual); */
|
||||
} else if (bTag == 0x0B) {
|
||||
/* log_info("Pop %x", bSizeActual); */
|
||||
} else {
|
||||
log_info("GLOBAL_ITEM Unknown btag :%x", bTag);
|
||||
return 2;
|
||||
}
|
||||
} else if (bType == LOCAL_ITEM) {
|
||||
/* log_info("LOCAL_ITEM"); */
|
||||
if (bTag == 0x00) {
|
||||
if (rpt->usage == 0) {
|
||||
rpt->usage = itemVal;
|
||||
log_info("set type %x", rpt->usage);
|
||||
}
|
||||
if (itemVal == 0x30) { //X
|
||||
} else if (itemVal == 0x31) { //y
|
||||
} else if (itemVal == 0x38) { //wheel
|
||||
} else {
|
||||
}
|
||||
/* log_info("\t change usage %x -> %x", cur_usage, itemVal); */
|
||||
cur_usage = itemVal;
|
||||
if (!collection_deep) {
|
||||
if (itemVal == 0x06 || itemVal == 0x07 || itemVal == 0x02) {
|
||||
//仅限键盘和鼠标
|
||||
rpt->usage = itemVal;
|
||||
log_info("set typee %x", rpt->usage);
|
||||
}
|
||||
}
|
||||
/* type = itemVal; */
|
||||
} else if (bTag == 0x01) {
|
||||
// log_info("Usage Minimum %x", itemVal);
|
||||
} else if (bTag == 0x02) {
|
||||
// log_info("Usage Maximum %x", itemVal);
|
||||
} else if (bTag == 0x03) {
|
||||
/* log_info("Designator Index %x", itemVal); */
|
||||
} else if (bTag == 0x04) {
|
||||
/* log_info("Designator Minimum %x", itemVal); */
|
||||
} else if (bTag == 0x05) {
|
||||
/* log_info("Designator Maximum %x", itemVal); */
|
||||
} else if (bTag == 0x07) {
|
||||
/* log_info("String Index %x", itemVal); */
|
||||
} else if (bTag == 0x08) {
|
||||
/* log_info("String Minimum %x", itemVal); */
|
||||
} else if (bTag == 0x09) {
|
||||
/* log_info("String Maximum %x", itemVal); */
|
||||
} else if (bTag == 0x0A) {
|
||||
/* log_info("Delimiter %x", itemVal); */
|
||||
} else {
|
||||
log_info("LOCAL_ITEM Unknown btag :%x", bTag);
|
||||
return 3;
|
||||
}
|
||||
} else {
|
||||
log_info("OTHER Unknown btag :%x", bTag);
|
||||
return 4;
|
||||
}
|
||||
if (!cur_ops_is_report_size_count && old_ops_is_report_size_count) {
|
||||
if (cur_section_bit != -1) {
|
||||
cur_section_bit += report_size * report_count;
|
||||
} else {
|
||||
cur_section_bit = 0;
|
||||
}
|
||||
}
|
||||
if (cur_section_bit == -1) {
|
||||
cur_section_bit = 0;
|
||||
}
|
||||
old_ops_is_report_size_count = cur_ops_is_report_size_count;
|
||||
index += bSize;
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static u32 hid_report_parse(struct hid_device_t *hid, const u8 *report, u32 len)
|
||||
{
|
||||
u8 type = _hid_report_parse(hid, report, len);
|
||||
for (int i = 0; i < hid->report_count; i++) {
|
||||
struct report_info_t *rpt = &hid->report_list[i];
|
||||
if (rpt->usage == 0x02) {
|
||||
if (rpt->report_id == 0) {
|
||||
rpt->report_id = 0xff;
|
||||
}
|
||||
rpt->btn_start_bit /= 8;
|
||||
rpt->btn_width /= 8;
|
||||
rpt->xy_start_bit /= 8;
|
||||
rpt->xy_width /= 8;
|
||||
rpt->wheel_start_bit /= 8;
|
||||
rpt->wheel_width /= 8;
|
||||
|
||||
log_info("mouse report_id %d",
|
||||
rpt->report_id);
|
||||
|
||||
log_info("btn_width %d-%d",
|
||||
rpt->btn_start_bit, rpt->btn_width);
|
||||
log_info("xy_width %d-%d",
|
||||
rpt->xy_start_bit, rpt->xy_width);
|
||||
log_info("wheel_width %d-%d",
|
||||
rpt->wheel_start_bit, rpt->wheel_width);
|
||||
|
||||
if (rpt->btn_width != 2) {
|
||||
rpt->btn_width = 1;
|
||||
}
|
||||
|
||||
log_info("btn_width %d-%d",
|
||||
rpt->btn_start_bit, rpt->btn_width);
|
||||
|
||||
} else if (rpt->usage == 6 || rpt->usage == 7) {
|
||||
if (rpt->report_id == 0) {
|
||||
rpt->report_id = 0xff;
|
||||
}
|
||||
log_info("keyboard report_id %d", rpt->report_id);
|
||||
} else {
|
||||
log_info("unknown usage %d", rpt->usage);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mouse_route(const struct mouse_data_t *p);
|
||||
/* __attribute__((weak)) void mouse_route(const struct mouse_data_t *p) */
|
||||
/* { */
|
||||
/* log_info("btn: %x x-y %d %d wheel %d ac_pan %d", */
|
||||
/* p->btn, p->x, p->y, p->wheel, p->ac_pan); */
|
||||
/* } */
|
||||
static void hid_convert_mouse(const struct report_info_t *mouse, const u8 *buffer)
|
||||
{
|
||||
struct mouse_data_t mouse_data;
|
||||
memset(&mouse_data, 0, sizeof(mouse_data));
|
||||
if (mouse->report_id != 0xff) {
|
||||
if (mouse->report_id != buffer[0]) {
|
||||
log_error("report_id = %x buffer[0] = %x", mouse->report_id, buffer[0]);
|
||||
return;
|
||||
}
|
||||
buffer++;
|
||||
}
|
||||
const u8 *ptr;
|
||||
ptr = &buffer[mouse->btn_start_bit];
|
||||
if (mouse->btn_width == 2) {
|
||||
mouse_data.btn = ptr[0] | (ptr[1] << 8);
|
||||
} else {
|
||||
mouse_data.btn = ptr[0] ;
|
||||
}
|
||||
s16 tmp;
|
||||
ptr = &buffer[mouse->xy_start_bit];
|
||||
if (mouse->xy_width == 1 || mouse->xy_width == 2) {
|
||||
mouse_data.x = (char)ptr[0];
|
||||
mouse_data.y = (char)ptr[1];
|
||||
} else if (mouse->xy_width == 4) {
|
||||
mouse_data.x = ptr[0] | (ptr[1] << 8);
|
||||
ptr += 2;
|
||||
mouse_data.y = ptr[0] | (ptr[1] << 8);
|
||||
} else if (mouse->xy_width == 3) {
|
||||
tmp = (ptr[1] & 0xf) << 12 | ptr[0] << 4;
|
||||
tmp = tmp >> 4;
|
||||
mouse_data.x = tmp;
|
||||
|
||||
tmp = (ptr[2] << 8) | ((ptr[1] >> 4) << 4);
|
||||
tmp = tmp >> 4;
|
||||
mouse_data.y = tmp;
|
||||
} else {
|
||||
log_error("error mouse xy_width %d", mouse->xy_width);
|
||||
}
|
||||
|
||||
ptr = &buffer[mouse->wheel_start_bit];
|
||||
|
||||
if (mouse->wheel_width == 1) {
|
||||
mouse_data.wheel = (char)ptr[0];
|
||||
} else {
|
||||
mouse_data.wheel = ptr[0] | (ptr[1] << 8);
|
||||
}
|
||||
|
||||
mouse_route(&mouse_data);
|
||||
}
|
||||
__attribute__((weak)) void keyboard_route(const u8 *p)
|
||||
{
|
||||
log_info("keyboard_buffer:");
|
||||
printf_buf(p, 12);
|
||||
}
|
||||
void hid_convert_krbd(const struct report_info_t *kbd, u8 *buffer)
|
||||
{
|
||||
#if 0
|
||||
u8 keyboard_buffer[12];
|
||||
memset(keyboard_buffer, 0, sizeof(keyboard_buffer));
|
||||
if (kbd->report_id != 0xff) {
|
||||
if (kbd->report_id != buffer[0]) {
|
||||
log_error("report_id = %x buffer[0] = %x", kbd->report_id, buffer[0]);
|
||||
return;
|
||||
}
|
||||
buffer++;
|
||||
}
|
||||
|
||||
u8 idx = 0;
|
||||
u8 index = 0;
|
||||
int i = 0;
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (buffer[0] & BIT(i)) {
|
||||
keyboard_buffer[idx++] = 0xe0 + i;
|
||||
}
|
||||
}
|
||||
|
||||
if (buffer[1] == 0) {
|
||||
buffer += 2;
|
||||
}
|
||||
index = idx;
|
||||
for (; idx < 12; idx++) {
|
||||
if (*buffer) {
|
||||
keyboard_buffer[index] = *buffer;
|
||||
index++;
|
||||
}
|
||||
buffer ++;
|
||||
}
|
||||
keyboard_route(keyboard_buffer);
|
||||
#else
|
||||
if (kbd->report_id != 0xff) {
|
||||
if (kbd->report_id != buffer[0]) {
|
||||
log_error("report_id = %x buffer[0] = %x", kbd->report_id, buffer[0]);
|
||||
return;
|
||||
}
|
||||
buffer++;
|
||||
}
|
||||
u8 keyboard_buffer[8];
|
||||
memset(keyboard_buffer, 0, sizeof(keyboard_buffer));
|
||||
|
||||
keyboard_buffer[0] = *buffer;
|
||||
buffer ++;
|
||||
|
||||
if (*buffer == 0) {
|
||||
buffer ++;
|
||||
}
|
||||
keyboard_buffer[1] = 0;
|
||||
|
||||
/* memcpy(&keyboard_buffer[2], buffer, 6); */
|
||||
u8 pos = 2;
|
||||
for (int i = pos; i < 8; i++) {
|
||||
if (*buffer) {
|
||||
keyboard_buffer[pos] = *buffer;
|
||||
pos++;
|
||||
}
|
||||
buffer++;
|
||||
}
|
||||
keyboard_route(keyboard_buffer);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void hid_route(const struct hid_device_t *hid, const u8 *buffer)
|
||||
{
|
||||
for (int i = 0; i < hid->report_count; i++) {
|
||||
if (hid->report_list[i].usage == 0x02) {
|
||||
hid_convert_mouse(&hid->report_list[i], buffer);
|
||||
} else if ((hid->report_list[i].usage == 0x06) ||
|
||||
(hid->report_list[i].usage == 0x07)) {
|
||||
hid_convert_krbd(&hid->report_list[i], buffer);
|
||||
} else {
|
||||
r_printf("usage %x", hid->report_list[i].usage);
|
||||
}
|
||||
}
|
||||
}
|
||||
static void hid_isr(struct usb_interface_info *usb_if, u32 ep)
|
||||
{
|
||||
u8 buffer[64] = {0};
|
||||
struct usb_host_device *host_dev = usb_if->dev.hid->parent;
|
||||
usb_dev usb_id = host_device2id(host_dev);
|
||||
u32 target_ep = usb_if->dev.hid->ep_pair[ep];
|
||||
u32 rx_len = usb_h_ep_read_async(usb_id, ep, target_ep, buffer, 64, USB_ENDPOINT_XFER_INT, 0);
|
||||
|
||||
if (rx_len) {
|
||||
hid_route(usb_if->dev.hid, buffer);
|
||||
}
|
||||
/* printf_buf(buffer, rx_len); */
|
||||
|
||||
usb_h_ep_read_async(usb_id, ep, target_ep, buffer, 8, USB_ENDPOINT_XFER_INT, 1);
|
||||
}
|
||||
void hid_process(u32 id)
|
||||
{
|
||||
struct usb_host_device *host_dev = host_id2device(id);
|
||||
u8 report[256 + 2];
|
||||
u8 ep_pair[4];
|
||||
|
||||
for (u8 i = 0; i < MAX_HOST_INTERFACE; i++) {
|
||||
struct usb_interface_info *usb_if = host_dev->interface_info[i];
|
||||
log_info("parent %x hid @ interface %d usb_if %x hid %x",
|
||||
host_dev, i, usb_if, usb_if ? usb_if->dev.hid : 0);
|
||||
if (usb_if &&
|
||||
(usb_if->ctrl->interface_class == USB_CLASS_HID)) {
|
||||
hid_set_idle(host_dev, i);
|
||||
memset(report, 0, sizeof(report));
|
||||
hid_get_report(host_dev, report, i, 0xff);
|
||||
printf_buf(report, 256);
|
||||
hid_report_parse(usb_if->dev.hid, report, 256);
|
||||
memcpy(ep_pair, usb_if->dev.hid->ep_pair, 4);
|
||||
|
||||
if (usb_if->dev.hid->report_count == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int i = 0; i < usb_if->dev.hid->bNumEndpoints; i++) {
|
||||
|
||||
u32 host_ep = usb_get_ep_num(id, USB_DIR_IN, USB_ENDPOINT_XFER_INT);
|
||||
|
||||
ASSERT(host_ep != -1, "ep not enough");
|
||||
|
||||
u32 target_ep = ep_pair[i];
|
||||
|
||||
usb_if->dev.hid->ep_pair[host_ep] = target_ep;
|
||||
|
||||
log_info("D2H ep: %x --> %x interval %d",
|
||||
target_ep, host_ep, interval[id][target_ep]);
|
||||
|
||||
usb_h_set_ep_isr(host_dev, host_ep | USB_DIR_IN, hid_isr, usb_if);
|
||||
|
||||
u8 *ep_buffer = usb_h_get_ep_buffer(id, host_ep | USB_DIR_OUT);
|
||||
usb_h_ep_config(id, host_ep | USB_DIR_IN, USB_ENDPOINT_XFER_INT, 1,
|
||||
interval[id][target_ep], ep_buffer, 64);
|
||||
int r = usb_h_ep_read_async(id, host_ep, target_ep, NULL, 0, USB_ENDPOINT_XFER_INT, 1);
|
||||
}
|
||||
} else {
|
||||
if (usb_if) {
|
||||
log_error("error hid class %x", usb_if->ctrl->interface_class);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
83
apps/common/device/usb/host/hid.h
Normal file
83
apps/common/device/usb/host/hid.h
Normal file
@ -0,0 +1,83 @@
|
||||
/**@file hid.h
|
||||
* @brief hid驱动头文件(做主机)
|
||||
* @details 结构体声明,功能函数声明
|
||||
* @author jieli
|
||||
* @date 2021-9-1
|
||||
* @version V1.0
|
||||
* @copyright Copyright(c)2010-2021 珠海市杰理科技股份有限公司
|
||||
*********************************************************
|
||||
* @attention
|
||||
* 硬件平台:AC632N
|
||||
* SDK版本:AC632N_V1.0.0_SDK
|
||||
* @修改日志:
|
||||
* <table>
|
||||
* <tr><th>Date <th>Version <th>Author <th>Description
|
||||
* <tr><td>2021-9-1 <td>1.0 <td>jieli <td>创建初始版本
|
||||
* </table>
|
||||
*
|
||||
*********************************************************
|
||||
*/
|
||||
#ifndef __HID_H__
|
||||
#define __HID_H__
|
||||
|
||||
#include "system/task.h"
|
||||
#include "device/device.h"
|
||||
#include "usb/scsi.h"
|
||||
#include "usb_bulk_transfer.h"
|
||||
#include "usb/host/usb_host.h"
|
||||
|
||||
/**@struct report_info_t
|
||||
* @brief 报告描述符包含的信息结构体\n
|
||||
* 自定义一些私有数据信息存储在该结构体中
|
||||
*/
|
||||
struct report_info_t {
|
||||
u8 report_id; ///<id号,不同hid设备对应不同id
|
||||
u8 usage; ///<描述该数据信息的用途
|
||||
|
||||
u8 btn_start_bit; ///<鼠标按键数据起始位
|
||||
u8 btn_width; ///<鼠标按键数据宽度
|
||||
|
||||
u8 xy_start_bit; ///<鼠标平移数据起始位
|
||||
u8 xy_width; ///<鼠标平移数据宽度
|
||||
|
||||
u8 wheel_start_bit; ///<鼠标滚轮数据起始位
|
||||
u8 wheel_width; ///<鼠标滚轮数据宽度
|
||||
};
|
||||
|
||||
#define MAX_REPORT_COUNT 4
|
||||
|
||||
/**@struct hid_device_t
|
||||
* @brief 报告描述符包含的信息结构体\n
|
||||
* 自定义一些私有数据信息存储在该结构体中
|
||||
*/
|
||||
struct hid_device_t {
|
||||
void *parent; ///<定义的parent指针,指向该hid的所属设备
|
||||
u8 ep_pair[4]; ///<端点对数组,数组下标存放主机端点,对应的元素存放目标端点
|
||||
u8 report_count; ///<报告描述符中item计数器
|
||||
u8 bNumEndpoints; ///<端点数量
|
||||
struct report_info_t report_list[MAX_REPORT_COUNT]; ///<报告描述符结构体
|
||||
};
|
||||
|
||||
/**@brief USB hid设备解析
|
||||
* @param[in] host_dev usb_host_device定义的结构体指针
|
||||
* @param[in] interface_num 接口号
|
||||
* @param[in] *pBuf 数据指针,指向数据存放的地址
|
||||
* @return 接口描述符长度
|
||||
* @par 示例:
|
||||
* @code
|
||||
* usb_hid_parser(host_dev,interface_num,pBuf);
|
||||
* @encode
|
||||
*/
|
||||
int usb_hid_parser(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf);
|
||||
|
||||
/**@brief USB hid设备信息处理
|
||||
* @param[in] id usb设备id号
|
||||
* @return 无
|
||||
* @par 示例:
|
||||
* @code
|
||||
* hid_process(id);
|
||||
* @encode
|
||||
*/
|
||||
void hid_process(u32 id);
|
||||
|
||||
#endif /*HID_H*/
|
||||
319
apps/common/device/usb/host/usb_bulk_transfer.c
Normal file
319
apps/common/device/usb/host/usb_bulk_transfer.c
Normal file
@ -0,0 +1,319 @@
|
||||
/**
|
||||
* @file usb_bulk_transfer.c
|
||||
* @brief bulk transfer driver
|
||||
* @author chenrixin@zh-jieli.com
|
||||
* @version 1.00
|
||||
* @date 2017-02-09
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "jiffies.h"
|
||||
#include "usb_config.h"
|
||||
#include "usb_bulk_transfer.h"
|
||||
#include "usb_ctrl_transfer.h"
|
||||
#include "usb_storage.h"
|
||||
#include "usb/host/usb_host.h"
|
||||
#include "usb/usb_phy.h"
|
||||
#include "app_config.h"
|
||||
#include "device_drive.h"
|
||||
|
||||
#if USB_HOST_ENABLE
|
||||
#define LOG_TAG_CONST USB
|
||||
#define LOG_TAG "[USB]"
|
||||
#define LOG_ERROR_ENABLE
|
||||
#define LOG_DEBUG_ENABLE
|
||||
#define LOG_INFO_ENABLE
|
||||
/* #define LOG_DUMP_ENABLE */
|
||||
#define LOG_CLI_ENABLE
|
||||
#include "debug.h"
|
||||
|
||||
struct usb_request_block {
|
||||
void *ptr;
|
||||
u32 len;
|
||||
u32 target_ep;
|
||||
u16 rxmap;
|
||||
u16 txmap;
|
||||
u32 msg;
|
||||
u32 async_mode;
|
||||
};
|
||||
static struct usb_request_block urb;
|
||||
|
||||
u8 get_async_mode(void)
|
||||
{
|
||||
u8 mode = BULK_ASYNC_MODE_EXIT ;
|
||||
#if UDISK_READ_512_ASYNC_ENABLE
|
||||
local_irq_disable();
|
||||
mode = urb.async_mode;
|
||||
local_irq_enable();
|
||||
#endif
|
||||
return mode;
|
||||
|
||||
}
|
||||
void set_async_mode(u8 mode)
|
||||
{
|
||||
#if UDISK_READ_512_ASYNC_ENABLE
|
||||
local_irq_disable();
|
||||
urb.async_mode = mode;
|
||||
local_irq_enable();
|
||||
#endif
|
||||
}
|
||||
static void usb_bulk_rx_isr(struct usb_host_device *host_dev, u32 ep)
|
||||
{
|
||||
usb_dev usb_id = host_device2id(host_dev);
|
||||
int l = min(urb.len, urb.rxmap);
|
||||
|
||||
l = usb_h_ep_read_async(usb_id, ep, urb.target_ep, urb.ptr, l, USB_ENDPOINT_XFER_BULK, 0);
|
||||
/* g_printf("%s() %d %d", __func__, l, urb.len); */
|
||||
if (l > 0) {
|
||||
urb.len -= l;
|
||||
if (urb.ptr) {
|
||||
urb.ptr += l;
|
||||
}
|
||||
urb.msg = 0;
|
||||
} else {
|
||||
urb.msg = l;
|
||||
urb.len = 0;
|
||||
}
|
||||
|
||||
if (urb.len == 0) {
|
||||
u32 async_mode = get_async_mode();
|
||||
|
||||
if (async_mode == BULK_ASYNC_MODE_EXIT) {
|
||||
usb_sem_post(host_dev);
|
||||
} else if (async_mode == BULK_ASYNC_MODE_SEM_PEND) {
|
||||
if (urb.msg == 0) {
|
||||
usb_sem_post(host_dev);
|
||||
} else {
|
||||
r_printf("usb async error");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
usb_h_ep_read_async(usb_id, ep, urb.target_ep, urb.ptr, urb.len, USB_ENDPOINT_XFER_BULK, 1);
|
||||
}
|
||||
}
|
||||
s32 usb_bulk_only_receive_async(struct device *device, u8 host_ep, u16 rxmaxp, u8 target_ep, u8 *pBuf, u32 len)
|
||||
{
|
||||
struct usb_host_device *host_dev = device_to_usbdev(device);
|
||||
const usb_dev usb_id = host_device2id(host_dev);
|
||||
u8 devnum = host_dev->private_data.devnum;
|
||||
|
||||
urb.ptr = pBuf;
|
||||
urb.len = len;
|
||||
urb.target_ep = target_ep;
|
||||
|
||||
#ifdef CONFIG_USB_SUPPORT_MRX_TX
|
||||
urb.rxmap = 1 * 1024;
|
||||
#else
|
||||
#if defined(FUSB_MODE) && FUSB_MODE == 0
|
||||
urb.rxmap = rxmaxp;
|
||||
#else
|
||||
urb.rxmap = 0x40;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
urb.msg = -DEV_ERR_OFFLINE;
|
||||
|
||||
usb_h_set_ep_isr(host_dev, host_ep | USB_DIR_IN, usb_bulk_rx_isr, host_dev);
|
||||
usb_set_intr_rxe(usb_id, host_ep);
|
||||
#ifdef USB_HW_20
|
||||
usb_write_rxfuncaddr(usb_id, host_ep, devnum);
|
||||
#endif
|
||||
|
||||
int ret = usb_h_ep_read_async(usb_id, host_ep, target_ep, urb.ptr, len, USB_ENDPOINT_XFER_BULK, 1);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
ret = usb_sem_pend(host_dev, 300);
|
||||
|
||||
usb_clr_intr_rxe(usb_id, host_ep);
|
||||
usb_h_set_ep_isr(host_dev, host_ep | USB_DIR_IN, NULL, host_dev);
|
||||
if (ret) {
|
||||
return -DEV_ERR_TIMEOUT;
|
||||
}
|
||||
return urb.msg ? urb.msg : len;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief usb_bulk_receive_async_no_wait 启动USB Bulk 异步预读
|
||||
* 不用等信号量,启动传输后返回
|
||||
* @param device 设备句柄
|
||||
* @param pBuf 读buffer缓冲区,芯片所有memory都可以
|
||||
* @param len 需要预读的长度
|
||||
*
|
||||
* @return 负数表示失败
|
||||
*/
|
||||
s32 usb_bulk_receive_async_no_wait(struct device *device, u8 host_ep, u16 rxmaxp, u8 target_ep, u8 *pBuf, u32 len)
|
||||
{
|
||||
struct usb_host_device *host_dev = device_to_usbdev(device);
|
||||
const usb_dev usb_id = host_device2id(host_dev);
|
||||
u8 devnum = host_dev->private_data.devnum;
|
||||
|
||||
set_async_mode(BULK_ASYNC_MODE_SEM_PEND);
|
||||
urb.ptr = pBuf;
|
||||
urb.len = len;
|
||||
urb.target_ep = target_ep;
|
||||
|
||||
#ifdef CONFIG_USB_SUPPORT_MRX_TX
|
||||
urb.rxmap = 1 * 1024;
|
||||
#else
|
||||
#if defined(FUSB_MODE) && FUSB_MODE == 0
|
||||
urb.rxmap = rxmaxp;
|
||||
#else
|
||||
urb.rxmap = 0x40;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
urb.msg = -DEV_ERR_OFFLINE;
|
||||
|
||||
usb_h_set_ep_isr(host_dev, host_ep | USB_DIR_IN, usb_bulk_rx_isr, host_dev);
|
||||
usb_set_intr_rxe(usb_id, host_ep);
|
||||
#ifdef USB_HW_20
|
||||
usb_write_rxfuncaddr(usb_id, host_ep, devnum);
|
||||
#endif
|
||||
|
||||
int ret = usb_h_ep_read_async(usb_id, host_ep, target_ep, urb.ptr, len, USB_ENDPOINT_XFER_BULK, 1);
|
||||
if (ret < 0) {
|
||||
if (ret == -DEV_ERR_RXSTALL) {
|
||||
ret = usb_clear_feature(host_dev, target_ep | USB_DIR_IN);
|
||||
if (ret == 0) {
|
||||
return -DEV_ERR_RXSTALL;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
static s32 _usb_bulk_only_receive(struct device *device, u8 host_ep, u16 rxmaxp, u8 target_ep, u8 *pBuf, u32 len)
|
||||
{
|
||||
#if 0
|
||||
struct usb_host_device *host_dev = device_to_usbdev(device);
|
||||
const usb_dev usb_id = host_device2id(host_dev);
|
||||
return usb_h_bulk_read(usb_id, host_ep, rxmaxp, target_ep, pBuf, len);
|
||||
#else
|
||||
return usb_bulk_only_receive_async(device, host_ep, rxmaxp, target_ep, pBuf, len);
|
||||
#endif
|
||||
}
|
||||
s32 usb_bulk_only_receive(struct device *device, u8 host_ep, u16 rxmaxp, u8 target_ep, u8 *pBuf, u32 len)
|
||||
{
|
||||
|
||||
struct usb_host_device *host_dev = device_to_usbdev(device);
|
||||
int ret = _usb_bulk_only_receive(device, host_ep, rxmaxp, target_ep, pBuf, len);
|
||||
if (ret == -DEV_ERR_RXSTALL) {
|
||||
ret = usb_clear_feature(host_dev, target_ep | USB_DIR_IN);
|
||||
if (ret == 0) {
|
||||
return -DEV_ERR_RXSTALL;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
static void usb_bulk_tx_isr(struct usb_host_device *host_dev, u32 ep)
|
||||
{
|
||||
usb_dev usb_id = host_device2id(host_dev);
|
||||
int l = min(urb.len, urb.txmap);
|
||||
l = usb_h_ep_write_async(usb_id, ep, urb.txmap, urb.target_ep, urb.ptr, l, USB_ENDPOINT_XFER_BULK, 0);
|
||||
|
||||
if (l > 0) {
|
||||
urb.len -= l;
|
||||
urb.ptr += l;
|
||||
urb.msg = 0;
|
||||
} else {
|
||||
urb.msg = l;
|
||||
urb.len = 0;
|
||||
}
|
||||
|
||||
if (urb.len == 0) {
|
||||
if (urb.msg || l == 0) {
|
||||
usb_sem_post(host_dev);
|
||||
}
|
||||
}
|
||||
}
|
||||
s32 usb_bulk_only_send_async(struct device *device, u8 host_ep, u16 txmaxp, u8 target_ep, const u8 *pBuf, u32 len)
|
||||
{
|
||||
struct usb_host_device *host_dev = device_to_usbdev(device);
|
||||
const usb_dev usb_id = host_device2id(host_dev);
|
||||
u8 devnum = host_dev->private_data.devnum;
|
||||
|
||||
urb.target_ep = target_ep;
|
||||
#ifdef CONFIG_USB_SUPPORT_MRX_TX
|
||||
urb.txmap = 8 * 1024;
|
||||
#else
|
||||
#if defined(FUSB_MODE) && FUSB_MODE == 0
|
||||
urb.txmap = rxmaxp;
|
||||
#else
|
||||
urb.txmap = 0x40;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
urb.msg = -DEV_ERR_OFFLINE;
|
||||
urb.len = len - min(len, urb.txmap);
|
||||
urb.ptr = (u8 *)pBuf + min(len, urb.txmap);
|
||||
|
||||
|
||||
usb_h_set_ep_isr(host_dev, host_ep, usb_bulk_tx_isr, host_dev);
|
||||
usb_set_intr_txe(usb_id, host_ep);
|
||||
#ifdef USB_HW_20
|
||||
usb_write_txfuncaddr(usb_id, host_ep, devnum);
|
||||
#endif
|
||||
|
||||
int ret = usb_h_ep_write_async(usb_id, host_ep, txmaxp, target_ep, pBuf, min(len, urb.txmap), USB_ENDPOINT_XFER_BULK, 1);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
ret = usb_sem_pend(host_dev, 250);
|
||||
|
||||
usb_clr_intr_txe(usb_id, host_ep);
|
||||
usb_h_set_ep_isr(host_dev, host_ep, NULL, host_dev);
|
||||
|
||||
if (ret) {
|
||||
r_printf("ret %d", ret);
|
||||
return -DEV_ERR_TIMEOUT;
|
||||
}
|
||||
/* g_printf("%s() %d %d", __func__, urb.len, urb.msg); */
|
||||
return urb.msg ? urb.msg : len;
|
||||
}
|
||||
/**
|
||||
* @brief usb_bulk_only_send
|
||||
*
|
||||
* @param device
|
||||
* @param host_ep 主机的端点号
|
||||
* @param target_ep 目标设备的端点号
|
||||
* @param pBuf
|
||||
* @param len
|
||||
*
|
||||
* @return 负数失败
|
||||
* 正数发送的字节数
|
||||
*/
|
||||
static s32 _usb_bulk_only_send(struct device *device, u8 host_ep, u16 txmaxp, u8 target_ep, const u8 *pBuf, u32 len)
|
||||
{
|
||||
#if 0
|
||||
struct usb_host_device *host_dev = device_to_usbdev(device);
|
||||
const usb_dev usb_id = host_device2id(host_dev);
|
||||
return usb_h_bulk_write(usb_id, host_ep, txmaxp, target_ep, pBuf, len);
|
||||
#elif 0
|
||||
if (len < 512) {
|
||||
struct usb_host_device *host_dev = device_to_usbdev(device);
|
||||
const usb_dev usb_id = host_device2id(host_dev);
|
||||
return usb_h_bulk_write(usb_id, host_ep, txmaxp, target_ep, pBuf, len);
|
||||
} else {
|
||||
return usb_bulk_only_send_async(device, host_ep, txmaxp, target_ep, pBuf, len);
|
||||
}
|
||||
#else
|
||||
return usb_bulk_only_send_async(device, host_ep, txmaxp, target_ep, pBuf, len);
|
||||
#endif
|
||||
}
|
||||
s32 usb_bulk_only_send(struct device *device, u8 host_ep, u16 txmaxp, u8 target_ep, const u8 *pBuf, u32 len)
|
||||
{
|
||||
struct usb_host_device *host_dev = device_to_usbdev(device);
|
||||
int ret = _usb_bulk_only_send(device, host_ep, txmaxp, target_ep, pBuf, len);
|
||||
|
||||
if (ret == -DEV_ERR_TXSTALL) {
|
||||
ret = usb_clear_feature(host_dev, target_ep);
|
||||
if (ret == 0) {
|
||||
return -DEV_ERR_TXSTALL;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
|
||||
}
|
||||
#endif
|
||||
120
apps/common/device/usb/host/usb_bulk_transfer.h
Normal file
120
apps/common/device/usb/host/usb_bulk_transfer.h
Normal file
@ -0,0 +1,120 @@
|
||||
/**@file usb_bulk_transfer.h
|
||||
* @brief usb_bulk_transfer批量传输头文件
|
||||
* @details 功能函数声明
|
||||
* @author jieli
|
||||
* @date 2021-8-1
|
||||
* @version V1.0
|
||||
* @copyright Copyright(c)2010-2021 珠海市杰理科技股份有限公司
|
||||
*********************************************************
|
||||
* @attention
|
||||
* 硬件平台:AC695N
|
||||
* SDK版本:AC695N_V1.0.0_SDK
|
||||
* @修改日志:
|
||||
* <table>
|
||||
* <tr><th>Date <th>Version <th>Author <th>Description
|
||||
* <tr><td>2021-8-1 <td>1.0 <td>jieli <td>创建初始版本
|
||||
* </table>
|
||||
*
|
||||
*********************************************************
|
||||
*/
|
||||
#ifndef __USB_BULK_TRANSFER_H__
|
||||
#define __USB_BULK_TRANSFER_H__
|
||||
#include "typedef.h"
|
||||
#include "device/device.h"
|
||||
|
||||
|
||||
/**@brief 批量传输只读取(异步模式)
|
||||
* @param[in] device定义的结构体指针
|
||||
* @param[in] host_ep 主机端点号
|
||||
* @param[in] rxmaxp 接收端点最大包长
|
||||
* @param[in] target_ep 目标端点号
|
||||
* @param[in] *pBuf BUFFER指针
|
||||
* @param[in] len 数据长度
|
||||
* @return
|
||||
* @par 示例:
|
||||
* @code
|
||||
* usb_bulk_only_receive_async(device, host_ep, rxmaxp, target_ep, pBuf, len);
|
||||
* @encode
|
||||
*/
|
||||
s32 usb_bulk_only_receive_async(struct device *device, u8 host_ep, u16 rxmaxp, u8 target_ep, u8 *pBuf, u32 len);
|
||||
|
||||
/**@brief 批量传输只读取(普通模式)
|
||||
* @param[in] device定义的结构体指针
|
||||
* @param[in] host_ep 主机端点号
|
||||
* @param[in] rxmaxp 接收端点最大包长
|
||||
* @param[in] ep 目标端点号
|
||||
* @param[in] *pBuf BUFFER指针
|
||||
* @param[in] len 数据长度
|
||||
* @return
|
||||
* @par 示例:
|
||||
* @code
|
||||
* usb_bulk_only_receive(device, host_ep, rxmaxp, ep, pBuf, len);
|
||||
* @encode
|
||||
*/
|
||||
s32 usb_bulk_only_receive(struct device *device, u8 host_ep, u16 rxmaxp, u8 ep, u8 *pBuf, u32 len);
|
||||
|
||||
/**@brief 批量传输只发送(异步模式)
|
||||
* @param[in] device定义的结构体指针
|
||||
* @param[in] host_ep 主机端点号
|
||||
* @param[in] txmaxp 发送端点最大包长
|
||||
* @param[in] target_ep 目标端点号
|
||||
* @param[in] *pBuf BUFFER指针
|
||||
* @param[in] len 数据长度
|
||||
* @return
|
||||
* @par 示例:
|
||||
* @code
|
||||
* usb_bulk_only_send_async(device, host_ep, txmaxp, target_ep, pBuf, len);
|
||||
* @encode
|
||||
*/
|
||||
s32 usb_bulk_only_send_async(struct device *device, u8 host_ep, u16 txmaxp, u8 target_ep, const u8 *pBuf, u32 len);
|
||||
|
||||
/**@brief 批量传输只发送(普通模式)
|
||||
* @param[in] device定义的结构体指针
|
||||
* @param[in] ep 主机端点号
|
||||
* @param[in] txmaxp 发送端点最大包长
|
||||
* @param[in] ep 目标端点号
|
||||
* @param[in] *pBuf BUFFER指针
|
||||
* @param[in] len 数据长度
|
||||
* @return
|
||||
* @par 示例:
|
||||
* @code
|
||||
* usb_bulk_only_send(device, host_ep, txmaxp, ep, pBuf, len);
|
||||
* @encode
|
||||
*/
|
||||
s32 usb_bulk_only_send(struct device *device, u8 host_ep, u16 txmaxp, u8 ep, const u8 *pBuf, u32 len);
|
||||
|
||||
/**@brief 获取异步模式当前状态
|
||||
* @param[in] 空
|
||||
* @return 当前状态
|
||||
* @par 示例:
|
||||
* @code
|
||||
* get_async_mode();
|
||||
* @encode
|
||||
*/
|
||||
u8 get_async_mode(void);
|
||||
|
||||
/**@brief 设置异步模式
|
||||
* @param[in] mode 需要设置的模式
|
||||
* @return 空
|
||||
* @par 示例:
|
||||
* @code
|
||||
* set_async_mode(BULK_ASYNC_MODE_EXIT);退出异步模式
|
||||
* @encode
|
||||
*/
|
||||
void set_async_mode(u8 mode);
|
||||
|
||||
/**@brief 批量传输异步模式读取并且不等待
|
||||
* @param[in] device定义的结构体指针
|
||||
* @param[in] ep 主机端点号
|
||||
* @param[in] rxmaxp 发送端点最大包长
|
||||
* @param[in] target_ep 目标端点号
|
||||
* @param[in] *pBuf BUFFER指针
|
||||
* @param[in] len 数据长度
|
||||
* @return
|
||||
* @par 示例:
|
||||
* @code
|
||||
* usb_bulk_only_send(device, host_ep, rxmaxp, ep, pBuf, len);
|
||||
* @encode
|
||||
*/
|
||||
s32 usb_bulk_receive_async_no_wait(struct device *device, u8 host_ep, u16 rxmaxp, u8 target_ep, u8 *pBuf, u32 len);
|
||||
#endif
|
||||
637
apps/common/device/usb/host/usb_ctrl_transfer.c
Normal file
637
apps/common/device/usb/host/usb_ctrl_transfer.c
Normal file
@ -0,0 +1,637 @@
|
||||
/**
|
||||
* @file usb_ctrl_transfer.c
|
||||
* @brief usb 控制传输接口
|
||||
* @author chenrixin@zh-jieli.com
|
||||
* @version 1.00
|
||||
* @date 2017-02-09
|
||||
*/
|
||||
|
||||
#include "usb/host/usb_host.h"
|
||||
#include "usb_ctrl_transfer.h"
|
||||
#include "app_config.h"
|
||||
#include "device_drive.h"
|
||||
#include "gpio.h"
|
||||
#include "usb/scsi.h"
|
||||
|
||||
#define LOG_TAG_CONST USB
|
||||
#define LOG_TAG "[USB]"
|
||||
#define LOG_ERROR_ENABLE
|
||||
#define LOG_DEBUG_ENABLE
|
||||
#define LOG_INFO_ENABLE
|
||||
/* #define LOG_DUMP_ENABLE */
|
||||
#define LOG_CLI_ENABLE
|
||||
#include "debug.h"
|
||||
|
||||
#if USB_HOST_ENABLE
|
||||
|
||||
_WEAK_
|
||||
void usb_dis_ep0_txdly(const usb_dev id)
|
||||
{
|
||||
}
|
||||
static void ep0_h_isr(struct usb_host_device *host_dev, u32 ep)
|
||||
{
|
||||
usb_dev usb_id = host_device2id(host_dev);
|
||||
usb_sem_post(host_dev);
|
||||
}
|
||||
/**
|
||||
* @brief usb_ctlXfer
|
||||
*
|
||||
* @param host_dev
|
||||
* @param urb
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
static int usb_ctlXfer(struct usb_host_device *host_dev, struct ctlXfer *urb)
|
||||
{
|
||||
u32 ret = DEV_ERR_NONE;
|
||||
u8 reg = 0;
|
||||
u32 data_len;
|
||||
usb_dev usb_id = host_device2id(host_dev);
|
||||
u8 devnum = host_dev->private_data.devnum;
|
||||
u32 max_packet_size = host_dev->private_data.ep0_max_packet_size;
|
||||
|
||||
usb_write_faddr(usb_id, devnum);
|
||||
#ifdef USB_HW_20
|
||||
usb_write_txfuncaddr(usb_id, 0, devnum);
|
||||
#endif
|
||||
|
||||
switch (urb->stage) {
|
||||
case USB_PID_SETUP :
|
||||
usb_write_ep0(usb_id, (u8 *)&urb->setup, 8);
|
||||
reg = CSR0H_SetupPkt | CSR0H_TxPktRdy;
|
||||
break;
|
||||
case USB_PID_IN :
|
||||
if (urb->setup.wLength) {
|
||||
reg = CSR0H_ReqPkt;
|
||||
} else {
|
||||
reg = CSR0H_StatusPkt | CSR0H_ReqPkt;
|
||||
}
|
||||
break;
|
||||
case USB_PID_OUT:
|
||||
if (urb->setup.wLength) {
|
||||
data_len = min(urb->setup.wLength, max_packet_size);
|
||||
reg = CSR0H_TxPktRdy;
|
||||
usb_write_ep0(usb_id, urb->buffer, data_len);
|
||||
urb->setup.wLength -= data_len;
|
||||
urb->buffer += data_len;
|
||||
} else {
|
||||
reg = CSR0H_StatusPkt | CSR0H_TxPktRdy;
|
||||
}
|
||||
break;
|
||||
default :
|
||||
break;
|
||||
}
|
||||
|
||||
#if USB_HOST_ASYNC
|
||||
//config ep0 callback fun
|
||||
usb_h_set_ep_isr(host_dev, 0, ep0_h_isr, host_dev);
|
||||
usb_set_intr_txe(usb_id, 0);
|
||||
#endif
|
||||
|
||||
#ifdef USB_HW_20
|
||||
usb_write_csr0(usb_id, reg | CSR0H_DISPING);
|
||||
#else
|
||||
usb_write_csr0(usb_id, reg);
|
||||
#endif
|
||||
|
||||
u32 st = 0;
|
||||
u32 ot = usb_get_jiffies() + 500;
|
||||
while (1) {
|
||||
if (usb_host_timeout(ot)) {
|
||||
log_error("time out %x\n", reg);
|
||||
ret = -DEV_ERR_TIMEOUT;
|
||||
goto __exit;
|
||||
}
|
||||
if (usb_h_dev_status(usb_id)) {
|
||||
st ++;
|
||||
} else {
|
||||
st = 0;
|
||||
}
|
||||
if (((usb_read_devctl(usb_id) & BIT(2)) == 0) || (st > 1000)) {
|
||||
log_error("usb%d_offline\n", usb_id);
|
||||
ret = -DEV_ERR_OFFLINE;
|
||||
goto __exit;
|
||||
}
|
||||
|
||||
#if USB_HOST_ASYNC
|
||||
ret = usb_sem_pend(host_dev, 250); //wait isr
|
||||
if (ret) {
|
||||
log_error("usb%d_offline\n", usb_id);
|
||||
ret = -DEV_ERR_OFFLINE;
|
||||
goto __exit;
|
||||
}
|
||||
#endif
|
||||
|
||||
reg = usb_read_csr0(usb_id);
|
||||
if (reg & CSR0H_RxStall) {
|
||||
log_error(" rxStall CSR0:0x%x", reg);
|
||||
ret = -DEV_ERR_CONTROL_STALL;
|
||||
goto __exit;
|
||||
}
|
||||
if (reg & CSR0H_Error) {
|
||||
log_error(" Error CSR0:0x%x", reg);
|
||||
usb_write_csr0(usb_id, 0);
|
||||
ret = -DEV_ERR_CONTROL;
|
||||
goto __exit;
|
||||
}
|
||||
if (USB_PID_IN == urb->stage) {
|
||||
|
||||
if (reg & CSR0H_RxPktRdy) {
|
||||
data_len = usb_read_count0(usb_id);
|
||||
data_len = min(data_len, urb->setup.wLength);
|
||||
usb_read_ep0(usb_id, urb->buffer, data_len);;
|
||||
urb->buffer += data_len;
|
||||
urb->setup.wLength -= data_len;
|
||||
if (data_len < max_packet_size) {
|
||||
urb->setup.wLength = 0;
|
||||
}
|
||||
if (urb->setup.wLength) {
|
||||
#ifdef USB_HW_20
|
||||
usb_write_csr0(usb_id, CSR0H_ReqPkt | CSR0H_DISPING);
|
||||
#else
|
||||
usb_write_csr0(usb_id, CSR0H_ReqPkt);
|
||||
#endif
|
||||
} else {
|
||||
#ifdef USB_HW_20
|
||||
usb_write_csr0(usb_id, CSR0H_DISPING);
|
||||
#else
|
||||
usb_write_csr0(usb_id, 0);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!(reg & CSR0H_TxPktRdy)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
__exit:
|
||||
usb_clr_intr_txe(usb_id, 0);
|
||||
usb_dis_ep0_txdly(usb_id);
|
||||
return ret;
|
||||
}
|
||||
/**
|
||||
* @brief usb_control_transfers
|
||||
*
|
||||
* @param struct host_dev
|
||||
* @param urb
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
static int usb_control_transfers(struct usb_host_device *host_dev, struct ctlXfer *urb)
|
||||
{
|
||||
usb_dev usb_id = host_device2id(host_dev);
|
||||
|
||||
int res;
|
||||
/*SETUP*/
|
||||
|
||||
urb->stage = USB_PID_SETUP; //SETUP transaction
|
||||
|
||||
res = usb_ctlXfer(host_dev, urb);
|
||||
|
||||
if (res) {
|
||||
return res;
|
||||
}
|
||||
|
||||
/*IN or OUT*/
|
||||
urb->stage = USB_PID_IN;
|
||||
|
||||
|
||||
while (urb->setup.wLength) {
|
||||
if (urb->setup.bRequestType & USB_DIR_IN) { //Request Direction
|
||||
urb->stage = USB_PID_IN; //IN transaction
|
||||
|
||||
res = usb_ctlXfer(host_dev, urb);
|
||||
|
||||
if (res) {
|
||||
return res;
|
||||
}
|
||||
|
||||
urb->stage = USB_PID_OUT;
|
||||
} else {
|
||||
urb->stage = USB_PID_OUT; //OUT transaction
|
||||
|
||||
res = usb_ctlXfer(host_dev, urb);
|
||||
|
||||
if (res) {
|
||||
return res;
|
||||
}
|
||||
|
||||
urb->stage = USB_PID_IN;
|
||||
}
|
||||
}
|
||||
|
||||
res = usb_ctlXfer(host_dev, urb);
|
||||
|
||||
if (res) {
|
||||
return res;
|
||||
}
|
||||
|
||||
return DEV_ERR_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief usb_control_msg
|
||||
*
|
||||
* @param host_dev
|
||||
* @param request
|
||||
* @param requesttype
|
||||
* @param value
|
||||
* @param index
|
||||
* @param data
|
||||
* @param size
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
int usb_control_msg(struct usb_host_device *host_dev,
|
||||
u8 request, u8 requesttype,
|
||||
u16 value, u16 index,
|
||||
void *data, u16 size)
|
||||
{
|
||||
struct ctlXfer urb;
|
||||
urb.setup.bRequestType = requesttype;
|
||||
urb.setup.bRequest = request;
|
||||
urb.setup.wValue = cpu_to_le16(value);
|
||||
urb.setup.wIndex = cpu_to_le16(index);
|
||||
urb.setup.wLength = cpu_to_le16(size);
|
||||
urb.buffer = data;
|
||||
|
||||
return usb_control_transfers(host_dev, &urb);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief usb_clear_feature
|
||||
*
|
||||
* @param host_dev
|
||||
* @param ep
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
int usb_clear_feature(struct usb_host_device *host_dev, u32 ep)
|
||||
{
|
||||
return usb_control_msg(host_dev, USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0, ep, NULL, 0);
|
||||
}
|
||||
|
||||
int set_address(struct usb_host_device *host_dev, u8 devnum)
|
||||
{
|
||||
return usb_control_msg(host_dev, USB_REQ_SET_ADDRESS, 0, devnum, 0, NULL, 0);
|
||||
}
|
||||
|
||||
int usb_get_device_descriptor(struct usb_host_device *host_dev, struct usb_device_descriptor *desc)
|
||||
{
|
||||
return usb_control_msg(host_dev,
|
||||
USB_REQ_GET_DESCRIPTOR,
|
||||
USB_DIR_IN,
|
||||
(USB_DT_DEVICE << 8),
|
||||
0,
|
||||
desc,
|
||||
USB_DT_DEVICE_SIZE
|
||||
);
|
||||
}
|
||||
|
||||
int usb_get_string_descriptor(struct usb_host_device *host_dev, struct usb_device_descriptor *desc)
|
||||
{
|
||||
int ret = DEV_ERR_NONE;
|
||||
#if 0
|
||||
struct usb_private_data *private_data = host_dev->private_data ;
|
||||
/**********get string language*********/
|
||||
u8 buf[16];
|
||||
memset(buf, 0x0, sizeof(buf));
|
||||
ret = usb_control_msg(host_dev,
|
||||
USB_REQ_GET_DESCRIPTOR,
|
||||
USB_DIR_IN,
|
||||
(USB_DT_STRING << 8),
|
||||
0,
|
||||
desc,
|
||||
sizeof(buf)
|
||||
);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
memcpy(&private_data->language, buf + 2, sizeof(private_data->language));
|
||||
|
||||
/**********get manufacturer string**********/
|
||||
memset(private_data->manufacturer, 0x0, sizeof(private_data->manufacturer));
|
||||
if (desc->iManufacturer) {
|
||||
ret = usb_control_msg(host_dev,
|
||||
USB_REQ_GET_DESCRIPTOR,
|
||||
USB_DIR_IN,
|
||||
(USB_DT_STRING << 8) | desc->iManufacturer,
|
||||
0,
|
||||
private_data->manufacturer,
|
||||
sizeof(private_data->manufacturer)
|
||||
);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
/**********get product string**********/
|
||||
memset(private_data->product, 0x0, sizeof(private_data->product));
|
||||
if (desc->iProduct) {
|
||||
ret = usb_control_msg(host_dev,
|
||||
USB_REQ_GET_DESCRIPTOR,
|
||||
USB_DIR_IN,
|
||||
(USB_DT_STRING << 8) | desc->iProduct,
|
||||
0,
|
||||
private_data->product,
|
||||
sizeof(private_data->product)
|
||||
);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
int set_configuration(struct usb_host_device *host_dev)
|
||||
{
|
||||
return usb_control_msg(host_dev, USB_REQ_SET_CONFIGURATION, 0, 1, 0, NULL, 0);
|
||||
}
|
||||
int set_configuration_add_value(struct usb_host_device *host_dev, u16 value)
|
||||
{
|
||||
return usb_control_msg(host_dev, USB_REQ_SET_CONFIGURATION, 0, value, 0, NULL, 0);
|
||||
}
|
||||
int get_config_descriptor(struct usb_host_device *host_dev, void *cfg_desc, u32 len)
|
||||
{
|
||||
return usb_control_msg(host_dev,
|
||||
USB_REQ_GET_DESCRIPTOR,
|
||||
USB_DIR_IN,
|
||||
(USB_DT_CONFIG << 8),
|
||||
0,
|
||||
cfg_desc,
|
||||
len);
|
||||
}
|
||||
|
||||
int get_config_descriptor_add_value_l(struct usb_host_device *host_dev, void *cfg_desc, u32 len, u8 value_l)
|
||||
{
|
||||
return usb_control_msg(host_dev,
|
||||
USB_REQ_GET_DESCRIPTOR,
|
||||
USB_DIR_IN,
|
||||
(USB_DT_CONFIG << 8) | value_l,
|
||||
0,
|
||||
cfg_desc,
|
||||
len);
|
||||
}
|
||||
|
||||
|
||||
int get_msd_max_lun(struct usb_host_device *host_dev, void *lun)
|
||||
{
|
||||
return usb_control_msg(host_dev,
|
||||
USB_MSD_MAX_LUN,
|
||||
USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
|
||||
0,
|
||||
0,
|
||||
lun,
|
||||
1);
|
||||
}
|
||||
int set_msd_reset(struct usb_host_device *host_dev)
|
||||
{
|
||||
return usb_control_msg(host_dev,
|
||||
0xff,
|
||||
USB_TYPE_CLASS | USB_RECIP_INTERFACE,
|
||||
0,
|
||||
0,
|
||||
NULL,
|
||||
0);
|
||||
}
|
||||
|
||||
int hid_set_idle(struct usb_host_device *host_dev, u32 id)
|
||||
{
|
||||
return usb_control_msg(host_dev, 0x0a, 0x21, 0, id << 8, NULL, 0);
|
||||
}
|
||||
int hid_get_report(struct usb_host_device *host_dev, u8 *report, u8 report_id, u16 report_len)
|
||||
{
|
||||
return usb_control_msg(host_dev,
|
||||
USB_REQ_GET_DESCRIPTOR,
|
||||
USB_DIR_IN | USB_RECIP_INTERFACE,
|
||||
0x2200,
|
||||
report_id,
|
||||
report,
|
||||
report_len);
|
||||
}
|
||||
int hid_set_output_report(struct usb_host_device *host_dev, u8 *report, u8 report_id, u8 report_len)
|
||||
{
|
||||
return usb_control_msg(host_dev,
|
||||
0x09,
|
||||
USB_TYPE_CLASS | USB_RECIP_INTERFACE,
|
||||
0x0201,
|
||||
report_id,
|
||||
report,
|
||||
report_len);
|
||||
}
|
||||
int usb_set_remote_wakeup(struct usb_host_device *host_dev)
|
||||
{
|
||||
return usb_control_msg(host_dev, USB_REQ_SET_FEATURE, USB_RECIP_DEVICE,
|
||||
USB_DEVICE_REMOTE_WAKEUP, 0, NULL, 0);
|
||||
}
|
||||
int get_device_status(struct usb_host_device *host_dev)
|
||||
{
|
||||
u16 status;
|
||||
return usb_control_msg(host_dev, USB_REQ_GET_STATUS, USB_DIR_IN, 0, 0, (u8 *)&status, 2);
|
||||
}
|
||||
int usb_get_device_qualifier(struct usb_host_device *host_dev, u8 *buffer)
|
||||
{
|
||||
return usb_control_msg(host_dev,
|
||||
USB_REQ_GET_DESCRIPTOR,
|
||||
USB_DIR_IN,
|
||||
(USB_DT_DEVICE_QUALIFIER << 8),
|
||||
0,
|
||||
buffer,
|
||||
0x0a);
|
||||
|
||||
}
|
||||
#define AOA_CMD51 0x33
|
||||
#define AOA_CMD52 0x34
|
||||
#define AOA_CMD53 0x35
|
||||
|
||||
|
||||
|
||||
|
||||
int usb_get_aoa_version(struct usb_host_device *host_dev, u16 *version)
|
||||
{
|
||||
return usb_control_msg(host_dev,
|
||||
AOA_CMD51,
|
||||
USB_DIR_IN | USB_TYPE_VENDOR,
|
||||
0,
|
||||
0,
|
||||
version,
|
||||
2);
|
||||
}
|
||||
int usb_set_credentials(struct usb_host_device *host_dev, const char *string, int index)
|
||||
{
|
||||
return usb_control_msg(host_dev,
|
||||
AOA_CMD52,
|
||||
USB_DIR_OUT | USB_TYPE_VENDOR,
|
||||
0,
|
||||
index,
|
||||
(u8 *)string,
|
||||
strlen(string));
|
||||
}
|
||||
int usb_switch2aoa(struct usb_host_device *host_dev)
|
||||
{
|
||||
return usb_control_msg(host_dev,
|
||||
AOA_CMD53,
|
||||
USB_DIR_OUT | USB_TYPE_VENDOR,
|
||||
0,
|
||||
0,
|
||||
NULL,
|
||||
0);
|
||||
}
|
||||
int usb_switch2slave(struct usb_host_device *host_dev)
|
||||
{
|
||||
return usb_control_msg(host_dev,
|
||||
0x51,
|
||||
USB_DIR_OUT | USB_TYPE_VENDOR,
|
||||
0,
|
||||
0,
|
||||
NULL,
|
||||
0);
|
||||
}
|
||||
/* Control request for registering a HID device.
|
||||
* Upon registering, a unique ID is sent by the accessory in the
|
||||
* value parameter. This ID will be used for future commands for
|
||||
* the device
|
||||
*
|
||||
* requestType: USB_DIR_OUT | USB_TYPE_VENDOR
|
||||
* request: ACCESSORY_REGISTER_HID_DEVICE
|
||||
* value: Accessory assigned ID for the HID device
|
||||
* index: total length of the HID report descriptor
|
||||
* data none
|
||||
*/
|
||||
#define ACCESSORY_REGISTER_HID 54
|
||||
int usb_aoa_register_hid(struct usb_host_device *host_dev, u16 value, u16 index)
|
||||
{
|
||||
return usb_control_msg(host_dev,
|
||||
ACCESSORY_REGISTER_HID,
|
||||
USB_DIR_OUT | USB_TYPE_VENDOR,
|
||||
value,
|
||||
index,
|
||||
NULL,
|
||||
0);
|
||||
}
|
||||
/* Control request for unregistering a HID device.
|
||||
*
|
||||
* requestType: USB_DIR_OUT | USB_TYPE_VENDOR
|
||||
* request: ACCESSORY_REGISTER_HID
|
||||
* value: Accessory assigned ID for the HID device
|
||||
* index: 0
|
||||
* data none
|
||||
*/
|
||||
#define ACCESSORY_UNREGISTER_HID 55
|
||||
int usb_aoa_unregister_hid(struct usb_host_device *host_dev, u16 value)
|
||||
{
|
||||
return usb_control_msg(host_dev,
|
||||
ACCESSORY_UNREGISTER_HID,
|
||||
USB_DIR_OUT | USB_TYPE_VENDOR,
|
||||
value,
|
||||
0,
|
||||
NULL,
|
||||
0);
|
||||
}
|
||||
|
||||
/* Control request for sending the HID report descriptor.
|
||||
* If the HID descriptor is longer than the endpoint zero max packet size,
|
||||
* the descriptor will be sent in multiple ACCESSORY_SET_HID_REPORT_DESC
|
||||
* commands. The data for the descriptor must be sent sequentially
|
||||
* if multiple packets are needed.
|
||||
*
|
||||
* requestType: USB_DIR_OUT | USB_TYPE_VENDOR
|
||||
* request: ACCESSORY_SET_HID_REPORT_DESC
|
||||
* value: Accessory assigned ID for the HID device
|
||||
* index: offset of data in descriptor
|
||||
* (needed when HID descriptor is too big for one packet)
|
||||
* data the HID report descriptor
|
||||
*/
|
||||
#define ACCESSORY_SET_HID_REPORT_DESC 56
|
||||
int usb_aoa_set_hid_report_desc(struct usb_host_device *host_dev, u16 value, u16 offset, const char *pbuf, u32 len)
|
||||
{
|
||||
return usb_control_msg(host_dev,
|
||||
ACCESSORY_SET_HID_REPORT_DESC,
|
||||
USB_DIR_OUT | USB_TYPE_VENDOR,
|
||||
value,
|
||||
offset,
|
||||
(u8 *)pbuf,
|
||||
len);
|
||||
}
|
||||
|
||||
/* Control request for sending HID events.
|
||||
*
|
||||
* requestType: USB_DIR_OUT | USB_TYPE_VENDOR
|
||||
* request: ACCESSORY_SEND_HID_EVENT
|
||||
* value: Accessory assigned ID for the HID device
|
||||
* index: 0
|
||||
* data the HID report for the event
|
||||
*/
|
||||
#define ACCESSORY_SEND_HID_EVENT 57
|
||||
int usb_aoa_send_hid_event(struct usb_host_device *host_dev, u16 value, const u8 *pbuf, u32 len)
|
||||
{
|
||||
return usb_control_msg(host_dev,
|
||||
ACCESSORY_SEND_HID_EVENT,
|
||||
USB_DIR_OUT | USB_TYPE_VENDOR,
|
||||
value,
|
||||
0,
|
||||
(u8 *)pbuf,
|
||||
len);
|
||||
}
|
||||
int get_ms_extended_compat_id(struct usb_host_device *host_dev, u8 *buffer)
|
||||
{
|
||||
return usb_control_msg(host_dev,
|
||||
0x01,
|
||||
USB_DIR_IN | USB_RECIP_DEVICE | USB_TYPE_VENDOR,
|
||||
0x0000,
|
||||
4,
|
||||
buffer,
|
||||
0x28);
|
||||
}
|
||||
|
||||
|
||||
int usb_set_interface(struct usb_host_device *host_dev, u8 interface, u8 alternateSetting)
|
||||
{
|
||||
log_info("%s Set Interface:%d AlternateSetting:%d", __func__, interface, alternateSetting);
|
||||
return usb_control_msg(host_dev,
|
||||
USB_REQ_SET_INTERFACE,
|
||||
USB_RECIP_INTERFACE,
|
||||
alternateSetting,
|
||||
interface,
|
||||
NULL,
|
||||
0);
|
||||
|
||||
}
|
||||
|
||||
int usb_audio_sampling_frequency_control(struct usb_host_device *host_dev, u32 ep, u32 sampe_rate)
|
||||
{
|
||||
log_info("%s ep:%d sampe_rate:%d", __func__, ep, sampe_rate);
|
||||
return usb_control_msg(host_dev,
|
||||
1,
|
||||
USB_TYPE_CLASS | USB_RECIP_ENDPOINT,
|
||||
0x0100,
|
||||
ep,
|
||||
&sampe_rate,
|
||||
3);
|
||||
}
|
||||
int usb_audio_volume_control(struct usb_host_device *host_dev, u8 feature_id, u8 channel_num, u16 volume)
|
||||
{
|
||||
log_info("%s featureID:%d vol:%x", __func__, feature_id, volume);
|
||||
return usb_control_msg(host_dev,
|
||||
1,
|
||||
USB_TYPE_CLASS | USB_RECIP_INTERFACE,
|
||||
(0x02 << 8) | channel_num,
|
||||
feature_id << 8,
|
||||
&volume,
|
||||
2);
|
||||
}
|
||||
int usb_audio_mute_control(struct usb_host_device *host_dev, u8 feature_id, u8 mute)
|
||||
{
|
||||
log_info("%s featureID:%d mute:%d", __func__, feature_id, mute);
|
||||
return usb_control_msg(host_dev,
|
||||
1,
|
||||
USB_TYPE_CLASS | USB_RECIP_INTERFACE,
|
||||
0x0100,
|
||||
feature_id << 8,
|
||||
&mute,
|
||||
1);
|
||||
}
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user