feat: Add rfid feature and .gitignore file

This commit is contained in:
lmx
2025-11-28 16:25:35 +08:00
parent 818e8c3778
commit ade4b0a1f8
1244 changed files with 342105 additions and 0 deletions

View 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

View 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, &reg_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

View File

@ -0,0 +1,116 @@
/*
Copyright (c) 2019 Silan MEMS. All Rights Reserved.
*/
#ifndef SC7A20_H
#define SC7A20_H
/********添加IIC头文件******************/
//#include "i2c.h"
/***************************************/
/***使用驱动前请根据实际接线情况配置7bitIIC地址******/
/**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

View 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

View 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

View 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

View 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

View 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;
}

View 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

View 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>&copy; 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

View 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

View 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

View 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一次传输的长度)
// 该位清 0I2C_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模式设置为0latch-until-int-cleared模式设置为1
//bit4 中断锁存清除模式 status-read-only状态设置为0any-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

View 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 */

View 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__ */

View 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 */

View 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__ */

View 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__ */

View 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 */

View File

@ -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 */

View File

@ -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) */

View 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 */

View File

@ -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

View File

@ -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 */

View File

@ -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_ */

View File

@ -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

View File

@ -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 */

View File

@ -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;
}

View File

@ -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

View File

@ -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 */

View 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_ */
/** @} */

File diff suppressed because it is too large Load Diff

View 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_*/

View 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;
}

View 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_ */
/** @} */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View 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_ */
/** @} */

View 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_ */
/** @} */

File diff suppressed because it is too large Load Diff

View 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;
}

View 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_ */
/** @} */

View 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_ */

View 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 *)&timestamp, 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

View 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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View 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

File diff suppressed because it is too large Load Diff

View 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(不自检2G5Hz)
#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

File diff suppressed because it is too large Load Diff

View 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

File diff suppressed because it is too large Load Diff

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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 */

View 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 */

View 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 */

View 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 */

View 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

View 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 */

View 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 */

View 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 */

View 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) */

View 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

View 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__

View 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

View 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

View 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 */

View 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

View 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

File diff suppressed because it is too large Load Diff

View 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

View 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

File diff suppressed because it is too large Load Diff

View 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

View 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

View 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中断intrusbeintrtxe
//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;
}

View 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

View 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

View 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*/

View 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

View 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

View 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*/

View 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

View 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

View 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

View 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

View 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

View 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*/

View 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

View 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

View 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