first
This commit is contained in:
180
apps/common/audio/amplitude_statistic.c
Normal file
180
apps/common/audio/amplitude_statistic.c
Normal file
@ -0,0 +1,180 @@
|
||||
/*
|
||||
****************************************************************
|
||||
* Amplitude Statistics
|
||||
* 幅值统计模块
|
||||
* File : amplitude_statistic.c
|
||||
* By :
|
||||
* Notes :
|
||||
****************************************************************
|
||||
*/
|
||||
|
||||
#include "amplitude_statistic.h"
|
||||
|
||||
#if 0
|
||||
#define amplitude_log printf
|
||||
#else
|
||||
#define amplitude_log(...)
|
||||
#endif/*log_en*/
|
||||
|
||||
static const unsigned short am_va_tab[] = {
|
||||
32768, 29205, 26029, 23198, 20675, 18427, 16423, 14637, 13045, 11627, 10362, 9235, 8231, 7336, 6538, 5827,
|
||||
5193, 4629, 4125, 3677, 3277, 2920, 2603, 2320, 2068, 1843, 1642, 1464, 1305, 1163, 1036, 0
|
||||
};
|
||||
|
||||
static const int rms_va_tab[] = {
|
||||
134217728, 106612931, 84685661, 67268212, 53433040, 42443372, 33713969, 26779957, 21272076, 16897011,
|
||||
13421773, 10661293, 8468566, 6726821, 5343304, 4244337, 3371397, 2677996, 2127208, 1689701,
|
||||
1342177, 1066129, 846857, 672682, 534330, 424434, 337140, 267800, 212721, 168970,
|
||||
134218, 0
|
||||
};
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* Loudness meter init
|
||||
* Description: 响度计算初始化
|
||||
* Arguments : loud_obj
|
||||
* sr
|
||||
* print_dest
|
||||
* index
|
||||
* Return : NULL
|
||||
* Note(s) : NULL
|
||||
*********************************************************************
|
||||
*/
|
||||
void loudness_meter_init(LOUDNESS_M_STRUCT *loud_obj, int sr, int print_dest, u8 index)
|
||||
{
|
||||
memset(loud_obj, 0, sizeof(LOUDNESS_M_STRUCT));
|
||||
loud_obj->countperiod = sr / 50;
|
||||
loud_obj->inv_counterpreiod = 16777216 / loud_obj->countperiod;
|
||||
loud_obj->print_dest = print_dest;
|
||||
loud_obj->index = index;
|
||||
}
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* Loudness meter short
|
||||
* Description: 响度计算函数
|
||||
* Arguments : loud_obj
|
||||
* data
|
||||
* len
|
||||
* Return : NULL
|
||||
* Note(s) : NULL
|
||||
*********************************************************************
|
||||
*/
|
||||
void loudness_meter_short(LOUDNESS_M_STRUCT *loud_obj, short *data, int len)
|
||||
{
|
||||
int i;
|
||||
int loudness_val = 0;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
int tmp = data[i] * 256;
|
||||
loud_obj->dclevel = (loud_obj->dclevel * 511 + tmp) >> 9;
|
||||
|
||||
int xabs = (data[i] > 0) ? data[i] : (-data[i]);
|
||||
int xabs2 = (xabs * xabs) >> 10;
|
||||
loud_obj->rms += xabs2;
|
||||
loud_obj->maxval = (loud_obj->maxval > xabs) ? loud_obj->maxval : xabs;
|
||||
|
||||
if (xabs >= 32767) {
|
||||
loud_obj->errprintfcount0++;
|
||||
}
|
||||
|
||||
loud_obj->counti++;
|
||||
if (loud_obj->counti > loud_obj->countperiod) {
|
||||
if (loud_obj->maxval_print < loud_obj->maxval) {
|
||||
loud_obj->maxval_print = loud_obj->maxval;
|
||||
}
|
||||
|
||||
if (loud_obj->rms_print < loud_obj->rms) {
|
||||
loud_obj->rms_print = loud_obj->rms;
|
||||
}
|
||||
|
||||
loud_obj->counti = 0;
|
||||
loud_obj->maxval = 0;
|
||||
loud_obj->rms = 0;
|
||||
|
||||
if (loud_obj->errprintfcount0 > 2) {
|
||||
loud_obj->errprintfcount0 = 0;
|
||||
amplitude_log("[%d]overflow occur... \n", loud_obj->index);
|
||||
}
|
||||
|
||||
loud_obj->print_cnt++;
|
||||
|
||||
if (loud_obj->print_cnt >= loud_obj->print_dest) {
|
||||
|
||||
int rmsval = ((__int64)loud_obj->rms_print * (__int64)loud_obj->inv_counterpreiod) >> (24 - (10 - 3));
|
||||
|
||||
if (rmsval > 25837266) {
|
||||
amplitude_log("[%d]energy high... \n", loud_obj->index);
|
||||
}
|
||||
|
||||
{
|
||||
int compi = 0, found = 0;;
|
||||
while (compi < 31) {
|
||||
if (rmsval >= rms_va_tab[compi]) {
|
||||
// float upval = (0 - compi) * 0.5;
|
||||
// float dwonval = (0 - compi - 1) * 0.5;
|
||||
// amplitude_log("rms level: %f to %f dB\n", upval, dwonval);
|
||||
|
||||
int upval = (0 - compi);
|
||||
int dwonval = (0 - compi - 1);
|
||||
|
||||
amplitude_log("[%d]rms level: %d to %d dB\n", loud_obj->index, upval, dwonval);
|
||||
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
compi++;
|
||||
}
|
||||
|
||||
if (found == 0) {
|
||||
amplitude_log("[%d]rms level < -30dB \n", loud_obj->index);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
int compi = 0, found = 0;;
|
||||
while (compi < 31) {
|
||||
if (loud_obj->maxval_print >= am_va_tab[compi]) {
|
||||
// float upval = (0 - compi) * 0.5;
|
||||
// float dwonval = (0 - compi - 1) * 0.5;
|
||||
// amplitude_log("peak level: %f to %f dB\n", upval, dwonval);
|
||||
int upval = (0 - compi);
|
||||
int dwonval = (0 - compi - 1);
|
||||
loud_obj->peak_val = dwonval;
|
||||
amplitude_log("[%d]peak level: %d to %d dB\n", loud_obj->index, upval, dwonval);
|
||||
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
compi++;
|
||||
}
|
||||
|
||||
if (found == 0) {
|
||||
loud_obj->peak_val = -31;
|
||||
amplitude_log("[%d]peak level < -30dB \n", loud_obj->index);
|
||||
}
|
||||
}
|
||||
|
||||
loud_obj->print_cnt = 0;
|
||||
loud_obj->maxval_print = 0;
|
||||
loud_obj->rms_print = 0;
|
||||
|
||||
if (loud_obj->dclevel > (255 * 256)) {
|
||||
amplitude_log("[%d] why ??? dc level : %d \n", loud_obj->index, loud_obj->dclevel >> 8);
|
||||
}
|
||||
amplitude_log("\n\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
void loudness_meter_demo(void)
|
||||
{
|
||||
loudness_meter_init(&loudness_adc, 16000, 1);
|
||||
loudness_meter_short(&loudness_adc, datain, points);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
26
apps/common/audio/amplitude_statistic.h
Normal file
26
apps/common/audio/amplitude_statistic.h
Normal file
@ -0,0 +1,26 @@
|
||||
#ifndef _AMPLITUDE_STATISTIC_H_
|
||||
#define _AMPLITUDE_STATISTIC_H_
|
||||
|
||||
#include "generic/typedef.h"
|
||||
|
||||
typedef struct _LOUDNESS_M_STRUCT_ {
|
||||
int mutecnt;
|
||||
int rms;
|
||||
int counti;
|
||||
int maxval;
|
||||
int countperiod;
|
||||
int inv_counterpreiod;
|
||||
int errprintfcount0;
|
||||
short print_cnt;
|
||||
short print_dest;
|
||||
int dclevel;
|
||||
int rms_print;
|
||||
int maxval_print;
|
||||
int peak_val;
|
||||
u8 index;
|
||||
} LOUDNESS_M_STRUCT;
|
||||
|
||||
void loudness_meter_init(LOUDNESS_M_STRUCT *loud_obj, int sr, int print_dest, u8 index);
|
||||
void loudness_meter_short(LOUDNESS_M_STRUCT *loud_obj, short *data, int len);
|
||||
|
||||
#endif /*_AMPLITUDE_STATISTIC_H_*/
|
||||
13
apps/common/audio/audio_NoiseGate.h
Normal file
13
apps/common/audio/audio_NoiseGate.h
Normal file
@ -0,0 +1,13 @@
|
||||
#ifndef _AUDIO_NOISE_GATE_H_
|
||||
#define _AUDIO_NOISE_GATE_H_
|
||||
|
||||
#include "generic/typedef.h"
|
||||
|
||||
|
||||
u8 *audio_noise_gate_open(int attack_time, int release_time, float thr, float gain, int sr, int ch);
|
||||
|
||||
void audio_noise_gate_run(u8 *runbuf, void *in, void *out, u16 len);
|
||||
|
||||
void audio_noise_gate_close(u8 *runbuf);
|
||||
|
||||
#endif/*_AUDIO_NOISE_GATE_H_*/
|
||||
79
apps/common/audio/audio_digital_vol.h
Normal file
79
apps/common/audio/audio_digital_vol.h
Normal file
@ -0,0 +1,79 @@
|
||||
#ifndef _AUDIO_DIGITAL_VOL_H_
|
||||
#define _AUDIO_DIGITAL_VOL_H_
|
||||
|
||||
#include "generic/typedef.h"
|
||||
#include "os/os_type.h"
|
||||
#include "os/os_api.h"
|
||||
#include "generic/list.h"
|
||||
|
||||
#define BG_DVOL_FADE_ENABLE 1 /*多路声音叠加,背景声音自动淡出小声*/
|
||||
|
||||
typedef struct {
|
||||
u8 toggle; /*数字音量开关*/
|
||||
u8 fade; /*淡入淡出标志*/
|
||||
u8 vol; /*淡入淡出当前音量(level)*/
|
||||
u8 vol_max; /*淡入淡出最大音量(level)*/
|
||||
s16 vol_fade; /*淡入淡出对应的起始音量*/
|
||||
#if BG_DVOL_FADE_ENABLE
|
||||
s16 vol_bk; /*后台自动淡出前音量值*/
|
||||
struct list_head entry;
|
||||
#endif
|
||||
volatile s16 vol_target; /*淡入淡出对应的目标音量*/
|
||||
volatile u16 fade_step; /*淡入淡出的步进*/
|
||||
} dvol_handle;
|
||||
|
||||
|
||||
int audio_digital_vol_init(void);
|
||||
void audio_digital_vol_bg_fade(u8 fade_out);
|
||||
dvol_handle *audio_digital_vol_open(u8 vol, u8 vol_max, u16 fade_step);
|
||||
void audio_digital_vol_close(dvol_handle *dvol);
|
||||
void audio_digital_vol_set(dvol_handle *dvol, u8 vol);
|
||||
u8 audio_digital_vol_get(void);
|
||||
int audio_digital_vol_run(dvol_handle *dvol, void *data, u32 len);
|
||||
void audio_digital_vol_reset_fade(dvol_handle *dvol);
|
||||
|
||||
/*************************自定义支持重入的数字音量调节****************************/
|
||||
void *user_audio_digital_volume_open(u8 vol, u8 vol_max, u16 fade_step);
|
||||
int user_audio_digital_volume_close(void *_d_volume);
|
||||
u8 user_audio_digital_volume_get(void *_d_volume);
|
||||
int user_audio_digital_volume_set(void *_d_volume, u8 vol);
|
||||
int user_audio_digital_volume_reset_fade(void *_d_volume);
|
||||
int user_audio_digital_volume_run(void *_d_volume, void *data, u32 len, u8 ch_num);
|
||||
void user_audio_digital_handler_run(void *_d_volume, void *data, u32 len);
|
||||
void user_audio_digital_set_volume_tab(void *_d_volume, u16 *user_vol_tab, u8 user_vol_max);
|
||||
|
||||
void *user_audio_process_open(void *parm, void *priv, void (*handler)(void *priv, void *data, int len, u8 ch_num));
|
||||
int user_audio_process_close(void *_uparm_hdl);
|
||||
void user_audio_process_handler_run(void *_uparm_hdl, void *data, u32 len, u8 ch_num);
|
||||
|
||||
struct user_audio_digital_parm {
|
||||
u8 en;
|
||||
u8 vol;
|
||||
u8 vol_max;
|
||||
u16 fade_step;
|
||||
};
|
||||
|
||||
struct digital_volume {
|
||||
u8 toggle; /*数字音量开关*/
|
||||
u8 fade; /*淡入淡出标志*/
|
||||
u8 vol; /*淡入淡出当前音量*/
|
||||
u8 vol_max; /*淡入淡出最大音量*/
|
||||
s16 vol_fade; /*淡入淡出对应的起始音量*/
|
||||
volatile s16 vol_target; /*淡入淡出对应的目标音量*/
|
||||
volatile u16 fade_step; /*淡入淡出的步进*/
|
||||
|
||||
OS_MUTEX mutex;
|
||||
u8 ch_num;
|
||||
void *priv;
|
||||
u8 user_vol_max; /*自定义音量表级数*/
|
||||
volatile s16 *user_vol_tab; /*自定义音量表*/
|
||||
|
||||
};
|
||||
|
||||
struct user_audio_parm {
|
||||
void *priv;
|
||||
void (*handler)(void *priv, void *data, int len, u8 ch_num);/*用户自定义回调处理*/
|
||||
struct digital_volume *dvol_hdl;
|
||||
};
|
||||
|
||||
#endif
|
||||
450
apps/common/audio/audio_dvol.c
Normal file
450
apps/common/audio/audio_dvol.c
Normal file
@ -0,0 +1,450 @@
|
||||
/*
|
||||
****************************************************************
|
||||
* AUDIO DIGITAL VOLUME
|
||||
* File : audio_dvol.c
|
||||
* By :
|
||||
* Notes : 数字音量模块,支持多通道音量控制
|
||||
****************************************************************
|
||||
*/
|
||||
|
||||
#include "audio_dvol.h"
|
||||
|
||||
#if 0
|
||||
#define dvol_log y_printf
|
||||
#else
|
||||
#define dvol_log(...)
|
||||
#endif
|
||||
|
||||
#define DIGITAL_FADE_EN 1
|
||||
#define DIGITAL_FADE_STEP 4
|
||||
|
||||
#define BG_DVOL_MAX 14
|
||||
#define BG_DVOL_MID 10
|
||||
#define BG_DVOL_MIN 6
|
||||
#define BG_DVOL_MAX_FADE 13 /*>= BG_DVOL_MAX:自动淡出BG_DVOL_MAX_FADE*/
|
||||
#define BG_DVOL_MID_FADE 9 /*>= BG_DVOL_MID:自动淡出BG_DVOL_MID_FADE*/
|
||||
#define BG_DVOL_MIN_FADE 5 /*>= BG_DVOL_MIN:自动淡出BG_DVOL_MIN_FADE*/
|
||||
|
||||
#define ASM_ENABLE 1
|
||||
#define L_sat(b,a) __asm__ volatile("%0=sat16(%1)(s)":"=&r"(b) : "r"(a));
|
||||
#define L_sat32(b,a,n) __asm__ volatile("%0=%1>>%2(s)":"=&r"(b) : "r"(a),"r"(n));
|
||||
|
||||
typedef struct {
|
||||
u8 bg_dvol_fade_out;
|
||||
u8 start;
|
||||
OS_MUTEX mutex;
|
||||
struct list_head dvol_head;
|
||||
} dvol_t;
|
||||
static dvol_t dvol_attr;
|
||||
|
||||
/*
|
||||
*数字音量级数 DEFAULT_DIGITAL_VOL_MAX
|
||||
*数组长度 DEFAULT_DIGITAL_VOL_MAX + 1
|
||||
*/
|
||||
#define DEFAULT_DIGITAL_VOL_MAX (31)
|
||||
const u16 default_dig_vol_table[DEFAULT_DIGITAL_VOL_MAX + 1] = {
|
||||
0 , //0
|
||||
93 , //1
|
||||
111 , //2
|
||||
132 , //3
|
||||
158 , //4
|
||||
189 , //5
|
||||
226 , //6
|
||||
270 , //7
|
||||
323 , //8
|
||||
386 , //9
|
||||
462 , //10
|
||||
552 , //11
|
||||
660 , //12
|
||||
789 , //13
|
||||
943 , //14
|
||||
1127, //15
|
||||
1347, //16
|
||||
1610, //17
|
||||
1925, //18
|
||||
2301, //19
|
||||
2751, //20
|
||||
3288, //21
|
||||
3930, //22
|
||||
4698, //23
|
||||
5616, //24
|
||||
6713, //25
|
||||
8025, //26
|
||||
9592, //27
|
||||
11466,//28
|
||||
15200,//29
|
||||
16000,//30
|
||||
16384 //31
|
||||
};
|
||||
|
||||
static u16 digital_vol_max = DEFAULT_DIGITAL_VOL_MAX;
|
||||
static u16 *dig_vol_table = default_dig_vol_table;
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* Audio Digital Volume Init
|
||||
* Description: 数字音量模块初始化
|
||||
* Arguments : None.
|
||||
* Return : 0 成功 其他 失败
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
int audio_digital_vol_init(u16 *vol_table, u16 vol_max)
|
||||
{
|
||||
memset(&dvol_attr, 0, sizeof(dvol_attr));
|
||||
INIT_LIST_HEAD(&dvol_attr.dvol_head);
|
||||
os_mutex_create(&dvol_attr.mutex);
|
||||
|
||||
if (vol_table != NULL) {
|
||||
dig_vol_table = vol_table;
|
||||
digital_vol_max = vol_max;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*背景音乐淡出使能*/
|
||||
void audio_digital_vol_bg_fade(u8 fade_out)
|
||||
{
|
||||
dvol_log("audio_digital_vol_bg_fade:%d", fade_out);
|
||||
dvol_attr.bg_dvol_fade_out = fade_out;
|
||||
}
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* Audio Digital Volume Open
|
||||
* Description: 数字音量模块打开
|
||||
* Arguments : dvol_idx 数字音量通道索引,详见audio_dvol.h宏定义
|
||||
* vol 当前数字音量等级
|
||||
* vol_max 最大数字音量等级
|
||||
* fade_step 淡入淡出步进
|
||||
* vol_limit 数字音量限制,即可以给vol_max等分的最大音量
|
||||
* Return : 数字音量通道句柄
|
||||
* Note(s) : fade_step一般不超过两级数字音量的最小差值
|
||||
* (1)通话如果用数字音量,一般步进小一点,音量调节的时候不会有杂音
|
||||
* (2)淡出的时候可以快一点,尽快淡出到0
|
||||
*********************************************************************
|
||||
*/
|
||||
dvol_handle *audio_digital_vol_open(u8 dvol_idx, u8 vol, u8 vol_max, u16 fade_step, char vol_limit)
|
||||
{
|
||||
dvol_log("dvol_open:%d-%d-%d-%d\n", vol, vol_max, fade_step, vol_limit);
|
||||
dvol_handle *dvol = NULL;
|
||||
dvol = zalloc(sizeof(dvol_handle));
|
||||
if (dvol) {
|
||||
u8 vol_level;
|
||||
dvol->fade = DIGITAL_FADE_EN;
|
||||
dvol->vol = (vol > vol_max) ? vol_max : vol;
|
||||
if (vol > vol_max) {
|
||||
printf("[warning]cur digital_vol(%d) > digital_vol_max(%d)!!", vol, vol_max);
|
||||
}
|
||||
dvol->vol_max = vol_max;
|
||||
if (vol_limit == -1) {
|
||||
dvol->vol_limit = digital_vol_max;
|
||||
} else {
|
||||
dvol->vol_limit = (vol_limit > digital_vol_max) ? digital_vol_max : vol_limit;
|
||||
}
|
||||
vol_level = dvol->vol * dvol->vol_limit / vol_max;
|
||||
dvol->vol_target = dig_vol_table[vol_level];
|
||||
dvol->vol_fade = dvol->vol_target;
|
||||
dvol->fade_step = fade_step;
|
||||
dvol->toggle = 1;
|
||||
dvol->idx = dvol_idx;
|
||||
local_irq_disable();
|
||||
list_add(&dvol->entry, &dvol_attr.dvol_head);
|
||||
#if BG_DVOL_FADE_ENABLE
|
||||
dvol->vol_bk = -1;
|
||||
if (dvol_attr.bg_dvol_fade_out) {
|
||||
dvol_handle *hdl;
|
||||
list_for_each_entry(hdl, &dvol_attr.dvol_head, entry) {
|
||||
if ((hdl != dvol) && (hdl->idx)) {
|
||||
hdl->vol_bk = hdl->vol;
|
||||
if (hdl->vol >= BG_DVOL_MAX) {
|
||||
hdl->vol -= BG_DVOL_MAX_FADE;
|
||||
} else if (hdl->vol >= BG_DVOL_MID) {
|
||||
hdl->vol -= BG_DVOL_MID_FADE;
|
||||
} else if (hdl->vol >= BG_DVOL_MIN) {
|
||||
hdl->vol -= BG_DVOL_MIN_FADE;
|
||||
} else {
|
||||
hdl->vol_bk = -1;
|
||||
continue;
|
||||
}
|
||||
u8 vol_level = hdl->vol * dvol->vol_limit / hdl->vol_max;
|
||||
hdl->vol_target = dig_vol_table[vol_level];
|
||||
//y_printf("bg_dvol fade_out:%x,vol_bk:%d,vol_set:%d,tartget:%d",hdl,hdl->vol_bk,hdl->vol,hdl->vol_target);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif/*BG_DVOL_FADE_ENABLE*/
|
||||
local_irq_enable();
|
||||
dvol_log("dvol_open[%x]:%x-%d-%d-%d\n", dvol_idx, dvol, dvol->vol, dvol->vol_max, fade_step);
|
||||
}
|
||||
return dvol;
|
||||
}
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* Audio Digital Volume Close
|
||||
* Description: 数字音量模块关闭
|
||||
* Arguments : dvol_idx 数字音量通道索引,详见audio_dvol.h宏定义
|
||||
* Return : None.
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
void audio_digital_vol_close(u8 dvol_idx)
|
||||
{
|
||||
dvol_log("dvol_close[%x]\n", dvol_idx);
|
||||
dvol_handle *dvol = NULL;
|
||||
u8 dvol_valid = 0;
|
||||
list_for_each_entry(dvol, &dvol_attr.dvol_head, entry) {
|
||||
if (dvol && (dvol->idx == dvol_idx)) {
|
||||
dvol_log("dvol_close[%x]:%x", dvol_idx, dvol);
|
||||
dvol_valid = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (dvol_valid == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (dvol) {
|
||||
local_irq_disable();
|
||||
#if BG_DVOL_FADE_ENABLE
|
||||
dvol_handle *hdl;
|
||||
list_for_each_entry(hdl, &dvol_attr.dvol_head, entry) {
|
||||
if ((hdl != dvol) && (hdl->vol_bk >= 0)) {
|
||||
//y_printf("bg_dvol fade_in:%x,%d",hdl,hdl->vol_bk);
|
||||
hdl->vol = hdl->vol_bk;
|
||||
u8 vol_level = hdl->vol_bk * dvol->vol_limit / hdl->vol_max;
|
||||
hdl->vol_target = dig_vol_table[vol_level];
|
||||
hdl->vol_bk = -1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
list_del(&dvol->entry);
|
||||
free(dvol);
|
||||
dvol = NULL;
|
||||
local_irq_enable();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* Audio Digital Volume Get
|
||||
* Description: 数字音量获取
|
||||
* Arguments : dvol_idx 数字音量通道索引,详见audio_dvol.h宏定义
|
||||
* Return : 对应的数字音量通道的当前音量等级.
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
int audio_digital_vol_get(u8 dvol_idx)
|
||||
{
|
||||
dvol_handle *dvol = NULL;
|
||||
u8 dvol_valid = 0;
|
||||
local_irq_disable();
|
||||
list_for_each_entry(dvol, &dvol_attr.dvol_head, entry) {
|
||||
if (dvol && (dvol->idx == dvol_idx)) {
|
||||
dvol_valid = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
local_irq_enable();
|
||||
if (dvol && dvol_valid) {
|
||||
return dvol->vol;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* Audio Digital Volume Set
|
||||
* Description: 数字音量设置
|
||||
* Arguments : dvol_idx 数字音量通道索引,详见audio_dvol.h宏定义
|
||||
* vol 目标音量等级
|
||||
* Return : None.
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
void audio_digital_vol_set(u8 dvol_idx, u8 vol)
|
||||
{
|
||||
dvol_log("audio_digital_vol set:%d,%d\n", dvol_idx, vol);
|
||||
dvol_handle *dvol = NULL;
|
||||
u8 dvol_valid = 0;
|
||||
local_irq_disable();
|
||||
list_for_each_entry(dvol, &dvol_attr.dvol_head, entry) {
|
||||
if (dvol && (dvol->idx == dvol_idx)) {
|
||||
dvol_log("dvol_set[%x]:%x", dvol_idx, dvol);
|
||||
dvol_valid = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
local_irq_enable();
|
||||
if ((dvol == NULL) || (dvol_valid == 0)) {
|
||||
return;
|
||||
}
|
||||
if (dvol->toggle == 0) {
|
||||
return;
|
||||
}
|
||||
dvol->vol = (vol > dvol->vol_max) ? dvol->vol_max : vol;
|
||||
#if BG_DVOL_FADE_ENABLE
|
||||
if (dvol->vol_bk != -1) {
|
||||
dvol->vol_bk = vol;
|
||||
}
|
||||
#endif
|
||||
dvol->fade = DIGITAL_FADE_EN;
|
||||
u8 vol_level = dvol->vol * dvol->vol_limit / dvol->vol_max;
|
||||
dvol->vol_target = dig_vol_table[vol_level];
|
||||
dvol_log("digital_vol:%d-%d-%d-%d\n", vol, vol_level, dvol->vol_fade, dvol->vol_target);
|
||||
}
|
||||
/*********************************************************************
|
||||
* Audio Digital Volume Set
|
||||
* Description: 数字音量设置,设置数字音量的当前值,不用淡入淡出
|
||||
* Arguments : dvol_idx 数字音量通道索引,详见audio_dvol.h宏定义
|
||||
* vol 目标音量等级
|
||||
* Return : None.
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
|
||||
void audio_digital_vol_set_no_fade(u8 dvol_idx, u8 vol)
|
||||
{
|
||||
dvol_log("audio_digital_vol set:%d,%d\n", dvol_idx, vol);
|
||||
dvol_handle *dvol = NULL;
|
||||
u8 dvol_valid = 0;
|
||||
local_irq_disable();
|
||||
list_for_each_entry(dvol, &dvol_attr.dvol_head, entry) {
|
||||
if (dvol && (dvol->idx == dvol_idx)) {
|
||||
dvol_log("dvol_set[%x]:%x", dvol_idx, dvol);
|
||||
dvol_valid = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
local_irq_enable();
|
||||
if ((dvol == NULL) || (dvol_valid == 0)) {
|
||||
return;
|
||||
}
|
||||
if (dvol->toggle == 0) {
|
||||
return;
|
||||
}
|
||||
dvol->vol = (vol > dvol->vol_max) ? dvol->vol_max : vol;
|
||||
#if BG_DVOL_FADE_ENABLE
|
||||
if (dvol->vol_bk != -1) {
|
||||
dvol->vol_bk = vol;
|
||||
}
|
||||
#endif
|
||||
dvol->fade = DIGITAL_FADE_EN;
|
||||
u8 vol_level = dvol->vol * dvol->vol_limit / dvol->vol_max;
|
||||
dvol->vol_fade = dig_vol_table[vol_level];
|
||||
dvol_log("digital_vol:%d-%d-%d-%d\n", vol, vol_level, dvol->vol_fade, dvol->vol_target);
|
||||
}
|
||||
|
||||
void audio_digital_vol_reset_fade(u8 dvol_idx)
|
||||
{
|
||||
dvol_handle *dvol = NULL;
|
||||
u8 dvol_valid = 0;
|
||||
local_irq_disable();
|
||||
list_for_each_entry(dvol, &dvol_attr.dvol_head, entry) {
|
||||
if (dvol && (dvol->idx == dvol_idx)) {
|
||||
dvol_valid = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
local_irq_enable();
|
||||
if (dvol && dvol_valid) {
|
||||
dvol->vol_fade = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* Audio Digital Volume Process
|
||||
* Description: 数字音量运算核心
|
||||
* Arguments : dvol_idx 数字音量通道索引,详见audio_dvol.h宏定义
|
||||
* data 待运算数据
|
||||
* len 待运算数据长度
|
||||
* Return : 0 成功 其他 失败
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
/*rounding处理*/
|
||||
#define MUL32_PSHIFT(x,y,s) (((x) * (y) + (1 << ((s)-1))) >> (s))
|
||||
|
||||
int audio_digital_vol_run(u8 dvol_idx, void *data, u32 len)
|
||||
{
|
||||
s32 valuetemp;
|
||||
s16 *buf;
|
||||
|
||||
os_mutex_pend(&dvol_attr.mutex, 0);
|
||||
dvol_handle *dvol = NULL;
|
||||
u8 dvol_valid = 0;
|
||||
local_irq_disable();
|
||||
list_for_each_entry(dvol, &dvol_attr.dvol_head, entry) {
|
||||
if (dvol && (dvol->idx == dvol_idx)) {
|
||||
dvol_valid = 1;
|
||||
#if 0
|
||||
static dvol_handle *last_dvol = NULL;
|
||||
if (last_dvol != dvol) {
|
||||
dvol_log("dvol_run[%x]:%x", dvol_idx, dvol);
|
||||
last_dvol = dvol;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
local_irq_enable();
|
||||
|
||||
if ((dvol->toggle == 0) || (dvol_valid == 0)) {
|
||||
os_mutex_post(&dvol_attr.mutex);
|
||||
return -1;
|
||||
}
|
||||
|
||||
buf = data;
|
||||
len >>= 1; //byte to point
|
||||
|
||||
for (u32 i = 0; i < len; i += 2) {
|
||||
///left channel
|
||||
if (dvol->fade) {
|
||||
if (dvol->vol_fade > dvol->vol_target) {
|
||||
dvol->vol_fade -= dvol->fade_step;
|
||||
if (dvol->vol_fade < dvol->vol_target) {
|
||||
dvol->vol_fade = dvol->vol_target;
|
||||
}
|
||||
} else if (dvol->vol_fade < dvol->vol_target) {
|
||||
dvol->vol_fade += dvol->fade_step;
|
||||
if (dvol->vol_fade > dvol->vol_target) {
|
||||
dvol->vol_fade = dvol->vol_target;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
dvol->vol_fade = dvol->vol_target;
|
||||
}
|
||||
|
||||
valuetemp = buf[i];
|
||||
if (valuetemp < 0) {
|
||||
/*负数先转换成正数,运算完再转换回去,是为了避免负数右移位引入1的误差,增加底噪*/
|
||||
valuetemp = -valuetemp;
|
||||
/*rounding处理(加入0.5),减少小信号时候的误差和谐波幅值*/
|
||||
valuetemp = (valuetemp * dvol->vol_fade + (1 << 13)) >> 14 ;
|
||||
valuetemp = -valuetemp;
|
||||
} else {
|
||||
valuetemp = (valuetemp * dvol->vol_fade + (1 << 13)) >> 14 ;
|
||||
}
|
||||
/*饱和处理*/
|
||||
buf[i] = (s16)data_sat_s16(valuetemp);
|
||||
|
||||
///right channel
|
||||
valuetemp = buf[i + 1];
|
||||
if (valuetemp < 0) {
|
||||
/*负数先转换成正数,运算完再转换回去,是为了避免负数右移位引入1的误差,增加底噪*/
|
||||
valuetemp = -valuetemp;
|
||||
valuetemp = (valuetemp * dvol->vol_fade + (1 << 13)) >> 14 ;
|
||||
valuetemp = -valuetemp;
|
||||
} else {
|
||||
valuetemp = (valuetemp * dvol->vol_fade + (1 << 13)) >> 14 ;
|
||||
}
|
||||
/*饱和处理*/
|
||||
buf[i + 1] = (s16)data_sat_s16(valuetemp);
|
||||
}
|
||||
os_mutex_post(&dvol_attr.mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
55
apps/common/audio/audio_dvol.h
Normal file
55
apps/common/audio/audio_dvol.h
Normal file
@ -0,0 +1,55 @@
|
||||
#ifndef _AUDIO_DVOL_H_
|
||||
#define _AUDIO_DVOL_H_
|
||||
|
||||
#include "generic/typedef.h"
|
||||
#include "os/os_type.h"
|
||||
#include "os/os_api.h"
|
||||
#include "generic/list.h"
|
||||
|
||||
#define BG_DVOL_FADE_ENABLE 1 /*多路声音叠加,背景声音自动淡出小声*/
|
||||
|
||||
/*Digital Volume Channel*/
|
||||
#define MUSIC_DVOL 0xA1
|
||||
#define CALL_DVOL 0xA2
|
||||
#define TONE_DVOL 0xA3
|
||||
#define HEARING_DVOL 0xA4
|
||||
|
||||
/*Digital Volume Fade Step*/
|
||||
#define MUSIC_DVOL_FS 2
|
||||
#define CALL_DVOL_FS 4
|
||||
#define TONE_DVOL_FS 30
|
||||
#define HEARING_DVOL_FS 2
|
||||
|
||||
/*Digital Volume Max Level*/
|
||||
#define MUSIC_DVOL_MAX 16
|
||||
#define CALL_DVOL_MAX 15
|
||||
#define TONE_DVOL_MAX 16
|
||||
#define HEARING_DVOL_MAX 16
|
||||
|
||||
typedef struct {
|
||||
u8 toggle; /*数字音量开关*/
|
||||
u8 fade; /*淡入淡出标志*/
|
||||
u8 vol; /*淡入淡出当前音量(level)*/
|
||||
u8 vol_max; /*淡入淡出最大音量(level)*/
|
||||
char vol_limit; /*最大数字音量限制*/
|
||||
u8 idx; /*数字音量通道索引*/
|
||||
s16 vol_fade; /*淡入淡出对应的起始音量*/
|
||||
#if BG_DVOL_FADE_ENABLE
|
||||
s16 vol_bk; /*后台自动淡出前音量值*/
|
||||
#endif/*BG_DVOL_FADE_ENABLE*/
|
||||
struct list_head entry;
|
||||
volatile s16 vol_target; /*淡入淡出对应的目标音量*/
|
||||
volatile u16 fade_step; /*淡入淡出的步进*/
|
||||
} dvol_handle;
|
||||
|
||||
int audio_digital_vol_init(u16 *vol_table, u16 vol_max);
|
||||
void audio_digital_vol_bg_fade(u8 fade_out);
|
||||
dvol_handle *audio_digital_vol_open(u8 dvol_idx, u8 vol, u8 vol_max, u16 fade_step, char vol_limit);
|
||||
void audio_digital_vol_close(u8 dvol_idx);
|
||||
void audio_digital_vol_set(u8 dvol_idx, u8 vol);
|
||||
int audio_digital_vol_get(u8 dvol_idx);
|
||||
int audio_digital_vol_run(u8 dvol_idx, void *data, u32 len);
|
||||
void audio_digital_vol_reset_fade(u8 dvol_idx);
|
||||
void audio_digital_vol_set_no_fade(u8 dvol_idx, u8 vol);
|
||||
|
||||
#endif/*_AUDIO_DVOL_H_*/
|
||||
140
apps/common/audio/audio_export_demo.c
Normal file
140
apps/common/audio/audio_export_demo.c
Normal file
@ -0,0 +1,140 @@
|
||||
#include "app_config.h"
|
||||
#ifdef AUDIO_PCM_DEBUG
|
||||
#include "uartPcmSender.h"
|
||||
|
||||
extern int aec_uart_init();
|
||||
extern int aec_uart_fill(u8 ch, void *buf, u16 size);
|
||||
extern void aec_uart_write(void);
|
||||
extern int aec_uart_close(void);
|
||||
|
||||
/*
|
||||
16k 正选波 pcm 数据
|
||||
*/
|
||||
static short const sin0_16k[16] = {
|
||||
0x0000, 0x30fd, 0x5a83, 0x7641, 0x7fff, 0x7642, 0x5a82, 0x30fc, 0x0000, 0xcf04, 0xa57d, 0x89be, 0x8000, 0x89be, 0xa57e, 0xcf05,
|
||||
};
|
||||
static u16 tx1_s_cnt = 0;
|
||||
static int get_sine0_data(u16 *s_cnt, s16 *data, u16 points, u8 ch)
|
||||
{
|
||||
while (points--) {
|
||||
if (*s_cnt >= 16) {
|
||||
*s_cnt = 0;
|
||||
}
|
||||
*data++ = sin0_16k[*s_cnt] / 2;
|
||||
if (ch == 2) {
|
||||
*data++ = sin0_16k[*s_cnt] / 2;
|
||||
}
|
||||
(*s_cnt)++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
*************************************************************
|
||||
* uart data export 接口使用说明
|
||||
* 1、每个通道一次只能固定发送512byte数据,数据不够会被丢弃
|
||||
* 2、aec_uart_write()一次会发送3个通道的数据,没有填数的通道会发送空白数据
|
||||
* 3、UART DMA发送一次数据需要约8ms时间,两次发数间隔需 > 8ms
|
||||
* 4、发送波特率、发送引脚在 uartPcmSender.h 配置
|
||||
* 5、该接口的接收端需使用JL的串口导出工具接收数据
|
||||
*
|
||||
*************************************************************
|
||||
*/
|
||||
void audio_export_demo_task(void *param)
|
||||
{
|
||||
printf("audio_export_demo_task\n");
|
||||
s16 data[256];
|
||||
int len = 512;
|
||||
/*生成256个点的16k的正选波数据*/
|
||||
get_sine0_data(&tx1_s_cnt, data, len / 2, 1);
|
||||
|
||||
while (1) {
|
||||
putchar('.');
|
||||
|
||||
{
|
||||
/*run code*/
|
||||
}
|
||||
|
||||
aec_uart_fill(0, data, 512); //往通道0填数据
|
||||
|
||||
{
|
||||
/*run code*/
|
||||
}
|
||||
|
||||
aec_uart_fill(1, data, 512); //往通道1填数据
|
||||
|
||||
{
|
||||
/*run code*/
|
||||
}
|
||||
|
||||
aec_uart_fill(2, data, 512); //往通道2填数据
|
||||
aec_uart_write(); //一次把3路数据发送出去
|
||||
os_time_dly(2); //等待发送完成,发送一次要8ms,发完才可以进行下一次发数
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
**********************************************************
|
||||
* uart data export 接口使用示例
|
||||
*********************************************************
|
||||
*/
|
||||
int audio_export_demo_init()
|
||||
{
|
||||
printf("audio_export_demo_init\n");
|
||||
/* uartSendInit(); //串口初始化,已经在开机时调用初始化,这里不需调用 */
|
||||
aec_uart_init(); //uart export 初始化
|
||||
os_task_create(audio_export_demo_task, NULL, 1, 1024, 128, "audio_export_task");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*************************************************************
|
||||
* 通用 uart 发数接口(uartSendData())使用说明
|
||||
* 1、发数的数据长度可以根据需要修改
|
||||
* 2、一般发送512byte,DMA模式需要2.7ms
|
||||
* 3、发送波特率、发送引脚在 uartPcmSender.h 配置
|
||||
* 4、可以使用该接口自定义发数方式、协议等
|
||||
*
|
||||
*************************************************************
|
||||
*/
|
||||
void audio_uart_transmit_demo_task(void *param)
|
||||
{
|
||||
printf("audio_uart_transmit_demo_task\n");
|
||||
s16 data[256];
|
||||
int len = 512;
|
||||
/*生成256个点的16k的正选波数据*/
|
||||
get_sine0_data(&tx1_s_cnt, data, len / 2, 1);
|
||||
|
||||
while (1) {
|
||||
putchar('.');
|
||||
uartSendData(data, len); //uart 发送数据接口
|
||||
os_time_dly(1); //一般发送512byte,DMA模式需要2.7ms
|
||||
}
|
||||
}
|
||||
/*
|
||||
**********************************************************
|
||||
* 通用uart发数使用示例
|
||||
*********************************************************
|
||||
*/
|
||||
int audio_uart_transmit_demo_init()
|
||||
{
|
||||
printf("audio_uart_transmit_demo_init\n");
|
||||
/* uartSendInit(); //串口初始化,已经在开机时调用初始化,这里不需调用 */
|
||||
os_task_create(audio_uart_transmit_demo_task, NULL, 1, 1024, 128, "audio_uart_transmit_task");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u8 audio_export_demo_idle_query()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
REGISTER_LP_TARGET(audio_export_demo_lp_target) = {
|
||||
.name = "audio_export__demo",
|
||||
.is_idle = audio_export_demo_idle_query,
|
||||
};
|
||||
|
||||
#endif /*AUDIO_PCM_DEBUG*/
|
||||
|
||||
126
apps/common/audio/audio_noise_gate.c
Normal file
126
apps/common/audio/audio_noise_gate.c
Normal file
@ -0,0 +1,126 @@
|
||||
/*
|
||||
******************************************************************
|
||||
* Limiter_NoiseGate Module(限幅器/噪声门限模块)
|
||||
*1. Limiter:限制最大幅度
|
||||
*2. NoiseGate:
|
||||
*(1)启动时间
|
||||
*(2)释放时间
|
||||
*(3)噪声阈值
|
||||
*(4)噪声增益
|
||||
*3. Usage:
|
||||
*(1)LIMITER_THR:限幅器参数,限制信号的最大值
|
||||
*(2)LIMITER_NOISE_GATE:噪声门限的阈值,配合LIMITER_NOISE_GAIN使用
|
||||
*(3)LIMITER_NOISE_GAIN:当信号小于噪声门限LIMITER_NOISE_GATE的时候
|
||||
*信号增益为LIMITER_NOISE_GAIN,范围是0到1,增益0为静音,增益1为直通
|
||||
*效果。噪声门限用来优化声音的底噪
|
||||
******************************************************************
|
||||
*/
|
||||
|
||||
#include "system/includes.h"
|
||||
#include "os/os_api.h"
|
||||
#include "limiter_noiseGate_api.h"
|
||||
#include "audio_noise_gate.h"
|
||||
|
||||
|
||||
//#define NG_LOG_ENABLE
|
||||
#ifdef NG_LOG_ENABLE
|
||||
#define NG_LOG y_printf
|
||||
#else
|
||||
#define NG_LOG(...)
|
||||
#endif/*NG_LOG_ENABLE*/
|
||||
|
||||
/*限幅器上限*/
|
||||
#define LIMITER_THR -10000 /*-12000 = -12dB,放大1000倍,(-10000参考)*/
|
||||
/*小于CONST_NOISE_GATE的当成噪声处理,防止清0近端声音*/
|
||||
#define LIMITER_NOISE_GATE -40000 /*-12000 = -12dB,放大1000倍,(-40000参考)*/
|
||||
/*低于噪声门限阈值的增益 */
|
||||
#define LIMITER_NOISE_GAIN (0 << 30) /*(0~1)*2^30*/
|
||||
|
||||
enum {
|
||||
NG_STA_CLOSE = 0,
|
||||
NG_STA_OPEN,
|
||||
NG_STA_RUN,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
u8 state;
|
||||
OS_MUTEX mutex;
|
||||
u8 *run_buf;
|
||||
} audio_noise_gate_t;
|
||||
audio_noise_gate_t NoiseGate;
|
||||
|
||||
int audio_noise_gate_open(u16 sample_rate, int limiter_thr, int noise_gate, int noise_gain)
|
||||
{
|
||||
NG_LOG("audio_noise_gate_open");
|
||||
NoiseGate.run_buf = malloc(need_limiter_noiseGate_buf(1));
|
||||
NG_LOG("Limiter_noisegate_buf size:%d\n", need_limiter_noiseGate_buf(1));
|
||||
if (NoiseGate.run_buf) {
|
||||
//限幅器启动因子 int32(exp(-0.65/(16000 * 0.005))*2^30) 16000为采样率 0.005 为启动时间(s)
|
||||
int limiter_attfactor = 1065053018;
|
||||
//限幅器释放因子 int32(exp(-0.15/(16000 * 0.1))*2^30) 16000为采样率 0.1 为释放时间(s)
|
||||
int limiter_relfactor = 1073641165;
|
||||
//限幅器阈值(mdb)
|
||||
//int limiter_threshold = CONST_LIMITER_THR;
|
||||
|
||||
//噪声门限启动因子 int32(exp(-1/(16000 * 0.1))*2^30) 16000为采样率 0.1 为启动时间(s)
|
||||
/*
|
||||
*import math
|
||||
*int(math.exp(-1.0/(16000*0.1))*2**30)
|
||||
*/
|
||||
int noiseGate_attfactor = 1073070945;
|
||||
//噪声门限释放因子 int32(exp(-1/(16000 * 0.005))*2^30) 16000为采样率 0.005 为释放时间(s)
|
||||
int noiseGate_relfactor = 1060403589;
|
||||
//噪声门限(mdb)
|
||||
//int noiseGate_threshold = -25000;
|
||||
//低于噪声门限阈值的增益 (0~1)*2^30
|
||||
//int noise
|
||||
//Gate_low_thr_gain = 0 << 30;
|
||||
|
||||
if (sample_rate == 8000) {
|
||||
limiter_attfactor = 1056434522;
|
||||
limiter_relfactor = 1073540516;
|
||||
noiseGate_attfactor = 1072400485;
|
||||
noiseGate_relfactor = 1047231044;
|
||||
}
|
||||
|
||||
limiter_noiseGate_init(NoiseGate.run_buf,
|
||||
limiter_attfactor,
|
||||
limiter_relfactor,
|
||||
noiseGate_attfactor,
|
||||
noiseGate_relfactor,
|
||||
limiter_thr,
|
||||
noise_gate,
|
||||
noise_gain,
|
||||
sample_rate, 1);
|
||||
os_mutex_create(&NoiseGate.mutex);
|
||||
NoiseGate.state = NG_STA_OPEN;
|
||||
NG_LOG("audio_noise_gate_open succ");
|
||||
return 0;
|
||||
}
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
void audio_noise_gate_run(void *in, void *out, u16 len)
|
||||
{
|
||||
if (NoiseGate.state == NG_STA_CLOSE) {
|
||||
return;
|
||||
}
|
||||
os_mutex_pend(&NoiseGate.mutex, 0);
|
||||
if (NoiseGate.run_buf) {
|
||||
limiter_noiseGate_run(NoiseGate.run_buf, in, out, len / 2);
|
||||
}
|
||||
os_mutex_post(&NoiseGate.mutex);
|
||||
}
|
||||
|
||||
void audio_noise_gate_close()
|
||||
{
|
||||
NG_LOG("audio_noise_gate_close");
|
||||
os_mutex_pend(&NoiseGate.mutex, 0);
|
||||
NoiseGate.state = NG_STA_CLOSE;
|
||||
if (NoiseGate.run_buf) {
|
||||
free(NoiseGate.run_buf);
|
||||
}
|
||||
os_mutex_post(&NoiseGate.mutex);
|
||||
NG_LOG("audio_noise_gate_close succ");
|
||||
}
|
||||
|
||||
11
apps/common/audio/audio_noise_gate.h
Normal file
11
apps/common/audio/audio_noise_gate.h
Normal file
@ -0,0 +1,11 @@
|
||||
#ifndef _AUDIO_LIMITER_NOISE_GATE_H_
|
||||
#define _AUDIO_LIMITER_NOISE_GATE_H_
|
||||
|
||||
#include "generic/typedef.h"
|
||||
|
||||
|
||||
int audio_noise_gate_open(u16 sample_rate, int limiter_thr, int noise_gate, int noise_gain);
|
||||
void audio_noise_gate_run(void *in, void *out, u16 len);
|
||||
void audio_noise_gate_close();
|
||||
|
||||
#endif/*_AUDIO_NOISE_GATE_H_*/
|
||||
112
apps/common/audio/audio_ns.c
Normal file
112
apps/common/audio/audio_ns.c
Normal file
@ -0,0 +1,112 @@
|
||||
/*
|
||||
******************************************************************
|
||||
* Noise Suppress Module(降噪模块)
|
||||
*Notes:
|
||||
*(1)支持降噪的数据采样率:8k/16k
|
||||
*(2)增加多5k左右代码
|
||||
*(3)内存消耗跟数据采样率有关,具体可通过以下接口查询:
|
||||
* int ns_mem_size = noise_suppress_mem_query(&ans->ns_para);
|
||||
******************************************************************
|
||||
*/
|
||||
|
||||
#include "audio_ns.h"
|
||||
|
||||
#ifdef CONFIG_MEDIA_NEW_ENABLE
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* NoiseSuppress Process
|
||||
* Description: 降噪处理主函数
|
||||
* Arguments : ns 降噪句柄
|
||||
* in 输入数据
|
||||
* out 输出数据
|
||||
* len 输入数据长度
|
||||
* Return : 降噪输出长度
|
||||
* Note(s) : 由于降噪是固定处理帧长的,所以如果输入数据长度不是降噪
|
||||
* 帧长整数倍,则某一次会输出0长度,即没有输出
|
||||
*********************************************************************
|
||||
*/
|
||||
int audio_ns_run(audio_ns_t *ns, short *in, short *out, u16 len)
|
||||
{
|
||||
if (ns == NULL) {
|
||||
return len;
|
||||
}
|
||||
#if 0
|
||||
int wlen = cbuf_write(&ns->cbuf, in, len);
|
||||
if (wlen != len) {
|
||||
printf("ns_cbuf full\n");
|
||||
}
|
||||
if (ns->cbuf.data_len >= NS_FRAME_SIZE) {
|
||||
cbuf_read(&ns->cbuf, out, NS_FRAME_SIZE);
|
||||
putchar('.');
|
||||
noise_suppress_run(out, out, NS_FRAME_POINTS);
|
||||
return NS_FRAME_SIZE;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
//putchar('.');
|
||||
int nOut = noise_suppress_run(in, out, (len / 2));
|
||||
return (nOut << 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* Noise Suppress Open
|
||||
* Description: 初始化降噪模块
|
||||
* Arguments : sr 数据采样率
|
||||
* mode 降噪模式(0,1,2:越大越耗资源,效果越好)
|
||||
* NoiseLevel 初始噪声水平(评估初始噪声,加快收敛)
|
||||
* AggressFactor 降噪强度(越大越强:1~2)
|
||||
* MinSuppress 降噪最小压制(越小越强:0~1)
|
||||
* Return : 降噪模块句柄
|
||||
* Note(s) : (1)采样率只支持8k、16k
|
||||
* (2)如果内存不足,可以考虑wideband强制为0,即只做窄带降噪
|
||||
* ans-ns_para.wideband = 0;
|
||||
*********************************************************************
|
||||
*/
|
||||
audio_ns_t *audio_ns_open(u16 sr, u8 mode, float NoiseLevel, float AggressFactor, float MinSuppress)
|
||||
{
|
||||
audio_ns_t *ans = zalloc(sizeof(audio_ns_t));
|
||||
//cbuf_init(&ans->cbuf, ans->in, sizeof(ans->in));
|
||||
|
||||
ans->ns_para.wideband = (sr == 16000) ? 1 : 0;
|
||||
ans->ns_para.mode = mode;
|
||||
ans->ns_para.NoiseLevel = NoiseLevel;
|
||||
ans->ns_para.AggressFactor = AggressFactor;
|
||||
ans->ns_para.MinSuppress = MinSuppress;
|
||||
printf("ns wideband:%d\n", ans->ns_para.wideband);
|
||||
//int ns_mem_size = noise_suppress_mem_query(&ans->ns_para);
|
||||
//printf("ns mem_size:%d\n", ns_mem_size);
|
||||
noise_suppress_open(&ans->ns_para);
|
||||
float lowcut = -60.f;
|
||||
noise_suppress_config(NS_CMD_LOWCUTTHR, 0, &lowcut);
|
||||
float noise_floor = -60.f;
|
||||
noise_suppress_config(NS_CMD_NOISE_FLOOR, 0, &noise_floor);
|
||||
printf("audio_ns_open ok\n");
|
||||
return ans;
|
||||
}
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* Noise Suppress Close
|
||||
* Description: 关闭降噪模块
|
||||
* Arguments : ns 降噪模块句柄
|
||||
* Return : 0 成功 其他 失败
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
int audio_ns_close(audio_ns_t *ns)
|
||||
{
|
||||
noise_suppress_close();
|
||||
if (ns) {
|
||||
free(ns);
|
||||
ns = NULL;
|
||||
}
|
||||
printf("esco_ans_close ok\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /*CONFIG_MEDIA_NEW_ENABLE*/
|
||||
|
||||
61
apps/common/audio/audio_ns.h
Normal file
61
apps/common/audio/audio_ns.h
Normal file
@ -0,0 +1,61 @@
|
||||
#ifndef _AUDIO_NOISE_SUPPRESS_H_
|
||||
#define _AUDIO_NOISE_SUPPRESS_H_
|
||||
|
||||
#include "generic/typedef.h"
|
||||
#include "generic/circular_buf.h"
|
||||
#include "commproc_ns.h"
|
||||
|
||||
/*降噪数据帧长(单位:点数)*/
|
||||
#define NS_FRAME_POINTS 160
|
||||
#define NS_FRAME_SIZE (NS_FRAME_POINTS << 1)
|
||||
/*降噪输出buf长度*/
|
||||
#define NS_OUT_POINTS_MAX (NS_FRAME_POINTS << 1)
|
||||
|
||||
typedef struct {
|
||||
//s16 in[512];
|
||||
//cbuffer_t cbuf;
|
||||
noise_suppress_param ns_para;
|
||||
} audio_ns_t;
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* Noise Suppress Open
|
||||
* Description: 初始化降噪模块
|
||||
* Arguments : sr 数据采样率
|
||||
* mode 降噪模式(0,1,2:越大越耗资源,效果越好)
|
||||
* NoiseLevel 初始噪声水平(评估初始噪声,加快收敛)
|
||||
* AggressFactor 降噪强度(越大越强:1~2)
|
||||
* MinSuppress 降噪最小压制(越小越强:0~1)
|
||||
* Return : 降噪模块句柄
|
||||
* Note(s) : 采样率只支持8k、16k
|
||||
*********************************************************************
|
||||
*/
|
||||
audio_ns_t *audio_ns_open(u16 sr, u8 mode, float NoiseLevel, float AggressFactor, float MinSuppress);
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* NoiseSuppress Process
|
||||
* Description: 降噪处理主函数
|
||||
* Arguments : ns 降噪句柄
|
||||
* in 输入数据
|
||||
* out 输出数据
|
||||
* len 输入数据长度
|
||||
* Return : 降噪输出长度
|
||||
* Note(s) : 由于降噪是固定处理帧长的,所以如果输入数据长度不是降噪
|
||||
* 帧长整数倍,则某一次会输出0长度,即没有输出
|
||||
*********************************************************************
|
||||
*/
|
||||
int audio_ns_run(audio_ns_t *ns, short *in, short *out, u16 len);
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* Noise Suppress Close
|
||||
* Description: 关闭降噪模块
|
||||
* Arguments : ns 降噪模块句柄
|
||||
* Return : 0 成功 其他 失败
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
int audio_ns_close(audio_ns_t *ns);
|
||||
|
||||
#endif/*_AUDIO_NOISE_SUPPRESS_H_*/
|
||||
138
apps/common/audio/audio_plc.c
Normal file
138
apps/common/audio/audio_plc.c
Normal file
@ -0,0 +1,138 @@
|
||||
/*
|
||||
************************************************************
|
||||
*
|
||||
*
|
||||
*
|
||||
************************************************************
|
||||
*/
|
||||
#include "system/includes.h"
|
||||
#include "PLC.h"
|
||||
#include "os/os_api.h"
|
||||
#include "app_config.h"
|
||||
#include "audio_config.h"
|
||||
|
||||
#if TCFG_ESCO_PLC
|
||||
|
||||
//#define AUDIO_PLC_LOG_ENABLE
|
||||
#ifdef AUDIO_PLC_LOG_ENABLE
|
||||
#define PLC_LOG y_printf
|
||||
#else
|
||||
#define PLC_LOG(...)
|
||||
#endif/*AUDIO_PLC_LOG_ENABLE*/
|
||||
|
||||
enum {
|
||||
PLC_STA_CLOSE = 0,
|
||||
PLC_STA_OPEN,
|
||||
PLC_STA_RUN,
|
||||
};
|
||||
|
||||
|
||||
#define PLC_FRAME_LEN 120
|
||||
typedef struct {
|
||||
u8 state;
|
||||
u8 repair;
|
||||
u8 wideband;
|
||||
OS_MUTEX mutex;
|
||||
s16 *run_buf;
|
||||
} audio_plc_t;
|
||||
static audio_plc_t plc;
|
||||
|
||||
int audio_plc_open(u16 sr)
|
||||
{
|
||||
PLC_LOG("audio_plc_open:%d\n", sr);
|
||||
memset((u8 *)&plc, 0, sizeof(audio_plc_t));
|
||||
plc.run_buf = malloc(PLC_query()); /*buf_size:1040*/
|
||||
PLC_LOG("PLC_buf:%x,size:%d\n", plc.run_buf, PLC_query());
|
||||
if (plc.run_buf) {
|
||||
s8 err = PLC_init(plc.run_buf);
|
||||
if (err) {
|
||||
PLC_LOG("PLC_init err:%d", err);
|
||||
free(plc.run_buf);
|
||||
return -EINVAL;
|
||||
}
|
||||
os_mutex_create(&plc.mutex);
|
||||
if (sr == 16000) {
|
||||
plc.wideband = 1;
|
||||
}
|
||||
plc.state = PLC_STA_OPEN;
|
||||
}
|
||||
PLC_LOG("audio_plc_open succ\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void audio_plc_run(s16 *data, u16 len, u8 repair)
|
||||
{
|
||||
u16 repair_point, tmp_point;
|
||||
s16 *p_in, *p_out;
|
||||
p_in = data;
|
||||
p_out = data;
|
||||
tmp_point = len / 2;
|
||||
u8 repair_flag = 0;
|
||||
|
||||
os_mutex_pend(&plc.mutex, 0);
|
||||
if (plc.state == PLC_STA_CLOSE) {
|
||||
os_mutex_post(&plc.mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
#if 0 //debug
|
||||
static u16 repair_cnt = 0;
|
||||
if (repair) {
|
||||
repair_cnt++;
|
||||
y_printf("[E%d]", repair_cnt);
|
||||
} else {
|
||||
repair_cnt = 0;
|
||||
}
|
||||
//printf("[%d]",point);
|
||||
#endif/*debug*/
|
||||
|
||||
repair_flag = repair;
|
||||
if (plc.wideband) {
|
||||
/*
|
||||
*msbc plc deal
|
||||
*如果上一帧是错误,则当前帧也要修复
|
||||
*/
|
||||
if (plc.repair) {
|
||||
repair_flag = 1;
|
||||
}
|
||||
plc.repair = repair;
|
||||
}
|
||||
|
||||
while (tmp_point) {
|
||||
repair_point = (tmp_point > PLC_FRAME_LEN) ? PLC_FRAME_LEN : tmp_point;
|
||||
tmp_point = tmp_point - repair_point;
|
||||
PLC_run(p_in, p_out, repair_point, repair_flag);
|
||||
p_in += repair_point;
|
||||
p_out += repair_point;
|
||||
}
|
||||
os_mutex_post(&plc.mutex);
|
||||
}
|
||||
|
||||
int audio_plc_close(void)
|
||||
{
|
||||
PLC_LOG("audio_plc_close\n");
|
||||
os_mutex_pend(&plc.mutex, 0);
|
||||
plc.state = PLC_STA_CLOSE;
|
||||
if (plc.run_buf) {
|
||||
free(plc.run_buf);
|
||||
plc.run_buf = NULL;
|
||||
}
|
||||
os_mutex_post(&plc.mutex);
|
||||
PLC_LOG("audio_plc_close succ\n");
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
int audio_plc_open(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void audio_plc_run(s16 *dat, u16 len, u8 repair_flag)
|
||||
{
|
||||
}
|
||||
|
||||
int audio_plc_close()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif/*TCFG_ESCO_PLC*/
|
||||
10
apps/common/audio/audio_plc.h
Normal file
10
apps/common/audio/audio_plc.h
Normal file
@ -0,0 +1,10 @@
|
||||
#ifndef _AUDIO_PLC_H_
|
||||
#define _AUDIO_PLC_H_
|
||||
|
||||
#include "generic/typedef.h"
|
||||
|
||||
int audio_plc_open(u16 sr);
|
||||
void audio_plc_run(s16 *dat, u16 len, u8 repair_flag);
|
||||
int audio_plc_close(void);
|
||||
|
||||
#endif/*_AUDIO_PLC_H_*/
|
||||
28
apps/common/audio/audio_utils.c
Normal file
28
apps/common/audio/audio_utils.c
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
************************************************************
|
||||
* Audio Utils
|
||||
*Brief:数字信号处理常用模块合集
|
||||
*Notes:
|
||||
************************************************************
|
||||
*/
|
||||
|
||||
#include "audio_utils.h"
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* Audio Digital Phase Inverter
|
||||
* Description: 数字反相器,用来反转数字音频信号的相位
|
||||
* Arguments : dat 数据buf地址
|
||||
* len 数据长度(unit:byte)
|
||||
* Return : None.
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
void digital_phase_inverter_s16(s16 *dat, int len)
|
||||
{
|
||||
int data_size = len / 2;
|
||||
for (int i = 0; i < data_size; i++) {
|
||||
dat[i] = (dat[i] == -32768) ? 32767 : -dat[i];
|
||||
}
|
||||
}
|
||||
|
||||
18
apps/common/audio/audio_utils.h
Normal file
18
apps/common/audio/audio_utils.h
Normal file
@ -0,0 +1,18 @@
|
||||
#ifndef _AUDIO_UTILS_H_
|
||||
#define _AUDIO_UTILS_H_
|
||||
|
||||
#include "generic/typedef.h"
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* Audio Digital Phase Inverter
|
||||
* Description: 数字反相器,用来反转数字音频信号的相位
|
||||
* Arguments : dat 数据buf地址
|
||||
* len 数据长度(unit:byte)
|
||||
* Return : None.
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
void digital_phase_inverter_s16(s16 *dat, int len);
|
||||
|
||||
#endif/*_AUDIO_UTILS_H_*/
|
||||
707
apps/common/audio/decode/audio_key_tone.c
Normal file
707
apps/common/audio/decode/audio_key_tone.c
Normal file
@ -0,0 +1,707 @@
|
||||
#include "asm/includes.h"
|
||||
#include "media/includes.h"
|
||||
#include "system/includes.h"
|
||||
#include "app_config.h"
|
||||
#include "audio_config.h"
|
||||
/* #include "audio_dec.h" */
|
||||
#include "application/audio_dec_app.h"
|
||||
#include "tone_player.h"
|
||||
#include "sine_make.h"
|
||||
|
||||
#if TCFG_KEY_TONE_EN
|
||||
|
||||
// 按键提示音任务名
|
||||
#define AUDIO_KEY_TONE_TASK_NAME "key_tone"
|
||||
|
||||
// 按键提示音数字音量控制
|
||||
#if (SYS_DIGVOL_GROUP_EN && defined(CONFIG_MEDIA_DEVELOP_ENABLE))
|
||||
#define AUDIO_KEY_TONE_DIGVOL_EN 0
|
||||
#define AUDIO_KEY_TONE_DIGVOL_NAME "key_tone"
|
||||
#else
|
||||
#define AUDIO_KEY_TONE_DIGVOL_EN 0
|
||||
#endif
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*
|
||||
* 使用audio_dec_app.h里面的接口,可以实现普通文件、正弦波文件、正弦波数组播放
|
||||
*/
|
||||
|
||||
// 参数
|
||||
struct __key_tone_play_info {
|
||||
const char *file_name; // 文件名
|
||||
struct audio_sin_param *sin; // 正弦波数组
|
||||
u8 sin_num; // 正弦波数组长度
|
||||
u8 preemption; // 1-抢占,0-叠加
|
||||
void (*evt_handler)(void *priv, int flag); // 事件回调
|
||||
void *evt_priv; // 事件回调私有句柄
|
||||
};
|
||||
|
||||
// 按键提示音
|
||||
struct __key_tone {
|
||||
volatile u8 busy; // 任务工作中
|
||||
volatile u8 start; // 运行标志
|
||||
volatile u8 play;
|
||||
#if AUDIO_KEY_TONE_DIGVOL_EN
|
||||
u8 volume; // 音量
|
||||
#endif
|
||||
struct __key_tone_play_info play_info; // 输入参数
|
||||
struct audio_dec_sine_app_hdl *dec_sin; // 文件播放句柄
|
||||
struct audio_dec_file_app_hdl *dec_file; // sine播放句柄
|
||||
void (*evt_handler)(void *priv, int flag); // 事件回调
|
||||
void *evt_priv; // 事件回调私有句柄
|
||||
const char *evt_owner; // 事件回调所在任务
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
extern struct audio_mixer mixer;
|
||||
|
||||
static struct __key_tone *key_tone = NULL;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* Audio Key Tone Get File Ext Name
|
||||
* Description: 获取文件名后缀
|
||||
* Arguments : *name 文件名
|
||||
* Return : 后缀
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
static char *get_file_ext_name(char *name)
|
||||
{
|
||||
int len = strlen(name);
|
||||
char *ext = (char *)name;
|
||||
|
||||
while (len--) {
|
||||
if (*ext++ == '.') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (len <= 0) {
|
||||
ext = name + (strlen(name) - 3);
|
||||
}
|
||||
|
||||
return ext;
|
||||
}
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* Audio Key Tone Post Event
|
||||
* Description: 解码事件
|
||||
* Arguments : *ktone 按键提示音解码句柄
|
||||
* end_flag 结束标志
|
||||
* Return : true 成功
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
static int key_tone_dec_event_handler(struct __key_tone *ktone, u8 end_flag)
|
||||
{
|
||||
int argv[4];
|
||||
if (!ktone->evt_handler) {
|
||||
log_i("evt_handler null\n");
|
||||
return false;
|
||||
}
|
||||
argv[0] = (int)ktone->evt_handler;
|
||||
argv[1] = 2;
|
||||
argv[2] = (int)ktone->evt_priv;
|
||||
argv[3] = (int)end_flag; //0正常关闭,1被打断关闭
|
||||
|
||||
int ret = os_taskq_post_type(ktone->evt_owner, Q_CALLBACK, 4, argv);
|
||||
if (ret) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* Audio Key Tone Reelease
|
||||
* Description: 提示音解码器释放
|
||||
* Arguments : *ktone 按键提示音解码句柄
|
||||
* Return : None.
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
static void key_tone_dec_hdl_release(struct __key_tone *ktone)
|
||||
{
|
||||
if (ktone->dec_file) {
|
||||
audio_dec_file_app_close(ktone->dec_file);
|
||||
ktone->dec_file = NULL;
|
||||
}
|
||||
if (ktone->dec_sin) {
|
||||
audio_dec_sine_app_close(ktone->dec_sin);
|
||||
ktone->dec_sin = NULL;
|
||||
}
|
||||
#if (!defined(CONFIG_MEDIA_DEVELOP_ENABLE))
|
||||
app_audio_state_exit(APP_AUDIO_STATE_WTONE);
|
||||
#endif
|
||||
/* clock_remove_set(DEC_TONE_CLK); */
|
||||
}
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* Audio Key Tone Init OK
|
||||
* Description: 解码初始化完成
|
||||
* Arguments : *ktone 按键提示音解码句柄
|
||||
* Return : None.
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
static void key_tone_dec_hdl_init_ok(struct __key_tone *ktone)
|
||||
{
|
||||
#if (!defined(CONFIG_MEDIA_DEVELOP_ENABLE))
|
||||
if (audio_mixer_get_ch_num(&mixer) <= 1) {
|
||||
#ifdef TCFG_WTONT_ONCE_VOL
|
||||
extern u8 get_tone_once_vol(void);
|
||||
app_audio_state_switch(APP_AUDIO_STATE_WTONE, get_tone_once_vol());
|
||||
#else
|
||||
app_audio_state_switch(APP_AUDIO_STATE_WTONE, get_tone_vol());
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
/* clock_add_set(DEC_TONE_CLK); */
|
||||
}
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* Audio Key Tone Close
|
||||
* Description: 关闭提示音解码
|
||||
* Arguments : *ktone 按键提示音解码句柄
|
||||
* Return : None.
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
static void key_tone_play_close(struct __key_tone *ktone)
|
||||
{
|
||||
/* log_i("ktone:0x%x, sin:0x%x, file:0x%x \n", ktone, ktone->dec_file, ktone->dec_file); */
|
||||
if (ktone->dec_file || ktone->dec_sin) {
|
||||
key_tone_dec_hdl_release(ktone);
|
||||
key_tone_dec_event_handler(ktone, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* Audio Key Tone Event Callback
|
||||
* Description: 解码回调处理
|
||||
* Arguments : *ktone 按键提示音解码句柄
|
||||
* event 事件
|
||||
* *param 事件参数
|
||||
* Return : 0 正常
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
static int key_tone_dec_app_evt_cb(struct __key_tone *ktone, enum audio_dec_app_event event, int *param)
|
||||
{
|
||||
switch (event) {
|
||||
case AUDIO_DEC_APP_EVENT_START_INIT_OK:
|
||||
log_i("key_tone start init ok\n");
|
||||
key_tone_dec_hdl_init_ok(ktone);
|
||||
break;
|
||||
case AUDIO_DEC_APP_EVENT_PLAY_END:
|
||||
log_i("key_tone play end\n");
|
||||
key_tone_dec_hdl_release(ktone);
|
||||
key_tone_dec_event_handler(ktone, 0);
|
||||
break;
|
||||
|
||||
#if defined(CONFIG_MEDIA_DEVELOP_ENABLE)
|
||||
case AUDIO_DEC_APP_EVENT_STREAM_OPEN: {
|
||||
#if AUDIO_KEY_TONE_DIGVOL_EN
|
||||
struct audio_dec_stream_entries_hdl *entries_hdl = (struct audio_dec_stream_entries_hdl *)param;
|
||||
void *dvol_entry = NULL;
|
||||
audio_dig_vol_param temp_digvol_param = {
|
||||
.vol_start = ktone->volume,//get_max_sys_vol(),
|
||||
.vol_max = get_max_sys_vol(),
|
||||
.ch_total = audio_output_channel_num(),
|
||||
.fade_en = 0,
|
||||
.fade_points_step = 5,
|
||||
.fade_gain_step = 10,
|
||||
.vol_list = NULL,
|
||||
};
|
||||
dvol_entry = sys_digvol_group_ch_open(AUDIO_KEY_TONE_DIGVOL_NAME, -1, &temp_digvol_param);
|
||||
(entries_hdl->entries_addr)[entries_hdl->entries_cnt++] = dvol_entry;
|
||||
#endif // SYS_DIGVOL_GROUP_EN
|
||||
}
|
||||
break;
|
||||
|
||||
case AUDIO_DEC_APP_EVENT_STREAM_CLOSE: {
|
||||
}
|
||||
break;
|
||||
|
||||
#endif /*#if defined(CONFIG_MEDIA_DEVELOP_ENABLE)*/
|
||||
|
||||
case AUDIO_DEC_APP_EVENT_DEC_CLOSE:
|
||||
|
||||
#if AUDIO_KEY_TONE_DIGVOL_EN
|
||||
sys_digvol_group_ch_close(AUDIO_KEY_TONE_DIGVOL_NAME);
|
||||
#endif // SYS_DIGVOL_GROUP_EN
|
||||
|
||||
break;
|
||||
|
||||
default :
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* Audio Key Tone Sin Event Callback
|
||||
* Description: sine提示音解码回调
|
||||
* Arguments : *priv 私有句柄
|
||||
* event 事件
|
||||
* *param 事件参数
|
||||
* Return : 0 正常
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
static int key_tone_dec_sine_app_evt_cb(void *priv, enum audio_dec_app_event event, int *param)
|
||||
{
|
||||
struct audio_dec_sine_app_hdl *sine_dec = priv;
|
||||
struct __key_tone *ktone = sine_dec->priv;
|
||||
switch (event) {
|
||||
case AUDIO_DEC_APP_EVENT_DEC_PROBE:
|
||||
if (sine_dec->sin_maker) {
|
||||
break;
|
||||
}
|
||||
audio_dec_sine_app_probe(sine_dec);
|
||||
if (!sine_dec->sin_maker) {
|
||||
return -ENOENT;
|
||||
}
|
||||
break;
|
||||
|
||||
default :
|
||||
return key_tone_dec_app_evt_cb(ktone, event, param);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* Audio Key Tone File Event Callback
|
||||
* Description: file提示音解码回调
|
||||
* Arguments : *priv 私有句柄
|
||||
* event 事件
|
||||
* *param 事件参数
|
||||
* Return : 0 正常
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
static int key_tone_dec_file_app_evt_cb(void *priv, enum audio_dec_app_event event, int *param)
|
||||
{
|
||||
struct audio_dec_file_app_hdl *file_dec = priv;
|
||||
struct __key_tone *ktone = file_dec->priv;
|
||||
switch (event) {
|
||||
case AUDIO_DEC_APP_EVENT_DEC_PROBE:
|
||||
break;
|
||||
default :
|
||||
return key_tone_dec_app_evt_cb(ktone, event, param);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* Audio Key Tone Run
|
||||
* Description: 按键提示音运行
|
||||
* Arguments : *ktone 按键提示音解码句柄
|
||||
* Return : 0 正常
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
static int key_tone_play_run(struct __key_tone *ktone)
|
||||
{
|
||||
if (!ktone->start) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct __key_tone_play_info info = {0};
|
||||
local_irq_disable();
|
||||
if (!ktone->play) {
|
||||
local_irq_enable();
|
||||
return 0;
|
||||
}
|
||||
// 保存播放参数
|
||||
memcpy(&info, &ktone->play_info, sizeof(struct __key_tone_play_info));
|
||||
ktone->play = 0;
|
||||
local_irq_enable();
|
||||
|
||||
// 关闭现有play
|
||||
key_tone_play_close(ktone);
|
||||
|
||||
// 设置参数
|
||||
ktone->evt_handler = info.evt_handler;
|
||||
ktone->evt_priv = info.evt_priv;
|
||||
ktone->evt_owner = "app_core";
|
||||
|
||||
// 正弦波数组播放
|
||||
if (info.sin && info.sin_num) {
|
||||
ktone->dec_sin = audio_dec_sine_app_create_by_parm(info.sin, info.sin_num, !info.preemption);
|
||||
if (ktone->dec_sin == NULL) {
|
||||
return -1;
|
||||
}
|
||||
ktone->dec_sin->dec->evt_cb = key_tone_dec_sine_app_evt_cb;
|
||||
ktone->dec_sin->priv = ktone;
|
||||
/* audio_dec_sine_app_open(ktone->dec_sin); */
|
||||
ktone->dec_sin->dec->wait.only_del = 1;
|
||||
audio_dec_app_start(ktone->dec_sin->dec);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 判断文件名后缀
|
||||
u8 file_name[16];
|
||||
char *format = NULL;
|
||||
FILE *file = fopen(info.file_name, "r");
|
||||
if (!file) {
|
||||
return -1;
|
||||
}
|
||||
fget_name(file, file_name, 16);
|
||||
format = get_file_ext_name((char *)file_name);
|
||||
fclose(file);
|
||||
|
||||
// 正弦波文件播放
|
||||
if (ASCII_StrCmpNoCase(format, "sin", 3) == 0) {
|
||||
ktone->dec_sin = audio_dec_sine_app_create(info.file_name, !info.preemption);
|
||||
if (ktone->dec_sin == NULL) {
|
||||
return -1;
|
||||
}
|
||||
ktone->dec_sin->dec->evt_cb = key_tone_dec_sine_app_evt_cb;
|
||||
ktone->dec_sin->priv = ktone;
|
||||
/* audio_dec_sine_app_open(ktone->dec_sin); */
|
||||
ktone->dec_sin->dec->wait.only_del = 1;
|
||||
audio_dec_app_start(ktone->dec_sin->dec);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 普通文件播放
|
||||
ktone->dec_file = audio_dec_file_app_create(info.file_name, !info.preemption);
|
||||
if (ktone->dec_file == NULL) {
|
||||
return -1;
|
||||
}
|
||||
if (ktone->dec_file->dec->dec_type == AUDIO_CODING_SBC) {
|
||||
audio_dec_app_set_frame_info(ktone->dec_file->dec, 0x4e, ktone->dec_file->dec->dec_type);
|
||||
}
|
||||
ktone->dec_file->dec->evt_cb = key_tone_dec_file_app_evt_cb;
|
||||
ktone->dec_file->priv = ktone;
|
||||
/* audio_dec_file_app_open(ktone->dec_file); */
|
||||
ktone->dec_file->dec->wait.only_del = 1;
|
||||
audio_dec_app_start(ktone->dec_file->dec);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* Audio Key Tone Task Run
|
||||
* Description: 按键提示音任务处理
|
||||
* Arguments : *p 按键提示音解码句柄
|
||||
* Return : None.
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
static void key_tone_task_deal(void *p)
|
||||
{
|
||||
int res = 0;
|
||||
int msg[16];
|
||||
struct __key_tone *ktone = (struct __key_tone *)p;
|
||||
ktone->start = 1;
|
||||
ktone->busy = 1;
|
||||
while (1) {
|
||||
os_taskq_pend(NULL, msg, ARRAY_SIZE(msg));
|
||||
res = key_tone_play_run(ktone);
|
||||
if (res) {
|
||||
///等待删除线程
|
||||
key_tone_play_close(ktone);
|
||||
ktone->busy = 0;
|
||||
while (1) {
|
||||
os_time_dly(10000);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* Audio Key Tone Destroy
|
||||
* Description: 注销按键提示音播放
|
||||
* Arguments : None.
|
||||
* Return : None.
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
void audio_key_tone_destroy(void)
|
||||
{
|
||||
if (!key_tone) {
|
||||
return ;
|
||||
}
|
||||
|
||||
key_tone->start = 0;
|
||||
|
||||
while (key_tone->busy) {
|
||||
os_taskq_post_msg(AUDIO_KEY_TONE_TASK_NAME, 1, 0);
|
||||
os_time_dly(1);
|
||||
}
|
||||
|
||||
task_kill(AUDIO_KEY_TONE_TASK_NAME);
|
||||
|
||||
local_irq_disable();
|
||||
free(key_tone);
|
||||
key_tone = NULL;
|
||||
local_irq_enable();
|
||||
}
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* Audio Key Tone Init
|
||||
* Description: 按键提示音初始化
|
||||
* Arguments : None.
|
||||
* Return : true 成功
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
int audio_key_tone_init(void)
|
||||
{
|
||||
int err = 0;
|
||||
if (key_tone) {
|
||||
return true;
|
||||
}
|
||||
struct __key_tone *ktone = zalloc(sizeof(struct __key_tone));
|
||||
err = task_create(key_tone_task_deal, (void *)ktone, AUDIO_KEY_TONE_TASK_NAME);
|
||||
if (err != OS_NO_ERR) {
|
||||
log_e("%s creat fail %x\n", __FUNCTION__, err);
|
||||
free(ktone);
|
||||
return false;
|
||||
}
|
||||
#if AUDIO_KEY_TONE_DIGVOL_EN
|
||||
ktone->volume = get_max_sys_vol();
|
||||
#endif
|
||||
key_tone = ktone;
|
||||
return true;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// 正弦波序号
|
||||
#define KTONE_SINE_NORAML 0
|
||||
|
||||
// 按键提示音序号
|
||||
enum {
|
||||
KTONE_IDEX_NORAML = 0,
|
||||
KTONE_IDEX_NUM_0,
|
||||
KTONE_IDEX_NUM_1,
|
||||
|
||||
KTONE_IDEX_MAX,
|
||||
};
|
||||
|
||||
// 序号对应表
|
||||
static const char *const key_tone_index[] = {
|
||||
[KTONE_IDEX_NORAML] = DEFAULT_SINE_TONE(KTONE_SINE_NORAML),
|
||||
[KTONE_IDEX_NUM_0] = SDFILE_RES_ROOT_PATH"tone/0.*",
|
||||
[KTONE_IDEX_NUM_1] = SDFILE_RES_ROOT_PATH"tone/1.*",
|
||||
};
|
||||
|
||||
/*
|
||||
* 正弦波参数配置:
|
||||
* freq : 实际频率 * 512
|
||||
* points : 正弦波点数
|
||||
* win : 正弦窗
|
||||
* decay : 衰减系数(百分比), 正弦窗模式下为频率设置:频率*512
|
||||
*/
|
||||
static const struct sin_param sine_16k_normal[] = {
|
||||
/*{0, 1000, 0, 100},*/
|
||||
{200 << 9, 4000, 0, 100},
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* Audio Key Tone Get Sine Param Data
|
||||
* Description: 获取正弦波数组
|
||||
* Arguments : id 正弦波序号
|
||||
* *num 正弦波数组长度
|
||||
* Return : 正弦波数组
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
static const struct sin_param *get_sine_param_data(u8 id, u8 *num)
|
||||
{
|
||||
const struct sin_param *param_data = NULL;
|
||||
switch (id) {
|
||||
case KTONE_SINE_NORAML:
|
||||
param_data = sine_16k_normal;
|
||||
*num = ARRAY_SIZE(sine_16k_normal);
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
return param_data;
|
||||
};
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* Audio Key Tone Open With Callback
|
||||
* Description: 打开文件播放
|
||||
* Arguments : *file_name 文件名
|
||||
* *sin 正弦波数组
|
||||
* sin_num 正弦波数组长度
|
||||
* preemption 1-抢断播放;0-叠加播放
|
||||
* evt_handler 事件回调
|
||||
* evt_priv 事件回调参数
|
||||
* Return : 0 正常
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
static int ktone_play_open_with_callback_base(const char *file_name, struct audio_sin_param *sin, u8 sin_num, u8 preemption, void (*evt_handler)(void *priv, int flag), void *evt_priv)
|
||||
{
|
||||
struct __key_tone *ktone = key_tone;
|
||||
if ((!ktone) || (!ktone->start)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct __key_tone_play_info info = {0};
|
||||
info.preemption = preemption;
|
||||
info.evt_handler = evt_handler;
|
||||
info.evt_priv = evt_priv;
|
||||
if (sin && sin_num) {
|
||||
info.sin = sin;
|
||||
info.sin_num = sin_num;
|
||||
} else {
|
||||
info.file_name = file_name;
|
||||
if (IS_DEFAULT_SINE(file_name)) {
|
||||
info.sin = get_sine_param_data(DEFAULT_SINE_ID(file_name), &info.sin_num);
|
||||
}
|
||||
}
|
||||
|
||||
local_irq_disable();
|
||||
memcpy(&ktone->play_info, &info, sizeof(struct __key_tone_play_info));
|
||||
ktone->play = 1;
|
||||
local_irq_enable();
|
||||
|
||||
os_taskq_post_msg(AUDIO_KEY_TONE_TASK_NAME, 1, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* Audio Key Tone Play Sine
|
||||
* Description: 播放正弦波数组
|
||||
* Arguments : *sin 正弦波数组
|
||||
* sin_num 正弦波数组长度
|
||||
* preemption 1-抢断播放;0-叠加播放
|
||||
* Return : 0 正常
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
int audio_key_tone_play_sin(struct audio_sin_param *sin, u8 sin_num, u8 preemption)
|
||||
{
|
||||
/* y_printf("n:0x%x \n", name); */
|
||||
return ktone_play_open_with_callback_base(NULL, sin, sin_num, preemption, NULL, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* Audio Key Tone Play File
|
||||
* Description: 播放文件
|
||||
* Arguments : *name 文件名
|
||||
* preemption 1-抢断播放;0-叠加播放
|
||||
* Return : 0 正常
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
int audio_key_tone_play_name(const char *name, u8 preemption)
|
||||
{
|
||||
/* y_printf("n:0x%x \n", name); */
|
||||
return ktone_play_open_with_callback_base(name, NULL, 0, preemption, NULL, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* Audio Key Tone Play Index
|
||||
* Description: 按序号播放文件
|
||||
* Arguments : index 序号
|
||||
* preemption 1-抢断播放;0-叠加播放
|
||||
* Return : 0 正常
|
||||
* Note(s) : 使用key_tone_index[]数组
|
||||
*********************************************************************
|
||||
*/
|
||||
int audio_key_tone_play_index(u8 index, u8 preemption)
|
||||
{
|
||||
if (index >= KTONE_IDEX_MAX) {
|
||||
return -1;
|
||||
}
|
||||
return audio_key_tone_play_name(key_tone_index[index], preemption);
|
||||
}
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* Audio Key Tone Play
|
||||
* Description: 按键提示音播放
|
||||
* Arguments : None.
|
||||
* Return : None.
|
||||
* Note(s) : 默认播放
|
||||
*********************************************************************
|
||||
*/
|
||||
void audio_key_tone_play(void)
|
||||
{
|
||||
audio_key_tone_play_index(KTONE_IDEX_NORAML, 0);
|
||||
/* audio_key_tone_play_index(KTONE_IDEX_NUM_0, 0); */
|
||||
/* audio_key_tone_play_sin(sine_16k_normal, ARRAY_SIZE(sine_16k_normal), 0); */
|
||||
}
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* Audio Key Tone Check Play
|
||||
* Description: 检测按键提示音是否在播放
|
||||
* Arguments : None.
|
||||
* Return : true 正在播放
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
int audio_key_tone_is_play(void)
|
||||
{
|
||||
if ((!key_tone) || (!key_tone->start)) {
|
||||
return false;
|
||||
}
|
||||
if (key_tone->dec_file || key_tone->dec_sin) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* Audio Key Tone Set Digvol
|
||||
* Description: 设置按键提示音的音量
|
||||
* Arguments : volume 音量
|
||||
* Return : None.
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
void audio_key_tone_digvol_set(u8 volume)
|
||||
{
|
||||
#if AUDIO_KEY_TONE_DIGVOL_EN
|
||||
log_i("vol:%d \n", volume);
|
||||
if (!key_tone) {
|
||||
return ;
|
||||
}
|
||||
key_tone->volume = volume;
|
||||
void *vol_hdl = audio_dig_vol_group_hdl_get(sys_digvol_group, AUDIO_KEY_TONE_DIGVOL_NAME);
|
||||
if (vol_hdl == NULL) {
|
||||
return;
|
||||
}
|
||||
audio_dig_vol_set(vol_hdl, AUDIO_DIG_VOL_ALL_CH, volume);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
325
apps/common/audio/decode/decode.c
Normal file
325
apps/common/audio/decode/decode.c
Normal file
@ -0,0 +1,325 @@
|
||||
|
||||
#include "application/audio_dec_app.h"
|
||||
#include "app_config.h"
|
||||
#include "audio_config.h"
|
||||
#include "app_main.h"
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
extern struct audio_decoder_task decode_task;
|
||||
extern struct audio_mixer mixer;
|
||||
extern struct audio_dac_hdl dac_hdl;
|
||||
#if AUDIO_DAC_MULTI_CHANNEL_ENABLE
|
||||
extern struct audio_dac_channel default_dac;
|
||||
#endif
|
||||
|
||||
extern const int audio_dec_app_mix_en;
|
||||
|
||||
extern u32 audio_output_channel_num(void);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
struct audio_dec_app_audio_state_hdl {
|
||||
struct audio_mixer *p_mixer;
|
||||
u32 dec_mix : 1; // 1:叠加模式
|
||||
u32 flag;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
const struct audio_dec_format_hdl decode_format_list[] = {
|
||||
{"wtg", AUDIO_CODING_G729},
|
||||
{"msbc", AUDIO_CODING_MSBC},
|
||||
{"msb", AUDIO_CODING_MSBC},
|
||||
{"sbc", AUDIO_CODING_SBC},
|
||||
{"mty", AUDIO_CODING_MTY},
|
||||
{"aac", AUDIO_CODING_AAC},
|
||||
{"mp3", AUDIO_CODING_MP3},
|
||||
{"wma", AUDIO_CODING_WMA},
|
||||
{"wav", AUDIO_CODING_WAV},
|
||||
#if (defined(TCFG_DEC_MIDI_ENABLE) && TCFG_DEC_MIDI_ENABLE)
|
||||
//midi 文件播放,需要对应音色文件配合
|
||||
{"midi", AUDIO_CODING_MIDI},
|
||||
{"mid", AUDIO_CODING_MIDI},
|
||||
#endif //TCFG_DEC_MIDI_ENABLE
|
||||
|
||||
#if TCFG_DEC_WTGV2_ENABLE
|
||||
{"wts", AUDIO_CODING_WTGV2},
|
||||
#endif
|
||||
{"speex", AUDIO_CODING_SPEEX},
|
||||
{"opus", AUDIO_CODING_OPUS},
|
||||
{0, 0},
|
||||
};
|
||||
|
||||
#if defined(CONFIG_MEDIA_DEVELOP_ENABLE)
|
||||
static struct audio_stream_entry *audio_dec_app_entries[2] = {NULL};
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/**@brief 解码创建参数初始化
|
||||
@param *dec: 解码句柄
|
||||
@return 0-正常
|
||||
@note 弱函数重定义
|
||||
*/
|
||||
/*----------------------------------------------------------------------------*/
|
||||
int audio_dec_app_create_param_init(struct audio_dec_app_hdl *dec)
|
||||
{
|
||||
dec->p_decode_task = &decode_task;
|
||||
#if defined(CONFIG_MEDIA_DEVELOP_ENABLE)
|
||||
if (!audio_dec_app_mix_en) {
|
||||
#if AUDIO_DAC_MULTI_CHANNEL_ENABLE
|
||||
audio_dec_app_entries[0] = &default_dac.entry;
|
||||
#else
|
||||
audio_dec_app_entries[0] = &dac_hdl.entry;
|
||||
#endif
|
||||
dec->entries = audio_dec_app_entries;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
dec->p_mixer = &mixer;
|
||||
}
|
||||
#if defined(CONFIG_MEDIA_DEVELOP_ENABLE)
|
||||
u8 dac_connect_mode = app_audio_output_mode_get();
|
||||
if (dac_connect_mode == DAC_OUTPUT_FRONT_LR_REAR_LR) {
|
||||
dec->out_ch_num = 4;
|
||||
} else {
|
||||
dec->out_ch_num = audio_output_channel_num();
|
||||
}
|
||||
#else
|
||||
u8 dac_connect_mode = audio_dac_get_channel(&dac_hdl);
|
||||
switch (dac_connect_mode) {
|
||||
/* case DAC_OUTPUT_DUAL_LR_DIFF: */
|
||||
case DAC_OUTPUT_LR:
|
||||
dec->out_ch_num = 2;
|
||||
break;
|
||||
/* case DAC_OUTPUT_FRONT_LR_REAR_LR: */
|
||||
/* dec->out_ch_num = 4; */
|
||||
/* break; */
|
||||
default :
|
||||
dec->out_ch_num = 1;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/**@brief 文件解码创建参数初始化
|
||||
@param *file_dec: 文件解码句柄
|
||||
@return 0-正常
|
||||
@note 弱函数重定义
|
||||
*/
|
||||
/*----------------------------------------------------------------------------*/
|
||||
int audio_dec_file_app_create_param_init(struct audio_dec_file_app_hdl *file_dec)
|
||||
{
|
||||
file_dec->format = (struct audio_dec_format_hdl *)decode_format_list;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/**@brief 解码输出状态设置
|
||||
@param *dec: 解码句柄
|
||||
@param flag: 解码标签
|
||||
@return 0-正常
|
||||
@note
|
||||
*/
|
||||
/*----------------------------------------------------------------------------*/
|
||||
int audio_dec_app_audio_state_switch(struct audio_dec_app_hdl *dec, u32 flag)
|
||||
{
|
||||
u8 need_set_audio = 1;
|
||||
/* if ((dec->dec_mix) && (audio_mixer_get_ch_num(dec->p_mixer) > 1)) { */
|
||||
/* need_set_audio = 0; */
|
||||
/* } */
|
||||
if (app_audio_get_state() == APP_AUDIO_STATE_IDLE) {
|
||||
need_set_audio = 1;
|
||||
}
|
||||
if (need_set_audio) {
|
||||
if (flag == AUDIO_DEC_FILE_FLAG_AUDIO_STATE_MUSIC) {
|
||||
app_audio_state_switch(APP_AUDIO_STATE_MUSIC, get_max_sys_vol());
|
||||
} else {
|
||||
#ifdef TCFG_WTONT_ONCE_VOL
|
||||
extern u8 get_tone_once_vol(void);
|
||||
app_audio_state_switch(APP_AUDIO_STATE_WTONE, get_tone_once_vol());
|
||||
#else
|
||||
app_audio_state_switch(APP_AUDIO_STATE_WTONE, get_tone_vol());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/**@brief 解码输出状态退出
|
||||
@param *p_aud_state: 输出状态
|
||||
@return 0-正常
|
||||
@note
|
||||
*/
|
||||
/*----------------------------------------------------------------------------*/
|
||||
int audio_dec_app_audio_state_exit(struct audio_dec_app_audio_state_hdl *p_aud_state)
|
||||
{
|
||||
u8 need_set_audio = 1;
|
||||
/* if ((p_aud_state->dec_mix) && (audio_mixer_get_ch_num(p_aud_state->p_mixer) > 1)) { */
|
||||
/* need_set_audio = 0; */
|
||||
/* } */
|
||||
/* if (app_audio_get_state() == APP_AUDIO_STATE_IDLE) { */
|
||||
/* need_set_audio = 1; */
|
||||
/* } */
|
||||
if (need_set_audio) {
|
||||
if (p_aud_state->flag == AUDIO_DEC_FILE_FLAG_AUDIO_STATE_MUSIC) {
|
||||
app_audio_state_exit(APP_AUDIO_STATE_MUSIC);
|
||||
} else {
|
||||
app_audio_state_exit(APP_AUDIO_STATE_WTONE);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/**@brief 文件解码初始化完成
|
||||
@param *file_dec: 文件解码句柄
|
||||
@return 0-正常
|
||||
@note 弱函数重定义
|
||||
*/
|
||||
/*----------------------------------------------------------------------------*/
|
||||
int audio_dec_file_app_init_ok(struct audio_dec_file_app_hdl *file_dec)
|
||||
{
|
||||
audio_dec_app_audio_state_switch(file_dec->dec, file_dec->flag & AUDIO_DEC_FILE_FLAG_AUDIO_STATE_MASK);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/**@brief 文件解码结束
|
||||
@param *file_dec: 文件解码句柄
|
||||
@return 0-正常
|
||||
@note 弱函数重定义
|
||||
*/
|
||||
/*----------------------------------------------------------------------------*/
|
||||
int audio_dec_file_app_play_end(struct audio_dec_file_app_hdl *file_dec)
|
||||
{
|
||||
struct audio_dec_app_audio_state_hdl aud_state = {0};
|
||||
aud_state.p_mixer = file_dec->dec->p_mixer;
|
||||
aud_state.dec_mix = file_dec->dec->dec_mix;
|
||||
aud_state.flag = file_dec->flag & AUDIO_DEC_FILE_FLAG_AUDIO_STATE_MASK;
|
||||
audio_dec_file_app_close(file_dec);
|
||||
audio_dec_app_audio_state_exit(&aud_state);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/**@brief 正弦波解码初始化完成
|
||||
@param *sine_dec: 正弦波解码句柄
|
||||
@return 0-正常
|
||||
@note 弱函数重定义
|
||||
*/
|
||||
/*----------------------------------------------------------------------------*/
|
||||
int audio_dec_sine_app_init_ok(struct audio_dec_sine_app_hdl *sine_dec)
|
||||
{
|
||||
audio_dec_app_audio_state_switch(sine_dec->dec, sine_dec->flag & AUDIO_DEC_FILE_FLAG_AUDIO_STATE_MASK);
|
||||
return 0;
|
||||
}
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/**@brief 正弦波解码结束
|
||||
@param *sine_dec: 正弦波解码句柄
|
||||
@return 0-正常
|
||||
@note 弱函数重定义
|
||||
*/
|
||||
/*----------------------------------------------------------------------------*/
|
||||
int audio_dec_sine_app_play_end(struct audio_dec_sine_app_hdl *sine_dec)
|
||||
{
|
||||
struct audio_dec_app_audio_state_hdl aud_state = {0};
|
||||
aud_state.p_mixer = sine_dec->dec->p_mixer;
|
||||
aud_state.dec_mix = sine_dec->dec->dec_mix;
|
||||
aud_state.flag = sine_dec->flag & AUDIO_DEC_FILE_FLAG_AUDIO_STATE_MASK;
|
||||
audio_dec_sine_app_close(sine_dec);
|
||||
audio_dec_app_audio_state_exit(&aud_state);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if (!defined(CONFIG_MEDIA_DEVELOP_ENABLE))
|
||||
void audio_dec_app_output_sr_set(struct audio_dec_app_hdl *dec)
|
||||
{
|
||||
/* #if defined(CONFIG_CPU_BR23) */
|
||||
/* extern u32 audio_output_rate(int input_rate); */
|
||||
/* dec->src_out_sr = audio_output_rate(dec->src_out_sr); */
|
||||
/* #endif */
|
||||
if (dec->src_out_sr == 0) {
|
||||
dec->src_out_sr = audio_dac_get_sample_rate(&dac_hdl);
|
||||
if (dec->src_out_sr == 0) {
|
||||
dec->src_out_sr = 16000;
|
||||
log_w("src out is zero \n");
|
||||
}
|
||||
}
|
||||
if (dec->sample_rate == 0) {
|
||||
dec->sample_rate = dec->src_out_sr;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// test
|
||||
#if 0
|
||||
#include "tone_player.h"
|
||||
|
||||
void audio_dec_file_test(void)
|
||||
{
|
||||
struct audio_dec_file_app_hdl *hdl;
|
||||
hdl = audio_dec_file_app_create(TONE_POWER_ON, 1);
|
||||
if (hdl) {
|
||||
audio_dec_file_app_open(hdl);
|
||||
}
|
||||
os_time_dly(2);
|
||||
hdl = audio_dec_file_app_create(TONE_POWER_OFF, 1);
|
||||
if (hdl) {
|
||||
audio_dec_file_app_open(hdl);
|
||||
}
|
||||
os_time_dly(300);
|
||||
}
|
||||
|
||||
static const struct audio_sin_param sine_test[] = {
|
||||
/*{0, 1000, 0, 100},*/
|
||||
{200 << 9, 4000, 0, 100},
|
||||
};
|
||||
static const struct audio_sin_param sine_test1[] = {
|
||||
{450 << 9, 24960, 1, 16.667 * 512},
|
||||
{0, 16000, 0, 100},
|
||||
};
|
||||
void audio_dec_sine_test(void)
|
||||
{
|
||||
struct audio_dec_sine_app_hdl *hdl;
|
||||
/* hdl = audio_dec_sine_app_create(SDFILE_RES_ROOT_PATH"tone/vol_max.sin", 1); */
|
||||
hdl = audio_dec_sine_app_create_by_parm(sine_test1, ARRAY_SIZE(sine_test1), 1);
|
||||
if (hdl) {
|
||||
audio_dec_sine_app_open(hdl);
|
||||
}
|
||||
os_time_dly(2);
|
||||
hdl = audio_dec_sine_app_create_by_parm(sine_test, ARRAY_SIZE(sine_test), 1);
|
||||
if (hdl) {
|
||||
audio_dec_sine_app_open(hdl);
|
||||
}
|
||||
/* os_time_dly(300); */
|
||||
}
|
||||
|
||||
void audio_dec_usb_file_test(void)
|
||||
{
|
||||
tone_play_stop();
|
||||
clk_set("sys", 192 * 1000000L);
|
||||
|
||||
struct audio_dec_file_app_hdl *hdl;
|
||||
/* hdl = audio_dec_file_app_create("storage/udisk/C/1.mp3", 1); */
|
||||
hdl = audio_dec_file_app_create("storage/udisk/C/1.wav", 1);
|
||||
if (hdl) {
|
||||
audio_dec_file_app_open(hdl);
|
||||
}
|
||||
os_time_dly(2);
|
||||
/* hdl = audio_dec_file_app_create("storage/udisk/C/2.mp3", 1); */
|
||||
hdl = audio_dec_file_app_create("storage/udisk/C/2.wav", 1);
|
||||
if (hdl) {
|
||||
audio_dec_file_app_open(hdl);
|
||||
}
|
||||
os_time_dly(300);
|
||||
}
|
||||
|
||||
#endif /*test*/
|
||||
|
||||
|
||||
212
apps/common/audio/demo/audio_decoder_test.c
Normal file
212
apps/common/audio/demo/audio_decoder_test.c
Normal file
@ -0,0 +1,212 @@
|
||||
/*
|
||||
****************************************************************
|
||||
* AUDIO DECODER TEST
|
||||
* File : audio_decoder_test.c
|
||||
* By :
|
||||
* Notes : 解码测试
|
||||
* before和after之间就是解码对应功能的处理,
|
||||
* 可以在before和after中分别翻转IO来卡一下处理时间
|
||||
****************************************************************
|
||||
*/
|
||||
|
||||
|
||||
#include "media/includes.h"
|
||||
|
||||
|
||||
#define DEC_IO_DEBUG_1(i,x) {JL_PORT##i->DIR &= ~BIT(x), JL_PORT##i->OUT |= BIT(x);}
|
||||
#define DEC_IO_DEBUG_0(i,x) {JL_PORT##i->DIR &= ~BIT(x), JL_PORT##i->OUT &= ~BIT(x);}
|
||||
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* Audio Decoder test output before
|
||||
* Description: 解码输出
|
||||
* Arguments : *dec 解码句柄
|
||||
* *buff 输出buf
|
||||
* len 输出长度
|
||||
* Return : None.
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
void audio_decoder_test_out_before(struct audio_decoder *dec, void *buff, int len)
|
||||
{
|
||||
DEC_IO_DEBUG_1(C, 3);
|
||||
}
|
||||
/*
|
||||
*********************************************************************
|
||||
* Audio Decoder test output after
|
||||
* Description: 解码输出
|
||||
* Arguments : *dec 解码句柄
|
||||
* wlen 实际输出长度
|
||||
* Return : None.
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
void audio_decoder_test_out_after(struct audio_decoder *dec, int wlen)
|
||||
{
|
||||
DEC_IO_DEBUG_0(C, 3);
|
||||
}
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* Audio Decoder test read file before
|
||||
* Description: 解码获取文件数据
|
||||
* Arguments : *dec 解码句柄
|
||||
* len 获取数据长度
|
||||
* offset 获取数据偏移地址
|
||||
* Return : None.
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
void audio_decoder_test_read_before(struct audio_decoder *dec, int len, u32 offset)
|
||||
{
|
||||
DEC_IO_DEBUG_1(C, 2);
|
||||
}
|
||||
/*
|
||||
*********************************************************************
|
||||
* Audio Decoder test read file after
|
||||
* Description: 解码获取文件数据
|
||||
* Arguments : *dec 解码句柄
|
||||
* *data 获取到的数据
|
||||
* rlen 获取到的数据长度
|
||||
* Return : None.
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
void audio_decoder_test_read_after(struct audio_decoder *dec, u8 *data, int rlen)
|
||||
{
|
||||
DEC_IO_DEBUG_0(C, 2);
|
||||
}
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* Audio Decoder test get frame before
|
||||
* Description: 解码获取帧数据
|
||||
* Arguments : *dec 解码句柄
|
||||
* Return : None.
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
void audio_decoder_test_get_frame_before(struct audio_decoder *dec)
|
||||
{
|
||||
DEC_IO_DEBUG_1(C, 2);
|
||||
}
|
||||
/*
|
||||
*********************************************************************
|
||||
* Audio Decoder test get frame after
|
||||
* Description: 解码获取帧数据
|
||||
* Arguments : *dec 解码句柄
|
||||
* *frame 获取到的帧数据
|
||||
* rlen 获取到的帧数据长度
|
||||
* Return : None.
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
void audio_decoder_test_get_frame_after(struct audio_decoder *dec, u8 *frame, int rlen)
|
||||
{
|
||||
DEC_IO_DEBUG_0(C, 2);
|
||||
}
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* Audio Decoder test fetch frame before
|
||||
* Description: 解码检查帧数据
|
||||
* Arguments : *dec 解码句柄
|
||||
* Return : None.
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
void audio_decoder_test_fetch_before(struct audio_decoder *dec)
|
||||
{
|
||||
DEC_IO_DEBUG_1(C, 2);
|
||||
}
|
||||
/*
|
||||
*********************************************************************
|
||||
* Audio Decoder test fetch frame after
|
||||
* Description: 解码检查帧数据
|
||||
* Arguments : *dec 解码句柄
|
||||
* *frame 获取到的帧数据
|
||||
* rlen 获取到的帧数据长度
|
||||
* Return : None.
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
void audio_decoder_test_fetch_after(struct audio_decoder *dec, u8 *frame, int rlen)
|
||||
{
|
||||
DEC_IO_DEBUG_0(C, 2);
|
||||
}
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* Audio Decoder test run before
|
||||
* Description: 解码处理
|
||||
* Arguments : *dec 解码句柄
|
||||
* Return : None.
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
void audio_decoder_test_run_before(struct audio_decoder *dec)
|
||||
{
|
||||
DEC_IO_DEBUG_1(C, 1);
|
||||
}
|
||||
/*
|
||||
*********************************************************************
|
||||
* Audio Decoder test run after
|
||||
* Description: 解码处理
|
||||
* Arguments : *dec 解码句柄
|
||||
* err 解码处理返回值
|
||||
* Return : None.
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
void audio_decoder_test_run_after(struct audio_decoder *dec, int err)
|
||||
{
|
||||
DEC_IO_DEBUG_0(C, 1);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 数据流节点统计时间示例
|
||||
* 这里的时间是数据流节点运行的时间加上输出的时间
|
||||
* 数据流节点的运行时间约等于当前统计的时间减去下一个节点的统计时间
|
||||
* */
|
||||
#if 0
|
||||
|
||||
// 保存原来的数据流数据处理
|
||||
static void *demo_data_handler_save;
|
||||
// 数据流data_handler处理
|
||||
static int demo_new_data_handler(struct audio_stream_entry *entry,
|
||||
struct audio_data_frame *in,
|
||||
struct audio_data_frame *out)
|
||||
{
|
||||
DEC_IO_DEBUG_1(C, 1);
|
||||
|
||||
// 调用原来的接口输出
|
||||
int wlen = ((int (*)(struct audio_stream_entry *, struct audio_data_frame *, struct audio_data_frame *))demo_data_handler_save)(entry, in, out);
|
||||
|
||||
DEC_IO_DEBUG_0(C, 1);
|
||||
return wlen;
|
||||
}
|
||||
|
||||
|
||||
void test_start(void)
|
||||
{
|
||||
#if 1
|
||||
// 用变量保存原来的数据处理接口,然后重新赋值新的数据处理
|
||||
// 这里以获取mix节点的数据为例
|
||||
demo_data_handler_save = (void *)bt_a2dp_dec->mix_ch.entry.data_handler;
|
||||
bt_a2dp_dec->mix_ch.entry.data_handler = demo_new_data_handler;
|
||||
#endif
|
||||
|
||||
// 数据流串联
|
||||
struct audio_stream_entry *entries[8] = {NULL};
|
||||
u8 entry_cnt = 0;
|
||||
entries[entry_cnt++] = &dec->dec.decoder.entry;
|
||||
entries[entry_cnt++] = &dec->mix_ch.entry;
|
||||
// ...
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
106
apps/common/audio/demo/audio_demo.c
Normal file
106
apps/common/audio/demo/audio_demo.c
Normal file
@ -0,0 +1,106 @@
|
||||
|
||||
#include "system/includes.h"
|
||||
#include "audio_config.h"
|
||||
#include "asm/dac.h"
|
||||
|
||||
|
||||
short const sin_1k_44100[441] = {
|
||||
0x0000, 0x122d, 0x23fb, 0x350f, 0x450f, 0x53aa, 0x6092, 0x6b85, 0x744b, 0x7ab5, 0x7ea2, 0x7fff, 0x7ec3, 0x7af6, 0x74ab, 0x6c03,
|
||||
0x612a, 0x545a, 0x45d4, 0x35e3, 0x24db, 0x1314, 0x00e9, 0xeeba, 0xdce5, 0xcbc6, 0xbbb6, 0xad08, 0xa008, 0x94fa, 0x8c18, 0x858f,
|
||||
0x8181, 0x8003, 0x811d, 0x84ca, 0x8af5, 0x9380, 0x9e3e, 0xaaf7, 0xb969, 0xc94a, 0xda46, 0xec06, 0xfe2d, 0x105e, 0x223a, 0x3365,
|
||||
0x4385, 0x5246, 0x5f5d, 0x6a85, 0x7384, 0x7a2d, 0x7e5b, 0x7ffa, 0x7f01, 0x7b75, 0x7568, 0x6cfb, 0x6258, 0x55b7, 0x4759, 0x3789,
|
||||
0x2699, 0x14e1, 0x02bc, 0xf089, 0xdea7, 0xcd71, 0xbd42, 0xae6d, 0xa13f, 0x95fd, 0x8ce1, 0x861a, 0x81cb, 0x800b, 0x80e3, 0x844e,
|
||||
0x8a3c, 0x928c, 0x9d13, 0xa99c, 0xb7e6, 0xc7a5, 0xd889, 0xea39, 0xfc5a, 0x0e8f, 0x2077, 0x31b8, 0x41f6, 0x50de, 0x5e23, 0x697f,
|
||||
0x72b8, 0x799e, 0x7e0d, 0x7fee, 0x7f37, 0x7bed, 0x761f, 0x6ded, 0x6380, 0x570f, 0x48db, 0x392c, 0x2855, 0x16ad, 0x048f, 0xf259,
|
||||
0xe06b, 0xcf20, 0xbed2, 0xafd7, 0xa27c, 0x9705, 0x8db0, 0x86ab, 0x821c, 0x801a, 0x80b0, 0x83da, 0x8988, 0x919c, 0x9bee, 0xa846,
|
||||
0xb666, 0xc603, 0xd6ce, 0xe86e, 0xfa88, 0x0cbf, 0x1eb3, 0x3008, 0x4064, 0x4f73, 0x5ce4, 0x6874, 0x71e6, 0x790a, 0x7db9, 0x7fdc,
|
||||
0x7f68, 0x7c5e, 0x76d0, 0x6ed9, 0x64a3, 0x5863, 0x4a59, 0x3acc, 0x2a0f, 0x1878, 0x0661, 0xf42a, 0xe230, 0xd0d0, 0xc066, 0xb145,
|
||||
0xa3bd, 0x9813, 0x8e85, 0x8743, 0x8274, 0x8030, 0x8083, 0x836b, 0x88da, 0x90b3, 0x9acd, 0xa6f5, 0xb4ea, 0xc465, 0xd515, 0xe6a3,
|
||||
0xf8b6, 0x0aee, 0x1ced, 0x2e56, 0x3ecf, 0x4e02, 0x5ba1, 0x6764, 0x710e, 0x786f, 0x7d5e, 0x7fc3, 0x7f91, 0x7cc9, 0x777a, 0x6fc0,
|
||||
0x65c1, 0x59b3, 0x4bd3, 0x3c6a, 0x2bc7, 0x1a41, 0x0833, 0xf5fb, 0xe3f6, 0xd283, 0xc1fc, 0xb2b7, 0xa503, 0x9926, 0x8f60, 0x87e1,
|
||||
0x82d2, 0x804c, 0x805d, 0x8303, 0x8833, 0x8fcf, 0x99b2, 0xa5a8, 0xb372, 0xc2c9, 0xd35e, 0xe4da, 0xf6e4, 0x091c, 0x1b26, 0x2ca2,
|
||||
0x3d37, 0x4c8e, 0x5a58, 0x664e, 0x7031, 0x77cd, 0x7cfd, 0x7fa3, 0x7fb4, 0x7d2e, 0x781f, 0x70a0, 0x66da, 0x5afd, 0x4d49, 0x3e04,
|
||||
0x2d7d, 0x1c0a, 0x0a05, 0xf7cd, 0xe5bf, 0xd439, 0xc396, 0xb42d, 0xa64d, 0x9a3f, 0x9040, 0x8886, 0x8337, 0x806f, 0x803d, 0x82a2,
|
||||
0x8791, 0x8ef2, 0x989c, 0xa45f, 0xb1fe, 0xc131, 0xd1aa, 0xe313, 0xf512, 0x074a, 0x195d, 0x2aeb, 0x3b9b, 0x4b16, 0x590b, 0x6533,
|
||||
0x6f4d, 0x7726, 0x7c95, 0x7f7d, 0x7fd0, 0x7d8c, 0x78bd, 0x717b, 0x67ed, 0x5c43, 0x4ebb, 0x3f9a, 0x2f30, 0x1dd0, 0x0bd6, 0xf99f,
|
||||
0xe788, 0xd5f1, 0xc534, 0xb5a7, 0xa79d, 0x9b5d, 0x9127, 0x8930, 0x83a2, 0x8098, 0x8024, 0x8247, 0x86f6, 0x8e1a, 0x978c, 0xa31c,
|
||||
0xb08d, 0xbf9c, 0xcff8, 0xe14d, 0xf341, 0x0578, 0x1792, 0x2932, 0x39fd, 0x499a, 0x57ba, 0x6412, 0x6e64, 0x7678, 0x7c26, 0x7f50,
|
||||
0x7fe6, 0x7de4, 0x7955, 0x7250, 0x68fb, 0x5d84, 0x5029, 0x412e, 0x30e0, 0x1f95, 0x0da7, 0xfb71, 0xe953, 0xd7ab, 0xc6d4, 0xb725,
|
||||
0xa8f1, 0x9c80, 0x9213, 0x89e1, 0x8413, 0x80c9, 0x8012, 0x81f3, 0x8662, 0x8d48, 0x9681, 0xa1dd, 0xaf22, 0xbe0a, 0xce48, 0xdf89,
|
||||
0xf171, 0x03a6, 0x15c7, 0x2777, 0x385b, 0x481a, 0x5664, 0x62ed, 0x6d74, 0x75c4, 0x7bb2, 0x7f1d, 0x7ff5, 0x7e35, 0x79e6, 0x731f,
|
||||
0x6a03, 0x5ec1, 0x5193, 0x42be, 0x328f, 0x2159, 0x0f77, 0xfd44, 0xeb1f, 0xd967, 0xc877, 0xb8a7, 0xaa49, 0x9da8, 0x9305, 0x8a98,
|
||||
0x848b, 0x80ff, 0x8006, 0x81a5, 0x85d3, 0x8c7c, 0x957b, 0xa0a3, 0xadba, 0xbc7b, 0xcc9b, 0xddc6, 0xefa2, 0x01d3, 0x13fa, 0x25ba,
|
||||
0x36b6, 0x4697, 0x5509, 0x61c2, 0x6c80, 0x750b, 0x7b36, 0x7ee3, 0x7ffd, 0x7e7f, 0x7a71, 0x73e8, 0x6b06, 0x5ff8, 0x52f8, 0x444a,
|
||||
0x343a, 0x231b, 0x1146, 0xff17, 0xecec, 0xdb25, 0xca1d, 0xba2c, 0xaba6, 0x9ed6, 0x93fd, 0x8b55, 0x850a, 0x813d, 0x8001, 0x815e,
|
||||
0x854b, 0x8bb5, 0x947b, 0x9f6e, 0xac56, 0xbaf1, 0xcaf1, 0xdc05, 0xedd3
|
||||
};
|
||||
|
||||
extern struct audio_dac_hdl dac_hdl;
|
||||
|
||||
static void dac_test_task_handle(void *p)
|
||||
{
|
||||
int len = 0;
|
||||
int wlen = 0;
|
||||
s16 *ptr;
|
||||
s16 *data_addr;
|
||||
u32 data_len;
|
||||
int res = 0;
|
||||
int msg[16];
|
||||
|
||||
printf(">>>>>>>>>>>>>>>>>>>>>audio_dac_demo>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
|
||||
app_audio_state_switch(APP_AUDIO_STATE_MUSIC, get_max_sys_vol()); // 音量状态设置
|
||||
audio_dac_set_volume(&dac_hdl, get_max_sys_vol()); // dac 音量设置
|
||||
audio_dac_set_sample_rate(&dac_hdl, 44100); // 采样率设置
|
||||
audio_dac_start(&dac_hdl); // dac 启动
|
||||
|
||||
// 循环一直往dac写数据
|
||||
while (1) {
|
||||
// 这句是为了防止线程太久没有响应系统而产生异常,实际使用不需要
|
||||
/* res = os_taskq_accept(ARRAY_SIZE(msg), msg); */
|
||||
ptr = sin_1k_44100;
|
||||
len = 441 * 2;
|
||||
while (len) {
|
||||
// 往 dac 写数据
|
||||
wlen = audio_dac_write(&dac_hdl, ptr, len);
|
||||
/* void debug_random_read(u32 size); */
|
||||
/* debug_random_read(32 * 1024); */
|
||||
if (wlen != len) { // dac缓存满了,延时 10ms 后再继续写
|
||||
putchar('W');
|
||||
os_time_dly(1);
|
||||
}
|
||||
ptr += wlen / 2;
|
||||
len -= wlen;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void audio_demo(void)
|
||||
{
|
||||
int ret = os_task_create(dac_test_task_handle, NULL, 31, 512, 0, "dac_task");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef BT_DUT_INTERFERE
|
||||
|
||||
void idle_hook(void)
|
||||
{
|
||||
while (1) {
|
||||
wdt_close();
|
||||
//cpu 测试
|
||||
/* void coremark_main(void); */
|
||||
/* coremark_main(); */
|
||||
void debug_random_read(u32 size);
|
||||
debug_random_read(32 * 1024);
|
||||
local_irq_disable();
|
||||
putchar('c');
|
||||
putchar('o');
|
||||
putchar('r');
|
||||
putchar('e');
|
||||
local_irq_enable();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
110
apps/common/audio/demo/audio_encoder_test.c
Normal file
110
apps/common/audio/demo/audio_encoder_test.c
Normal file
@ -0,0 +1,110 @@
|
||||
/*
|
||||
****************************************************************
|
||||
* AUDIO ENCODE TEST
|
||||
* File : audio_encoder_test.c
|
||||
* By :
|
||||
* Notes : 编码测试
|
||||
* before和after之间就是编码对应功能的处理,
|
||||
* 可以在before和after中分别翻转IO来卡一下处理时间
|
||||
****************************************************************
|
||||
*/
|
||||
|
||||
|
||||
#include "media/includes.h"
|
||||
|
||||
|
||||
#define ENC_IO_DEBUG_1(i,x) {JL_PORT##i->DIR &= ~BIT(x), JL_PORT##i->OUT |= BIT(x);}
|
||||
#define ENC_IO_DEBUG_0(i,x) {JL_PORT##i->DIR &= ~BIT(x), JL_PORT##i->OUT &= ~BIT(x);}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* Audio encoder test output before
|
||||
* Description: 编码输出
|
||||
* Arguments : *enc 编码句柄
|
||||
* *buff 输出buf
|
||||
* len 输出长度
|
||||
* Return : None.
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
void audio_encoder_test_out_before(struct audio_encoder *enc, void *buff, int len)
|
||||
{
|
||||
ENC_IO_DEBUG_1(C, 3);
|
||||
}
|
||||
/*
|
||||
*********************************************************************
|
||||
* Audio encoder test output after
|
||||
* Description: 编码输出
|
||||
* Arguments : *enc 编码句柄
|
||||
* wlen 实际输出长度
|
||||
* Return : None.
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
void audio_encoder_test_out_after(struct audio_encoder *enc, int wlen)
|
||||
{
|
||||
ENC_IO_DEBUG_0(C, 3);
|
||||
}
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* Audio encoder test get frame before
|
||||
* Description: 编码获取帧数据
|
||||
* Arguments : *enc 编码句柄
|
||||
* Return : None.
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
void audio_encoder_test_get_frame_before(struct audio_encoder *enc, u16 frame_len)
|
||||
{
|
||||
ENC_IO_DEBUG_1(C, 2);
|
||||
}
|
||||
/*
|
||||
*********************************************************************
|
||||
* Audio encoder test get frame after
|
||||
* Description: 编码获取帧数据
|
||||
* Arguments : *enc 编码句柄
|
||||
* *frame 获取到的帧数据
|
||||
* rlen 获取到的帧数据长度
|
||||
* Return : None.
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
void audio_encoder_test_get_frame_after(struct audio_encoder *enc, s16 *frame, int rlen)
|
||||
{
|
||||
ENC_IO_DEBUG_0(C, 2);
|
||||
}
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* Audio encoder test run before
|
||||
* Description: 编码处理
|
||||
* Arguments : *enc 编码句柄
|
||||
* Return : None.
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
void audio_encoder_test_run_before(struct audio_encoder *enc)
|
||||
{
|
||||
ENC_IO_DEBUG_1(C, 1);
|
||||
}
|
||||
/*
|
||||
*********************************************************************
|
||||
* Audio encoder test run after
|
||||
* Description: 编码处理
|
||||
* Arguments : *enc 编码句柄
|
||||
* err 编码处理返回值
|
||||
* Return : None.
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
void audio_encoder_test_run_after(struct audio_encoder *enc, int err)
|
||||
{
|
||||
ENC_IO_DEBUG_0(C, 1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
211
apps/common/audio/online_debug/aud_data_export.c
Normal file
211
apps/common/audio/online_debug/aud_data_export.c
Normal file
@ -0,0 +1,211 @@
|
||||
#include "aud_data_export.h"
|
||||
#include "audio_online_debug.h"
|
||||
#include "circular_buf.h"
|
||||
#include "timer.h"
|
||||
|
||||
#define AUD_DE_LOG y_printf
|
||||
|
||||
/*支持的数据通道数:1~3*/
|
||||
#define AUDIO_DATA_EXPORT_CH 1
|
||||
|
||||
enum {
|
||||
AEC_ST_STOP = 0,
|
||||
AEC_ST_INIT,
|
||||
AEC_ST_START,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
u8 state;
|
||||
u8 ch; /*export data ch num*/
|
||||
u16 send_timer;
|
||||
u8 packet[256];
|
||||
#if (AUDIO_DATA_EXPORT_CH > 0)
|
||||
u8 buf0[1024];
|
||||
cbuffer_t data_cbuf0;
|
||||
u32 seqn0;
|
||||
#endif /*AUDIO_DATA_EXPORT_CH*/
|
||||
#if (AUDIO_DATA_EXPORT_CH > 1)
|
||||
u8 buf1[1024];
|
||||
cbuffer_t data_cbuf1;
|
||||
u32 seqn1;
|
||||
#endif /*AUDIO_DATA_EXPORT_CH*/
|
||||
#if (AUDIO_DATA_EXPORT_CH > 2)
|
||||
u8 buf2[1024];
|
||||
cbuffer_t data_cbuf2;
|
||||
u32 seqn2;
|
||||
#endif /*AUDIO_DATA_EXPORT_CH*/
|
||||
} aud_data_export_t;
|
||||
aud_data_export_t *aud_de = NULL;
|
||||
|
||||
typedef struct {
|
||||
int cmd;
|
||||
int data;
|
||||
} rec_cmd_t;
|
||||
|
||||
int audio_data_export_start(u8 ch)
|
||||
{
|
||||
if (aud_de) {
|
||||
AUD_DE_LOG("aud_de re-malloc !!!");
|
||||
return 0;
|
||||
}
|
||||
aud_de = zalloc(sizeof(aud_data_export_t));
|
||||
if (aud_de == NULL) {
|
||||
AUD_DE_LOG("aud_de malloc failed!!!");
|
||||
return -1;
|
||||
}
|
||||
if (ch <= AUDIO_DATA_EXPORT_CH) {
|
||||
aud_de->ch = ch;
|
||||
} else {
|
||||
aud_de->ch = AUDIO_DATA_EXPORT_CH;
|
||||
}
|
||||
#if (AUDIO_DATA_EXPORT_CH > 0)
|
||||
cbuf_init(&aud_de->data_cbuf0, aud_de->buf0, sizeof(aud_de->buf0));
|
||||
aud_de->seqn0 = 0;
|
||||
#endif /*AUDIO_DATA_EXPORT_CH*/
|
||||
#if (AUDIO_DATA_EXPORT_CH > 1)
|
||||
cbuf_init(&aud_de->data_cbuf1, aud_de->buf1, sizeof(aud_de->buf1));
|
||||
aud_de->seqn1 = 0;
|
||||
#endif /*AUDIO_DATA_EXPORT_CH*/
|
||||
#if (AUDIO_DATA_EXPORT_CH > 2)
|
||||
cbuf_init(&aud_de->data_cbuf2, aud_de->buf2, sizeof(aud_de->buf2));
|
||||
aud_de->seqn2 = 0;
|
||||
#endif /*AUDIO_DATA_EXPORT_CH*/
|
||||
aud_de->state = AEC_ST_START;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void audio_data_export_stop(void)
|
||||
{
|
||||
if (aud_de) {
|
||||
if (aud_de->send_timer) {
|
||||
sys_timer_del(aud_de->send_timer);
|
||||
aud_de->send_timer = 0;
|
||||
}
|
||||
aud_de->state = AEC_ST_STOP;
|
||||
free(aud_de);
|
||||
aud_de = NULL;
|
||||
}
|
||||
}
|
||||
static int spp_data_export(u8 ch, u8 *buf, u16 len)
|
||||
{
|
||||
u8 data_ch;
|
||||
putchar('.');
|
||||
if (ch == 0) {
|
||||
data_ch = DB_PKT_TYPE_DAT_CH0;
|
||||
} else if (ch == 1) {
|
||||
data_ch = DB_PKT_TYPE_DAT_CH1;
|
||||
} else {
|
||||
data_ch = DB_PKT_TYPE_DAT_CH2;
|
||||
}
|
||||
int err = app_online_db_send_more(data_ch, buf, len);
|
||||
if (err) {
|
||||
printf("tx_err:%d", err);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
int audio_data_export_run(u8 ch, u8 *data, int len)
|
||||
{
|
||||
int ret = 0;
|
||||
if (aud_de && (aud_de->state == AEC_ST_START)) {
|
||||
#if (AUDIO_DATA_EXPORT_CH > 0)
|
||||
if (ch == 0) {
|
||||
int wlen = cbuf_write(&aud_de->data_cbuf0, data, len);
|
||||
if (cbuf_get_data_size(&aud_de->data_cbuf0) >= 640) {
|
||||
u8 tmp_buf[RECORD_CH0_LENGTH];
|
||||
memcpy(tmp_buf, &aud_de->seqn0, 4);
|
||||
s16 *data_buf = &tmp_buf[4];
|
||||
cbuf_read(&aud_de->data_cbuf0, data_buf, 640);
|
||||
spp_data_export(ch, tmp_buf, 644);
|
||||
aud_de->seqn0 ++;
|
||||
putchar('s');
|
||||
|
||||
}
|
||||
}
|
||||
#endif /*AUDIO_DATA_EXPORT_CH*/
|
||||
#if (AUDIO_DATA_EXPORT_CH > 1)
|
||||
else if (ch == 1) {
|
||||
int wlen = cbuf_write(&aud_de->data_cbuf1, data, len);
|
||||
if (cbuf_get_data_size(&aud_de->data_cbuf1) >= 640) {
|
||||
u8 tmp_buf[RECORD_CH1_LENGTH];
|
||||
memcpy(tmp_buf, &aud_de->seqn1, 4);
|
||||
s16 *data_buf = &tmp_buf[4];
|
||||
cbuf_read(&aud_de->data_cbuf1, data_buf, 640);
|
||||
spp_data_export(ch, tmp_buf, 644);
|
||||
aud_de->seqn1 ++;
|
||||
putchar('s');
|
||||
}
|
||||
|
||||
}
|
||||
#endif /*AUDIO_DATA_EXPORT_CH*/
|
||||
#if (AUDIO_DATA_EXPORT_CH > 2)
|
||||
else if (ch == 2) {
|
||||
int wlen = cbuf_write(&aud_de->data_cbuf2, data, len);
|
||||
if (cbuf_get_data_size(&aud_de->data_cbuf2) >= 640) {
|
||||
u8 tmp_buf[RECORD_CH2_LENGTH];
|
||||
memcpy(tmp_buf, &aud_de->seqn2, 4);
|
||||
s16 *data_buf = &tmp_buf[4];
|
||||
cbuf_read(&aud_de->data_cbuf2, data_buf, 640);
|
||||
spp_data_export(ch, tmp_buf, 644);
|
||||
aud_de->seqn2 ++;
|
||||
putchar('s');
|
||||
}
|
||||
}
|
||||
#endif /*AUDIO_DATA_EXPORT_CH*/
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
static int aud_online_data_export_parse(u8 *packet, u8 size, u8 *ext_data, u16 ext_size)
|
||||
{
|
||||
int res_data = 0;
|
||||
rec_cmd_t rec_cmd;
|
||||
int err = 0;
|
||||
u8 parse_seq = ext_data[1];
|
||||
//AUD_DE_LOG("aec_spp_rx,seq:%d,size:%d\n", parse_seq, size);
|
||||
//put_buf(packet, size);
|
||||
memcpy(&rec_cmd, packet, sizeof(rec_cmd_t));
|
||||
switch (rec_cmd.cmd) {
|
||||
case AUD_RECORD_COUNT:
|
||||
if (aud_de) {
|
||||
/* res_data = aud_de->ch; */
|
||||
res_data = AUDIO_DATA_EXPORT_CH;
|
||||
} else {
|
||||
res_data = AUDIO_DATA_EXPORT_CH;
|
||||
}
|
||||
err = app_online_db_ack(parse_seq, (u8 *)&res_data, 4);
|
||||
AUD_DE_LOG("query record_ch num:%d\n", res_data);
|
||||
break;
|
||||
case AUD_RECORD_START:
|
||||
audio_data_export_start(AUDIO_DATA_EXPORT_CH);
|
||||
err = app_online_db_ack(parse_seq, (u8 *)&res_data, 1); //该命令随便ack一个byte即可
|
||||
AUD_DE_LOG("record_start\n");
|
||||
break;
|
||||
case AUD_RECORD_STOP:
|
||||
AUD_DE_LOG("record_stop\n");
|
||||
audio_data_export_stop();
|
||||
app_online_db_ack(parse_seq, (u8 *)&res_data, 1); //该命令随便ack一个byte即可
|
||||
break;
|
||||
case ONLINE_OP_QUERY_RECORD_PACKAGE_LENGTH:
|
||||
if (rec_cmd.data == 0) {
|
||||
res_data = RECORD_CH0_LENGTH;
|
||||
} else if (rec_cmd.data == 1) {
|
||||
res_data = RECORD_CH1_LENGTH;
|
||||
} else {
|
||||
res_data = RECORD_CH2_LENGTH;
|
||||
}
|
||||
AUD_DE_LOG("query record ch%d packet length:%d\n", rec_cmd.data, res_data);
|
||||
err = app_online_db_ack(parse_seq, (u8 *)&res_data, 4); //回复对应的通道数据长度
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int aud_data_export_open(void)
|
||||
{
|
||||
app_online_db_register_handle(DB_PKT_TYPE_EXPORT, aud_online_data_export_parse);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int aud_data_export_close(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
8
apps/common/audio/online_debug/aud_data_export.h
Normal file
8
apps/common/audio/online_debug/aud_data_export.h
Normal file
@ -0,0 +1,8 @@
|
||||
#ifndef _AUD_DATA_EXPORT_H_
|
||||
#define _AUD_DATA_EXPORT_H_
|
||||
|
||||
#include "generic/typedef.h"
|
||||
|
||||
|
||||
|
||||
#endif/*_AUD_DATA_EXPORT_H_*/
|
||||
354
apps/common/audio/online_debug/aud_mic_dut.c
Normal file
354
apps/common/audio/online_debug/aud_mic_dut.c
Normal file
@ -0,0 +1,354 @@
|
||||
#include "aud_mic_dut.h"
|
||||
#include "audio_online_debug.h"
|
||||
#include "online_db_deal.h"
|
||||
#include "app_config.h"
|
||||
#include "system/includes.h"
|
||||
|
||||
#if ((defined TCFG_AUDIO_MIC_DUT_ENABLE) && TCFG_AUDIO_MIC_DUT_ENABLE)
|
||||
#include "mic_dut_process.h"
|
||||
|
||||
#define AUDIO_MIC_DUT_TASK_NAME "AudioMicDut"
|
||||
|
||||
typedef struct {
|
||||
u8 start; /*mic dut 开始和结束标志*/
|
||||
u16 mic_gain; /*保存在线调试的mic gain*/
|
||||
u32 sr; /*保存在线调试的mic采样率*/
|
||||
u8 mic_idx; /*记录当前使用的那个mic*/
|
||||
u8 scan_start; /*mic dut scan 开始和结束的标志*/
|
||||
u8 dac_gain; /*保存在线调试的dac gain*/
|
||||
u32 send_timer; /*定时器句柄*/
|
||||
u32 seqn; /*数据的seqn*/
|
||||
OS_SEM sem; /*信号量*/
|
||||
} mic_online_info_t;
|
||||
|
||||
/*硬件信息*/
|
||||
static mic_dut_info_t mic_info;
|
||||
|
||||
/*在线调试信息*/
|
||||
static mic_online_info_t online_info_t;
|
||||
static mic_online_info_t *online_info_hdl = &online_info_t;
|
||||
|
||||
static int spp_data_export(u8 ch, u8 *buf, u16 len)
|
||||
{
|
||||
u8 data_ch;
|
||||
putchar('.');
|
||||
if (ch == 0) {
|
||||
data_ch = DB_PKT_TYPE_DAT_CH0;
|
||||
} else if (ch == 1) {
|
||||
data_ch = DB_PKT_TYPE_DAT_CH1;
|
||||
} else {
|
||||
data_ch = DB_PKT_TYPE_DAT_CH2;
|
||||
}
|
||||
int err = app_online_db_send_more(data_ch, buf, len);
|
||||
if (err) {
|
||||
printf("tx_err:%d", err);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
/*在线数据初始化*/
|
||||
static void mic_dut_online_init(void)
|
||||
{
|
||||
if (online_info_hdl) {
|
||||
online_info_hdl->start = 0;
|
||||
online_info_hdl->mic_gain = mic_info.mic_gain_default;
|
||||
online_info_hdl->sr = mic_info.sr_default;
|
||||
online_info_hdl->mic_idx = 0;
|
||||
online_info_hdl->scan_start = 0;
|
||||
online_info_hdl->dac_gain = mic_info.dac_gain_default;
|
||||
online_info_hdl->send_timer = 0;
|
||||
online_info_hdl->seqn = 1;
|
||||
} else {
|
||||
printf("online_info_hdl is NULL !!!\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void audio_mic_dut_data_export_run(void)
|
||||
{
|
||||
if (online_info_hdl) {
|
||||
u8 buf[644];
|
||||
u8 *data = &buf[4];
|
||||
int len = 640;
|
||||
int rlen = 0;
|
||||
if (audio_mic_dut_get_data_len() >= len) {
|
||||
memcpy(buf, &online_info_hdl->seqn, 4);
|
||||
rlen = audio_mic_dut_data_get(data, len);
|
||||
extern void audio_mic_dut_eq_run(s16 * data, int len);
|
||||
audio_mic_dut_eq_run(data, len);
|
||||
/* printf("%d, %d", len, rlen); */
|
||||
int ret = spp_data_export(0, buf, rlen + 4);
|
||||
|
||||
online_info_hdl->seqn ++;
|
||||
/* printf("seqn %d %d\n", mic_online_info.seqn,*((int *) buf)); */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void audio_mic_dut_timer(void *p)
|
||||
{
|
||||
audio_mic_dut_data_export_run();
|
||||
}
|
||||
|
||||
static void audio_mic_dut_task(void *p)
|
||||
{
|
||||
while (1) {
|
||||
os_sem_pend(&online_info_hdl->sem, 0);
|
||||
audio_mic_dut_data_export_run();
|
||||
}
|
||||
}
|
||||
|
||||
static void mic_dut_online_start(void)
|
||||
{
|
||||
if (online_info_hdl) {
|
||||
#if MIC_DUT_DATA_SEND_BY_TIMER
|
||||
online_info_hdl->send_timer = usr_timer_add(NULL, audio_mic_dut_timer, MIC_DATA_SEND_INTERVAL, 1);
|
||||
#else
|
||||
os_sem_create(&online_info_hdl->sem, 0);
|
||||
os_task_create(audio_mic_dut_task, NULL, 1, 768, 64, AUDIO_MIC_DUT_TASK_NAME);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/*释放mic dut 信号量*/
|
||||
void mic_dut_online_sem_post(void)
|
||||
{
|
||||
if (online_info_hdl) {
|
||||
#if (MIC_DUT_DATA_SEND_BY_TIMER == 0)
|
||||
os_sem_post(&online_info_hdl->sem);
|
||||
#endif /*SPP_SEND_BY_TIMER*/
|
||||
}
|
||||
}
|
||||
|
||||
static void mic_dut_online_stop(void)
|
||||
{
|
||||
if (online_info_hdl) {
|
||||
if (online_info_hdl->start) {
|
||||
audio_mic_dut_stop();
|
||||
online_info_hdl->start = 0;
|
||||
}
|
||||
if (online_info_hdl->scan_start) {
|
||||
audio_mic_dut_scan_stop();
|
||||
online_info_hdl->scan_start = 0;
|
||||
}
|
||||
|
||||
#if MIC_DUT_DATA_SEND_BY_TIMER
|
||||
if (online_info_hdl->send_timer) {
|
||||
usr_timer_del(online_info_hdl->send_timer);
|
||||
online_info_hdl->send_timer = 0;
|
||||
}
|
||||
#else
|
||||
os_task_del(AUDIO_MIC_DUT_TASK_NAME);
|
||||
os_sem_del(&online_info_hdl->sem, 0);
|
||||
#endif
|
||||
/* online_info_hdl = NULL; */
|
||||
}
|
||||
}
|
||||
|
||||
/*数据解析*/
|
||||
static int mic_dut_online_parse(u8 *packet, u8 size, u8 *ext_data, u16 ext_size)
|
||||
{
|
||||
int res_data = 0;
|
||||
online_cmd_t mic_dut_cmd;
|
||||
int err = 0;
|
||||
u8 parse_seq = ext_data[1];
|
||||
//AEC_ONLINE_LOG("[MIC_DUT]spp_rx,seq:%d,size:%d\n", parse_seq, size);
|
||||
put_buf(packet, size);
|
||||
memcpy(&mic_dut_cmd, packet, sizeof(online_cmd_t));
|
||||
printf("[MIC_DUT]cmd:0x%x\n", mic_dut_cmd.cmd);
|
||||
switch (mic_dut_cmd.cmd) {
|
||||
case AUD_RECORD_COUNT:
|
||||
y_printf("AEC_RECORD_COUNT\n");
|
||||
res_data = 1;
|
||||
err = app_online_db_ack(parse_seq, (u8 *)&res_data, 4);
|
||||
break;
|
||||
case ONLINE_OP_QUERY_RECORD_PACKAGE_LENGTH:
|
||||
y_printf("ONLINE_OP_QUERY_RECORD_PACKAGE_LENGTH\n");
|
||||
if (mic_dut_cmd.data == 0) {
|
||||
res_data = RECORD_CH0_LENGTH;
|
||||
} else if (mic_dut_cmd.data == 1) {
|
||||
res_data = RECORD_CH1_LENGTH;
|
||||
} else {
|
||||
res_data = RECORD_CH2_LENGTH;
|
||||
}
|
||||
printf("query record ch%d packet length:%d\n", mic_dut_cmd.data, res_data);
|
||||
err = app_online_db_ack(parse_seq, (u8 *)&res_data, 4); //回复对应的通道数据长度
|
||||
break;
|
||||
case MIC_DUT_INFO_QUERY:
|
||||
y_printf("MIC_DUT_INFO_QUERY\n");
|
||||
/*获取mic dut硬件数据*/
|
||||
audio_mic_dut_info_get(&mic_info);
|
||||
/*在线数据初始化*/
|
||||
mic_dut_online_init();
|
||||
err = app_online_db_ack(parse_seq, (u8 *)&mic_info, sizeof(mic_info));
|
||||
break;
|
||||
case MIC_DUT_GAIN_SET:
|
||||
y_printf("MIC_DUT_GAIN_SET:%d\n", mic_dut_cmd.data);
|
||||
if (online_info_hdl) {
|
||||
online_info_hdl->mic_gain = mic_dut_cmd.data;
|
||||
}
|
||||
audio_mic_dut_gain_set(mic_dut_cmd.data);
|
||||
err = app_online_db_ack(parse_seq, (u8 *)"OK", 2);
|
||||
break;
|
||||
case MIC_DUT_SAMPLE_RATE_SET:
|
||||
y_printf("MIC_DUT_SAMPLE_RATE_SET:%d\n", mic_dut_cmd.data);
|
||||
if (online_info_hdl) {
|
||||
online_info_hdl->sr = mic_dut_cmd.data;
|
||||
}
|
||||
audio_mic_dut_sample_rate_set(mic_dut_cmd.data);
|
||||
err = app_online_db_ack(parse_seq, (u8 *)"OK", 2);
|
||||
break;
|
||||
case MIC_DUT_START:
|
||||
y_printf("MIC_DUT_START\n");
|
||||
/*打开发数资源*/
|
||||
mic_dut_online_start();
|
||||
/*打开mic*/
|
||||
audio_mic_dut_start();
|
||||
if (online_info_hdl) {
|
||||
online_info_hdl->start = 1;
|
||||
}
|
||||
err = app_online_db_ack(parse_seq, (u8 *)"OK", 2);
|
||||
break;
|
||||
case MIC_DUT_STOP:
|
||||
y_printf("MIC_DUT_STOP\n");
|
||||
if (online_info_hdl) {
|
||||
online_info_hdl->start = 0;
|
||||
}
|
||||
/*关闭mic*/
|
||||
audio_mic_dut_stop();
|
||||
/*关闭发数资源*/
|
||||
mic_dut_online_stop();
|
||||
err = app_online_db_ack(parse_seq, (u8 *)"OK", 2);
|
||||
break;
|
||||
case MIC_DUT_AMIC_SEL:
|
||||
y_printf("MIC_DUT_AMIC_SEL:%d\n", mic_dut_cmd.data);
|
||||
if (online_info_hdl) {
|
||||
online_info_hdl->mic_idx = mic_dut_cmd.data;
|
||||
}
|
||||
audio_mic_dut_amic_select(mic_dut_cmd.data);
|
||||
err = app_online_db_ack(parse_seq, (u8 *)"OK", 2);
|
||||
break;
|
||||
case MIC_DUT_DMIC_SEL:
|
||||
y_printf("MIC_DUT_DMIC_SEL:%d\n", mic_dut_cmd.data);
|
||||
if (online_info_hdl) {
|
||||
online_info_hdl->mic_idx = mic_dut_cmd.data;
|
||||
}
|
||||
audio_mic_dut_dmic_select(mic_dut_cmd.data);
|
||||
err = app_online_db_ack(parse_seq, (u8 *)"OK", 2);
|
||||
break;
|
||||
case MIC_DUT_DAC_GAIN_SET:
|
||||
y_printf("MIC_DUT_DAC_GAIN_SET:%d\n", mic_dut_cmd.data);
|
||||
if (online_info_hdl) {
|
||||
online_info_hdl->dac_gain = mic_dut_cmd.data;
|
||||
}
|
||||
audio_mic_dut_dac_gain_set(mic_dut_cmd.data);
|
||||
err = app_online_db_ack(parse_seq, (u8 *)"OK", 2);
|
||||
break;
|
||||
case MIC_DUT_SCAN_START:
|
||||
y_printf("MIC_DUT_SCAN_START\n");
|
||||
/*打开发数资源*/
|
||||
mic_dut_online_start();
|
||||
/*打开dac*/
|
||||
audio_mic_dut_scan_start();
|
||||
if (online_info_hdl) {
|
||||
online_info_hdl->scan_start = 1;
|
||||
}
|
||||
err = app_online_db_ack(parse_seq, (u8 *)"OK", 2);
|
||||
break;
|
||||
case MIC_DUT_SCAN_STOP:
|
||||
y_printf("MIC_DUT_SCAN_STOP\n");
|
||||
if (online_info_hdl) {
|
||||
online_info_hdl->scan_start = 0;
|
||||
}
|
||||
/*关闭dac*/
|
||||
audio_mic_dut_scan_stop();
|
||||
/*关闭发数资源*/
|
||||
mic_dut_online_stop();
|
||||
err = app_online_db_ack(parse_seq, (u8 *)"OK", 2);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
printf("err:%d\n", err);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
/*获取当前设置的mic增益*/
|
||||
int mic_dut_online_get_mic_gain(void)
|
||||
{
|
||||
if (online_info_hdl) {
|
||||
return online_info_hdl->mic_gain;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*获取当前设置的dac增益*/
|
||||
int mic_dut_online_get_dac_gain(void)
|
||||
{
|
||||
if (online_info_hdl) {
|
||||
return online_info_hdl->dac_gain;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*获取当前设置的采样率*/
|
||||
int mic_dut_online_get_sample_rate(void)
|
||||
{
|
||||
if (online_info_hdl) {
|
||||
return online_info_hdl->sr;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*获取当前使能的模拟mic*/
|
||||
u8 mic_dut_online_amic_enable_bit(void)
|
||||
{
|
||||
return mic_info.amic_enable_bit;
|
||||
}
|
||||
|
||||
/*获取当前使能的数字mic*/
|
||||
u8 mic_dut_online_dmic_enable_bit(void)
|
||||
{
|
||||
return mic_info.dmic_enable_bit;
|
||||
}
|
||||
|
||||
/*获取当前在线使用的mic*/
|
||||
int mic_dut_online_get_mic_idx(void)
|
||||
{
|
||||
if (online_info_hdl) {
|
||||
return online_info_hdl->mic_idx;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*获取mic dut状态*/
|
||||
int mic_dut_online_get_mic_state(void)
|
||||
{
|
||||
if (online_info_hdl) {
|
||||
return online_info_hdl->start;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*获取dut scan状态*/
|
||||
int mic_dut_online_get_scan_state(void)
|
||||
{
|
||||
if (online_info_hdl) {
|
||||
return online_info_hdl->scan_start;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*注册mic dut解析回调*/
|
||||
int aud_mic_dut_open(void)
|
||||
{
|
||||
app_online_db_register_handle(DB_PKT_TYPE_MIC_DUT, mic_dut_online_parse);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int aud_mic_dut_close(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /*((defined TCFG_AUDIO_MIC_DUT_ENABLE) && TCFG_AUDIO_MIC_DUT_ENABLE)*/
|
||||
68
apps/common/audio/online_debug/aud_mic_dut.h
Normal file
68
apps/common/audio/online_debug/aud_mic_dut.h
Normal file
@ -0,0 +1,68 @@
|
||||
#ifndef _AUD_MIC_DUT_H_
|
||||
#define _AUD_MIC_DUT_H_
|
||||
|
||||
#include "generic/typedef.h"
|
||||
|
||||
|
||||
#define MIC_DUT_DATA_SEND_BY_TIMER 0 /*1:使用定时器发spp数据,0:使用任务发数*/
|
||||
|
||||
/*定时器发送间隔*/
|
||||
#define MIC_DATA_SEND_INTERVAL 4
|
||||
|
||||
//MIC采样率bitmap
|
||||
#define MIC_ADC_SR_8000 BIT(0)
|
||||
#define MIC_ADC_SR_11025 BIT(1)
|
||||
#define MIC_ADC_SR_12000 BIT(2)
|
||||
#define MIC_ADC_SR_16000 BIT(3)
|
||||
#define MIC_ADC_SR_22050 BIT(4)
|
||||
#define MIC_ADC_SR_24000 BIT(5)
|
||||
#define MIC_ADC_SR_32000 BIT(6)
|
||||
#define MIC_ADC_SR_44100 BIT(7)
|
||||
#define MIC_ADC_SR_48000 BIT(8)
|
||||
|
||||
typedef struct {
|
||||
u16 version;
|
||||
u16 amic_enable_bit; /*模拟MIC使能位:AMIC0-AMIC15,默认使能模拟MIC最低使能位*/
|
||||
u16 dmic_enable_bit; /*数字MIC使能位:DMIC0-DMIC15*/
|
||||
u8 channel; /*声道*/
|
||||
u8 bit_wide; /*位宽,有符号*/
|
||||
u32 sr_enable_bit; /*采样率支持列表使能位*/
|
||||
u32 sr_default; /*采样率默认值:16000*/
|
||||
u16 mic_gain; /*MIC增益范围*/
|
||||
u16 mic_gain_default; /*MIC增益默认值*/
|
||||
u16 dac_gain; /*DAC增益范围*/
|
||||
u16 dac_gain_default; /*DAC增益默认值*/
|
||||
} mic_dut_info_t;
|
||||
|
||||
|
||||
/*获取当前设置的mic增益*/
|
||||
int mic_dut_online_get_mic_gain(void);
|
||||
|
||||
/*获取当前设置的dac增益*/
|
||||
int mic_dut_online_get_dac_gain(void);
|
||||
|
||||
/*获取当前设置的采样率*/
|
||||
int mic_dut_online_get_sample_rate(void);
|
||||
|
||||
/*获取当前使能的模拟mic*/
|
||||
u8 mic_dut_online_amic_enable_bit(void);
|
||||
|
||||
/*获取当前使能的数字mic*/
|
||||
u8 mic_dut_online_dmic_enable_bit(void);
|
||||
|
||||
/*获取当前在线使用的mic*/
|
||||
int mic_dut_online_get_mic_idx(void);
|
||||
|
||||
/*获取mic dut状态*/
|
||||
int mic_dut_online_get_mic_state(void);
|
||||
|
||||
/*获取dut scan状态*/
|
||||
int mic_dut_online_get_scan_state(void);
|
||||
|
||||
|
||||
int aud_mic_dut_open(void);
|
||||
int aud_mic_dut_close(void);
|
||||
|
||||
|
||||
#endif/*_AUD_MIC_DUT_H_*/
|
||||
|
||||
160
apps/common/audio/online_debug/aud_spatial_effect_dut.c
Normal file
160
apps/common/audio/online_debug/aud_spatial_effect_dut.c
Normal file
@ -0,0 +1,160 @@
|
||||
#include "aud_spatial_effect_dut.h"
|
||||
#include "audio_online_debug.h"
|
||||
#include "config/config_interface.h"
|
||||
#include "app_config.h"
|
||||
#include "os/os_api.h"
|
||||
#include "classic/tws_api.h"
|
||||
#include "timer.h"
|
||||
|
||||
#if (defined(TCFG_AUDIO_SPATIAL_EFFECT_ENABLE) && TCFG_AUDIO_SPATIAL_EFFECT_ENABLE && TCFG_SPATIAL_EFFECT_ONLINE_ENABLE)
|
||||
|
||||
#define IMU_DATA_SEND_INTERVAL 100
|
||||
// 配置参数
|
||||
typedef struct _RP_PARM_CONIFG {
|
||||
int trackKIND; //角度合成算法选择: P360_T0或者P360_T1
|
||||
int ReverbKIND; //混响算法选择:P360_R0或者P360_R1
|
||||
int reverbance; //混响值 : 0到100
|
||||
int dampingval; //高频decay:0到80
|
||||
} RP_PARM_CONIFG;
|
||||
static RP_PARM_CONIFG parmK;
|
||||
|
||||
extern void spatial_effect_online_updata(RP_PARM_CONIFG *params);
|
||||
extern void get_spatial_effect_reverb_params(RP_PARM_CONIFG *params);
|
||||
|
||||
static u32 send_timer = 0;
|
||||
static int global_angle = 0;
|
||||
|
||||
int set_bt_media_imu_angle(int angle)
|
||||
{
|
||||
global_angle = angle;
|
||||
return global_angle;
|
||||
}
|
||||
|
||||
void spatial_effect_imu_dut_data_timer(void *p)
|
||||
{
|
||||
int tmp_angle = 0;
|
||||
extern u8 bt_media_is_running(void);
|
||||
#if TCFG_USER_TWS_ENABLE
|
||||
/*TWS连接的时候*/
|
||||
if ((tws_api_get_tws_state() & TWS_STA_SIBLING_CONNECTED)) {
|
||||
/*主机发送角度*/
|
||||
if (tws_api_get_role() == TWS_ROLE_MASTER) {
|
||||
/*播歌的时候*/
|
||||
if (bt_media_is_running()) {
|
||||
tmp_angle = global_angle;
|
||||
if (tmp_angle > 180) {
|
||||
tmp_angle = tmp_angle - 360;
|
||||
}
|
||||
int buf[2];
|
||||
buf[0] = SPATIAL_EFFECT_IMU_DUT_DATA;
|
||||
buf[1] = tmp_angle;
|
||||
/* app_online_db_send(DB_PKT_TYPE_SPATIAL_EFFECT, buf, sizeof(buf)); */
|
||||
app_online_db_send_more(DB_PKT_TYPE_SPATIAL_EFFECT, buf, sizeof(buf));
|
||||
}
|
||||
}
|
||||
} else
|
||||
#endif /*TCFG_USER_TWS_ENABLE*/
|
||||
{
|
||||
/*没有tws连接的时候*/
|
||||
if (bt_media_is_running()) {/*发送播歌角度*/
|
||||
tmp_angle = global_angle;
|
||||
if (tmp_angle > 180) {
|
||||
tmp_angle = tmp_angle - 360;
|
||||
}
|
||||
int buf[2];
|
||||
buf[0] = SPATIAL_EFFECT_IMU_DUT_DATA;
|
||||
buf[1] = tmp_angle;
|
||||
/* app_online_db_send(DB_PKT_TYPE_SPATIAL_EFFECT, buf, sizeof(buf)); */
|
||||
app_online_db_send_more(DB_PKT_TYPE_SPATIAL_EFFECT, buf, sizeof(buf));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int spatial_effect_imu_dut_start()
|
||||
{
|
||||
|
||||
if (send_timer == 0) {
|
||||
send_timer = usr_timer_add(NULL, spatial_effect_imu_dut_data_timer, IMU_DATA_SEND_INTERVAL, 1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spatial_effect_imu_dut_stop()
|
||||
{
|
||||
if (send_timer) {
|
||||
usr_timer_del(send_timer);
|
||||
send_timer = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int spatial_effect_online_parse(u8 *packet, u8 size, u8 *ext_data, u16 ext_size)
|
||||
{
|
||||
put_buf(packet, size);
|
||||
int res_data = 0;
|
||||
int err = 0;
|
||||
u8 parse_seq = ext_data[1];
|
||||
int cmd;
|
||||
memcpy(&cmd, packet, sizeof(cmd));
|
||||
u8 *data = &packet[4];
|
||||
|
||||
printf("[SPATIAL EFFECT]cmd:0x%x\n", cmd);
|
||||
switch (cmd) {
|
||||
case SPATIAL_EFFECT_REVERB_INFO_QUERY:
|
||||
printf("SPATIAL_EFFECT_REVERB_INFO_QUERY\n");
|
||||
get_spatial_effect_reverb_params(&parmK);
|
||||
err = app_online_db_ack(parse_seq, (u8 *)&parmK, sizeof(parmK));
|
||||
break;
|
||||
|
||||
case SPATIAL_EFFECT_REVERB_PARAM:
|
||||
printf("SPATIAL_EFFECT_REVERB_PARAM\n");
|
||||
memcpy(&parmK, data, sizeof(parmK));
|
||||
|
||||
spatial_effect_online_updata(&parmK);
|
||||
|
||||
printf("%s\n trackKIND:%d, ReverbKIND:%d, reverbance:%d, dampingval:%d\n", __func__,
|
||||
parmK.trackKIND, parmK.ReverbKIND, parmK.reverbance, parmK.dampingval);
|
||||
err = app_online_db_ack(parse_seq, (u8 *)"OK", 2);
|
||||
break;
|
||||
case SPATIAL_EFFECT_IMU_TRIM:
|
||||
printf("SPATIAL_EFFECT_IMU_TRIM\n");
|
||||
static int tmp = -2;
|
||||
|
||||
extern int spatial_imu_trim_start();
|
||||
spatial_imu_trim_start();
|
||||
|
||||
/*测试代码*/
|
||||
res_data = 0;
|
||||
err = app_online_db_ack(parse_seq, (u8 *)&res_data, 4);
|
||||
break;
|
||||
case SPATIAL_EFFECT_IMU_DUT_START:
|
||||
printf("SPATIAL_EFFECT_IMU_DUT_START\n");
|
||||
spatial_effect_imu_dut_start();
|
||||
err = app_online_db_ack(parse_seq, (u8 *)"OK", 2);
|
||||
break;
|
||||
case SPATIAL_EFFECT_IMU_DUT_STOP:
|
||||
printf("SPATIAL_EFFECT_IMU_DUT_STOP\n");
|
||||
spatial_effect_imu_dut_stop();
|
||||
err = app_online_db_ack(parse_seq, (u8 *)"OK", 2);
|
||||
break;
|
||||
default :
|
||||
break;
|
||||
}
|
||||
printf("err:%d\n", err);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int aud_spatial_effect_dut_open()
|
||||
{
|
||||
app_online_db_register_handle(DB_PKT_TYPE_SPATIAL_EFFECT, spatial_effect_online_parse);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int aud_spatial_effect_dut_close()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /*(defined(TCFG_SPATIAL_EFFECT_ONLINE_ENABLE) && (TCFG_SPATIAL_EFFECT_ONLINE_ENABLE == 1))*/
|
||||
9
apps/common/audio/online_debug/aud_spatial_effect_dut.h
Normal file
9
apps/common/audio/online_debug/aud_spatial_effect_dut.h
Normal file
@ -0,0 +1,9 @@
|
||||
|
||||
#ifndef _AUD_SPATIAL_EFFECT_DUT__
|
||||
#define _AUD_SPATIAL_EFFECT_DUT__
|
||||
|
||||
|
||||
int aud_spatial_effect_dut_open();
|
||||
int aud_spatial_effect_dut_close();
|
||||
|
||||
#endif _AUD_SPATIAL_EFFECT_DUT__
|
||||
52
apps/common/audio/online_debug/audio_online_debug.c
Normal file
52
apps/common/audio/online_debug/audio_online_debug.c
Normal file
@ -0,0 +1,52 @@
|
||||
#include "audio_online_debug.h"
|
||||
#include "system/includes.h"
|
||||
#include "generic/list.h"
|
||||
#include "aud_mic_dut.h"
|
||||
#include "aud_data_export.h"
|
||||
#include "aud_spatial_effect_dut.h"
|
||||
#include "board_config.h"
|
||||
|
||||
typedef struct {
|
||||
struct list_head parser_head;
|
||||
|
||||
} aud_online_ctx_t;
|
||||
aud_online_ctx_t *aud_online_ctx = NULL;
|
||||
|
||||
int audio_online_debug_init(void)
|
||||
{
|
||||
//aud_online_ctx = zalloc(sizeof(aud_online_ctx_t));
|
||||
if (aud_online_ctx) {
|
||||
//INIT_LIST_HEAD(&aud_online_ctx->parser_head);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int audio_online_debug_open()
|
||||
{
|
||||
/*空间音频陀螺仪数据导出*/
|
||||
#if (TCFG_SENSOR_DATA_EXPORT_ENABLE == SENSOR_DATA_EXPORT_USE_SPP)
|
||||
aud_data_export_open();
|
||||
#endif /*TCFG_SENSOR_DATA_EXPORT_ENABLE*/
|
||||
|
||||
/*麦克风测试*/
|
||||
#if (defined(TCFG_AUDIO_MIC_DUT_ENABLE) && (TCFG_AUDIO_MIC_DUT_ENABLE == 1))
|
||||
aud_mic_dut_open();
|
||||
#endif/*TCFG_AUDIO_MIC_DUT_ENABLE*/
|
||||
|
||||
/*空间音效在线调试*/
|
||||
#if (defined(TCFG_SPATIAL_EFFECT_ONLINE_ENABLE) && (TCFG_SPATIAL_EFFECT_ONLINE_ENABLE == 1))
|
||||
aud_spatial_effect_dut_open();
|
||||
#endif /*(defined(TCFG_SPATIAL_EFFECT_ONLINE_ENABLE) && (TCFG_SPATIAL_EFFECT_ONLINE_ENABLE == 1))*/
|
||||
return 0;
|
||||
}
|
||||
__initcall(audio_online_debug_open);
|
||||
|
||||
int audio_online_debug_close()
|
||||
{
|
||||
if (aud_online_ctx) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
45
apps/common/audio/online_debug/audio_online_debug.h
Normal file
45
apps/common/audio/online_debug/audio_online_debug.h
Normal file
@ -0,0 +1,45 @@
|
||||
#ifndef _AUD_ONLINE_DEBUG_
|
||||
#define _AUD_ONLINE_DEBUG_
|
||||
|
||||
#include "generic/typedef.h"
|
||||
#include "online_db_deal.h"
|
||||
|
||||
enum {
|
||||
AUD_RECORD_COUNT = 0x200,
|
||||
AUD_RECORD_START,
|
||||
AUD_RECORD_STOP,
|
||||
ONLINE_OP_QUERY_RECORD_PACKAGE_LENGTH,
|
||||
|
||||
MIC_DUT_INFO_QUERY = 0x300,
|
||||
MIC_DUT_GAIN_SET,
|
||||
MIC_DUT_SAMPLE_RATE_SET,
|
||||
MIC_DUT_START,
|
||||
MIC_DUT_STOP,
|
||||
MIC_DUT_AMIC_SEL,
|
||||
MIC_DUT_DMIC_SEL,
|
||||
MIC_DUT_DAC_GAIN_SET,
|
||||
MIC_DUT_SCAN_START,
|
||||
MIC_DUT_SCAN_STOP,
|
||||
|
||||
|
||||
SPATIAL_EFFECT_REVERB_PARAM = 0x400,
|
||||
SPATIAL_EFFECT_IMU_TRIM,
|
||||
SPATIAL_EFFECT_IMU_DUT_START,
|
||||
SPATIAL_EFFECT_IMU_DUT_STOP,
|
||||
SPATIAL_EFFECT_IMU_DUT_DATA,
|
||||
SPATIAL_EFFECT_REVERB_INFO_QUERY,
|
||||
};
|
||||
|
||||
#define RECORD_CH0_LENGTH 644
|
||||
#define RECORD_CH1_LENGTH 644
|
||||
#define RECORD_CH2_LENGTH 644
|
||||
|
||||
typedef struct {
|
||||
int cmd;
|
||||
int data;
|
||||
} online_cmd_t;
|
||||
|
||||
int audio_online_debug_open();
|
||||
|
||||
|
||||
#endif/*_AUD_ONLINE_DEBUG_*/
|
||||
410
apps/common/audio/sine_make.c
Normal file
410
apps/common/audio/sine_make.c
Normal file
@ -0,0 +1,410 @@
|
||||
/*****************************************************************
|
||||
>file name : apps/common/sine_make.c
|
||||
>author : lichao
|
||||
>create time : Sun 05 May 2019 08:37:35 PM CST
|
||||
*****************************************************************/
|
||||
#include "system/includes.h"
|
||||
#include "sine_make.h"
|
||||
|
||||
#define SINE_USE_MALLOC 1
|
||||
|
||||
struct audio_sin_maker {
|
||||
u8 open;
|
||||
u8 id;
|
||||
u8 sin_num;
|
||||
u8 channel;
|
||||
u8 repeat;
|
||||
u8 next_param;
|
||||
u16 fade_points;
|
||||
/*int sample_rate;*/
|
||||
int volume;
|
||||
int points;
|
||||
int sin_index;
|
||||
int win_sin_index;
|
||||
const struct sin_param *sin;
|
||||
};
|
||||
|
||||
#ifndef SINE_USE_MALLOC
|
||||
static struct audio_sin_maker sin_maker_handle;
|
||||
#endif
|
||||
|
||||
void *sin_tone_open(const struct sin_param *param, int num, u8 channel, u8 repeat)
|
||||
{
|
||||
if (!param || !num) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef SINE_USE_MALLOC
|
||||
struct audio_sin_maker *sin = zalloc(sizeof(struct audio_sin_maker));
|
||||
#else
|
||||
struct audio_sin_maker *sin = &sin_maker_handle;
|
||||
#endif
|
||||
|
||||
if (!sin) {
|
||||
return NULL;
|
||||
}
|
||||
if (sin->open) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sin->sin = param;
|
||||
sin->sin_num = num;
|
||||
sin->open = 1;
|
||||
sin->points = param[0].points;
|
||||
sin->id = 0;
|
||||
sin->channel = channel;
|
||||
sin->repeat = repeat;
|
||||
#if (defined CONFIG_CPU_BR18 || \
|
||||
defined CONFIG_CPU_BR21)
|
||||
/*这里如果加多fade points,会导致结束的时候有噪声,不是在淡出尾部*/
|
||||
sin->fade_points = 0;
|
||||
#else
|
||||
sin->fade_points = 480;
|
||||
#endif
|
||||
sin->next_param = 1;
|
||||
|
||||
return (void *)sin;
|
||||
}
|
||||
#if !defined(SINE_MAKE_IN_MASK)
|
||||
const int sf_sin_tab1[513] = {
|
||||
0x00000000, 0x0000c910, 0x0001921f, 0x00025b2d, 0x0003243a, 0x0003ed45, 0x0004b64e, 0x00057f53,
|
||||
0x00064855, 0x00071154, 0x0007da4e, 0x0008a343, 0x00096c33, 0x000a351d, 0x000afe00, 0x000bc6dd,
|
||||
0x000c8fb3, 0x000d5881, 0x000e2147, 0x000eea03, 0x000fb2b7, 0x00107b61, 0x00114401, 0x00120c96,
|
||||
0x0012d521, 0x00139d9f, 0x00146611, 0x00152e77, 0x0015f6d0, 0x0016bf1b, 0x00178758, 0x00184f87,
|
||||
0x001917a7, 0x0019dfb7, 0x001aa7b7, 0x001b6fa7, 0x001c3786, 0x001cff53, 0x001dc70f, 0x001e8eb8,
|
||||
0x001f564e, 0x00201dd1, 0x0020e541, 0x0021ac9b, 0x002273e2, 0x00233b13, 0x0024022e, 0x0024c933,
|
||||
0x00259021, 0x002656f8, 0x00271db7, 0x0027e45f, 0x0028aaed, 0x00297163, 0x002a37bf, 0x002afe01,
|
||||
0x002bc429, 0x002c8a35, 0x002d5026, 0x002e15fb, 0x002edbb4, 0x002fa14f, 0x003066ce, 0x00312c2e,
|
||||
0x0031f170, 0x0032b694, 0x00337b98, 0x0034407c, 0x00350540, 0x0035c9e4, 0x00368e66, 0x003752c6,
|
||||
0x00381705, 0x0038db21, 0x00399f19, 0x003a62ef, 0x003b26a0, 0x003bea2c, 0x003cad94, 0x003d70d7,
|
||||
0x003e33f3, 0x003ef6e9, 0x003fb9b8, 0x00407c60, 0x00413ee0, 0x00420138, 0x0042c367, 0x0043856d,
|
||||
0x0044474a, 0x004508fc, 0x0045ca83, 0x00468be0, 0x00474d11, 0x00480e16, 0x0048ceef, 0x00498f9a,
|
||||
0x004a5019, 0x004b1069, 0x004bd08b, 0x004c907f, 0x004d5043, 0x004e0fd8, 0x004ecf3c, 0x004f8e70,
|
||||
0x00504d72, 0x00510c43, 0x0051cae3, 0x0052894f, 0x00534789, 0x0054058f, 0x0054c362, 0x00558100,
|
||||
0x00563e6a, 0x0056fb9e, 0x0057b89d, 0x00587565, 0x005931f7, 0x0059ee52, 0x005aaa76, 0x005b6662,
|
||||
0x005c2215, 0x005cdd8f, 0x005d98d0, 0x005e53d8, 0x005f0ea5, 0x005fc937, 0x0060838f, 0x00613dab,
|
||||
0x0061f78b, 0x0062b12e, 0x00636a95, 0x006423be, 0x0064dcaa, 0x00659557, 0x00664dc6, 0x006705f5,
|
||||
0x0067bde5, 0x00687595, 0x00692d05, 0x0069e433, 0x006a9b21, 0x006b51cc, 0x006c0836, 0x006cbe5c,
|
||||
0x006d7440, 0x006e29e0, 0x006edf3d, 0x006f9454, 0x00704927, 0x0070fdb5, 0x0071b1fd, 0x007265ff,
|
||||
0x007319ba, 0x0073cd2f, 0x0074805c, 0x00753341, 0x0075e5dd, 0x00769831, 0x00774a3c, 0x0077fbfe,
|
||||
0x0078ad75, 0x00795ea2, 0x007a0f84, 0x007ac01a, 0x007b7065, 0x007c2064, 0x007cd016, 0x007d7f7c,
|
||||
0x007e2e93, 0x007edd5d, 0x007f8bd9, 0x00803a06, 0x0080e7e4, 0x00819573, 0x008242b1, 0x0082ef9f,
|
||||
0x00839c3d, 0x00844889, 0x0084f484, 0x0085a02c, 0x00864b82, 0x0086f686, 0x0087a136, 0x00884b92,
|
||||
0x0088f59b, 0x00899f4e, 0x008a48ad, 0x008af1b7, 0x008b9a6b, 0x008c42c9, 0x008cead0, 0x008d9281,
|
||||
0x008e39da, 0x008ee0db, 0x008f8784, 0x00902dd5, 0x0090d3cd, 0x0091796b, 0x00921eb0, 0x0092c39a,
|
||||
0x0093682a, 0x00940c5f, 0x0094b039, 0x009553b7, 0x0095f6d9, 0x0096999f, 0x00973c07, 0x0097de12,
|
||||
0x00987fc0, 0x0099210f, 0x0099c200, 0x009a6293, 0x009b02c6, 0x009ba299, 0x009c420c, 0x009ce11f,
|
||||
0x009d7fd1, 0x009e1e22, 0x009ebc12, 0x009f599f, 0x009ff6cb, 0x00a09393, 0x00a12ff9, 0x00a1cbfb,
|
||||
0x00a26799, 0x00a302d3, 0x00a39da9, 0x00a4381a, 0x00a4d225, 0x00a56bcb, 0x00a6050a, 0x00a69de3,
|
||||
0x00a73656, 0x00a7ce61, 0x00a86605, 0x00a8fd41, 0x00a99415, 0x00aa2a80, 0x00aac082, 0x00ab561b,
|
||||
0x00abeb4a, 0x00ac800f, 0x00ad1469, 0x00ada859, 0x00ae3bde, 0x00aecef7, 0x00af61a5, 0x00aff3e6,
|
||||
0x00b085bb, 0x00b11722, 0x00b1a81d, 0x00b238aa, 0x00b2c8c9, 0x00b3587a, 0x00b3e7bc, 0x00b4768f,
|
||||
0x00b504f3, 0x00b592e7, 0x00b6206c, 0x00b6ad7f, 0x00b73a23, 0x00b7c655, 0x00b85216, 0x00b8dd65,
|
||||
0x00b96842, 0x00b9f2ac, 0x00ba7ca4, 0x00bb0629, 0x00bb8f3b, 0x00bc17d9, 0x00bca003, 0x00bd27b8,
|
||||
0x00bdaef9, 0x00be35c5, 0x00bebc1b, 0x00bf41fc, 0x00bfc767, 0x00c04c5c, 0x00c0d0da, 0x00c154e1,
|
||||
0x00c1d870, 0x00c25b89, 0x00c2de29, 0x00c36051, 0x00c3e200, 0x00c46337, 0x00c4e3f5, 0x00c56439,
|
||||
0x00c5e403, 0x00c66354, 0x00c6e22a, 0x00c76085, 0x00c7de65, 0x00c85bca, 0x00c8d8b3, 0x00c95521,
|
||||
0x00c9d112, 0x00ca4c87, 0x00cac77f, 0x00cb41fa, 0x00cbbbf8, 0x00cc3578, 0x00ccae79, 0x00cd26fd,
|
||||
0x00cd9f02, 0x00ce1689, 0x00ce8d90, 0x00cf0417, 0x00cf7a1f, 0x00cfefa8, 0x00d064af, 0x00d0d937,
|
||||
0x00d14d3d, 0x00d1c0c2, 0x00d233c6, 0x00d2a649, 0x00d31849, 0x00d389c7, 0x00d3fac3, 0x00d46b3b,
|
||||
0x00d4db31, 0x00d54aa4, 0x00d5b993, 0x00d627fe, 0x00d695e5, 0x00d70348, 0x00d77026, 0x00d7dc7f,
|
||||
0x00d84853, 0x00d8b3a1, 0x00d91e6a, 0x00d988ad, 0x00d9f26a, 0x00da5ba0, 0x00dac450, 0x00db2c79,
|
||||
0x00db941a, 0x00dbfb34, 0x00dc61c7, 0x00dcc7d1, 0x00dd2d53, 0x00dd924d, 0x00ddf6be, 0x00de5aa6,
|
||||
0x00debe05, 0x00df20db, 0x00df8327, 0x00dfe4e9, 0x00e04621, 0x00e0a6cf, 0x00e106f2, 0x00e1668a,
|
||||
0x00e1c598, 0x00e2241a, 0x00e28210, 0x00e2df7b, 0x00e33c5a, 0x00e398ac, 0x00e3f473, 0x00e44fac,
|
||||
0x00e4aa59, 0x00e50479, 0x00e55e0b, 0x00e5b710, 0x00e60f88, 0x00e66771, 0x00e6becc, 0x00e71599,
|
||||
0x00e76bd8, 0x00e7c187, 0x00e816a8, 0x00e86b39, 0x00e8bf3c, 0x00e912ae, 0x00e96591, 0x00e9b7e4,
|
||||
0x00ea09a7, 0x00ea5ad9, 0x00eaab7b, 0x00eafb8c, 0x00eb4b0c, 0x00eb99fb, 0x00ebe858, 0x00ec3624,
|
||||
0x00ec835e, 0x00ecd007, 0x00ed1c1d, 0x00ed67a1, 0x00edb293, 0x00edfcf2, 0x00ee46be, 0x00ee8ff8,
|
||||
0x00eed89e, 0x00ef20b0, 0x00ef6830, 0x00efaf1b, 0x00eff573, 0x00f03b37, 0x00f08066, 0x00f0c501,
|
||||
0x00f10908, 0x00f14c7a, 0x00f18f57, 0x00f1d19f, 0x00f21352, 0x00f25470, 0x00f294f8, 0x00f2d4eb,
|
||||
0x00f31447, 0x00f3530e, 0x00f3913f, 0x00f3ced9, 0x00f40bdd, 0x00f4484b, 0x00f48422, 0x00f4bf62,
|
||||
0x00f4fa0b, 0x00f5341d, 0x00f56d97, 0x00f5a67b, 0x00f5dec6, 0x00f6167a, 0x00f64d97, 0x00f6841b,
|
||||
0x00f6ba07, 0x00f6ef5b, 0x00f72417, 0x00f7583a, 0x00f78bc5, 0x00f7beb7, 0x00f7f110, 0x00f822d1,
|
||||
0x00f853f8, 0x00f88486, 0x00f8b47b, 0x00f8e3d6, 0x00f91298, 0x00f940c0, 0x00f96e4e, 0x00f99b43,
|
||||
0x00f9c79d, 0x00f9f35e, 0x00fa1e84, 0x00fa4910, 0x00fa7302, 0x00fa9c59, 0x00fac516, 0x00faed37,
|
||||
0x00fb14be, 0x00fb3bab, 0x00fb61fc, 0x00fb87b2, 0x00fbaccd, 0x00fbd14d, 0x00fbf531, 0x00fc187a,
|
||||
0x00fc3b28, 0x00fc5d3a, 0x00fc7eb0, 0x00fc9f8a, 0x00fcbfc9, 0x00fcdf6c, 0x00fcfe73, 0x00fd1cdd,
|
||||
0x00fd3aac, 0x00fd57de, 0x00fd7474, 0x00fd906e, 0x00fdabcc, 0x00fdc68c, 0x00fde0b1, 0x00fdfa38,
|
||||
0x00fe1324, 0x00fe2b72, 0x00fe4323, 0x00fe5a38, 0x00fe70b0, 0x00fe868b, 0x00fe9bc9, 0x00feb069,
|
||||
0x00fec46d, 0x00fed7d4, 0x00feea9d, 0x00fefcc9, 0x00ff0e58, 0x00ff1f49, 0x00ff2f9d, 0x00ff3f54,
|
||||
0x00ff4e6d, 0x00ff5ce9, 0x00ff6ac7, 0x00ff7808, 0x00ff84ab, 0x00ff90b1, 0x00ff9c18, 0x00ffa6e3,
|
||||
0x00ffb10f, 0x00ffba9e, 0x00ffc38f, 0x00ffcbe2, 0x00ffd397, 0x00ffdaaf, 0x00ffe129, 0x00ffe705,
|
||||
0x00ffec43, 0x00fff0e3, 0x00fff4e6, 0x00fff84a, 0x00fffb11, 0x00fffd39, 0x00fffec4, 0x00ffffb1,
|
||||
0x00ffffff,
|
||||
};
|
||||
#else
|
||||
extern const int sf_sin_tab1[513] ;
|
||||
#endif
|
||||
|
||||
|
||||
#define SINE_INT_ZOOM 16384
|
||||
#define SINE_INT_ZBIT 14
|
||||
#define __int64 long long
|
||||
/*软件索引实现sin生成*/
|
||||
static int get_sine_value(int mx_idx)
|
||||
{
|
||||
int ret = 0;
|
||||
int idx = 0;
|
||||
int tm_idx = mx_idx & 0x1FFFFFF; //2^25
|
||||
int phase = tm_idx & 0x3FFF;
|
||||
int tp_idx0 = tm_idx >> 14;
|
||||
int tp_idx1 = tp_idx0 + 1;
|
||||
int sign = 1, dt0, dt1;
|
||||
|
||||
if (tp_idx0 > 1024) {
|
||||
sign = -1;
|
||||
tp_idx0 = 2048 - tp_idx0;
|
||||
}
|
||||
if (tp_idx0 < 513) {
|
||||
dt0 = sf_sin_tab1[tp_idx0];
|
||||
} else {
|
||||
dt0 = sf_sin_tab1[1024 - tp_idx0];
|
||||
}
|
||||
|
||||
if (tp_idx1 > 1024) {
|
||||
sign = -1;
|
||||
tp_idx1 = 2048 - tp_idx1;
|
||||
}
|
||||
if (tp_idx1 < 513) {
|
||||
dt1 = sf_sin_tab1[tp_idx1];
|
||||
} else {
|
||||
dt1 = sf_sin_tab1[1024 - tp_idx1];
|
||||
}
|
||||
|
||||
ret = ((__int64)dt0 * (SINE_INT_ZOOM - phase) + (__int64)dt1 * phase) >> SINE_INT_ZBIT;
|
||||
|
||||
ret *= sign;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void hw_sin_value(int a, int *sin_res, u8 precision)
|
||||
{
|
||||
u64 s64 = a;
|
||||
|
||||
*sin_res = __asm_sine(s64, precision);
|
||||
}
|
||||
|
||||
int sin_tone_make(void *_maker, void *data, int len)
|
||||
{
|
||||
struct audio_sin_maker *maker = (struct audio_sin_maker *)_maker;
|
||||
s16 *pcm = (s16 *)data;
|
||||
int sin_value = 0;
|
||||
int win_sin_value = 0;
|
||||
int add_idx = 0, sub_vol = 0, win_add_idx = 0;
|
||||
int offset = 0;
|
||||
u8 id = maker->id;
|
||||
u8 sin_num = maker->sin_num;
|
||||
u8 repeat = maker->repeat;
|
||||
u8 channel = maker->channel;
|
||||
int sin_index;
|
||||
int win_sin_index;
|
||||
int volume;
|
||||
u32 reamin_points = len / 2 / channel;
|
||||
|
||||
do {
|
||||
if (maker->next_param) {
|
||||
maker->volume = SINE_TOTAL_VOLUME;
|
||||
maker->sin_index = 0;
|
||||
maker->win_sin_index = 0;
|
||||
maker->next_param = 0;
|
||||
}
|
||||
|
||||
u8 win = maker->sin[id].win;
|
||||
add_idx = ((u64)(1 << 25) * maker->sin[id].freq / DEFAULT_SINE_SAMPLE_RATE) >> 9;
|
||||
if (win) {
|
||||
win_add_idx = ((u64)(1 << 25) * maker->sin[id].decay / DEFAULT_SINE_SAMPLE_RATE) >> 9;
|
||||
/*sub_vol = 0;*/
|
||||
} else {
|
||||
sub_vol = maker->sin[id].decay;
|
||||
}
|
||||
|
||||
sin_index = maker->sin_index;
|
||||
win_sin_index = maker->win_sin_index;
|
||||
volume = maker->volume;
|
||||
u32 points = 0;
|
||||
if (maker->fade_points) {
|
||||
points = maker->fade_points > reamin_points ? reamin_points : maker->fade_points;
|
||||
sub_vol = 0;
|
||||
maker->fade_points -= points;
|
||||
} else {
|
||||
points = maker->points > reamin_points ? reamin_points : maker->points;
|
||||
maker->points -= points;
|
||||
}
|
||||
reamin_points -= points;
|
||||
while (points--) {
|
||||
/*hw_sin_value(sin_index, &sin_value, 0);*/
|
||||
sin_value = __asm_sine((s64)sin_index, 2);
|
||||
if (win) {
|
||||
/*hw_sin_value(win_sin_index, &win_sin_value, 0);*/
|
||||
win_sin_value = __asm_sine((s64)win_sin_index, 2);
|
||||
#if ((defined CONFIG_CPU_BR36) || (defined CONFIG_CPU_BR28))
|
||||
sin_value = ((s64)sin_value * (s64)win_sin_value) >> 44;
|
||||
#else
|
||||
sin_value = ((s64)sin_value * (s64)win_sin_value) >> 34;
|
||||
#endif
|
||||
win_sin_index += win_add_idx;
|
||||
win_sin_index &= 0x1ffffff;
|
||||
} else {
|
||||
#if ((defined CONFIG_CPU_BR36) || (defined CONFIG_CPU_BR28))
|
||||
sin_value = ((s64)volume * sin_value) >> 39;
|
||||
#else
|
||||
sin_value = ((s64)volume * sin_value) >> 34;
|
||||
#endif
|
||||
}
|
||||
sin_index += add_idx;
|
||||
sin_index &= 0x1ffffff;
|
||||
|
||||
volume -= sub_vol;
|
||||
if (volume < 0) {
|
||||
volume = 0;
|
||||
}
|
||||
|
||||
*pcm++ = sin_value;
|
||||
if (channel == 2) {
|
||||
*pcm++ = sin_value;
|
||||
} else if (channel == 4) {
|
||||
*pcm++ = sin_value;
|
||||
*pcm++ = sin_value;
|
||||
*pcm++ = sin_value;
|
||||
}
|
||||
}
|
||||
|
||||
maker->volume = volume;
|
||||
maker->sin_index = sin_index;
|
||||
maker->win_sin_index = win_sin_index;
|
||||
if (!maker->points) {
|
||||
if (++id >= sin_num) {
|
||||
if (!repeat) {
|
||||
break;
|
||||
}
|
||||
id = 0;
|
||||
}
|
||||
maker->points = maker->sin[id].points;
|
||||
maker->id = id;
|
||||
maker->next_param = 1;
|
||||
}
|
||||
|
||||
if (!reamin_points) {
|
||||
break;
|
||||
}
|
||||
} while (1);
|
||||
|
||||
return len - (reamin_points * 2 * channel);
|
||||
}
|
||||
|
||||
int sin_tone_points(void *_maker)
|
||||
{
|
||||
struct audio_sin_maker *maker = (struct audio_sin_maker *)_maker;
|
||||
int points = 0;
|
||||
u8 i = 0;
|
||||
|
||||
for (i = 0; i < maker->sin_num; i++) {
|
||||
points += maker->sin[i].points;
|
||||
}
|
||||
|
||||
return points;
|
||||
}
|
||||
|
||||
void sin_tone_close(void *_maker)
|
||||
{
|
||||
struct audio_sin_maker *maker = (struct audio_sin_maker *)_maker;
|
||||
|
||||
#ifdef SINE_USE_MALLOC
|
||||
if (maker) {
|
||||
free(maker);
|
||||
}
|
||||
#else
|
||||
if (sin_maker_handle.open) {
|
||||
sin_maker_handle.open = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#include "asm/math_fast_function.h"
|
||||
|
||||
#ifndef DATA16
|
||||
#define DATA16 32767
|
||||
#endif
|
||||
|
||||
/*********************************
|
||||
* fc : 正弦波中心频率
|
||||
* fs : 采样频率
|
||||
* FrameSize :每次计算输出点数
|
||||
* idx :当前计算起始indix
|
||||
* rst :结果存放地址
|
||||
* *******************************/
|
||||
void SinWave_Generator(int fc, int fs, int FrameSize, int idx, short *rst)
|
||||
{
|
||||
float tmp0, tmp1, tmp2;
|
||||
tmp0 = (float)fc / fs;
|
||||
for (int i = 0; i < FrameSize; i++) {
|
||||
tmp1 = (i + idx) * tmp0 * 2;
|
||||
tmp2 = sin_float(tmp1);
|
||||
*rst = (short)(tmp2 * DATA16);
|
||||
rst++;
|
||||
}
|
||||
}
|
||||
/*********************************
|
||||
* fs : 采样频率
|
||||
* FrameSize :每次计算输出点数
|
||||
* idx :当前计算起始indix
|
||||
* ts :期望一次扫频所持续时间
|
||||
* rst :结果存放地址
|
||||
* *******************************/
|
||||
void SweepSin_Generator(int fs, int FrameSize, int idx, float ts, short *rst)
|
||||
{
|
||||
float fp, fc, tmp1, tmp2;
|
||||
int Ncnt, NPoint, DPoint;
|
||||
|
||||
NPoint = fs * ts;
|
||||
// fp = (fs/2)/(fs*ts);
|
||||
fp = 1 / (2 * 2 * ts);
|
||||
|
||||
for (int i = 0; i < FrameSize; i++) {
|
||||
Ncnt = (i + idx) / NPoint;
|
||||
DPoint = (i + idx) - Ncnt * NPoint;
|
||||
//printf("idx:%d \n",DPoint);
|
||||
tmp1 = ((DPoint * fp) / fs) * DPoint * 2;
|
||||
tmp2 = sin_float(tmp1);
|
||||
//printf("Sin[%d]:%d",i,(int)(tmp2*1000));
|
||||
*rst = (short)(tmp2 * DATA16);
|
||||
rst++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* Description: 正弦信号生成
|
||||
* Arguments : fc 信号中心频率
|
||||
* fs 信号采样率
|
||||
* buf 数据输出地址
|
||||
* len 数据生成长度,单位是bytes
|
||||
* Return : None.
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
int sin_idx = 0;
|
||||
void sin_pcm_fill(int fc, int fs, void *buf, u32 len)
|
||||
{
|
||||
SinWave_Generator(fc, fs, len / 2, sin_idx, buf);
|
||||
sin_idx += len / 2;
|
||||
}
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* Description: 扫频信号生成
|
||||
* Arguments : fs 信号采样率
|
||||
* buf 数据输出地址
|
||||
* len 数据生成长度,单位是bytes
|
||||
* Return : None.
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
int sweep_sin_idx = 0;
|
||||
void sweepsin_pcm_fill(int fs, void *buf, u32 len)
|
||||
{
|
||||
SweepSin_Generator(fs, len / 2, sweep_sin_idx, 25, buf);
|
||||
sweep_sin_idx += len / 2;
|
||||
}
|
||||
47
apps/common/audio/sine_make.h
Normal file
47
apps/common/audio/sine_make.h
Normal file
@ -0,0 +1,47 @@
|
||||
#ifndef __SINE_MAKE_H_
|
||||
#define __SINE_MAKE_H_
|
||||
|
||||
#include "generic/typedef.h"
|
||||
|
||||
#define DEFAULT_SINE_SAMPLE_RATE 16000
|
||||
#define SINE_TOTAL_VOLUME 26843546//16106128//20132660 //26843546
|
||||
|
||||
struct sin_param {
|
||||
//int idx_increment;
|
||||
int freq;
|
||||
int points;
|
||||
int win;
|
||||
int decay;
|
||||
};
|
||||
|
||||
int sin_tone_make(void *_maker, void *data, int len);
|
||||
void *sin_tone_open(const struct sin_param *param, int num, u8 channel, u8 repeat);
|
||||
int sin_tone_points(void *_maker);
|
||||
void sin_tone_close(void *_maker);
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* Description: 正弦信号生成
|
||||
* Arguments : fc 信号中心频率
|
||||
* fs 信号采样率
|
||||
* buf 数据输出地址
|
||||
* len 数据生成长度,单位是bytes
|
||||
* Return : None.
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
void sin_pcm_fill(int fc, int fs, void *buf, u32 len);
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* Description: 扫频信号生成
|
||||
* Arguments : fs 信号采样率
|
||||
* buf 数据输出地址
|
||||
* len 数据生成长度,单位是bytes
|
||||
* Return : None.
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
void sweepsin_pcm_fill(int fs, void *buf, u32 len);
|
||||
|
||||
#endif/*__SINE_MAKE_H_*/
|
||||
20
apps/common/audio/stream/stream_entry.h
Normal file
20
apps/common/audio/stream/stream_entry.h
Normal file
@ -0,0 +1,20 @@
|
||||
#ifndef __STREAM_ENTRY_H__
|
||||
#define __STREAM_ENTRY_H__
|
||||
|
||||
#include "system/includes.h"
|
||||
#include "media/includes.h"
|
||||
|
||||
// struct __stream_entry;
|
||||
struct __stream_entry {
|
||||
u8 is_end;
|
||||
void *data_priv;
|
||||
int (*data_callback)(void *priv, struct audio_data_frame *in);
|
||||
struct audio_stream_entry entry;
|
||||
};
|
||||
|
||||
struct __stream_entry *stream_entry_open(void *priv, int (*data_callback)(void *priv, struct audio_data_frame *in), u8 is_end);
|
||||
void stream_entry_close(struct __stream_entry **hdl);
|
||||
void stream_entry_resume(struct __stream_entry *hdl);
|
||||
|
||||
#endif// __STREAM_ENTRY_H__
|
||||
|
||||
129
apps/common/audio/uartPcmSender.c
Normal file
129
apps/common/audio/uartPcmSender.c
Normal file
@ -0,0 +1,129 @@
|
||||
#include "app_config.h"
|
||||
|
||||
#ifdef AUDIO_PCM_DEBUG
|
||||
#include "system/includes.h"
|
||||
#include "asm/uart_dev.h"
|
||||
#include "uartPcmSender.h"
|
||||
|
||||
static u8 uart_cbuf[32] __attribute__((aligned(4)));
|
||||
const uart_bus_t *uart_bus = NULL;
|
||||
|
||||
//设备事件响应demo
|
||||
void uart_event_handler(struct sys_event *e)
|
||||
{
|
||||
u8 uart_rxbuf[12] = {0};
|
||||
u8 uart_txbuf[12] = {0};
|
||||
const uart_bus_t *_uart_bus;
|
||||
u32 uart_rxcnt = 0;
|
||||
u8 i = 0;
|
||||
|
||||
if (0) {//!strcmp(e->arg, "uart_rx_overflow")) {
|
||||
if (e->u.dev.event == DEVICE_EVENT_CHANGE) {
|
||||
printf("uart event: %s\n", e->arg);
|
||||
_uart_bus = (const uart_bus_t *)e->u.dev.value;
|
||||
uart_rxcnt = _uart_bus->read(uart_rxbuf, sizeof(uart_rxbuf), 0);
|
||||
if (uart_rxcnt) {
|
||||
g_printf("rx:%s", uart_rxbuf);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (0) { //(!strcmp(e->arg, "uart_rx_outtime")) {
|
||||
if (e->u.dev.event == DEVICE_EVENT_CHANGE) {
|
||||
printf("uart event: %s\n", e->arg);
|
||||
_uart_bus = (const uart_bus_t *)e->u.dev.value;
|
||||
uart_rxcnt = _uart_bus->read(uart_rxbuf, sizeof(uart_rxbuf), 0);
|
||||
if (uart_rxcnt) {
|
||||
printf("get_buffer:\n");
|
||||
for (int i = 0; i < uart_rxcnt; i++) {
|
||||
putbyte(uart_rxbuf[i]);
|
||||
if (i % 16 == 15) {
|
||||
putchar('\n');
|
||||
}
|
||||
}
|
||||
if (uart_rxcnt % 16) {
|
||||
putchar('\n');
|
||||
}
|
||||
_uart_bus->write(uart_rxbuf, uart_rxcnt);
|
||||
}
|
||||
printf("uart out\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
SYS_EVENT_HANDLER(SYS_DEVICE_EVENT, uart_event_handler, 0);
|
||||
|
||||
void gpio_change(void *priv);
|
||||
static void uart_isr_hook(void *arg, u32 status)
|
||||
{
|
||||
const uart_bus_t *ubus = arg;
|
||||
struct sys_event e;
|
||||
|
||||
//当CONFIG_UARTx_ENABLE_TX_DMA(x = 0, 1)为1时,不要在中断里面调用ubus->write(),因为中断不能pend信号量
|
||||
if (status == UT_RX) {
|
||||
printf("uart_rx_isr\n");
|
||||
#if 1//(UART_DEV_USAGE_TEST_SEL == 1)
|
||||
e.type = SYS_DEVICE_EVENT;
|
||||
e.arg = "uart_rx_overflow";
|
||||
e.u.dev.event = DEVICE_EVENT_CHANGE;
|
||||
e.u.dev.value = (int)ubus;
|
||||
sys_event_notify(&e);
|
||||
#endif
|
||||
}
|
||||
if (status == UT_RX_OT) {
|
||||
printf("uart_rx_ot_isr\n");
|
||||
#if 1//(UART_DEV_USAGE_TEST_SEL == 1)
|
||||
e.type = SYS_DEVICE_EVENT;
|
||||
e.arg = "uart_rx_outtime";
|
||||
e.u.dev.event = DEVICE_EVENT_CHANGE;
|
||||
e.u.dev.value = (int)ubus;
|
||||
sys_event_notify(&e);
|
||||
#endif
|
||||
}
|
||||
if (status == UT_TX) {
|
||||
/* putchar('T'); */
|
||||
/* gpio_change(0); */
|
||||
}
|
||||
}
|
||||
|
||||
void uartSendData(void *buf, u16 len) //发送数据的接口。
|
||||
{
|
||||
if (uart_bus) {
|
||||
uart_bus->write(buf, len); //把数据写到DMA
|
||||
}
|
||||
}
|
||||
|
||||
/* char *TickPage = "uart online"; */
|
||||
/* void uartTickSend(void *priv){ */
|
||||
/* if(uartTickSendFlag){ */
|
||||
/* r_printf("sizeof:%d\n", sizeof(TickPage)); */
|
||||
/* uartSendData(TickPage, sizeof(TickPage)); */
|
||||
/* } */
|
||||
/* } */
|
||||
|
||||
void uartSendInit()
|
||||
{
|
||||
struct uart_platform_data_t u_arg = {0};
|
||||
u_arg.tx_pin = PCM_UART1_TX_PORT;
|
||||
u_arg.rx_pin = PCM_UART1_RX_PORT;
|
||||
u_arg.rx_cbuf = uart_cbuf;
|
||||
u_arg.rx_cbuf_size = 32;
|
||||
u_arg.frame_length = 6;
|
||||
u_arg.rx_timeout = 100;
|
||||
u_arg.isr_cbfun = uart_isr_hook;
|
||||
u_arg.baud = PCM_UART1_BAUDRATE;
|
||||
u_arg.is_9bit = 0;
|
||||
|
||||
|
||||
r_printf("uart_dev_open() ...\n");
|
||||
uart_bus = uart_dev_open(&u_arg);
|
||||
r_printf("comming %s,%d\n", __func__, __LINE__);
|
||||
if (uart_bus != NULL) {
|
||||
r_printf("success\n");
|
||||
gpio_set_hd(PCM_UART1_TX_PORT, 1);
|
||||
gpio_set_hd0(PCM_UART1_TX_PORT, 1);
|
||||
//os_task_create(uart_u_task, (void *)uart_bus, 31, 512, 0, "uart_u_task");
|
||||
} else {
|
||||
r_printf("false\n");
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
21
apps/common/audio/uartPcmSender.h
Normal file
21
apps/common/audio/uartPcmSender.h
Normal file
@ -0,0 +1,21 @@
|
||||
#ifndef _UARTPCMSENDER_H_
|
||||
#define _UARTPCMSENDER_H_
|
||||
#include "system/includes.h"
|
||||
#include "app_config.h"
|
||||
/*
|
||||
*串口导出数据配置
|
||||
*注意IO口设置不要和普通log输出uart冲突
|
||||
*/
|
||||
#define PCM_UART1_TX_PORT IO_PORT_DM /*数据导出发送IO*/
|
||||
#define PCM_UART1_RX_PORT -1
|
||||
#define PCM_UART1_BAUDRATE 2000000 /*数据导出波特率,不用修改,和接收端设置一直*/
|
||||
|
||||
#if ((TCFG_UART0_ENABLE == ENABLE_THIS_MOUDLE) && (PCM_UART1_TX_PORT == TCFG_UART0_TX_PORT))
|
||||
//IO口配置冲突,请检查修改
|
||||
#error "PCM_UART1_TX_PORT conflict with TCFG_UART0_TX_PORT"
|
||||
#endif/*PCM_UART1_TX_PORT*/
|
||||
|
||||
void uartSendInit(); //串口发数初始化
|
||||
void uartSendData(void *buf, u16 len); //发送数据的接口
|
||||
|
||||
#endif /*_UARTPCMSENDER_H_*/
|
||||
414
apps/common/audio/wm8978/iic.c
Normal file
414
apps/common/audio/wm8978/iic.c
Normal file
@ -0,0 +1,414 @@
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/**@file iic_io.c
|
||||
@brief IO模拟的IIC的驱动
|
||||
@details
|
||||
@author zhiying
|
||||
@date 2013-3-26
|
||||
@note
|
||||
*/
|
||||
/*----------------------------------------------------------------------------*/
|
||||
#include "iic.h"
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/** @brief: IIC 模块初始化函数
|
||||
@param: void
|
||||
@return:void
|
||||
@author:Juntham
|
||||
@note: void iic_init_io(void)
|
||||
*/
|
||||
/*----------------------------------------------------------------------------*/
|
||||
void iic_init_io(void)
|
||||
{
|
||||
iic_data_h();
|
||||
iic_data_out(); //SDA设置成输出
|
||||
iic_clk_h();
|
||||
iic_clk_out(); //SCL设置成输出
|
||||
}
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/**@brief
|
||||
@param 无
|
||||
@return
|
||||
@note
|
||||
*/
|
||||
/*----------------------------------------------------------------------------*/
|
||||
void iic_start(void)
|
||||
{
|
||||
iic_init_io();
|
||||
iic_delay();
|
||||
iic_data_l();
|
||||
iic_delay();
|
||||
iic_clk_l();
|
||||
iic_delay();
|
||||
//iic_data_h();
|
||||
}
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/**@brief STOP IIC
|
||||
@param 无
|
||||
@return 无
|
||||
@note void iic_stop(void)
|
||||
*/
|
||||
/*----------------------------------------------------------------------------*/
|
||||
void iic_stop(void)
|
||||
{
|
||||
iic_data_out();
|
||||
iic_data_l();
|
||||
iic_delay();
|
||||
iic_clk_h();
|
||||
iic_delay();
|
||||
iic_data_h();
|
||||
iic_delay();
|
||||
}
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/**@brief 读取ACK
|
||||
@param 无
|
||||
@return 都会的ACK/NACK的电平
|
||||
@note tbool r_ack(void)
|
||||
*/
|
||||
/*----------------------------------------------------------------------------*/
|
||||
tbool r_ack(void)
|
||||
{
|
||||
tbool tnack;
|
||||
iic_data_in();
|
||||
iic_delay();
|
||||
iic_clk_h();
|
||||
iic_delay();
|
||||
iic_delay();
|
||||
iic_delay();
|
||||
iic_delay();
|
||||
iic_delay();
|
||||
tnack = iic_data_r();
|
||||
iic_clk_l();
|
||||
iic_delay();
|
||||
return tnack;
|
||||
}
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/**@brief 发送一个ACK信号的数据,
|
||||
@param flag :发送的ACK/nack的类型
|
||||
@return 无
|
||||
@note void s_ack(u8 flag)
|
||||
*/
|
||||
/*----------------------------------------------------------------------------*/
|
||||
void s_ack(u8 flag)
|
||||
{
|
||||
iic_data_out();
|
||||
iic_clk_l();
|
||||
if (flag) {
|
||||
iic_data_h();
|
||||
} else {
|
||||
iic_data_l();
|
||||
}
|
||||
iic_delay();
|
||||
iic_clk_h();
|
||||
iic_delay();
|
||||
iic_clk_l();
|
||||
}
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/**@brief 从IIC总线接收一个BYTE的数据,
|
||||
@param 无
|
||||
@return 读取回的数据
|
||||
@note u8 iic_revbyte_io( void )
|
||||
*/
|
||||
/*----------------------------------------------------------------------------*/
|
||||
tu8 iic_revbyte_io(void)
|
||||
{
|
||||
u8 tbyteI2C = 0X00;
|
||||
u8 i;
|
||||
iic_data_in();
|
||||
iic_delay();
|
||||
for (i = 0; i < 8; i++) {
|
||||
iic_clk_h();
|
||||
tbyteI2C <<= 1;
|
||||
iic_delay();
|
||||
if (iic_data_r()) {
|
||||
tbyteI2C++;
|
||||
}
|
||||
iic_clk_l();
|
||||
iic_delay();
|
||||
}
|
||||
return tbyteI2C;
|
||||
}
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/**@brief 从IIC总线接收一个BYTE的数据,并发送一个指定的ACK
|
||||
@param para :发送ACK 还是 NACK
|
||||
@return 读取回的数据
|
||||
@note u8 iic_revbyte( u8 para )
|
||||
*/
|
||||
/*----------------------------------------------------------------------------*/
|
||||
tu8 iic_revbyte(u8 para)
|
||||
{
|
||||
u8 tbyte;
|
||||
tbyte = iic_revbyte_io();
|
||||
s_ack(para);
|
||||
delay(30000);
|
||||
return tbyte;
|
||||
}
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/**@brief 向IIC总线发送一个BYTE的数据
|
||||
@param byte :要写的EEROM的地址
|
||||
@return 无
|
||||
@note void iic_sendbyte_io(u8 byte)
|
||||
*/
|
||||
/*----------------------------------------------------------------------------*/
|
||||
void iic_sendbyte_io(u8 byte)
|
||||
{
|
||||
u8 i;
|
||||
iic_data_out();
|
||||
iic_delay();
|
||||
//otp_printf("byte: %02x\n", byte);
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (byte & BIT(7)) {
|
||||
iic_data_h(); //最高位是否为1,为1则SDA= 1,否则 SDA=0
|
||||
} else {
|
||||
iic_data_l();
|
||||
}
|
||||
iic_delay();
|
||||
iic_clk_h();
|
||||
iic_delay();
|
||||
byte <<= 1; //数据左移一位,进入下一轮送数
|
||||
iic_clk_l();
|
||||
iic_delay();
|
||||
}
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/**@brief 向IIC总线发送一个BYTE的数据,并读取ACK
|
||||
@param byte :要写的EEROM的地址
|
||||
@return 无
|
||||
@note void iic_sendbyte(u8 byte)
|
||||
*/
|
||||
/*----------------------------------------------------------------------------*/
|
||||
void iic_sendbyte(u8 byte)
|
||||
{
|
||||
iic_sendbyte_io(byte);
|
||||
r_ack();
|
||||
delay(30000);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///------------------------------------------------------------------------------
|
||||
///------------------------------------IIC_API-----------------------------------
|
||||
///------------------------------------------------------------------------------
|
||||
|
||||
|
||||
bool g_iic_busy = 0; ///<iic繁忙标记
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/** @brief: IIC 模块初始化函数
|
||||
@param: void
|
||||
@return:void
|
||||
@author:Juntham
|
||||
@note: void iic_init(void)
|
||||
*/
|
||||
/*----------------------------------------------------------------------------*/
|
||||
void iic_init(void)
|
||||
{
|
||||
// iic_data_out();
|
||||
iic_data_h();
|
||||
iic_data_out();
|
||||
//iic_clk_out();
|
||||
iic_clk_h(); ///<配置接口函数IO
|
||||
iic_clk_out();
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/** @brief: eeprom 核实
|
||||
@param: void
|
||||
@return:void
|
||||
@author:Juntham
|
||||
@note: void eeprom_verify(void)
|
||||
*/
|
||||
/*----------------------------------------------------------------------------*/
|
||||
void eeprom_verify(void)
|
||||
{
|
||||
puts("eeprom_verify 1\n");
|
||||
|
||||
if ((read_eerom(0) != 0x55)
|
||||
|| (read_eerom(1) != 0xAA)) {
|
||||
write_eerom(0, 0x55);
|
||||
write_eerom(1, 0xAA);
|
||||
}
|
||||
|
||||
puts("eeprom_verify 2\n");
|
||||
if ((read_eerom(0) != 0x55)
|
||||
|| (read_eerom(1) != 0xAA)) {
|
||||
puts("iic-no\n");//外接eeprom无效
|
||||
} else {
|
||||
puts("iic-yes\n"); //有外接eeprom
|
||||
}
|
||||
}
|
||||
|
||||
void iic_write_one_byte(u8 iic_dat)
|
||||
{
|
||||
g_iic_busy = 1;
|
||||
iic_start(); //I2C启动
|
||||
iic_sendbyte(iic_dat); //写数据
|
||||
iic_stop(); //I2C停止时序
|
||||
}
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/**@brief IIC写函数
|
||||
@param chip_id :目标IC的ID号
|
||||
@param iic_addr: 目标IC的目标寄存器的地址
|
||||
@param *iic_dat: 写望目标IC的数据的指针
|
||||
@param n:需要写的数据的数目
|
||||
@return 无
|
||||
@note void iic_write(u8 chip_id,u8 iic_addr,u8 *iic_dat,u8 n)
|
||||
*/
|
||||
/*----------------------------------------------------------------------------*/
|
||||
void iic_write(u8 chip_id, u8 iic_addr, u8 *iic_dat, u8 n)
|
||||
{
|
||||
g_iic_busy = 1;
|
||||
iic_start(); //I2C启动
|
||||
iic_sendbyte(chip_id); //写命令
|
||||
|
||||
if (0xff != iic_addr) {
|
||||
iic_sendbyte(iic_addr); //写地址
|
||||
}
|
||||
for (; n > 0; n--) {
|
||||
iic_sendbyte(*iic_dat++); //写数据
|
||||
}
|
||||
iic_stop(); //I2C停止时序
|
||||
g_iic_busy = 0;
|
||||
}
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/**@brief IIC总线向一个目标ID读取几个数据
|
||||
@param address : 目标ID
|
||||
@param *p : 存档读取到的数据的buffer指针
|
||||
@param number : 需要读取的数据的个数
|
||||
@return 无
|
||||
@note void i2c_read_nbyte(u8 address,u8 *p,u8 number)
|
||||
*/
|
||||
/*----------------------------------------------------------------------------*/
|
||||
void iic_readn(u8 chip_id, u8 iic_addr, u8 *iic_dat, u8 n)
|
||||
{
|
||||
g_iic_busy = 1;
|
||||
iic_start(); //I2C启动
|
||||
iic_sendbyte(chip_id); //写命令
|
||||
if (0xff != iic_addr) {
|
||||
iic_sendbyte(iic_addr); //写地址
|
||||
}
|
||||
for (; n > 1; n--) {
|
||||
*iic_dat++ = iic_revbyte(0); //读数据
|
||||
}
|
||||
*iic_dat++ = iic_revbyte(1);
|
||||
iic_stop(); //I2C停止时序
|
||||
g_iic_busy = 0;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/**@brief EEROM/RTC RAM读函数
|
||||
@param addr :要写的EEROM/RTC RAM的地址
|
||||
@return 读到的数据
|
||||
@note u8 read_info(u8 addr)
|
||||
*/
|
||||
/*----------------------------------------------------------------------------*/
|
||||
tu8 read_info(u8 addr)
|
||||
{
|
||||
return read_eerom(addr);
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/**@brief EEROM/RTC RAM写函数
|
||||
@param addr :要读的EEROM/RTC RAM的地址
|
||||
@param dat :需要读的数据
|
||||
@return 无
|
||||
@note void write_info(u8 addr,u8 dat)
|
||||
*/
|
||||
/*----------------------------------------------------------------------------*/
|
||||
void write_info(u8 addr, u8 dat)
|
||||
{
|
||||
write_eerom(addr, dat);
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/**@brief eeprom START
|
||||
@param 无
|
||||
@return 无
|
||||
@note void eeprom_page_write_start(void)
|
||||
*/
|
||||
/*----------------------------------------------------------------------------*/
|
||||
void eeprom_page_write_start(void)
|
||||
{
|
||||
g_iic_busy = 1;
|
||||
iic_start(); //I2C启动
|
||||
iic_sendbyte(0xa0); //写命令
|
||||
}
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/**@brief IIC STOP
|
||||
@param 无
|
||||
@return 无
|
||||
@note void eeprom_page_write_stop(void)
|
||||
*/
|
||||
/*----------------------------------------------------------------------------*/
|
||||
void eeprom_page_write_stop(void)
|
||||
{
|
||||
iic_stop(); //I2C停止iic_data_out
|
||||
g_iic_busy = 0;
|
||||
}
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/**@brief EEROM读函数
|
||||
@param addr :要写的EEROM的地址
|
||||
@param 无
|
||||
@return 无
|
||||
@note u8 iic_read(u8 iic_addr)
|
||||
*/
|
||||
/*----------------------------------------------------------------------------*/
|
||||
tu8 read_eerom(u8 iic_addr)
|
||||
{
|
||||
u8 tbyte;
|
||||
g_iic_busy = 1;
|
||||
iic_start(); //I2C启动
|
||||
iic_sendbyte(0xa0); //写命令
|
||||
iic_sendbyte(iic_addr); //写地址
|
||||
iic_start(); //写转为读命令,需要再次启动I2C
|
||||
iic_sendbyte(0xa1); //读命令
|
||||
tbyte = iic_revbyte(1);
|
||||
iic_stop(); //I2C停止
|
||||
g_iic_busy = 0;
|
||||
return tbyte;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/**@brief 带有毫秒延时的EEROM写函数
|
||||
@param addr :要写的EEROM的地址
|
||||
@param dat :需要写的数据
|
||||
@return 无
|
||||
@note void write_info(u8 addr,u8 dat)
|
||||
*/
|
||||
/*----------------------------------------------------------------------------*/
|
||||
void write_eerom(u8 addr, u8 dat)
|
||||
{
|
||||
iic_write(0xa0, addr, &dat, 1);
|
||||
iic_delay();
|
||||
iic_delay();
|
||||
iic_delay();
|
||||
iic_delay();
|
||||
iic_delay();
|
||||
iic_delay();
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/** @brief: 记忆信息到存储器(EEPROM)
|
||||
@param: void
|
||||
@return:void
|
||||
@author:Juntham
|
||||
@note: void set_memory(u8 addr, u8 dat)
|
||||
*/
|
||||
/*----------------------------------------------------------------------------*/
|
||||
void set_memory(u8 addr, u8 dat)
|
||||
{
|
||||
write_eerom(addr, dat);
|
||||
}
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/** @brief: 获取记忆信息(EEPROM)
|
||||
@param: void
|
||||
@return:void
|
||||
@author:Juntham
|
||||
@note: u8 get_memory(u8 addr)
|
||||
*/
|
||||
/*----------------------------------------------------------------------------*/
|
||||
u8 get_memory(u8 addr)
|
||||
{
|
||||
return read_eerom(addr);
|
||||
}
|
||||
63
apps/common/audio/wm8978/iic.h
Normal file
63
apps/common/audio/wm8978/iic.h
Normal file
@ -0,0 +1,63 @@
|
||||
#ifndef _IIC_H_
|
||||
#define _IIC_H_
|
||||
|
||||
#include "generic/typedef.h"
|
||||
typedef unsigned int tu8, tbool ;
|
||||
|
||||
void iic_write(u8 chip_id, u8 iic_addr, u8 *iic_dat, u8 n);
|
||||
void iic_readn(u8 chip_id, u8 iic_addr, u8 *iic_dat, u8 n);
|
||||
void iic_init(void);
|
||||
void iic_init_io(void);
|
||||
void write_info(u8 addr, u8 dat);
|
||||
tu8 read_info(u8 addr);
|
||||
|
||||
void write_eerom(u8 addr, u8 dat);
|
||||
tu8 read_eerom(u8 iic_addr);
|
||||
void eeprom_page_write_stop(void);
|
||||
void eeprom_page_write_start(void);
|
||||
void eeprom_verify(void);
|
||||
|
||||
void iic_start(void);
|
||||
void iic_stop(void);
|
||||
void iic_sendbyte_io(u8 byte);
|
||||
void iic_sendbyte(u8 byte);
|
||||
tu8 iic_revbyte(u8 para);
|
||||
|
||||
extern bool g_iic_busy;
|
||||
|
||||
//#define iic_delay() delay(3000)
|
||||
#define iic_delay() delay(100)
|
||||
|
||||
|
||||
#define IIC_PORT JL_PORTB
|
||||
#define IIC_DATA_PORT 5
|
||||
#define IIC_CLK_PORT 6
|
||||
|
||||
#define iic_clk_out() do{IIC_PORT->DIR &= ~BIT(IIC_CLK_PORT);IIC_PORT->PU &= ~BIT(IIC_CLK_PORT);}while(0)
|
||||
#define iic_clk_h() do{IIC_PORT->OUT |= BIT(IIC_CLK_PORT);IIC_PORT->DIR &=~BIT(IIC_CLK_PORT);}while(0)
|
||||
#define iic_clk_l() do{IIC_PORT->OUT &=~BIT(IIC_CLK_PORT);IIC_PORT->DIR &=~BIT(IIC_CLK_PORT);}while(0)
|
||||
|
||||
#define iic_data_out() do{IIC_PORT->DIR &= ~BIT(IIC_DATA_PORT);IIC_PORT->PU &= ~BIT(IIC_DATA_PORT);}while(0)
|
||||
#define iic_data_in() do{IIC_PORT->DIR |= BIT(IIC_DATA_PORT);IIC_PORT->PU |= BIT(IIC_DATA_PORT);}while(0)
|
||||
#define iic_data_r() (IIC_PORT->IN&BIT(IIC_DATA_PORT))
|
||||
#define iic_data_h() do{IIC_PORT->OUT |= BIT(IIC_DATA_PORT);IIC_PORT->DIR &= ~BIT(IIC_DATA_PORT);}while(0)
|
||||
#define iic_data_l() do{IIC_PORT->OUT &=~BIT(IIC_DATA_PORT);IIC_PORT->DIR &= ~BIT(IIC_DATA_PORT);}while(0)
|
||||
|
||||
/*
|
||||
#define app_IIC_write(a, b, c, d) \
|
||||
iic_write(a, b, c, d)
|
||||
#define app_IIC_readn(a, b, c, d) \
|
||||
iic_readn(a, b, c, d)
|
||||
#define app_E2PROM_write(a, b) \
|
||||
write_eerom(a, b)
|
||||
#define app_E2PROM_read(a) \
|
||||
read_eerom(a)
|
||||
*/
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
359
apps/common/audio/wm8978/wm8978.c
Normal file
359
apps/common/audio/wm8978/wm8978.c
Normal file
@ -0,0 +1,359 @@
|
||||
#include "iic.h"
|
||||
#include "wm8978.h"
|
||||
|
||||
extern tbool r_ack(void);
|
||||
//--------------------------------------------------------------------------------
|
||||
#define IIC_Init iic_init_io
|
||||
#define IIC_Start iic_start
|
||||
#define IIC_Stop iic_stop
|
||||
#define IIC_Send_Byte iic_sendbyte_io
|
||||
#define IIC_Wait_Ack r_ack
|
||||
|
||||
|
||||
|
||||
|
||||
//WM8978寄存器值缓存区(总共58个寄存器,0~57),占用116字节内存
|
||||
//因为WM8978的IIC操作不支持读操作,所以在本地保存所有寄存器值
|
||||
//写WM8978寄存器时,同步更新到本地寄存器值,读寄存器时,直接返回本地保存的寄存器值.
|
||||
//注意:WM8978的寄存器值是9位的,所以要用u16来存储.
|
||||
static u16 WM8978_REGVAL_TBL[58] = {
|
||||
0X0000, 0X0000, 0X0000, 0X0000, 0X0050, 0X0000, 0X0140, 0X0000,
|
||||
0X0000, 0X0000, 0X0000, 0X00FF, 0X00FF, 0X0000, 0X0100, 0X00FF,
|
||||
0X00FF, 0X0000, 0X012C, 0X002C, 0X002C, 0X002C, 0X002C, 0X0000,
|
||||
0X0032, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000,
|
||||
0X0038, 0X000B, 0X0032, 0X0000, 0X0008, 0X000C, 0X0093, 0X00E9,
|
||||
0X0000, 0X0000, 0X0000, 0X0000, 0X0003, 0X0010, 0X0010, 0X0100,
|
||||
0X0100, 0X0002, 0X0001, 0X0001, 0X0039, 0X0039, 0X0039, 0X0039,
|
||||
0X0001, 0X0001
|
||||
};
|
||||
|
||||
//WM8978写寄存器
|
||||
//reg:寄存器地址
|
||||
//val:要写入寄存器的值
|
||||
//返回值:0,成功;
|
||||
// 其他,错误代码
|
||||
u8 WM8978_Write_Reg(u8 reg, u16 val)
|
||||
{
|
||||
IIC_Start();
|
||||
IIC_Send_Byte((WM8978_ADDR << 1) | 0); //发送器件地址+写命令
|
||||
if (IIC_Wait_Ack()) {
|
||||
return 1; //等待应答(成功?/失败?)
|
||||
}
|
||||
IIC_Send_Byte((reg << 1) | ((val >> 8) & 0X01)); //写寄存器地址+数据的最高位
|
||||
if (IIC_Wait_Ack()) {
|
||||
return 2; //等待应答(成功?/失败?)
|
||||
}
|
||||
IIC_Send_Byte(val & 0XFF); //发送数据
|
||||
if (IIC_Wait_Ack()) {
|
||||
return 3; //等待应答(成功?/失败?)
|
||||
}
|
||||
IIC_Stop();
|
||||
WM8978_REGVAL_TBL[reg] = val; //保存寄存器值到本地
|
||||
return 0;
|
||||
}
|
||||
|
||||
//WM8978初始化
|
||||
//返回值:0,初始化正常
|
||||
//其他,错误代码
|
||||
u8 WM8978_Init(u8 dacen, u8 adcen)
|
||||
{
|
||||
u8 res;
|
||||
IIC_Init();//初始化IIC接口
|
||||
|
||||
int i = 10;
|
||||
while (--i) {
|
||||
res = WM8978_Write_Reg(0, 0); //软复位WM8978
|
||||
if (!res) {
|
||||
printf("wm8978 reset ok,i=%d\n", i);
|
||||
break;
|
||||
} else {
|
||||
printf("wm8978 cmu err!!!\n");
|
||||
}
|
||||
delay(50000);
|
||||
}
|
||||
if (0 == i) {
|
||||
printf("Rest WM8978 10 times FAIL\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
//以下为通用设置
|
||||
WM8978_Write_Reg(1, 0X1B); //R1,MICEN设置为1(MIC使能),BIASEN设置为1(模拟器工作),VMIDSEL[1:0]设置为:11(5K)
|
||||
WM8978_Write_Reg(2, 0X1B0); //R2,ROUT1,LOUT1输出使能(耳机可以工作),BOOSTENR,BOOSTENL使能
|
||||
WM8978_Write_Reg(3, 0X6C); //R3,LOUT2,ROUT2输出使能(喇叭工作),RMIX,LMIX使能
|
||||
WM8978_Write_Reg(6, 0); //R6,MCLK由外部提供
|
||||
WM8978_Write_Reg(43, 1 << 4); //R43,INVROUT2反向,驱动喇叭
|
||||
WM8978_Write_Reg(47, 0 << 8); //R47设置,PGABOOSTL,左通道MIC获得20倍增益
|
||||
WM8978_Write_Reg(48, 0 << 8); //R48设置,PGABOOSTR,右通道MIC获得20倍增益
|
||||
WM8978_Write_Reg(49, 1 << 1); //R49,TSDEN,开启过热保护
|
||||
WM8978_Write_Reg(10, 1 << 3); //R10,SOFTMUTE关闭,128x采样,最佳SNR
|
||||
WM8978_Write_Reg(14, 1 << 3); //R14,ADC 128x采样率
|
||||
|
||||
|
||||
//
|
||||
delay(10000);
|
||||
WM8978_HPvol_Set(30, 30); //耳机音量设置
|
||||
WM8978_SPKvol_Set(60); //喇叭音量设置
|
||||
delay(10000);
|
||||
WM8978_ADDA_Cfg(dacen, adcen); //开启DAC
|
||||
WM8978_Input_Cfg(adcen, 0, 0); //关闭输入通道
|
||||
WM8978_Output_Cfg(dacen, adcen); //开启DAC输出
|
||||
delay(10000);
|
||||
WM8978_I2S_Cfg(2, 0); //飞利浦标准,16位数据长度
|
||||
WM8978_MIC_Gain(63);
|
||||
|
||||
printf("WM8978_Init Finish\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//WM8978读寄存器
|
||||
//就是读取本地寄存器值缓冲区内的对应值
|
||||
//reg:寄存器地址
|
||||
//返回值:寄存器值
|
||||
u16 WM8978_Read_Reg(u8 reg)
|
||||
{
|
||||
return WM8978_REGVAL_TBL[reg];
|
||||
}
|
||||
//WM8978 DAC/ADC配置
|
||||
//adcen:adc使能(1)/关闭(0)
|
||||
//dacen:dac使能(1)/关闭(0)
|
||||
void WM8978_ADDA_Cfg(u8 dacen, u8 adcen)
|
||||
{
|
||||
u16 regval;
|
||||
regval = WM8978_Read_Reg(3); //读取R3
|
||||
if (dacen) {
|
||||
regval |= 3 << 0; //R3最低2个位设置为1,开启DACR&DACL
|
||||
} else {
|
||||
regval &= ~(3 << 0); //R3最低2个位清零,关闭DACR&DACL.
|
||||
}
|
||||
WM8978_Write_Reg(3, regval); //设置R3
|
||||
regval = WM8978_Read_Reg(2); //读取R2
|
||||
if (adcen) {
|
||||
regval |= 3 << 0; //R2最低2个位设置为1,开启ADCR&ADCL
|
||||
} else {
|
||||
regval &= ~(3 << 0); //R2最低2个位清零,关闭ADCR&ADCL.
|
||||
}
|
||||
WM8978_Write_Reg(2, regval); //设置R2
|
||||
}
|
||||
//WM8978 输入通道配置
|
||||
//micen:MIC开启(1)/关闭(0)
|
||||
//lineinen:Line In开启(1)/关闭(0)
|
||||
//auxen:aux开启(1)/关闭(0)
|
||||
void WM8978_Input_Cfg(u8 micen, u8 lineinen, u8 auxen)
|
||||
{
|
||||
u16 regval;
|
||||
regval = WM8978_Read_Reg(2); //读取R2
|
||||
if (micen) {
|
||||
regval |= 3 << 2; //开启INPPGAENR,INPPGAENL(MIC的PGA放大)
|
||||
} else {
|
||||
regval &= ~(3 << 2); //关闭INPPGAENR,INPPGAENL.
|
||||
}
|
||||
WM8978_Write_Reg(2, regval); //设置R2
|
||||
|
||||
regval = WM8978_Read_Reg(44); //读取R44
|
||||
if (micen) {
|
||||
regval |= 3 << 4 | 3 << 0; //开启LIN2INPPGA,LIP2INPGA,RIN2INPPGA,RIP2INPGA.
|
||||
} else {
|
||||
regval &= ~(3 << 4 | 3 << 0); //关闭LIN2INPPGA,LIP2INPGA,RIN2INPPGA,RIP2INPGA.
|
||||
}
|
||||
WM8978_Write_Reg(44, regval); //设置R44
|
||||
|
||||
if (lineinen) {
|
||||
WM8978_LINEIN_Gain(5); //LINE IN 0dB增益
|
||||
} else {
|
||||
WM8978_LINEIN_Gain(0); //关闭LINE IN
|
||||
}
|
||||
if (auxen) {
|
||||
WM8978_AUX_Gain(7); //AUX 6dB增益
|
||||
} else {
|
||||
WM8978_AUX_Gain(0); //关闭AUX输入
|
||||
}
|
||||
}
|
||||
//WM8978 输出配置
|
||||
//dacen:DAC输出(放音)开启(1)/关闭(0)
|
||||
//bpsen:Bypass输出(录音,包括MIC,LINE IN,AUX等)开启(1)/关闭(0)
|
||||
void WM8978_Output_Cfg(u8 dacen, u8 bpsen)
|
||||
{
|
||||
u16 regval = 0;
|
||||
if (dacen) {
|
||||
regval |= 1 << 0; //DAC输出使能
|
||||
}
|
||||
if (bpsen) {
|
||||
regval |= 1 << 1; //BYPASS使能
|
||||
regval |= 5 << 2; //0dB增益
|
||||
}
|
||||
WM8978_Write_Reg(50, regval); //R50设置
|
||||
WM8978_Write_Reg(51, regval); //R51设置
|
||||
}
|
||||
//WM8978 MIC增益设置(不包括BOOST的20dB,MIC-->ADC输入部分的增益)
|
||||
//gain:0~63,对应-12dB~35.25dB,0.75dB/Step
|
||||
void WM8978_MIC_Gain(u8 gain)
|
||||
{
|
||||
gain &= 0X3F;
|
||||
WM8978_Write_Reg(45, gain); //R45,左通道PGA设置
|
||||
WM8978_Write_Reg(46, gain | 1 << 8); //R46,右通道PGA设置
|
||||
}
|
||||
//WM8978 L2/R2(也就是Line In)增益设置(L2/R2-->ADC输入部分的增益)
|
||||
//gain:0~7,0表示通道禁止,1~7,对应-12dB~6dB,3dB/Step
|
||||
void WM8978_LINEIN_Gain(u8 gain)
|
||||
{
|
||||
u16 regval;
|
||||
gain &= 0X07;
|
||||
regval = WM8978_Read_Reg(47); //读取R47
|
||||
regval &= ~(7 << 4); //清除原来的设置
|
||||
WM8978_Write_Reg(47, regval | gain << 4); //设置R47
|
||||
regval = WM8978_Read_Reg(48); //读取R48
|
||||
regval &= ~(7 << 4); //清除原来的设置
|
||||
WM8978_Write_Reg(48, regval | gain << 4); //设置R48
|
||||
}
|
||||
//WM8978 AUXR,AUXL(PWM音频部分)增益设置(AUXR/L-->ADC输入部分的增益)
|
||||
//gain:0~7,0表示通道禁止,1~7,对应-12dB~6dB,3dB/Step
|
||||
void WM8978_AUX_Gain(u8 gain)
|
||||
{
|
||||
u16 regval;
|
||||
gain &= 0X07;
|
||||
regval = WM8978_Read_Reg(47); //读取R47
|
||||
regval &= ~(7 << 0); //清除原来的设置
|
||||
WM8978_Write_Reg(47, regval | gain << 0); //设置R47
|
||||
regval = WM8978_Read_Reg(48); //读取R48
|
||||
regval &= ~(7 << 0); //清除原来的设置
|
||||
WM8978_Write_Reg(48, regval | gain << 0); //设置R48
|
||||
}
|
||||
//设置I2S工作模式
|
||||
//fmt:0,LSB(右对齐);1,MSB(左对齐);2,飞利浦标准I2S;3,PCM/DSP;
|
||||
//len:0,16位;1,20位;2,24位;3,32位;
|
||||
void WM8978_I2S_Cfg(u8 fmt, u8 len)
|
||||
{
|
||||
fmt &= 0X03;
|
||||
len &= 0X03; //限定范围
|
||||
WM8978_Write_Reg(4, (fmt << 3) | (len << 5)); //R4,WM8978工作模式设置
|
||||
}
|
||||
|
||||
//设置耳机左右声道音量
|
||||
//voll:左声道音量(0~63)
|
||||
//volr:右声道音量(0~63)
|
||||
void WM8978_HPvol_Set(u8 voll, u8 volr)
|
||||
{
|
||||
voll &= 0X3F;
|
||||
volr &= 0X3F; //限定范围
|
||||
if (voll == 0) {
|
||||
voll |= 1 << 6; //音量为0时,直接mute
|
||||
}
|
||||
if (volr == 0) {
|
||||
volr |= 1 << 6; //音量为0时,直接mute
|
||||
}
|
||||
WM8978_Write_Reg(52, voll); //R52,耳机左声道音量设置
|
||||
WM8978_Write_Reg(53, volr | (1 << 8)); //R53,耳机右声道音量设置,同步更新(HPVU=1)
|
||||
}
|
||||
//设置喇叭音量
|
||||
//voll:左声道音量(0~63)
|
||||
void WM8978_SPKvol_Set(u8 volx)
|
||||
{
|
||||
volx &= 0X3F; //限定范围
|
||||
if (volx == 0) {
|
||||
volx |= 1 << 6; //音量为0时,直接mute
|
||||
}
|
||||
WM8978_Write_Reg(54, volx); //R54,喇叭左声道音量设置
|
||||
WM8978_Write_Reg(55, volx | (1 << 8)); //R55,喇叭右声道音量设置,同步更新(SPKVU=1)
|
||||
}
|
||||
//设置3D环绕声
|
||||
//depth:0~15(3D强度,0最弱,15最强)
|
||||
void WM8978_3D_Set(u8 depth)
|
||||
{
|
||||
depth &= 0XF; //限定范围
|
||||
WM8978_Write_Reg(41, depth); //R41,3D环绕设置
|
||||
}
|
||||
//设置EQ/3D作用方向
|
||||
//dir:0,在ADC起作用
|
||||
// 1,在DAC起作用(默认)
|
||||
void WM8978_EQ_3D_Dir(u8 dir)
|
||||
{
|
||||
u16 regval;
|
||||
regval = WM8978_Read_Reg(0X12);
|
||||
if (dir) {
|
||||
regval |= 1 << 8;
|
||||
} else {
|
||||
regval &= ~(1 << 8);
|
||||
}
|
||||
WM8978_Write_Reg(18, regval); //R18,EQ1的第9位控制EQ/3D方向
|
||||
}
|
||||
|
||||
//设置EQ1
|
||||
//cfreq:截止频率,0~3,分别对应:80/105/135/175Hz
|
||||
//gain:增益,0~24,对应-12~+12dB
|
||||
void WM8978_EQ1_Set(u8 cfreq, u8 gain)
|
||||
{
|
||||
u16 regval;
|
||||
cfreq &= 0X3; //限定范围
|
||||
if (gain > 24) {
|
||||
gain = 24;
|
||||
}
|
||||
gain = 24 - gain;
|
||||
regval = WM8978_Read_Reg(18);
|
||||
regval &= 0X100;
|
||||
regval |= cfreq << 5; //设置截止频率
|
||||
regval |= gain; //设置增益
|
||||
WM8978_Write_Reg(18, regval); //R18,EQ1设置
|
||||
}
|
||||
//设置EQ2
|
||||
//cfreq:中心频率,0~3,分别对应:230/300/385/500Hz
|
||||
//gain:增益,0~24,对应-12~+12dB
|
||||
void WM8978_EQ2_Set(u8 cfreq, u8 gain)
|
||||
{
|
||||
u16 regval = 0;
|
||||
cfreq &= 0X3; //限定范围
|
||||
if (gain > 24) {
|
||||
gain = 24;
|
||||
}
|
||||
gain = 24 - gain;
|
||||
regval |= cfreq << 5; //设置截止频率
|
||||
regval |= gain; //设置增益
|
||||
WM8978_Write_Reg(19, regval); //R19,EQ2设置
|
||||
}
|
||||
//设置EQ3
|
||||
//cfreq:中心频率,0~3,分别对应:650/850/1100/1400Hz
|
||||
//gain:增益,0~24,对应-12~+12dB
|
||||
void WM8978_EQ3_Set(u8 cfreq, u8 gain)
|
||||
{
|
||||
u16 regval = 0;
|
||||
cfreq &= 0X3; //限定范围
|
||||
if (gain > 24) {
|
||||
gain = 24;
|
||||
}
|
||||
gain = 24 - gain;
|
||||
regval |= cfreq << 5; //设置截止频率
|
||||
regval |= gain; //设置增益
|
||||
WM8978_Write_Reg(20, regval); //R20,EQ3设置
|
||||
}
|
||||
//设置EQ4
|
||||
//cfreq:中心频率,0~3,分别对应:1800/2400/3200/4100Hz
|
||||
//gain:增益,0~24,对应-12~+12dB
|
||||
void WM8978_EQ4_Set(u8 cfreq, u8 gain)
|
||||
{
|
||||
u16 regval = 0;
|
||||
cfreq &= 0X3; //限定范围
|
||||
if (gain > 24) {
|
||||
gain = 24;
|
||||
}
|
||||
gain = 24 - gain;
|
||||
regval |= cfreq << 5; //设置截止频率
|
||||
regval |= gain; //设置增益
|
||||
WM8978_Write_Reg(21, regval); //R21,EQ4设置
|
||||
}
|
||||
//设置EQ5
|
||||
//cfreq:中心频率,0~3,分别对应:5300/6900/9000/11700Hz
|
||||
//gain:增益,0~24,对应-12~+12dB
|
||||
void WM8978_EQ5_Set(u8 cfreq, u8 gain)
|
||||
{
|
||||
u16 regval = 0;
|
||||
cfreq &= 0X3; //限定范围
|
||||
if (gain > 24) {
|
||||
gain = 24;
|
||||
}
|
||||
gain = 24 - gain;
|
||||
regval |= cfreq << 5; //设置截止频率
|
||||
regval |= gain; //设置增益
|
||||
WM8978_Write_Reg(22, regval); //R22,EQ5设置
|
||||
}
|
||||
|
||||
|
||||
55
apps/common/audio/wm8978/wm8978.h
Normal file
55
apps/common/audio/wm8978/wm8978.h
Normal file
@ -0,0 +1,55 @@
|
||||
#ifndef __WM8978_H
|
||||
#define __WM8978_H
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
#define WM8978_ADDR 0X1A //WM8978的器件地址,固定为0X1A
|
||||
|
||||
#define EQ1_80Hz 0X00
|
||||
#define EQ1_105Hz 0X01
|
||||
#define EQ1_135Hz 0X02
|
||||
#define EQ1_175Hz 0X03
|
||||
|
||||
#define EQ2_230Hz 0X00
|
||||
#define EQ2_300Hz 0X01
|
||||
#define EQ2_385Hz 0X02
|
||||
#define EQ2_500Hz 0X03
|
||||
|
||||
#define EQ3_650Hz 0X00
|
||||
#define EQ3_850Hz 0X01
|
||||
#define EQ3_1100Hz 0X02
|
||||
#define EQ3_14000Hz 0X03
|
||||
|
||||
#define EQ4_1800Hz 0X00
|
||||
#define EQ4_2400Hz 0X01
|
||||
#define EQ4_3200Hz 0X02
|
||||
#define EQ4_4100Hz 0X03
|
||||
|
||||
#define EQ5_5300Hz 0X00
|
||||
#define EQ5_6900Hz 0X01
|
||||
#define EQ5_9000Hz 0X02
|
||||
#define EQ5_11700Hz 0X03
|
||||
|
||||
|
||||
u8 WM8978_Init(u8 dacen, u8 adcen);
|
||||
void WM8978_ADDA_Cfg(u8 dacen, u8 adcen);
|
||||
void WM8978_Input_Cfg(u8 micen, u8 lineinen, u8 auxen);
|
||||
void WM8978_Output_Cfg(u8 dacen, u8 bpsen);
|
||||
void WM8978_MIC_Gain(u8 gain);
|
||||
void WM8978_LINEIN_Gain(u8 gain);
|
||||
void WM8978_AUX_Gain(u8 gain);
|
||||
u8 WM8978_Write_Reg(u8 reg, u16 val);
|
||||
u16 WM8978_Read_Reg(u8 reg);
|
||||
void WM8978_HPvol_Set(u8 voll, u8 volr);
|
||||
void WM8978_SPKvol_Set(u8 volx);
|
||||
void WM8978_I2S_Cfg(u8 fmt, u8 len);
|
||||
void WM8978_3D_Set(u8 depth);
|
||||
void WM8978_EQ_3D_Dir(u8 dir);
|
||||
void WM8978_EQ1_Set(u8 cfreq, u8 gain);
|
||||
void WM8978_EQ2_Set(u8 cfreq, u8 gain);
|
||||
void WM8978_EQ3_Set(u8 cfreq, u8 gain);
|
||||
void WM8978_EQ4_Set(u8 cfreq, u8 gain);
|
||||
void WM8978_EQ5_Set(u8 cfreq, u8 gain);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
246
apps/common/bt_common/bt_test_api.c
Normal file
246
apps/common/bt_common/bt_test_api.c
Normal file
@ -0,0 +1,246 @@
|
||||
|
||||
#include "typedef.h"
|
||||
#include "app_config.h"
|
||||
#include "task.h"
|
||||
#include "btctrler_task.h"
|
||||
#include "btcontroller_config.h"
|
||||
#include "system/includes.h"
|
||||
|
||||
#define LOG_TAG "[BT_DUT]"
|
||||
#define LOG_ERROR_ENABLE
|
||||
#define LOG_DEBUG_ENABLE
|
||||
#define LOG_INFO_ENABLE
|
||||
/* #define LOG_DUMP_ENABLE */
|
||||
#define LOG_CLI_ENABLE
|
||||
#include "debug.h"
|
||||
|
||||
//bredr test api
|
||||
extern void ble_enter_dut_tx_mode(void *param);
|
||||
extern void bt_ble_adv_enable(u8 enable);
|
||||
extern void bredr_fcc_init(u8 mode, u8 fre);
|
||||
|
||||
#if 0
|
||||
|
||||
static void bt_dut_api(void)
|
||||
{
|
||||
log_info("bt in dut \n");
|
||||
#if TCFG_AUTO_SHUT_DOWN_TIME
|
||||
extern void sys_auto_shut_down_disable(void);
|
||||
sys_auto_shut_down_disable();
|
||||
#endif
|
||||
|
||||
#if TCFG_USER_TWS_ENABLE
|
||||
extern void tws_cancle_all_noconn();
|
||||
tws_cancle_all_noconn() ;
|
||||
#else
|
||||
//sys_timer_del(app_var.auto_stop_page_scan_timer);
|
||||
extern void bredr_close_all_scan();
|
||||
bredr_close_all_scan();
|
||||
#endif
|
||||
|
||||
#if TCFG_USER_BLE_ENABLE
|
||||
#if (CONFIG_BT_MODE == BT_NORMAL)
|
||||
bt_ble_adv_enable(0);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void bit_clr_ie(unsigned char index);
|
||||
/* !!!Notice:when this api is called and sleep mode should be sure to exit; */
|
||||
void bt_fix_fre_api(u8 fre)
|
||||
{
|
||||
bt_dut_api();
|
||||
|
||||
bit_clr_ie(IRQ_BREDR_IDX);
|
||||
bit_clr_ie(IRQ_BT_CLKN_IDX);
|
||||
|
||||
bredr_fcc_init(BT_FRE, fre);
|
||||
}
|
||||
#endif
|
||||
|
||||
//ble test api
|
||||
enum BLE_DUT_PAYLOAD_TYPE {
|
||||
PAYLOAD_TYPE_PRBS9 = 0,
|
||||
PAYLOAD_TYPE_11110000,
|
||||
PAYLOAD_TYPE_10101010,
|
||||
PAYLOAD_TYPE_PRBS15,
|
||||
PAYLOAD_TYPE_11111111,
|
||||
PAYLOAD_TYPE_00000000,
|
||||
PAYLOAD_TYPE_00001111,
|
||||
PAYLOAD_TYPE_01010101,
|
||||
|
||||
PAYLOAD_TYPE_SINGLE_CARRIER = 0xf0,
|
||||
};
|
||||
|
||||
enum BLE_DUT_PHY_TYPE {
|
||||
BLE_1M_UNCODED_PHY = 1,
|
||||
BLE_2M_UNCODED_PHY,
|
||||
BLE_1M_CODED_PHY_S8,
|
||||
BLE_1M_CODED_PHY_S2,
|
||||
};
|
||||
|
||||
struct ble_dut_param_set {
|
||||
u8 ch_index; //tx ch index;(0~39 -> 2402~2480)
|
||||
u8 payload_type; //tx payload type
|
||||
u8 payload_len; //payload_len(0~0xff) when continuous_tx = 0;
|
||||
u8 continuous_tx; //enable or disable continuous transmission mode(0/1)
|
||||
};
|
||||
|
||||
/* !!!Notice:when this api is called and sleep mode should be sure to exit; */
|
||||
void ble_fix_fre_api()
|
||||
{
|
||||
#if TCFG_USER_BLE_ENABLE
|
||||
#if (CONFIG_BT_MODE == BT_NORMAL)
|
||||
bt_ble_adv_enable(0);
|
||||
#endif
|
||||
os_time_dly(10);
|
||||
|
||||
struct ble_dut_param_set dut_param = {
|
||||
.ch_index = 0,
|
||||
.payload_type = PAYLOAD_TYPE_10101010,
|
||||
.payload_len = 0x20,
|
||||
.continuous_tx = 1,
|
||||
};
|
||||
ble_enter_dut_tx_mode(&dut_param);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void *ble_dut_hdl = NULL;
|
||||
extern void ll_hci_destory(void);
|
||||
void ble_dut_mode_init(void)
|
||||
{
|
||||
if (!ble_dut_hdl) {
|
||||
ll_hci_destory();
|
||||
ble_dut_hdl = __ble_dut_ops->init();
|
||||
}
|
||||
}
|
||||
|
||||
void ble_dut_mode_exit(void)
|
||||
{
|
||||
if (ble_dut_hdl) {
|
||||
__ble_dut_ops->exit(ble_dut_hdl);
|
||||
ble_dut_hdl = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ble_dut_tx_fre_api(u8 ch)
|
||||
{
|
||||
ble_dut_mode_init();
|
||||
struct ble_dut_tx_param_t tx_param = {
|
||||
.ch_index = ch,
|
||||
.payload_len = 0x20,
|
||||
.payload_type = PAYLOAD_TYPE_PRBS9,
|
||||
.phy_type = BLE_1M_UNCODED_PHY,
|
||||
};
|
||||
|
||||
log_info("BLE_DUT_TX-ch:%x\n", ch);
|
||||
__ble_dut_ops->ioctrl(BLE_DUT_SET_TX_MODE, &tx_param);
|
||||
|
||||
}
|
||||
|
||||
void ble_dut_rx_fre_api(u8 ch)
|
||||
{
|
||||
ble_dut_mode_init();
|
||||
struct ble_dut_rx_param_t rx_param = {
|
||||
.ch_index = ch,
|
||||
.phy_type = BLE_1M_UNCODED_PHY,
|
||||
};
|
||||
|
||||
log_info("BLE_DUT_RX-ch:%x \n", ch);
|
||||
__ble_dut_ops->ioctrl(BLE_DUT_SET_RX_MODE, &rx_param);
|
||||
|
||||
}
|
||||
|
||||
int ble_dut_test_end(void)
|
||||
{
|
||||
int pkt_valid_cnt = 0;
|
||||
int pkt_err_cnt = 0;
|
||||
if (ble_dut_hdl) {
|
||||
__ble_dut_ops->ioctrl(BLE_DUT_SET_TEST_END, &pkt_valid_cnt, NULL);
|
||||
|
||||
log_info("pkt_rx_cnt:%d pkt_err_cnt:%d\n", pkt_valid_cnt, pkt_err_cnt);
|
||||
} else {
|
||||
log_error("ble dut hdl not inited\n");
|
||||
}
|
||||
|
||||
return pkt_valid_cnt;
|
||||
}
|
||||
|
||||
static volatile u8 bt_test_status = 0;
|
||||
|
||||
void ble_bqb_test_thread_init(void);
|
||||
static hci_transport_config_uart_t config = {
|
||||
HCI_TRANSPORT_CONFIG_UART,
|
||||
115200,
|
||||
0, // main baudrate
|
||||
0, // flow control
|
||||
NULL,
|
||||
};
|
||||
|
||||
extern void dut_hci_controller_init(const hci_transport_t *transport, const void *config);
|
||||
void ble_standard_dut_test_init(void)
|
||||
{
|
||||
log_info("%s\n", __FUNCTION__);
|
||||
bt_test_status = 1;
|
||||
ble_dut_mode_init();
|
||||
//ble_bqb_test_thread_init();
|
||||
dut_hci_controller_init((void *)hci_transport_uart_instance(), &config);
|
||||
}
|
||||
|
||||
void ble_standard_dut_test_close(void)
|
||||
{
|
||||
log_info("%s\n", __FUNCTION__);
|
||||
ble_dut_test_end();
|
||||
ble_dut_mode_exit();
|
||||
hci_transport_t *p_uart_trans = hci_transport_uart_instance();
|
||||
p_uart_trans->close();
|
||||
bt_test_status = 0;
|
||||
|
||||
}
|
||||
|
||||
void ble_dut_mode_key_handle(u8 type, u8 key_val)
|
||||
{
|
||||
static u8 rx_ch = 0;
|
||||
static u8 tx_ch = 0;
|
||||
switch (key_val) {
|
||||
case 3:
|
||||
ble_dut_tx_fre_api(tx_ch++);
|
||||
if (tx_ch > 39) {
|
||||
tx_ch = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
ble_dut_rx_fre_api(rx_ch++);
|
||||
if (rx_ch > 39) {
|
||||
rx_ch = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
ble_dut_test_end();
|
||||
break;
|
||||
|
||||
case 0:
|
||||
ble_standard_dut_test_init();
|
||||
break;
|
||||
|
||||
case 4:
|
||||
ble_standard_dut_test_close();
|
||||
break;
|
||||
|
||||
defualt:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static u8 bt_test_idle_query(void)
|
||||
{
|
||||
return !bt_test_status;
|
||||
}
|
||||
|
||||
REGISTER_LP_TARGET(bt_test_lp_target) = {
|
||||
.name = "bt_test",
|
||||
.is_idle = bt_test_idle_query,
|
||||
};
|
||||
|
||||
1528
apps/common/cJSON/cJSON.c
Normal file
1528
apps/common/cJSON/cJSON.c
Normal file
File diff suppressed because it is too large
Load Diff
150
apps/common/cJSON/cJSON.h
Normal file
150
apps/common/cJSON/cJSON.h
Normal file
@ -0,0 +1,150 @@
|
||||
|
||||
/*
|
||||
Copyright (c) 2009 Dave Gamble
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
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 NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef cJSON__h
|
||||
#define cJSON__h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/* cJSON Types: */
|
||||
#define cJSON_False 0
|
||||
#define cJSON_True 1
|
||||
#define cJSON_NULL 2
|
||||
#define cJSON_Number 3
|
||||
#define cJSON_String 4
|
||||
#define cJSON_Array 5
|
||||
#define cJSON_Object 6
|
||||
|
||||
#define cJSON_IsReference 256
|
||||
#define cJSON_StringIsConst 512
|
||||
|
||||
/* The cJSON structure: */
|
||||
typedef struct cJSON {
|
||||
struct cJSON *next, *prev; /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
|
||||
struct cJSON *child; /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
|
||||
|
||||
int type; /* The type of the item, as above. */
|
||||
|
||||
char *valuestring; /* The item's string, if type==cJSON_String */
|
||||
int valueint; /* The item's number, if type==cJSON_Number */
|
||||
double valuedouble; /* The item's number, if type==cJSON_Number */
|
||||
|
||||
char *string; /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
|
||||
} cJSON;
|
||||
|
||||
typedef struct cJSON_Hooks {
|
||||
void *(*malloc_fn)(size_t sz);
|
||||
void (*free_fn)(void *ptr);
|
||||
} cJSON_Hooks;
|
||||
|
||||
/* Supply malloc, realloc and free functions to cJSON */
|
||||
extern void cJSON_InitHooks(cJSON_Hooks *hooks);
|
||||
|
||||
|
||||
/* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */
|
||||
extern cJSON *cJSON_Parse(const char *value);
|
||||
/* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */
|
||||
extern char *cJSON_Print(cJSON *item);
|
||||
/* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */
|
||||
extern char *cJSON_PrintUnformatted(cJSON *item);
|
||||
/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */
|
||||
extern char *cJSON_PrintBuffered(cJSON *item, int prebuffer, int fmt);
|
||||
/* Delete a cJSON entity and all subentities. */
|
||||
extern void cJSON_Delete(cJSON *c);
|
||||
|
||||
/* Returns the number of items in an array (or object). */
|
||||
extern int cJSON_GetArraySize(cJSON *array);
|
||||
/* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */
|
||||
extern cJSON *cJSON_GetArrayItem(cJSON *array, int item);
|
||||
/* Get item "string" from object. Case insensitive. */
|
||||
extern cJSON *cJSON_GetObjectItem(cJSON *object, const char *string);
|
||||
|
||||
/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
|
||||
extern const char *cJSON_GetErrorPtr(void);
|
||||
|
||||
/* These calls create a cJSON item of the appropriate type. */
|
||||
extern cJSON *cJSON_CreateNull(void);
|
||||
extern cJSON *cJSON_CreateTrue(void);
|
||||
extern cJSON *cJSON_CreateFalse(void);
|
||||
extern cJSON *cJSON_CreateBool(int b);
|
||||
extern cJSON *cJSON_CreateNumber(double num);
|
||||
extern cJSON *cJSON_CreateString(const char *string);
|
||||
extern cJSON *cJSON_CreateArray(void);
|
||||
extern cJSON *cJSON_CreateObject(void);
|
||||
|
||||
/* These utilities create an Array of count items. */
|
||||
extern cJSON *cJSON_CreateIntArray(const int *numbers, int count);
|
||||
extern cJSON *cJSON_CreateFloatArray(const float *numbers, int count);
|
||||
extern cJSON *cJSON_CreateDoubleArray(const double *numbers, int count);
|
||||
extern cJSON *cJSON_CreateStringArray(const char **strings, int count);
|
||||
|
||||
/* Append item to the specified array/object. */
|
||||
extern void cJSON_AddItemToArray(cJSON *array, cJSON *item);
|
||||
extern void cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);
|
||||
extern void cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item); /* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object */
|
||||
/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
|
||||
extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
|
||||
extern void cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);
|
||||
|
||||
/* Remove/Detatch items from Arrays/Objects. */
|
||||
extern cJSON *cJSON_DetachItemFromArray(cJSON *array, int which);
|
||||
extern void cJSON_DeleteItemFromArray(cJSON *array, int which);
|
||||
extern cJSON *cJSON_DetachItemFromObject(cJSON *object, const char *string);
|
||||
extern void cJSON_DeleteItemFromObject(cJSON *object, const char *string);
|
||||
|
||||
/* Update array items. */
|
||||
extern void cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */
|
||||
extern void cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);
|
||||
extern void cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem);
|
||||
|
||||
/* Duplicate a cJSON item */
|
||||
extern cJSON *cJSON_Duplicate(cJSON *item, int recurse);
|
||||
/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
|
||||
need to be released. With recurse!=0, it will duplicate any children connected to the item.
|
||||
The item->next and ->prev pointers are always zero on return from Duplicate. */
|
||||
|
||||
/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
|
||||
extern cJSON *cJSON_ParseWithOpts(const char *value, const char **return_parse_end, int require_null_terminated);
|
||||
|
||||
extern void cJSON_Minify(char *json);
|
||||
|
||||
/* Macros for creating things quickly. */
|
||||
#define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull())
|
||||
#define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue())
|
||||
#define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse())
|
||||
#define cJSON_AddBoolToObject(object,name,b) cJSON_AddItemToObject(object, name, cJSON_CreateBool(b))
|
||||
#define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n))
|
||||
#define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s))
|
||||
|
||||
/* When assigning an integer value, it needs to be propagated to valuedouble too. */
|
||||
#define cJSON_SetIntValue(object,val) ((object)?(object)->valueint=(object)->valuedouble=(val):(val))
|
||||
#define cJSON_SetNumberValue(object,val) ((object)?(object)->valueint=(object)->valuedouble=(val):(val))
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
420
apps/common/colorful_lights/colorful_lights.c
Normal file
420
apps/common/colorful_lights/colorful_lights.c
Normal file
@ -0,0 +1,420 @@
|
||||
#include "colorful_lights/colorful_lights.h"
|
||||
#include "timer.h"
|
||||
|
||||
|
||||
#define colorful_lights_printf(format, ...) \
|
||||
printf("[colorful_lights]" format, ##__VA_ARGS__)
|
||||
|
||||
static colorful_lights_variable_struct colorful_lights_variable = {
|
||||
.prioritize_display_counter = 0,
|
||||
.prioritize_display_time = 0,
|
||||
.switch_display_flag = 0,
|
||||
.software_switch_enable = 0xff,
|
||||
.main_display_timer = 0,
|
||||
.display_data = 0,
|
||||
.display_data_length = 0,
|
||||
};
|
||||
|
||||
#if !COLORFUL_LIGHTS_USE_SPI
|
||||
static int colorful_lights_list[] = {
|
||||
IO_PORTB_07,
|
||||
};
|
||||
|
||||
static void colorful_lights_pins_reset()
|
||||
{
|
||||
for (unsigned char i = 0; i < sizeof(colorful_lights_list) / sizeof(int); i++) {
|
||||
gpio_direction_output(colorful_lights_list[i], 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if COLORFUL_LIGHTS_USE_SPI
|
||||
static unsigned char volatile colorful_lights_display_buffer[COLORFUL_LIGHTS_NUMBER * 3 * 8] __attribute__((aligned(4)));
|
||||
#else
|
||||
static unsigned char volatile colorful_lights_display_buffer[COLORFUL_LIGHTS_NUMBER * 3] __attribute__((aligned(4)));
|
||||
#endif
|
||||
|
||||
/*
|
||||
* @colorful_lights_write_data :
|
||||
* data[0] ~ data[COLORFUL_LIGHTS_NUMBER] : green[0] ~ green[COLORFUL_LIGHTS_NUMBER]
|
||||
* data[COLORFUL_LIGHTS_NUMBER] ~ data[COLORFUL_LIGHTS_NUMBER*2] : red[COLORFUL_LIGHTS_NUMBER] ~ red[COLORFUL_LIGHTS_NUMBER*2]
|
||||
* data[COLORFUL_LIGHTS_NUMBER*2] ~ data[COLORFUL_LIGHTS_NUMBER*3] : blue[COLORFUL_LIGHTS_NUMBER*2] ~ blue[COLORFUL_LIGHTS_NUMBER*3]
|
||||
*/
|
||||
static void colorful_lights_write_data(unsigned char data[COLORFUL_LIGHTS_NUMBER * 3])
|
||||
{
|
||||
#if COLORFUL_LIGHTS_ENABLE
|
||||
unsigned short i, j;
|
||||
#if COLORFUL_LIGHTS_USE_SPI
|
||||
if (colorful_lights_variable.software_switch_enable && data) {
|
||||
for (i = 0; i < COLORFUL_LIGHTS_NUMBER; i++) {
|
||||
for (j = 0; j < 8; j++) {
|
||||
if (data[i] << j & 0x80) {
|
||||
colorful_lights_display_buffer[24 * i + j] = SPI_SEND_HIGH_DATA;
|
||||
} else {
|
||||
colorful_lights_display_buffer[24 * i + j] = SPI_SEND_LOW_DATA;
|
||||
}
|
||||
}
|
||||
for (j = 0; j < 8; j++) {
|
||||
if (data[COLORFUL_LIGHTS_NUMBER + i] << j & 0x80) {
|
||||
colorful_lights_display_buffer[24 * i + 8 + j] = SPI_SEND_HIGH_DATA;
|
||||
} else {
|
||||
colorful_lights_display_buffer[24 * i + 8 + j] = SPI_SEND_LOW_DATA;
|
||||
}
|
||||
}
|
||||
for (j = 0; j < 8; j++) {
|
||||
if (data[COLORFUL_LIGHTS_NUMBER * 2 + i] << j & 0x80) {
|
||||
colorful_lights_display_buffer[24 * i + 16 + j] = SPI_SEND_HIGH_DATA;
|
||||
} else {
|
||||
colorful_lights_display_buffer[24 * i + 16 + j] = SPI_SEND_LOW_DATA;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
memset(colorful_lights_display_buffer, SPI_SEND_LOW_DATA, sizeof(colorful_lights_display_buffer));
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
static void colorful_lights_send_data()
|
||||
{
|
||||
#if COLORFUL_LIGHTS_USE_SPI
|
||||
spi_dma_set_addr_for_isr(COLORFUL_LIGHTS_SPI_ID, colorful_lights_display_buffer, COLORFUL_LIGHTS_NUMBER * 3 * 8, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* set_colorful_lights_brightness :
|
||||
* @ordinal : 0 ~ COLORFUL_LIGHTS_NUMBER - 1
|
||||
* @number : 1 ~ COLORFUL_LIGHTS_NUMBER
|
||||
* @color : color = green << 16 | red << 8 | blue
|
||||
* @background : background = green << 16 | red << 8 | blue
|
||||
*/
|
||||
static void set_colorful_lights_brightness(unsigned short ordinal, unsigned short number, unsigned int color, unsigned int background)
|
||||
{
|
||||
unsigned char data[COLORFUL_LIGHTS_NUMBER * 3] = { 0 };
|
||||
unsigned short i;
|
||||
if (ordinal >= COLORFUL_LIGHTS_NUMBER || number == 0 || number > COLORFUL_LIGHTS_NUMBER) {
|
||||
return;
|
||||
} else {
|
||||
if (number + ordinal >= COLORFUL_LIGHTS_NUMBER) {
|
||||
#if 0
|
||||
for(i = ordinal; i < COLORFUL_LIGHTS_NUMBER; i++) {
|
||||
data[i] = (unsigned char)(color >> 16);
|
||||
data[COLORFUL_LIGHTS_NUMBER + i] = (unsigned char)(color >> 8);
|
||||
data[COLORFUL_LIGHTS_NUMBER * 2 + i] = (unsigned char)color;
|
||||
}
|
||||
for(i = 0; i < number - (COLORFUL_LIGHTS_NUMBER - ordinal); i++) {
|
||||
data[i] = (unsigned char)(color >> 16);
|
||||
data[COLORFUL_LIGHTS_NUMBER + i] = (unsigned char)(color >> 8);
|
||||
data[COLORFUL_LIGHTS_NUMBER * 2 + i] = (unsigned char)color;
|
||||
}
|
||||
for(i = number - (COLORFUL_LIGHTS_NUMBER - ordinal); i < ordinal; i++) {
|
||||
data[i] = (unsigned char)(background >> 16);
|
||||
data[COLORFUL_LIGHTS_NUMBER + i] = (unsigned char)(background >> 8);
|
||||
data[COLORFUL_LIGHTS_NUMBER * 2 + i] = (unsigned char)background;
|
||||
}
|
||||
#endif
|
||||
memset(&data[ordinal], (unsigned char)(color >> 16), COLORFUL_LIGHTS_NUMBER - ordinal);
|
||||
memset(&data[COLORFUL_LIGHTS_NUMBER + ordinal], (unsigned char)(color >> 8), COLORFUL_LIGHTS_NUMBER - ordinal);
|
||||
memset(&data[COLORFUL_LIGHTS_NUMBER * 2 + ordinal], (unsigned char)color, COLORFUL_LIGHTS_NUMBER - ordinal);
|
||||
|
||||
memset(&data[0], (unsigned char)(color >> 16), number - (COLORFUL_LIGHTS_NUMBER - ordinal));
|
||||
memset(&data[COLORFUL_LIGHTS_NUMBER], (unsigned char)(color >> 8), number - (COLORFUL_LIGHTS_NUMBER - ordinal));
|
||||
memset(&data[COLORFUL_LIGHTS_NUMBER * 2], (unsigned char)color, number - (COLORFUL_LIGHTS_NUMBER - ordinal));
|
||||
|
||||
memset(&data[number - (COLORFUL_LIGHTS_NUMBER - ordinal)], (unsigned char)(background >> 16), COLORFUL_LIGHTS_NUMBER - number);
|
||||
memset(&data[COLORFUL_LIGHTS_NUMBER + number - (COLORFUL_LIGHTS_NUMBER - ordinal)], (unsigned char)(background >> 8), COLORFUL_LIGHTS_NUMBER - number);
|
||||
memset(&data[COLORFUL_LIGHTS_NUMBER * 2 + number - (COLORFUL_LIGHTS_NUMBER - ordinal)], (unsigned char)background, COLORFUL_LIGHTS_NUMBER - number);
|
||||
} else {
|
||||
#if 0
|
||||
for(i = ordinal; i < number + ordinal; i++) {
|
||||
data[i] = (unsigned char)(color >> 16);
|
||||
data[COLORFUL_LIGHTS_NUMBER + i] = (unsigned char)(color >> 8);
|
||||
data[COLORFUL_LIGHTS_NUMBER * 2 + i] = (unsigned char)color;
|
||||
}
|
||||
for(i = 0; i < ordinal; i++) {
|
||||
data[i] = (unsigned char)(background >> 16);
|
||||
data[COLORFUL_LIGHTS_NUMBER + i] = (unsigned char)(background >> 8);
|
||||
data[COLORFUL_LIGHTS_NUMBER * 2 + i] = (unsigned char)background;
|
||||
}
|
||||
for(i = number + ordinal; i < COLORFUL_LIGHTS_NUMBER; i++) {
|
||||
data[i] = (unsigned char)(background >> 16);
|
||||
data[COLORFUL_LIGHTS_NUMBER + i] = (unsigned char)(background >> 8);
|
||||
data[COLORFUL_LIGHTS_NUMBER * 2 + i] = (unsigned char)background;
|
||||
}
|
||||
#endif
|
||||
memset(&data[ordinal], (unsigned char)(color >> 16), number);
|
||||
memset(&data[COLORFUL_LIGHTS_NUMBER + ordinal], (unsigned char)(color >> 8), number);
|
||||
memset(&data[COLORFUL_LIGHTS_NUMBER * 2 + ordinal], (unsigned char)color, number);
|
||||
|
||||
memset(&data[0], (unsigned char)(background >> 16), ordinal);
|
||||
memset(&data[COLORFUL_LIGHTS_NUMBER], (unsigned char)(background >> 8), ordinal);
|
||||
memset(&data[COLORFUL_LIGHTS_NUMBER * 2], (unsigned char)background, ordinal);
|
||||
|
||||
memset(&data[number + ordinal], (unsigned char)(background >> 16), COLORFUL_LIGHTS_NUMBER - number - ordinal);
|
||||
memset(&data[COLORFUL_LIGHTS_NUMBER + number + ordinal], (unsigned char)(background >> 8), COLORFUL_LIGHTS_NUMBER - number - ordinal);
|
||||
memset(&data[COLORFUL_LIGHTS_NUMBER * 2 + number + ordinal], (unsigned char)background, COLORFUL_LIGHTS_NUMBER - number - ordinal);
|
||||
}
|
||||
colorful_lights_write_data(data);
|
||||
}
|
||||
}
|
||||
|
||||
static void set_prioritize_display_function(void (*prioritize_display_function)(unsigned char display_flag), unsigned short prioritize_display_time)
|
||||
{
|
||||
if (colorful_lights_variable.software_switch_enable) {
|
||||
colorful_lights_variable.prioritize_display_counter = 0;
|
||||
colorful_lights_variable.prioritize_display_time = prioritize_display_time ? prioritize_display_time : 1000;
|
||||
if (prioritize_display_function != colorful_lights_variable.prioritize_display_function) {
|
||||
colorful_lights_variable.switch_display_flag = 1;
|
||||
colorful_lights_variable.prioritize_display_function = prioritize_display_function;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void set_main_display_function(void (*main_display_function)(unsigned char display_flag))
|
||||
{
|
||||
if (colorful_lights_variable.software_switch_enable) {
|
||||
if (main_display_function != colorful_lights_variable.main_display_function) {
|
||||
colorful_lights_variable.switch_display_flag = 1;
|
||||
colorful_lights_variable.main_display_function = main_display_function;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void colorful_lights_main(void* data)
|
||||
{
|
||||
if (colorful_lights_variable.software_switch_enable) {
|
||||
if (colorful_lights_variable.prioritize_display_function) {
|
||||
colorful_lights_variable.prioritize_display_function(colorful_lights_variable.switch_display_flag);
|
||||
colorful_lights_variable.switch_display_flag = 0;
|
||||
colorful_lights_variable.prioritize_display_counter++;
|
||||
if (colorful_lights_variable.prioritize_display_counter >= colorful_lights_variable.prioritize_display_time / COLORFUL_LIGHTS_CYCLE) {
|
||||
colorful_lights_variable.prioritize_display_function = 0;
|
||||
colorful_lights_variable.switch_display_flag = 1;
|
||||
}
|
||||
} else if (colorful_lights_variable.main_display_function) {
|
||||
colorful_lights_variable.main_display_function(colorful_lights_variable.switch_display_flag);
|
||||
colorful_lights_variable.switch_display_flag = 0;
|
||||
} else {
|
||||
if (colorful_lights_variable.switch_display_flag) {
|
||||
colorful_lights_variable.switch_display_flag = 0;
|
||||
colorful_lights_write_data(0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (colorful_lights_variable.main_display_timer) {
|
||||
usr_timer_del(colorful_lights_variable.main_display_timer);
|
||||
colorful_lights_variable.main_display_timer = 0;
|
||||
}
|
||||
colorful_lights_write_data(0);
|
||||
}
|
||||
colorful_lights_send_data();
|
||||
}
|
||||
|
||||
static void set_software_switch(unsigned char enable)
|
||||
{
|
||||
#if COLORFUL_LIGHTS_ENABLE
|
||||
if (colorful_lights_variable.software_switch_enable != enable) {
|
||||
colorful_lights_variable.software_switch_enable = enable;
|
||||
#if COLORFUL_LIGHTS_POWER_PINS != NO_CONFIG_PINS
|
||||
gpio_set_pull_up(COLORFUL_LIGHTS_POWER_PINS, 0);
|
||||
gpio_set_pull_down(COLORFUL_LIGHTS_POWER_PINS, 0);
|
||||
gpio_set_direction(COLORFUL_LIGHTS_POWER_PINS, 0);
|
||||
gpio_set_output_value(COLORFUL_LIGHTS_POWER_PINS, enable);
|
||||
#endif
|
||||
if (colorful_lights_variable.software_switch_enable) {
|
||||
if (!colorful_lights_variable.main_display_timer) {
|
||||
colorful_lights_variable.main_display_timer = usr_timer_add(0, colorful_lights_main, COLORFUL_LIGHTS_CYCLE > 20 ? COLORFUL_LIGHTS_CYCLE : 20, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static unsigned char get_software_switch()
|
||||
{
|
||||
return colorful_lights_variable.software_switch_enable;
|
||||
}
|
||||
|
||||
static void set_hardware_switch(unsigned char enable)
|
||||
{
|
||||
static unsigned short hardware_switch_timer = 0;
|
||||
#if COLORFUL_LIGHTS_ENABLE
|
||||
if(enable) {
|
||||
#if COLORFUL_LIGHTS_USE_SPI
|
||||
if(hardware_switch_timer) {
|
||||
sys_timeout_del(hardware_switch_timer);
|
||||
hardware_switch_timer = 0;
|
||||
}
|
||||
spi_open(COLORFUL_LIGHTS_SPI_ID);
|
||||
#endif
|
||||
set_software_switch(1);
|
||||
} else {
|
||||
set_software_switch(0);
|
||||
#if COLORFUL_LIGHTS_USE_SPI
|
||||
if(!hardware_switch_timer) {
|
||||
hardware_switch_timer = sys_timeout_add((void*)COLORFUL_LIGHTS_SPI_ID, spi_close, 2 * (COLORFUL_LIGHTS_CYCLE > 20 ? COLORFUL_LIGHTS_CYCLE : 20));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void colorful_lights_breathe_function(unsigned char flag)
|
||||
{
|
||||
static unsigned char brightness_flag = 1;
|
||||
static short brightness = 0;
|
||||
static unsigned char color_number = 0;
|
||||
unsigned char data[COLORFUL_LIGHTS_NUMBER * 3] = { 0 };
|
||||
if (flag) {
|
||||
brightness_flag = 1;
|
||||
brightness = 0;
|
||||
color_number = 0;
|
||||
}
|
||||
if (brightness_flag) {
|
||||
brightness++;
|
||||
if (brightness >= 0xff) {
|
||||
brightness = 0xff;
|
||||
brightness_flag = 0;
|
||||
}
|
||||
} else {
|
||||
brightness--;
|
||||
if (brightness <= 0) {
|
||||
brightness = 0;
|
||||
color_number++;
|
||||
if (color_number >= 5) {
|
||||
color_number = 0;
|
||||
}
|
||||
brightness_flag = 1;
|
||||
}
|
||||
}
|
||||
switch (color_number) {
|
||||
case 0:
|
||||
memset(&data[COLORFUL_LIGHTS_NUMBER], brightness, COLORFUL_LIGHTS_NUMBER);
|
||||
break;
|
||||
case 1:
|
||||
memset(&data[0], brightness, COLORFUL_LIGHTS_NUMBER);
|
||||
memset(&data[COLORFUL_LIGHTS_NUMBER * 2], brightness, COLORFUL_LIGHTS_NUMBER);
|
||||
break;
|
||||
case 2:
|
||||
memset(&data[0], brightness, COLORFUL_LIGHTS_NUMBER);
|
||||
memset(&data[COLORFUL_LIGHTS_NUMBER], brightness, COLORFUL_LIGHTS_NUMBER);
|
||||
break;
|
||||
case 3:
|
||||
memset(&data[COLORFUL_LIGHTS_NUMBER * 2], brightness, COLORFUL_LIGHTS_NUMBER);
|
||||
break;
|
||||
case 4:
|
||||
memset(&data[COLORFUL_LIGHTS_NUMBER], brightness, COLORFUL_LIGHTS_NUMBER);
|
||||
memset(&data[COLORFUL_LIGHTS_NUMBER * 2], brightness, COLORFUL_LIGHTS_NUMBER);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
colorful_lights_write_data(data);
|
||||
}
|
||||
|
||||
static void colorful_lights_snakes(unsigned char flag)
|
||||
{
|
||||
}
|
||||
|
||||
static void colorful_lights_lines_mode(unsigned char flag)
|
||||
{
|
||||
}
|
||||
|
||||
static void colorful_lights_gradient_mode(unsigned char flag)
|
||||
{
|
||||
const unsigned char brightness = 150;
|
||||
static unsigned char data[COLORFUL_LIGHTS_NUMBER*3] = {0};
|
||||
/// 无->红->蓝->绿
|
||||
|
||||
static unsigned char delay_counter = 0;
|
||||
static unsigned char counter = 0;
|
||||
static unsigned char color_index = 0;
|
||||
if(flag) {
|
||||
memset(data, 0, sizeof(data));
|
||||
counter = 0;
|
||||
color_index = 0;
|
||||
delay_counter = 0;
|
||||
}
|
||||
if(counter < COLORFUL_LIGHTS_NUMBER) {
|
||||
switch (color_index) {
|
||||
case 0:
|
||||
data[0 * COLORFUL_LIGHTS_NUMBER + counter] = brightness; // // R
|
||||
data[1 * COLORFUL_LIGHTS_NUMBER + counter] = 0; // // B
|
||||
data[2 * COLORFUL_LIGHTS_NUMBER + counter] = 0; // // G
|
||||
break;
|
||||
|
||||
case 1:
|
||||
data[0 * COLORFUL_LIGHTS_NUMBER + counter] = 0; // // R
|
||||
data[1 * COLORFUL_LIGHTS_NUMBER + counter] = brightness; // // B
|
||||
data[2 * COLORFUL_LIGHTS_NUMBER + counter] = 0; // // G
|
||||
break;
|
||||
|
||||
case 2:
|
||||
data[0 * COLORFUL_LIGHTS_NUMBER + counter] = 0; // // R
|
||||
data[1 * COLORFUL_LIGHTS_NUMBER + counter] = 0; // // B
|
||||
data[2 * COLORFUL_LIGHTS_NUMBER + counter] = brightness; // // G
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
delay_counter++;
|
||||
if(delay_counter >= 200 / COLORFUL_LIGHTS_CYCLE) {
|
||||
delay_counter = 0;
|
||||
counter++;
|
||||
if(counter >= COLORFUL_LIGHTS_NUMBER) {
|
||||
color_index++;
|
||||
counter = 0;
|
||||
if(color_index >= 3) {
|
||||
color_index = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
colorful_lights_write_data(data);
|
||||
}
|
||||
|
||||
static void update_display_mode(unsigned char display)
|
||||
{
|
||||
switch (display) {
|
||||
case COLORFUL_LIGHTS_DISPLAY_NULL:
|
||||
set_prioritize_display_function(0, 0);
|
||||
set_main_display_function(0);
|
||||
break;
|
||||
case COLORFUL_LIGHTS_BREATHE_MODE:
|
||||
set_main_display_function(colorful_lights_breathe_function);
|
||||
break;
|
||||
case COLORFUL_LIGHTS_GRADIENT_MODE:
|
||||
set_main_display_function(colorful_lights_gradient_mode);
|
||||
break;
|
||||
// case COLORFUL_LIGHTS_SNAKES: /* 贪吃蛇 */
|
||||
// set_main_display_function(colorful_lights_snakes);
|
||||
// break;
|
||||
// case COLORFUL_LIGHTS_LINES_MODE:
|
||||
// set_main_display_function(colorful_lights_lines_mode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void update_display_data(unsigned char* data, unsigned int length)
|
||||
{
|
||||
colorful_lights_variable.display_data = data;
|
||||
colorful_lights_variable.display_data_length = length;
|
||||
}
|
||||
|
||||
static colorful_lights_function_struct this_colorful_lights_function = {
|
||||
.set_hardware_switch = set_hardware_switch,
|
||||
.set_software_switch = set_software_switch,
|
||||
.get_software_switch = get_software_switch,
|
||||
.update_display_mode = update_display_mode,
|
||||
.update_display_data = update_display_data,
|
||||
};
|
||||
|
||||
colorful_lights_function_struct colorful_lights_function()
|
||||
{
|
||||
return this_colorful_lights_function;
|
||||
}
|
||||
60
apps/common/colorful_lights/colorful_lights.h
Normal file
60
apps/common/colorful_lights/colorful_lights.h
Normal file
@ -0,0 +1,60 @@
|
||||
#ifndef __colorful_lights__
|
||||
#define __colorful_lights__
|
||||
#include "app_config.h"
|
||||
#include "gpio.h"
|
||||
#include "asm/spi.h"
|
||||
|
||||
|
||||
#define NO_CONFIG_PINS (-1)
|
||||
#define COLORFUL_LIGHTS_ENABLE 1
|
||||
#define COLORFUL_LIGHTS_NUMBER 60
|
||||
#define COLORFUL_LIGHTS_POWER_PINS IO_PORTB_02/* IO_PORTB_03 */
|
||||
|
||||
#define COLORFUL_LIGHTS_USE_SPI 1
|
||||
#define COLORFUL_LIGHTS_SPI_ID SPI1
|
||||
#define SPI_SEND_HIGH_DATA 0x0f
|
||||
#define SPI_SEND_LOW_DATA 0x01
|
||||
|
||||
#if COLORFUL_LIGHTS_USE_SPI
|
||||
#define COLORFUL_LIGHTS_CYCLE (COLORFUL_LIGHTS_NUMBER * 24 * 8 * 1000 / spi_get_baud(COLORFUL_LIGHTS_SPI_ID) + 2 > 20 ? \
|
||||
COLORFUL_LIGHTS_NUMBER * 24 * 8 * 1000 / spi_get_baud(COLORFUL_LIGHTS_SPI_ID) + 2 : 20)
|
||||
#else
|
||||
#define COLORFUL_LIGHTS_CYCLE (10)
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
COLORFUL_LIGHTS_DISPLAY_NULL = 0,
|
||||
COLORFUL_LIGHTS_GRADIENT_MODE,
|
||||
|
||||
COLORFUL_LIGHTS_MODE_END,
|
||||
COLORFUL_LIGHTS_LINES_MODE,
|
||||
COLORFUL_LIGHTS_BREATHE_MODE,
|
||||
} COLORFUL_LIGHTS_DISPLAY;
|
||||
|
||||
typedef struct struct_colorful_lights_variable {
|
||||
unsigned char pins_ordinal;
|
||||
unsigned short prioritize_display_counter;
|
||||
unsigned short prioritize_display_time;
|
||||
unsigned char switch_display_flag;
|
||||
unsigned char software_switch_enable;
|
||||
unsigned short main_display_timer;
|
||||
unsigned char* display_data;
|
||||
unsigned int display_data_length;
|
||||
void (*prioritize_display_function)(unsigned char display_flag);
|
||||
void (*main_display_function)(unsigned char display_flag);
|
||||
} colorful_lights_variable_struct;
|
||||
|
||||
typedef struct struct_colorful_lights_function {
|
||||
void (*set_hardware_switch)(unsigned char enable); //power on setup 1, power off setup 0
|
||||
void (*set_software_switch)(unsigned char enable); //called during running
|
||||
unsigned char (*get_software_switch)();
|
||||
void (*update_display_mode)(unsigned char display);
|
||||
void (*update_display_data)(unsigned char *data, unsigned int length);
|
||||
} colorful_lights_function_struct;
|
||||
colorful_lights_function_struct colorful_lights_function();
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
121
apps/common/config/app_config.c
Normal file
121
apps/common/config/app_config.c
Normal file
@ -0,0 +1,121 @@
|
||||
#include "system/includes.h"
|
||||
#include "app_config.h"
|
||||
#include "config/config_interface.h"
|
||||
|
||||
#define LOG_TAG "[APP-CONFIG]"
|
||||
#define LOG_ERROR_ENABLE
|
||||
#define LOG_INFO_ENABLE
|
||||
/* #define LOG_DUMP_ENABLE */
|
||||
#include "debug.h"
|
||||
|
||||
|
||||
extern void dec_eq_test();
|
||||
static int sdfile_test(const char *name);
|
||||
int jl_cfg_dec_test(void);
|
||||
|
||||
ci_transport_config_uart_t config = {
|
||||
CI_TRANSPORT_CONFIG_UART,
|
||||
115200,
|
||||
0,
|
||||
0,
|
||||
NULL,
|
||||
};
|
||||
|
||||
#if (TCFG_ONLINE_ENABLE || TCFG_CFG_TOOL_ENABLE)
|
||||
#if TCFG_COMM_TYPE == TCFG_UART_COMM
|
||||
void config_online_init()
|
||||
{
|
||||
log_info("-------online Config Start-------");
|
||||
config_layer_init(ci_transport_uart_instance(), &config);
|
||||
}
|
||||
__initcall(config_online_init);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void config_test(void)
|
||||
{
|
||||
|
||||
#if 1
|
||||
log_info("-------EQ online Config Start-------");
|
||||
|
||||
sys_clk_set(SYS_48M);
|
||||
|
||||
//Setup dev input
|
||||
config_layer_init(ci_transport_uart_instance(), &config);
|
||||
|
||||
dec_eq_test();
|
||||
while (1) {
|
||||
extern void clr_wdt();
|
||||
clr_wdt();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
log_info("-------SDFile test Start------");
|
||||
|
||||
#ifdef SDFILE_DEV
|
||||
|
||||
#define SDFILE_NAME1 SDFILE_ROOT_PATH"xx.bin"
|
||||
|
||||
void *mnt = mount(SDFILE_DEV, SDFILE_MOUNT_PATH, "jlfs", 0, NULL);
|
||||
if (mnt == NULL) {
|
||||
log_error("mount jlfs failed");
|
||||
}
|
||||
|
||||
sdfile_test(SDFILE_NAME1);
|
||||
|
||||
#endif /*SDFILE_DEV*/
|
||||
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
log_info("--------JL CFG test Start------");
|
||||
|
||||
jl_cfg_dec_test();
|
||||
#endif
|
||||
while (1);
|
||||
}
|
||||
|
||||
static int sdfile_test(const char *name)
|
||||
{
|
||||
log_d("SDFILE file path: %s", name);
|
||||
FILE *fp = NULL;
|
||||
u8 buf[16];
|
||||
u8 len;
|
||||
|
||||
fp = fopen(name, "r");
|
||||
if (!fp) {
|
||||
log_d("sdfile open file ERR!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
len = fread(fp, buf, sizeof(buf));
|
||||
|
||||
if (len != sizeof(buf)) {
|
||||
log_d("0-read file ERR!");
|
||||
goto _end;
|
||||
}
|
||||
|
||||
put_buf(buf, sizeof(buf));
|
||||
|
||||
fseek(fp, 16, SEEK_SET);
|
||||
|
||||
len = fread(fp, buf, sizeof(buf));
|
||||
|
||||
if (len != sizeof(buf)) {
|
||||
log_d("1-read file ERR!");
|
||||
goto _end;
|
||||
}
|
||||
|
||||
put_buf(buf, sizeof(buf));
|
||||
|
||||
log_d("SDFILE ok!");
|
||||
|
||||
_end:
|
||||
if (fp) {
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
216
apps/common/config/bt_profile_config.c
Normal file
216
apps/common/config/bt_profile_config.c
Normal file
@ -0,0 +1,216 @@
|
||||
#include "system/includes.h"
|
||||
#include "app_config.h"
|
||||
#include "btcontroller_config.h"
|
||||
#include "btstack/bt_profile_config.h"
|
||||
#include "bt_common.h"
|
||||
|
||||
#define LOG_TAG "[BT-CFG]"
|
||||
#define LOG_ERROR_ENABLE
|
||||
#define LOG_INFO_ENABLE
|
||||
/* #define LOG_DUMP_ENABLE */
|
||||
#include "debug.h"
|
||||
|
||||
|
||||
#if TCFG_APP_BT_EN
|
||||
|
||||
typedef struct {
|
||||
// linked list - assert: first field
|
||||
void *offset_item;
|
||||
|
||||
// data is contained in same memory
|
||||
u32 service_record_handle;
|
||||
u8 *service_record;
|
||||
} service_record_item_t;
|
||||
|
||||
extern const u8 sdp_pnp_service_data[];
|
||||
extern const u8 sdp_a2dp_service_data[];
|
||||
extern const u8 sdp_avctp_ct_service_data[];
|
||||
extern const u8 sdp_avctp_ta_service_data[];
|
||||
extern const u8 sdp_hfp_service_data[];
|
||||
extern const u8 sdp_spp_service_data[];
|
||||
extern const u8 sdp_hid_service_data[];
|
||||
extern service_record_item_t sdp_record_item_begin[];
|
||||
extern service_record_item_t sdp_record_item_end[];
|
||||
|
||||
#define SDP_RECORD_HANDLER_REGISTER(handler) \
|
||||
const service_record_item_t handler \
|
||||
sec(.sdp_record_item)
|
||||
|
||||
#if TCFG_USER_BLE_ENABLE
|
||||
|
||||
#if (TCFG_BLE_DEMO_SELECT == DEF_BLE_DEMO_ADV)
|
||||
const int config_stack_modules = (BT_BTSTACK_CLASSIC | BT_BTSTACK_LE_ADV);
|
||||
#else
|
||||
const int config_stack_modules = BT_BTSTACK_CLASSIC | BT_BTSTACK_LE;
|
||||
#endif
|
||||
|
||||
#else
|
||||
const int config_stack_modules = BT_BTSTACK_CLASSIC;
|
||||
#endif
|
||||
|
||||
#if (USER_SUPPORT_PROFILE_PNP==1)
|
||||
SDP_RECORD_HANDLER_REGISTER(pnp_sdp_record_item) = {
|
||||
.service_record = (u8 *)sdp_pnp_service_data,
|
||||
.service_record_handle = 0x1000A,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if (USER_SUPPORT_PROFILE_A2DP==1)
|
||||
u8 a2dp_profile_support = 1;
|
||||
SDP_RECORD_HANDLER_REGISTER(a2dp_sdp_record_item) = {
|
||||
.service_record = (u8 *)sdp_a2dp_service_data,
|
||||
.service_record_handle = 0x00010001,
|
||||
};
|
||||
#endif
|
||||
#if (USER_SUPPORT_PROFILE_AVCTP==1)
|
||||
u8 acp_profile_support = 1;
|
||||
SDP_RECORD_HANDLER_REGISTER(arp_ct_sdp_record_item) = {
|
||||
.service_record = (u8 *)sdp_avctp_ct_service_data,
|
||||
.service_record_handle = 0x00010002,
|
||||
};
|
||||
#if BT_SUPPORT_MUSIC_VOL_SYNC
|
||||
SDP_RECORD_HANDLER_REGISTER(arp_ta_sdp_record_item) = {
|
||||
.service_record = (u8 *)sdp_avctp_ta_service_data,
|
||||
.service_record_handle = 0x00010005,
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
#if (USER_SUPPORT_PROFILE_HFP==1)
|
||||
u8 hfp_profile_support = 1;
|
||||
SDP_RECORD_HANDLER_REGISTER(hfp_sdp_record_item) = {
|
||||
.service_record = (u8 *)sdp_hfp_service_data,
|
||||
.service_record_handle = 0x00010003,
|
||||
};
|
||||
#endif
|
||||
#if (USER_SUPPORT_PROFILE_SPP==1)
|
||||
|
||||
u8 spp_up_profile_support = 1;
|
||||
//FE010000-1234-5678-ABCD-00805F9B34FB
|
||||
const u8 sdp_user_spp_service_data[96] = {
|
||||
0x36, 0x00, 0x5B, 0x09, 0x00, 0x00, 0x0A, 0x00, 0x01, 0x00, 0x11, 0x09, 0x00, 0x01, 0x36, 0x00,
|
||||
0x11, 0x1C, 0xfe, 0x01, 0x00, 0x00, 0x12, 0x34, 0x56, 0x78, 0xab, 0xcd, 0x00, 0x80, 0x5F, 0x9b,
|
||||
0x34, 0xfb, 0x09, 0x00, 0x04, 0x36, 0x00, 0x0E, 0x36, 0x00, 0x03, 0x19, 0x01, 0x00, 0x36, 0x00,
|
||||
0x05, 0x19, 0x00, 0x03, 0x08, 0x0a, 0x09, 0x00, 0x09, 0x36, 0x00, 0x17, 0x36, 0x00, 0x14, 0x1C,
|
||||
0xfe, 0x01, 0x00, 0x00, 0x12, 0x34, 0x56, 0x78, 0xab, 0xcd, 0x00, 0x80, 0x5F, 0x9b, 0x34, 0xfb,
|
||||
0x09, 0x01, 0x00, 0x09, 0x01, 0x00, 0x25, 0x06, 0x4A, 0x4C, 0x5F, 0x53, 0x50, 0x50, 0x00, 0x00,
|
||||
};
|
||||
SDP_RECORD_HANDLER_REGISTER(spp_user_sdp_record_item) = {
|
||||
.service_record = (u8 *)sdp_user_spp_service_data,
|
||||
.service_record_handle = 0x00010011,
|
||||
};
|
||||
|
||||
u8 spp_profile_support = 1;
|
||||
SDP_RECORD_HANDLER_REGISTER(spp_sdp_record_item) = {
|
||||
.service_record = (u8 *)sdp_spp_service_data,
|
||||
.service_record_handle = 0x00010004,
|
||||
};
|
||||
|
||||
#endif
|
||||
#if (USER_SUPPORT_PROFILE_HID==1)
|
||||
u8 hid_profile_support = 1;
|
||||
SDP_RECORD_HANDLER_REGISTER(hid_sdp_record_item) = {
|
||||
.service_record = (u8 *)sdp_hid_service_data,
|
||||
.service_record_handle = 0x00010006,
|
||||
};
|
||||
#endif
|
||||
#if (USER_SUPPORT_PROFILE_PBAP==1)
|
||||
extern const u8 sdp_pbap_service_data[];
|
||||
u8 pbap_profile_support = 1;
|
||||
SDP_RECORD_HANDLER_REGISTER(pbap_sdp_record_item) = {
|
||||
.service_record = (u8 *)sdp_pbap_service_data,
|
||||
.service_record_handle = 0x00010008,
|
||||
};
|
||||
#endif
|
||||
#if (USER_SUPPORT_PROFILE_MAP==1)
|
||||
extern const u8 sdp_map_mce_service_data[];
|
||||
u8 map_profile_support = 1;
|
||||
SDP_RECORD_HANDLER_REGISTER(map_sdp_record_item) = {
|
||||
.service_record = (u8 *)sdp_map_mce_service_data,
|
||||
.service_record_handle = 0x00010009,
|
||||
};
|
||||
#endif
|
||||
|
||||
/*注意hid_conn_depend_on_dev_company置1之后,安卓手机会默认断开HID连接 */
|
||||
/*注意hid_conn_depend_on_dev_company置2之后,默认不断开HID连接 */
|
||||
const u8 hid_conn_depend_on_dev_company = 1;
|
||||
const u8 sdp_get_remote_pnp_info = 0;
|
||||
|
||||
#ifdef CONFIG_256K_FLASH
|
||||
const u8 pbg_support_enable = 0;
|
||||
const u8 adt_profile_support = 0;
|
||||
const u8 more_hfp_cmd_support = 0;
|
||||
#else
|
||||
|
||||
#if (TCFG_BLE_DEMO_SELECT == DEF_BLE_DEMO_ADV)
|
||||
const u8 pbg_support_enable = 1;
|
||||
const u8 adt_profile_support = 1;
|
||||
#else
|
||||
const u8 pbg_support_enable = 0;
|
||||
const u8 adt_profile_support = 0;
|
||||
#endif
|
||||
|
||||
const u8 more_hfp_cmd_support = 1;
|
||||
|
||||
#endif
|
||||
|
||||
#if (TCFG_BD_NUM == 2)
|
||||
const u8 a2dp_mutual_support = 1;
|
||||
const u8 more_addr_reconnect_support = 1;
|
||||
#if USER_SUPPORT_DUAL_A2DP_SOURCE
|
||||
const u8 more_avctp_cmd_support = 0;
|
||||
#else
|
||||
const u8 more_avctp_cmd_support = 1;
|
||||
#endif
|
||||
#else
|
||||
const u8 a2dp_mutual_support = 0;
|
||||
const u8 more_addr_reconnect_support = 0;
|
||||
#if ((RCSP_ADV_EN || SMART_BOX_EN) && JL_EARPHONE_APP_EN)
|
||||
const u8 more_avctp_cmd_support = 1;
|
||||
#else
|
||||
const u8 more_avctp_cmd_support = 0;
|
||||
#endif
|
||||
#endif
|
||||
#if TCFG_USER_EMITTER_ENABLE
|
||||
const u8 hci_inquiry_support = 1;
|
||||
const u8 btstack_emitter_support = 1; /*定义用于优化代码编译*/
|
||||
|
||||
#if USER_SUPPORT_PROFILE_A2DP
|
||||
const u8 emitter_hfp_hf_support = 0; /*置1时做发射器连接手机时只支持hfp*/
|
||||
#else
|
||||
const u8 emitter_hfp_hf_support = 1; /*置1时做发射器连接手机时只支持hfp*/
|
||||
#endif
|
||||
|
||||
extern const u8 sdp_a2dp_source_service_data[];
|
||||
|
||||
#if (USER_SUPPORT_PROFILE_A2DP==0)
|
||||
u8 a2dp_profile_support = 2;
|
||||
#endif
|
||||
|
||||
SDP_RECORD_HANDLER_REGISTER(a2dp_src_sdp_record_item) = {
|
||||
.service_record = (u8 *)sdp_a2dp_source_service_data,
|
||||
.service_record_handle = 0x0001000B,
|
||||
};
|
||||
#if (USER_SUPPORT_PROFILE_HFP_AG==1)
|
||||
extern const u8 sdp_hfp_ag_service_data[];
|
||||
u8 hfp_ag_profile_support = 1;
|
||||
SDP_RECORD_HANDLER_REGISTER(hfp_ag_sdp_record_item) = {
|
||||
.service_record = (u8 *)sdp_hfp_ag_service_data,
|
||||
.service_record_handle = 0x00010008,
|
||||
};
|
||||
#endif
|
||||
#else
|
||||
const u8 hci_inquiry_support = 0;
|
||||
const u8 btstack_emitter_support = 0; /*定义用于优化代码编译*/
|
||||
#endif
|
||||
/*u8 l2cap_debug_enable = 0xf0;
|
||||
u8 rfcomm_debug_enable = 0xf;
|
||||
u8 profile_debug_enable = 0xff;
|
||||
u8 ble_debug_enable = 0xff;
|
||||
u8 btstack_tws_debug_enable = 0xf;*/
|
||||
|
||||
#else
|
||||
const u8 btstack_emitter_support = 1; /*定义用于优化代码编译*/
|
||||
const u8 a2dp_mutual_support = 1;
|
||||
const u8 adt_profile_support = 0;
|
||||
const u8 pbg_support_enable = 0;
|
||||
#endif
|
||||
370
apps/common/config/ci_transport_uart.c
Normal file
370
apps/common/config/ci_transport_uart.c
Normal file
@ -0,0 +1,370 @@
|
||||
#include "system/includes.h"
|
||||
#include "config/config_interface.h"
|
||||
#include "system/event.h"
|
||||
#include "app_online_cfg.h"
|
||||
#include "asm/uart_dev.h"
|
||||
#include "app_config.h"
|
||||
#include "asm/crc16.h"
|
||||
|
||||
#define LOG_TAG "[CI-UART]"
|
||||
/* #define LOG_ERROR_ENABLE */
|
||||
/* #define LOG_INFO_ENABLE */
|
||||
/* #define LOG_DUMP_ENABLE */
|
||||
#include "debug.h"
|
||||
|
||||
#if (TCFG_ONLINE_ENABLE || TCFG_CFG_TOOL_ENABLE)
|
||||
struct config_uart {
|
||||
u32 baudrate;
|
||||
int flowcontrol;
|
||||
const char *dev_name;
|
||||
};
|
||||
|
||||
struct uart_hdl {
|
||||
|
||||
struct config_uart config;
|
||||
|
||||
uart_bus_t *udev;
|
||||
void *dbuf;
|
||||
|
||||
void *pRxBuffer;
|
||||
|
||||
u8 ucRxIndex;
|
||||
u8 rx_type;
|
||||
|
||||
u16 data_length;
|
||||
|
||||
void *pTxBuffer;
|
||||
|
||||
void (*packet_handler)(const u8 *packet, int size);
|
||||
};
|
||||
|
||||
|
||||
typedef struct {
|
||||
//head
|
||||
u16 preamble;
|
||||
u8 type;
|
||||
u16 length;
|
||||
u8 crc8;
|
||||
u16 crc16;
|
||||
u8 payload[0];
|
||||
} _GNU_PACKED_ uart_packet_t;
|
||||
|
||||
#define UART_FORMAT_HEAD sizeof(uart_packet_t)
|
||||
|
||||
typedef struct {
|
||||
//head
|
||||
u16 preamble0;
|
||||
u8 preamble1;
|
||||
u16 crc16;
|
||||
u8 length;
|
||||
u8 type;
|
||||
u8 sq;
|
||||
u8 payload[0];
|
||||
} _GNU_PACKED_ uart_tool_packet_t;
|
||||
|
||||
#define UART_TOOL_FORMAT_HEAD sizeof(uart_tool_packet_t)
|
||||
|
||||
static void dummy_handler(const u8 *packet, int size);
|
||||
|
||||
#define UART_PREAMBLE 0xBED6
|
||||
#define UART_NEW_TOOL_PREAMBLE0 0xAA5A
|
||||
#define UART_NEW_TOOL_PREAMBLE1 0xA5
|
||||
|
||||
#define UART_RX_SIZE 0x100
|
||||
#define UART_TX_SIZE 0x30
|
||||
#define UART_DB_SIZE 0x100
|
||||
#define UART_BAUD_RATE 115200
|
||||
|
||||
#ifdef HAVE_MALLOC
|
||||
static struct uart_hdl *hdl;
|
||||
#define __this (hdl)
|
||||
#else
|
||||
static struct uart_hdl hdl;
|
||||
#define __this (&hdl)
|
||||
|
||||
static u8 pRxBuffer_static[UART_RX_SIZE] __attribute__((aligned(4))); //rx memory
|
||||
static u8 pTxBuffer_static[UART_TX_SIZE] __attribute__((aligned(4))); //tx memory
|
||||
static u8 devBuffer_static[UART_DB_SIZE] __attribute__((aligned(4))); //dev DMA memory
|
||||
#endif
|
||||
|
||||
s16 get_ci_tx_size()
|
||||
{
|
||||
return UART_TX_SIZE;
|
||||
}
|
||||
static u8 procotol = 0;
|
||||
void ci_data_rx_handler(u8 type)
|
||||
{
|
||||
u16 crc16;
|
||||
uart_tool_packet_t *p_newtool;
|
||||
uart_packet_t *p;
|
||||
|
||||
__this->rx_type = type;
|
||||
|
||||
if (type == CI_UART && __this->udev) {
|
||||
__this->data_length += __this->udev->read(&__this->pRxBuffer[__this->data_length], (UART_RX_SIZE - __this->data_length), 0);//串口读取buf剩余空间的长度,实际长度比buf长,导致越界改写问题
|
||||
}
|
||||
|
||||
/* log_info("Rx : %d", __this->data_length); */
|
||||
/* log_info_hexdump(__this->pRxBuffer, __this->data_length); */
|
||||
if (__this->data_length > UART_RX_SIZE) {
|
||||
log_error("Wired");
|
||||
}
|
||||
|
||||
u8 *tmp_buf = NULL;
|
||||
tmp_buf = __this->pRxBuffer;
|
||||
if (__this->data_length >= 2) {
|
||||
unsigned i = 0;
|
||||
for (i = 0; i < __this->data_length - 1; ++i) {
|
||||
if ((tmp_buf[i] == 0x5A) && (tmp_buf[i + 1] == 0xAA) && (tmp_buf[i + 2] == 0xA5)) {
|
||||
procotol = 1;
|
||||
break;
|
||||
} else if (tmp_buf[i] == 0xD6 && tmp_buf[i + 1] == 0xBE) {
|
||||
procotol = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i != 0) {
|
||||
__this->data_length -= i;
|
||||
/* printf("__this->data_length %d i %d\n", __this->data_length, i); */
|
||||
if (__this->data_length > 0) {
|
||||
memmove(&__this->pRxBuffer[0], &tmp_buf[i], __this->data_length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (procotol) {
|
||||
if (__this->data_length <= UART_TOOL_FORMAT_HEAD) {
|
||||
return;
|
||||
}
|
||||
p_newtool = __this->pRxBuffer;
|
||||
|
||||
if ((p_newtool->preamble0 != UART_NEW_TOOL_PREAMBLE0) || (p_newtool->preamble1 != UART_NEW_TOOL_PREAMBLE1)) {
|
||||
log_error("preamble err\n");
|
||||
log_info_hexdump(__this->pRxBuffer, __this->data_length);
|
||||
goto reset_buf;
|
||||
}
|
||||
|
||||
if (__this->data_length >= p_newtool->length + 6) {
|
||||
crc16 = crc_get_16bit(&p_newtool->length, p_newtool->length + 1);
|
||||
/* log_info("CRC16 0x%x / 0x%x", crc16, p_newtool->crc16); */
|
||||
if (p_newtool->crc16 != crc16) {
|
||||
log_error("crc16 err\n");
|
||||
goto reset_buf;
|
||||
}
|
||||
/* log_info_hexdump(p_newtool, p_newtool->length + 6); */
|
||||
online_cfg_tool_data_deal(p_newtool, p_newtool->length + 6);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
} else {
|
||||
if (__this->data_length <= UART_FORMAT_HEAD) {
|
||||
return;
|
||||
}
|
||||
p = __this->pRxBuffer;
|
||||
|
||||
if (p->preamble != UART_PREAMBLE) {
|
||||
log_info("preamble err\n");
|
||||
log_info_hexdump(__this->pRxBuffer, __this->data_length);
|
||||
goto reset_buf;
|
||||
}
|
||||
|
||||
crc16 = crc_get_16bit(__this->pRxBuffer, UART_FORMAT_HEAD - 3);
|
||||
/* log_info("CRC8 0x%x / 0x%x", crc16, p->crc8); */
|
||||
if (p->crc8 != (crc16 & 0xff)) {
|
||||
log_info("crc8 err\n");
|
||||
goto reset_buf;
|
||||
}
|
||||
if (__this->data_length >= p->length + UART_FORMAT_HEAD) {
|
||||
/* log_info("Total length : 0x%x / Rx length : 0x%x", __this->data_length, p->length + CI_FORMAT_HEAD); */
|
||||
crc16 = crc_get_16bit(p->payload, p->length);
|
||||
/* log_info("CRC16 0x%x / 0x%x", crc16, p->crc16); */
|
||||
if (p->crc16 != crc16) {
|
||||
log_info("crc16 err\n");
|
||||
goto reset_buf;
|
||||
}
|
||||
__this->packet_handler(p->payload, p->length);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
reset_buf:
|
||||
__this->data_length = 0;
|
||||
}
|
||||
|
||||
static void ci_uart_isr_cb(void *ut_bus, u32 status)
|
||||
{
|
||||
if (status == UT_TX) {
|
||||
return ;
|
||||
}
|
||||
struct sys_event e;
|
||||
e.type = SYS_DEVICE_EVENT;
|
||||
e.arg = (void *)DEVICE_EVENT_FROM_CI_UART;
|
||||
e.u.dev.event = 0;
|
||||
e.u.dev.value = 0;
|
||||
sys_event_notify(&e);
|
||||
}
|
||||
|
||||
static int ci_uart_init()
|
||||
{
|
||||
struct uart_platform_data_t ut = {0};
|
||||
ut.tx_pin = TCFG_ONLINE_TX_PORT;
|
||||
ut.rx_pin = TCFG_ONLINE_RX_PORT;
|
||||
ut.baud = __this->config.baudrate;
|
||||
ut.rx_timeout = 1;
|
||||
ut.isr_cbfun = ci_uart_isr_cb;
|
||||
ut.rx_cbuf = devBuffer_static;
|
||||
ut.rx_cbuf_size = UART_DB_SIZE;
|
||||
ut.frame_length = UART_DB_SIZE;
|
||||
/* JL_CLOCK->CLK_CON1 |= BIT(11); */
|
||||
/* JL_CLOCK->CLK_CON1 &= ~BIT(10); */
|
||||
__this->dbuf = devBuffer_static;
|
||||
__this->data_length = 0;
|
||||
__this->udev = (uart_bus_t *)uart_dev_open(&ut);
|
||||
if (__this->udev == NULL) {
|
||||
log_error("open uart dev err\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ci_uart_putbyte(char a)
|
||||
{
|
||||
if (__this->udev) {
|
||||
__this->udev->putbyte(a);
|
||||
}
|
||||
}
|
||||
|
||||
void ci_uart_write(char *buf, u16 len)
|
||||
{
|
||||
if (__this->udev) {
|
||||
__this->udev->write(buf, len);
|
||||
}
|
||||
}
|
||||
|
||||
static void dummy_handler(const u8 *packet, int size)
|
||||
{
|
||||
log_error("Dummy");
|
||||
}
|
||||
|
||||
static void clock_critical_enter(void)
|
||||
{
|
||||
|
||||
}
|
||||
static void clock_critical_exit(void)
|
||||
{
|
||||
if (__this->udev) {
|
||||
__this->udev->set_baud(__this->config.baudrate);
|
||||
}
|
||||
}
|
||||
CLOCK_CRITICAL_HANDLE_REG(ci, clock_critical_enter, clock_critical_exit)
|
||||
|
||||
static void ci_dev_init(const void *config)
|
||||
{
|
||||
#ifdef HAVE_MALLOC
|
||||
__this = malloc(sizeof(struct uart_hdl));
|
||||
ASSERT(__this, "Fatal error");
|
||||
|
||||
memset(__this, 0x0, sizeof(struct uart_hdl));
|
||||
|
||||
__this->pRxBuffer = malloc(UART_RX_SIZE);
|
||||
ASSERT(__this->pRxBuffer, "Fatal error");
|
||||
|
||||
__this->pTxBuffer = malloc(UART_TX_SIZE);
|
||||
ASSERT(__this->pTxBuffer, "Fatal error");
|
||||
#else
|
||||
log_info("Static");
|
||||
__this->pRxBuffer = pRxBuffer_static;
|
||||
__this->pTxBuffer = pTxBuffer_static;
|
||||
#endif
|
||||
|
||||
__this->packet_handler = dummy_handler;
|
||||
|
||||
ci_transport_config_uart_t *ci_config_uart = (ci_transport_config_uart_t *)config;
|
||||
|
||||
__this->config.baudrate = ci_config_uart->baudrate_init;
|
||||
__this->config.flowcontrol = ci_config_uart->flowcontrol;
|
||||
__this->config.dev_name = ci_config_uart->device_name;
|
||||
|
||||
log_info("baudrate : %d", __this->config.baudrate);
|
||||
log_info("flowcontrol: %d", __this->config.flowcontrol);
|
||||
}
|
||||
|
||||
static int ci_dev_open(void)
|
||||
{
|
||||
ci_uart_init();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ci_dev_close(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ci_dev_register_packet_handler(void (*handler)(const u8 *packet, int size))
|
||||
{
|
||||
__this->packet_handler = handler;
|
||||
}
|
||||
|
||||
static int ci_dev_send_packet(const u8 *packet, int size)
|
||||
{
|
||||
/* dev_stream_out(); */
|
||||
int i = 0;
|
||||
uart_packet_t *p = (uart_packet_t *)__this->pTxBuffer;
|
||||
|
||||
p->preamble = UART_PREAMBLE;
|
||||
p->type = 0;
|
||||
p->length = size;
|
||||
p->crc8 = CRC16(p, UART_FORMAT_HEAD - 3) & 0xff;
|
||||
p->crc16 = CRC16(packet, size);
|
||||
|
||||
size += UART_FORMAT_HEAD;
|
||||
/* ASSERT(size <= UART_TX_SIZE, "Fatal Error"); */
|
||||
if (size > UART_TX_SIZE) {
|
||||
log_e("Fatal Error");
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(p->payload, packet, size);
|
||||
|
||||
/* log_info("Tx : %d", size); */
|
||||
/* log_info_hexdump(p, size); */
|
||||
if (__this->rx_type == CI_UART) {
|
||||
#if 0
|
||||
while (size--) {
|
||||
ci_uart_putbyte(((char *)p)[i++]);
|
||||
}
|
||||
#else
|
||||
ci_uart_write(p, size);
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ci_dev_can_send_packet_now(uint8_t packet_type)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// get dev api skeletons
|
||||
static const ci_transport_t ci_transport_uart = {
|
||||
/* const char * name; */ "CI_UART",
|
||||
/* void (*init) (const void *transport_config); */ &ci_dev_init,
|
||||
/* int (*open)(void); */ &ci_dev_open,
|
||||
/* int (*close)(void); */ &ci_dev_close,
|
||||
/* void (*register_packet_handler)(void (*handler)(...); */ &ci_dev_register_packet_handler,
|
||||
/* int (*can_send_packet_now)(uint8_t packet_type); */ &ci_dev_can_send_packet_now,
|
||||
/* int (*send_packet)(...); */ &ci_dev_send_packet,
|
||||
};
|
||||
|
||||
const ci_transport_t *ci_transport_uart_instance(void)
|
||||
{
|
||||
return &ci_transport_uart;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
125
apps/common/config/include/bt_profile_cfg.h
Normal file
125
apps/common/config/include/bt_profile_cfg.h
Normal file
@ -0,0 +1,125 @@
|
||||
|
||||
#ifndef _BT_PROFILE_CFG_H_
|
||||
#define _BT_PROFILE_CFG_H_
|
||||
|
||||
#include "app_config.h"
|
||||
#include "btcontroller_modules.h"
|
||||
|
||||
|
||||
#if (TRANS_DATA_EN || RCSP_BTMATE_EN || RCSP_ADV_EN || SMART_BOX_EN || ANCS_CLIENT_EN || LL_SYNC_EN || TUYA_DEMO_EN)
|
||||
#ifndef BT_FOR_APP_EN
|
||||
#define BT_FOR_APP_EN 1
|
||||
#endif
|
||||
#else
|
||||
#ifndef BT_FOR_APP_EN
|
||||
#define BT_FOR_APP_EN 0
|
||||
#endif
|
||||
#ifndef AI_APP_PROTOCOL
|
||||
#define AI_APP_PROTOCOL 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
///---sdp service record profile- 用户选择支持协议--///
|
||||
#if (BT_FOR_APP_EN || APP_ONLINE_DEBUG || AI_APP_PROTOCOL)
|
||||
#if (LL_SYNC_EN || TUYA_DEMO_EN)
|
||||
#undef USER_SUPPORT_PROFILE_SPP
|
||||
#define USER_SUPPORT_PROFILE_SPP 0
|
||||
#else
|
||||
#undef USER_SUPPORT_PROFILE_SPP
|
||||
#define USER_SUPPORT_PROFILE_SPP 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//ble demo的例子
|
||||
#define DEF_BLE_DEMO_NULL 0 //ble 没有使能
|
||||
#define DEF_BLE_DEMO_ADV 1 //only adv,can't connect
|
||||
#define DEF_BLE_DEMO_TRANS_DATA 2 //
|
||||
#define DEF_BLE_DEMO_RCSP_DEMO 4 //
|
||||
#define DEF_BLE_DEMO_ADV_RCSP 5
|
||||
#define DEF_BLE_DEMO_CLIENT 7 //
|
||||
#define DEF_BLE_ANCS_ADV 9
|
||||
#define DEF_BLE_DEMO_MULTI 11 //
|
||||
#define DEF_BLE_DEMO_LL_SYNC 13 //
|
||||
#define DEF_BLE_DEMO_WIRELESS_MIC_SERVER 14 //
|
||||
#define DEF_BLE_DEMO_WIRELESS_MIC_CLIENT 15 //
|
||||
#define DEF_BLE_DEMO_TUYA 16 //
|
||||
#define DEF_BLE_WL_MIC_1T1_TX 17
|
||||
#define DEF_BLE_WL_MIC_1T1_RX 18
|
||||
#define DEF_BLE_WL_MIC_1TN_TX 19
|
||||
#define DEF_BLE_WL_MIC_1TN_RX 20
|
||||
#define DEF_LE_AUDIO_CENTRAL 21
|
||||
#define DEF_LE_AUDIO_PERIPHERAL 22
|
||||
#define DEF_LE_AUDIO_BROADCASTER 23
|
||||
#define DEF_BLE_DEMO_HOGP 24
|
||||
|
||||
#define LE_AUDIO_EN 0 //DEF_LE_AUDIO_CENTRAL
|
||||
|
||||
//配置选择的demo
|
||||
#if TCFG_USER_BLE_ENABLE
|
||||
|
||||
#if (SMART_BOX_EN | RCSP_BTMATE_EN)
|
||||
#define TCFG_BLE_DEMO_SELECT DEF_BLE_DEMO_RCSP_DEMO
|
||||
|
||||
#elif TRANS_DATA_EN
|
||||
#define TCFG_BLE_DEMO_SELECT DEF_BLE_DEMO_TRANS_DATA
|
||||
|
||||
#elif LL_SYNC_EN
|
||||
#define TCFG_BLE_DEMO_SELECT DEF_BLE_DEMO_LL_SYNC
|
||||
|
||||
#elif TUYA_DEMO_EN
|
||||
#define TCFG_BLE_DEMO_SELECT DEF_BLE_DEMO_TUYA
|
||||
|
||||
#elif RCSP_ADV_EN
|
||||
#define TCFG_BLE_DEMO_SELECT DEF_BLE_DEMO_ADV_RCSP
|
||||
|
||||
#elif BLE_CLIENT_EN
|
||||
#define TCFG_BLE_DEMO_SELECT DEF_BLE_DEMO_CLIENT
|
||||
|
||||
#elif TRANS_MULTI_BLE_EN
|
||||
#define TCFG_BLE_DEMO_SELECT DEF_BLE_DEMO_MULTI
|
||||
|
||||
#elif ANCS_CLIENT_EN
|
||||
#define TCFG_BLE_DEMO_SELECT DEF_BLE_ANCS_ADV
|
||||
|
||||
#elif AI_APP_PROTOCOL
|
||||
#define TCFG_BLE_DEMO_SELECT DEF_BLE_DEMO_NULL
|
||||
|
||||
#elif (BLE_WIRELESS_CLIENT_EN)
|
||||
#define TCFG_BLE_DEMO_SELECT DEF_BLE_DEMO_WIRELESS_MIC_CLIENT
|
||||
|
||||
#elif (BLE_WIRELESS_SERVER_EN)
|
||||
#define TCFG_BLE_DEMO_SELECT DEF_BLE_DEMO_WIRELESS_MIC_SERVER
|
||||
|
||||
#elif (BLE_WIRELESS_1T1_TX_EN)
|
||||
#define TCFG_BLE_DEMO_SELECT DEF_BLE_WL_MIC_1T1_TX
|
||||
|
||||
#elif (BLE_WIRELESS_1T1_RX_EN)
|
||||
#define TCFG_BLE_DEMO_SELECT DEF_BLE_WL_MIC_1T1_RX
|
||||
|
||||
#elif (BLE_WIRELESS_1TN_TX_EN)
|
||||
#define TCFG_BLE_DEMO_SELECT DEF_BLE_WL_MIC_1TN_TX
|
||||
|
||||
#elif (BLE_WIRELESS_1TN_RX_EN)
|
||||
#define TCFG_BLE_DEMO_SELECT DEF_BLE_WL_MIC_1TN_RX
|
||||
|
||||
#elif (LE_AUDIO_EN)
|
||||
#define TCFG_BLE_DEMO_SELECT LE_AUDIO_EN
|
||||
|
||||
#elif (BLE_HID_EN)
|
||||
#define TCFG_BLE_DEMO_SELECT DEF_BLE_DEMO_HOGP
|
||||
|
||||
#else
|
||||
#define TCFG_BLE_DEMO_SELECT DEF_BLE5_DEMO
|
||||
#endif
|
||||
|
||||
#else
|
||||
#define TCFG_BLE_DEMO_SELECT DEF_BLE_DEMO_NULL//ble is closed
|
||||
#endif
|
||||
|
||||
//delete 2021-09-24;删除公共配置,放到各个profile自己配置
|
||||
// #define TCFG_BLE_SECURITY_EN 0 /*是否发请求加密命令*/
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
242
apps/common/config/include/cfg_tool.h
Normal file
242
apps/common/config/include/cfg_tool.h
Normal file
@ -0,0 +1,242 @@
|
||||
#ifndef _APP_SOUND_BOX_
|
||||
#define _APP_SOUND_BOX_
|
||||
|
||||
#include "typedef.h"
|
||||
#include "sdfile.h"
|
||||
#include "fs.h"
|
||||
#include "asm/sfc_norflash_api.h"
|
||||
#include "event.h"
|
||||
|
||||
/*
|
||||
* 波特率默认为 115200
|
||||
* 对于物理串口,且是异步形式的协议,封包方式如下
|
||||
*
|
||||
* CRC是 CRC16(L + T + SQ + DATA)
|
||||
* 其中,L是指(T+SQ+DATA)的长度
|
||||
* DATA包含CMD与具体的数据流
|
||||
*
|
||||
* +----+----+----+--+--+---+---+----+---....---+
|
||||
* | 5A | AA | A5 | CRC | L | T | SQ | DATA |
|
||||
* +----+----+----+--+--+---+---+----+---....---+
|
||||
*
|
||||
* T 表示包的类型,其中
|
||||
* 0x00 -- 表示回复,其中SQ是对应需要回应的包的序号
|
||||
* 无论哪种模式下,回复包都用该种类型
|
||||
* 0x12 -- 表示配置文件通道,是主动发送数据
|
||||
* 例如,在配置工具中,PC往小机或者小机往PC主动发都用这个
|
||||
*/
|
||||
|
||||
/*T 表示包的类型*/
|
||||
#define REPLY_STYLE 0x00 //无论哪种模式下,回复包都用该种类型
|
||||
#define INITIATIVE_STYLE 0x12 //主动发送数据的包用该类型
|
||||
#define SLAVE_ATIVE_SEND 0x01 //小机主动上发给PC
|
||||
#define EFF_CONFIG_ID 0x11 //调音
|
||||
/*
|
||||
*0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
||||
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
| VERSION |AT| X| X| X| X| X| X| X| X| X| X| X|
|
||||
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
*/
|
||||
#define PROTOCOL_VER_AT_NEW 0x0001 //使用新模式
|
||||
#define PROTOCOL_VER_AT_OLD 0x0011 //使用旧模式
|
||||
|
||||
|
||||
/*该文件所属文件ID为0*/
|
||||
#define CFG_TOOL_FILEID 0x00000000
|
||||
|
||||
/*该文件所属文件ID为0*/
|
||||
#if ((defined CONFIG_NEW_CFG_TOOL_ENABLE) && ((defined CONFIG_SOUNDBOX) \
|
||||
|| (defined CONFIG_EARPHONE_CASE_ENABLE)))
|
||||
#define CFG_TOOL_FILE SDFILE_RES_ROOT_PATH"cfg_tool.bin"
|
||||
#else
|
||||
#define CFG_TOOL_FILE SDFILE_APP_ROOT_PATH"cfg_tool.bin"
|
||||
#endif
|
||||
|
||||
/*旧调音工具eq文件所属文件ID为1*/
|
||||
#define CFG_OLD_EQ_FILEID 0x00000001
|
||||
#define CFG_OLD_EQ_FILE SDFILE_RES_ROOT_PATH"eq_cfg_hw.bin"
|
||||
|
||||
/*旧调音工具混响文件所属文件ID为2*/
|
||||
#define CFG_OLD_EFFECT_FILEID 0x00000002
|
||||
#define CFG_OLD_EFFECT_FILE SDFILE_RES_ROOT_PATH"effects_cfg.bin"
|
||||
|
||||
/*新调音工具eq文件所属文件ID为3*/
|
||||
#define CFG_EQ_FILEID 0x00000003
|
||||
#define CFG_EQ_FILE SDFILE_RES_ROOT_PATH"eq_cfg_hw.bin"
|
||||
|
||||
/*****************************************************************/
|
||||
/****PC与小机使用到的CMD,CMD包含在DATA中,为DATA的第一个Byte*****/
|
||||
/*****************************************************************/
|
||||
|
||||
#define ONLINE_SUB_OP_QUERY_BASIC_INFO 0x00000023 //查询固件的基本信息
|
||||
#define ONLINE_SUB_OP_QUERY_FILE_SIZE 0x0000000B //查询文件大小
|
||||
#define ONLINE_SUB_OP_QUERY_FILE_CONTENT 0x0000000C //读取文件内容
|
||||
#define ONLINE_SUB_OP_PREPARE_WRITE_FILE 0x00000022 //准备写入文件
|
||||
#define ONLINE_SUB_OP_READ_ADDR_RANGE 0x00000027 //读取地址范围内容
|
||||
#define ONLINE_SUB_OP_ERASE_ADDR_RANGE 0x00000024 //擦除地址范围内容
|
||||
#define ONLINE_SUB_OP_WRITE_ADDR_RANGE 0x00000025 //写入地址范围内容
|
||||
#define ONLINE_SUB_OP_ENTER_UPGRADE_MODE 0x00000026 //进入升级模式
|
||||
|
||||
/*收到其他工具的数据*/
|
||||
#define DEFAULT_ACTION 0x000000FF //其他工具的数据
|
||||
|
||||
/*****************************************************************/
|
||||
/*****小机接收PC的DATA,具体携带的数据,依据命令不同而不同**********/
|
||||
/*****************************************************************/
|
||||
|
||||
//查询固件的基本信息
|
||||
typedef struct {
|
||||
uint32_t cmd_id; //命令号,为0x23
|
||||
} R_QUERY_BASIC_INFO;
|
||||
|
||||
//查询文件大小
|
||||
typedef struct {
|
||||
uint32_t cmd_id; //命令号,为0x0B
|
||||
uint32_t file_id; //查询的文件的ID,配置文件的ID为0
|
||||
} R_QUERY_FILE_SIZE;
|
||||
|
||||
//读取文件内容
|
||||
typedef struct {
|
||||
uint32_t cmd_id; //命令号,为0x0C
|
||||
uint32_t file_id; //文件ID
|
||||
uint32_t offset; //偏移
|
||||
uint32_t size;
|
||||
} R_QUERY_FILE_CONTENT;
|
||||
|
||||
//准备写入文件
|
||||
typedef struct {
|
||||
uint32_t cmd_id; //命令号,为0x22
|
||||
uint32_t file_id; //文件ID
|
||||
uint32_t size; //文件大小
|
||||
} R_PREPARE_WRITE_FILE;
|
||||
|
||||
//读取地址范围内容
|
||||
typedef struct {
|
||||
uint32_t cmd_id; //命令号,为0x23
|
||||
uint32_t addr; //flash的物理地址
|
||||
uint32_t size; //读取的范围大小
|
||||
} R_READ_ADDR_RANGE;
|
||||
|
||||
//擦除地址范围内容
|
||||
typedef struct {
|
||||
uint32_t cmd_id; //命令号,为0x24
|
||||
uint32_t addr; //起始地址
|
||||
uint32_t size; //擦除大小
|
||||
} R_ERASE_ADDR_RANGE;
|
||||
|
||||
//写入地址范围内容
|
||||
typedef struct {
|
||||
uint32_t cmd_id; //命令号,为0x25
|
||||
uint32_t addr; //物理地址
|
||||
uint32_t size; //内容大小
|
||||
/*uint8_t body[0];*/ //具体内容,大小为size
|
||||
} R_WRITE_ADDR_RANGE;
|
||||
|
||||
//进入升级模式
|
||||
typedef struct {
|
||||
uint32_t cmd_id; //命令号,为0x26
|
||||
} R_ENTER_UPGRADE_MODE;
|
||||
|
||||
/*****************************************************************/
|
||||
/*******小机返回PC发送的DATA,具体的内容,依据命令不同而不同********/
|
||||
/*****************************************************************/
|
||||
|
||||
//(1)查询固件的基本信息
|
||||
typedef struct {
|
||||
uint16_t protocolVer; //协议版本,目前为1
|
||||
char progCrc[32]; //固件的CRC,返回字符串,\0 结尾
|
||||
char sdkName[32]; //SDK名字,\0 结尾
|
||||
char pid[16]; //PID,\0 结尾(注意最长是16字节,16字节的时候,末尾不需要0)
|
||||
char vid[16]; //VID,\0 结尾
|
||||
} S_QUERY_BASIC_INFO;
|
||||
|
||||
//(2)查询文件大小
|
||||
typedef struct {
|
||||
uint32_t file_size; //文件大小
|
||||
} S_QUERY_FILE_SIZE;
|
||||
|
||||
//(3)读取文件内容
|
||||
/*
|
||||
* 返回:具体的文件内容,长度为命令中的size参数
|
||||
* 注:PC工具在获取配置文件的大小后,会自行决定拆分成几次命令读取
|
||||
*/
|
||||
|
||||
//(4)准备写入文件
|
||||
/*
|
||||
* 例如,cfg_tool.bin 本身的物理地址可能是 100,而擦除单元是 4K(4096),cfg_tool.bin 本身大小是 3999 字节,则
|
||||
* file_addr = 100, file_size = 3999, earse_unit = 4096。
|
||||
* 注意,接下来,PC 端会读取```[0, 8192)```这个范围的内容,修改掉```[100,4099]```的内容,然后再通过其他命令,
|
||||
* 把```[0,8192)```这范围的内容写回去。
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t file_addr; //配置文件真实物理地址
|
||||
uint32_t file_size; //配置文件(cfg_tool.bin)本身的大小
|
||||
uint32_t earse_unit; //flash 擦除单元(如 4K 的时候,填 4096)
|
||||
} S_PREPARE_WRITE_FILE;
|
||||
|
||||
|
||||
//(5)读取地址范围内容
|
||||
/*
|
||||
* 返回:具体的文件内容,长度为命令中的size参数
|
||||
* 注:PC工具在获取配置文件的大小后,会自行决定拆分成几次命令读取
|
||||
*/
|
||||
|
||||
//(6)擦除地址范围内容
|
||||
/*
|
||||
*返回两个字节的内容,"FA"或者"OK",表示失败或者成功
|
||||
*/
|
||||
|
||||
//(7)写入地址范围内容
|
||||
/*
|
||||
*返回两个字节的内容,"FA"或者"OK",表示失败或者成功
|
||||
*/
|
||||
|
||||
//(8)进入升级模式
|
||||
/*
|
||||
*小机收到命令后,进入升级模式
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------------*/
|
||||
/**
|
||||
* @brief usb或者串口收到的数据流通过这个接口传入进行数据解析
|
||||
*
|
||||
* @param buf 存储普通串口/USB收到的数据包
|
||||
* @param len buf的长度(byte)
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
/* --------------------------------------------------------------------------*/
|
||||
void online_cfg_tool_data_deal(void *buf, u32 len);
|
||||
|
||||
/* --------------------------------------------------------------------------*/
|
||||
/**
|
||||
* @brief 设备组装数据包并发送给PC工具,支持普通串口/USB串口/蓝牙SPP
|
||||
*
|
||||
* @param id 表示包的类型(不同的数据通道)
|
||||
* @param sq 对应需要回应的包的序号
|
||||
* @param buf 要发送的数据爆DATA部分
|
||||
* @param len buf的长度(byte)
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
/* --------------------------------------------------------------------------*/
|
||||
void all_assemble_package_send_to_pc(u8 id, u8 sq, u8 *buf, u32 len);
|
||||
|
||||
int app_cfg_tool_event_handler(struct cfg_tool_event *cfg_tool_dev);
|
||||
|
||||
struct tool_interface {
|
||||
u8 id;//通道
|
||||
void (*tool_message_deal)(u8 *buf, u32 len);//数据处理接口
|
||||
};
|
||||
|
||||
#define REGISTER_DETECT_TARGET(interface) \
|
||||
static struct tool_interface interface sec(.tool_interface)
|
||||
|
||||
extern struct tool_interface tool_interface_begin[];
|
||||
extern struct tool_interface tool_interface_end[];
|
||||
|
||||
#define list_for_each_tool_interface(p) \
|
||||
for (p = tool_interface_begin; p < tool_interface_end; p++)
|
||||
|
||||
#endif
|
||||
|
||||
599
apps/common/config/new_cfg_tool.c
Normal file
599
apps/common/config/new_cfg_tool.c
Normal file
@ -0,0 +1,599 @@
|
||||
#include "cfg_tool.h"
|
||||
#include "event.h"
|
||||
#include "usb/device/cdc.h"
|
||||
#include "boot.h"
|
||||
#include "ioctl_cmds.h"
|
||||
#include "board_config.h"
|
||||
#include "app_online_cfg.h"
|
||||
#include "asm/crc16.h"
|
||||
#include "app_config.h"
|
||||
#include "config/config_target.h"
|
||||
#if APP_ONLINE_DEBUG
|
||||
#include "online_db_deal.h"
|
||||
#endif/*APP_ONLINE_DEBUG*/
|
||||
|
||||
/*
|
||||
*调音工具在线保存功能由协议接管,通道使用0x12,不分发给调音处理
|
||||
*配置工具通道为0x12,调音工具在线保存功能相关数据包通道必须设置为0x12
|
||||
*new_cfg_tool.c适用于新耳机/音箱配置工具和调音工具在线保存功能
|
||||
*支持异步协议和蓝牙SPP协议的数据解析与通信
|
||||
*/
|
||||
|
||||
#define LOG_TAG_CONST APP_CFG_TOOL
|
||||
#define LOG_TAG "[APP_CFG_TOOL]"
|
||||
#define LOG_ERROR_ENABLE
|
||||
#define LOG_DEBUG_ENABLE
|
||||
#define LOG_INFO_ENABLE
|
||||
/* #define LOG_DUMP_ENABLE */
|
||||
#define LOG_CLI_ENABLE
|
||||
#include "debug.h"
|
||||
|
||||
struct cfg_tool_info {
|
||||
/*PC往小机发送的DATA*/
|
||||
R_QUERY_BASIC_INFO r_basic_info;
|
||||
R_QUERY_FILE_SIZE r_file_size;
|
||||
R_QUERY_FILE_CONTENT r_file_content;
|
||||
R_PREPARE_WRITE_FILE r_prepare_write_file;
|
||||
R_READ_ADDR_RANGE r_read_addr_range;
|
||||
R_ERASE_ADDR_RANGE r_erase_addr_range;
|
||||
R_WRITE_ADDR_RANGE r_write_addr_range;
|
||||
R_ENTER_UPGRADE_MODE r_enter_upgrade_mode;
|
||||
|
||||
/*小机返回PC发送的DATA*/
|
||||
S_QUERY_BASIC_INFO s_basic_info;
|
||||
S_QUERY_FILE_SIZE s_file_size;
|
||||
S_PREPARE_WRITE_FILE s_prepare_write_file;
|
||||
};
|
||||
|
||||
static struct cfg_tool_info info = {
|
||||
.s_basic_info.protocolVer = PROTOCOL_VER_AT_OLD,
|
||||
};
|
||||
|
||||
#define TEMP_BUF_SIZE 256
|
||||
|
||||
extern const char *sdk_version_info_get(void);
|
||||
extern u8 *sdfile_get_burn_code(u8 *len);
|
||||
extern int norflash_erase(u32 cmd, u32 addr);
|
||||
|
||||
static u8 local_packet[TEMP_BUF_SIZE];
|
||||
const char error_return[] = "FA"; //表示失败
|
||||
const char ok_return[] = "OK"; //表示成功
|
||||
const char er_return[] = "ER"; //表示不能识别的命令
|
||||
static u32 size_total_write = 0;
|
||||
|
||||
extern void doe(u16 k, void *pBuf, u32 lenIn, u32 addr);
|
||||
extern int norflash_erase(u32 cmd, u32 addr);
|
||||
|
||||
#ifdef ALIGN
|
||||
#undef ALIGN
|
||||
#endif
|
||||
#define ALIGN(a, b) \
|
||||
({ \
|
||||
int m = (u32)(a) & ((b)-1); \
|
||||
int ret = (u32)(a) + (m?((b)-m):0); \
|
||||
ret;\
|
||||
})
|
||||
|
||||
static u32 cfg_tool_encode_data_by_user_key(u16 key, u8 *buff, u16 size, u32 dec_addr, u8 dec_len)
|
||||
{
|
||||
u16 key_addr;
|
||||
u16 r_len;
|
||||
|
||||
while (size) {
|
||||
r_len = (size > dec_len) ? dec_len : size;
|
||||
key_addr = (dec_addr >> 2)^key;
|
||||
doe(key_addr, buff, r_len, 0);
|
||||
buff += r_len;
|
||||
dec_addr += r_len;
|
||||
size -= r_len;
|
||||
}
|
||||
|
||||
return dec_addr;
|
||||
}
|
||||
|
||||
static u8 parse_seq = 0;
|
||||
static void ci_send_packet_new(u32 id, u8 *packet, int size)
|
||||
{
|
||||
#if APP_ONLINE_DEBUG
|
||||
app_online_db_ack(parse_seq, packet, size);
|
||||
#endif/*APP_ONLINE_DEBUG*/
|
||||
}
|
||||
|
||||
struct cfg_tool_event spp_packet;
|
||||
int cfg_tool_online_parse(u8 *buf, u32 len)
|
||||
{
|
||||
parse_seq = buf[2];
|
||||
u32 event = (buf[3] | (buf[4] << 8) | (buf[5] << 16) | (buf[6] << 24));
|
||||
spp_packet.event = event;
|
||||
spp_packet.packet = buf;
|
||||
spp_packet.size = len;
|
||||
return (app_cfg_tool_event_handler(&spp_packet));
|
||||
}
|
||||
|
||||
void all_assemble_package_send_to_pc(u8 id, u8 sq, u8 *buf, u32 len)
|
||||
{
|
||||
u8 *send_buf = NULL;
|
||||
u16 crc16_data;
|
||||
|
||||
send_buf = (u8 *)malloc(TEMP_BUF_SIZE);
|
||||
if (send_buf == NULL) {
|
||||
log_error("send_buf malloc err!");
|
||||
return;
|
||||
}
|
||||
|
||||
send_buf[0] = 0x5A;
|
||||
send_buf[1] = 0xAA;
|
||||
send_buf[2] = 0xA5;
|
||||
send_buf[5] = 2 + len;/*L*/
|
||||
send_buf[6] = id;/*T*/
|
||||
send_buf[7] = sq;/*SQ*/
|
||||
memcpy(send_buf + 8, buf, len);
|
||||
/*添加CRC16*/
|
||||
crc16_data = CRC16(&send_buf[5], len + 3);
|
||||
send_buf[3] = crc16_data & 0xff;
|
||||
send_buf[4] = (crc16_data >> 8) & 0xff;
|
||||
|
||||
/* printf_buf(send_buf, len + 8); */
|
||||
|
||||
#if (TCFG_CFG_TOOL_ENABLE || TCFG_ONLINE_ENABLE)
|
||||
#if (TCFG_COMM_TYPE == TCFG_SPP_COMM)
|
||||
ci_send_packet_new(INITIATIVE_STYLE, buf, len);
|
||||
#elif (TCFG_COMM_TYPE == TCFG_USB_COMM)
|
||||
cdc_write_data(0, send_buf, len + 8);
|
||||
#elif (TCFG_COMM_TYPE == TCFG_UART_COMM)
|
||||
ci_uart_write(send_buf, len + 8);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
free(send_buf);
|
||||
}
|
||||
|
||||
/*6个byte的校验码数组转为字符串*/
|
||||
void hex2text(u8 *buf, u8 *out)
|
||||
{
|
||||
sprintf(out, "%02x%02x-%02x%02x%02x%02x", buf[5], buf[4], buf[3], buf[2], buf[1], buf[0]);
|
||||
}
|
||||
|
||||
u32 packet_combined(u8 *packet, u8 num)
|
||||
{
|
||||
u32 _packet = 0;
|
||||
_packet = (packet[num] | (packet[num + 1] << 8) | (packet[num + 2] << 16) | (packet[num + 3] << 24));
|
||||
return _packet;
|
||||
}
|
||||
|
||||
FILE *cfg_open_file(u32 file_id)
|
||||
{
|
||||
FILE *cfg_fp = NULL;
|
||||
if (file_id <= CFG_EQ_FILEID) {
|
||||
if ((file_id == CFG_TOOL_FILEID)) {
|
||||
cfg_fp = fopen(CFG_TOOL_FILE, "r");
|
||||
log_info("open cfg_tool.bin\n");
|
||||
} else if ((file_id == CFG_OLD_EQ_FILEID)) {
|
||||
cfg_fp = fopen(CFG_OLD_EQ_FILE, "r");
|
||||
log_info("open old eq_cfg_hw.bin\n");
|
||||
} else if ((file_id == CFG_OLD_EFFECT_FILEID)) {
|
||||
cfg_fp = fopen(CFG_OLD_EFFECT_FILE, "r");
|
||||
log_info("open effects_cfg.bin\n");
|
||||
} else if ((file_id == CFG_EQ_FILEID)) {
|
||||
cfg_fp = fopen(CFG_EQ_FILE, "r");
|
||||
log_info("open eq_cfg_hw.bin\n");
|
||||
}
|
||||
}
|
||||
return cfg_fp;
|
||||
}
|
||||
|
||||
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 cfg_tool_go_mask_usb_updata()
|
||||
{
|
||||
local_irq_disable();
|
||||
ram_protect_close();
|
||||
hw_mmu_disable();
|
||||
nvram_set_boot_state(2);
|
||||
|
||||
JL_CLOCK->PWR_CON |= (1 << 4);
|
||||
/* chip_reset(); */
|
||||
/* cpu_reset(); */
|
||||
while (1);
|
||||
}
|
||||
|
||||
/*延时复位防止工具升级进度条显示错误*/
|
||||
static void delay_cpu_reset(void *priv)
|
||||
{
|
||||
extern void cpu_reset();
|
||||
cpu_reset();
|
||||
}
|
||||
|
||||
int app_cfg_tool_event_handler(struct cfg_tool_event *cfg_tool_dev)
|
||||
{
|
||||
u8 *buf = NULL;
|
||||
u8 *buf_temp = NULL;
|
||||
u8 *buf_temp_0 = NULL;
|
||||
u8 valid_cmd;
|
||||
u32 erase_cmd;
|
||||
int write_len;
|
||||
int send_len;
|
||||
u8 crc_temp_len, sdkname_temp_len;
|
||||
char proCrc_fw[32] = {0};
|
||||
char sdkName_fw[32] = {0};
|
||||
const struct tool_interface *p;
|
||||
struct vfs_attr attr;
|
||||
FILE *cfg_fp = NULL;
|
||||
|
||||
/* printf_buf(cfg_tool_dev->packet, cfg_tool_dev->size); */
|
||||
|
||||
buf = (u8 *)malloc(TEMP_BUF_SIZE);
|
||||
if (buf == NULL) {
|
||||
log_error("buf malloc err!");
|
||||
return 0;
|
||||
}
|
||||
buf_temp_0 = (u8 *)malloc(TEMP_BUF_SIZE);
|
||||
if (buf_temp_0 == NULL) {
|
||||
free(buf);
|
||||
log_error("buf_temp_0 malloc err!");
|
||||
return 0;
|
||||
}
|
||||
buf_temp_0 = (u8 *)ALIGN(buf_temp_0, 4);
|
||||
memset(buf_temp_0, 0, TEMP_BUF_SIZE);
|
||||
memcpy(buf_temp_0 + 1, cfg_tool_dev->packet, cfg_tool_dev->size);
|
||||
|
||||
/*数据进行处理*/
|
||||
list_for_each_tool_interface(p) {
|
||||
if (p->id == cfg_tool_dev->packet[1]) {
|
||||
p->tool_message_deal(buf_temp_0 + 2, cfg_tool_dev->size - 1);
|
||||
free(buf_temp_0);
|
||||
free(buf);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
memset(buf, 0, TEMP_BUF_SIZE);
|
||||
|
||||
switch (cfg_tool_dev->event) {
|
||||
case ONLINE_SUB_OP_QUERY_BASIC_INFO:
|
||||
valid_cmd = 1;
|
||||
/* log_info("event_ONLINE_SUB_OP_QUERY_BASIC_INFO\n"); */
|
||||
/*获取校验码*/
|
||||
u8 *p = sdfile_get_burn_code(&crc_temp_len);
|
||||
memcpy(info.s_basic_info.progCrc, p + 8, 6);
|
||||
/* printf_buf(info.s_basic_info.progCrc, 6); */
|
||||
hex2text(info.s_basic_info.progCrc, proCrc_fw);
|
||||
/* log_info("crc:%s\n", proCrc_fw); */
|
||||
|
||||
/*获取固件版本信息*/
|
||||
sdkname_temp_len = strlen(sdk_version_info_get());
|
||||
memcpy(info.s_basic_info.sdkName, sdk_version_info_get(), sdkname_temp_len);
|
||||
memcpy(sdkName_fw, info.s_basic_info.sdkName, sdkname_temp_len);
|
||||
/* log_info("version:%s\n", sdk_version_info_get()); */
|
||||
|
||||
struct flash_head flash_head_for_pid_vid;
|
||||
|
||||
for (u8 i = 0; i < 5; i++) {
|
||||
norflash_read(NULL, (u8 *)&flash_head_for_pid_vid, 32, 0x1000 * i);
|
||||
doe(0xffff, (u8 *)&flash_head_for_pid_vid, 32, 0);
|
||||
if (flash_head_for_pid_vid.crc == 0xffff) {
|
||||
continue;
|
||||
} else {
|
||||
log_info("flash head addr = 0x%x\n", 0x1000 * i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
struct flash_head _head;
|
||||
struct flash_head *temp_p = &_head;
|
||||
memcpy(temp_p, &flash_head_for_pid_vid, 32);
|
||||
|
||||
memset(info.s_basic_info.pid, 0, sizeof(info.s_basic_info.pid));
|
||||
memcpy(info.s_basic_info.pid, temp_p->pid, sizeof(info.s_basic_info.pid));
|
||||
for (u8 i = 0; i < sizeof(info.s_basic_info.pid); i++) {
|
||||
if (~info.s_basic_info.pid[i] == 0x00) {
|
||||
info.s_basic_info.pid[i] = 0x00;
|
||||
}
|
||||
}
|
||||
/* printf_buf(info.s_basic_info.pid, 16); */
|
||||
|
||||
memset(info.s_basic_info.vid, 0, sizeof(info.s_basic_info.vid));
|
||||
memcpy(info.s_basic_info.vid, temp_p->vid, 4);
|
||||
/* printf_buf(info.s_basic_info.vid, 16); */
|
||||
|
||||
send_len = sizeof(info.s_basic_info.protocolVer) + sizeof(proCrc_fw) + sizeof(sdkName_fw) + 32;
|
||||
buf[0] = info.s_basic_info.protocolVer & 0xff;
|
||||
buf[1] = (info.s_basic_info.protocolVer >> 8) & 0xff;
|
||||
memcpy(buf + 2, proCrc_fw, sizeof(proCrc_fw));
|
||||
memcpy(buf + 2 + sizeof(proCrc_fw), sdkName_fw, sizeof(sdkName_fw));
|
||||
memcpy(buf + 2 + sizeof(proCrc_fw) + sizeof(sdkName_fw), info.s_basic_info.pid, 16);
|
||||
memcpy(buf + 2 + sizeof(proCrc_fw) + sizeof(sdkName_fw) + 16, info.s_basic_info.vid, 16);
|
||||
break;
|
||||
case ONLINE_SUB_OP_QUERY_FILE_SIZE:
|
||||
valid_cmd = 1;
|
||||
/* log_info("event_ONLINE_SUB_OP_QUERY_FILE_SIZE\n"); */
|
||||
info.r_file_size.file_id = packet_combined(cfg_tool_dev->packet, 7);
|
||||
cfg_fp = cfg_open_file(info.r_file_size.file_id);
|
||||
|
||||
if (cfg_fp == NULL) {
|
||||
log_error("file open error!\n");
|
||||
goto _exit_;
|
||||
}
|
||||
fget_attrs(cfg_fp, &attr);
|
||||
|
||||
/* log_info("file addr:%x,file size:%d\n", attr.sclust, attr.fsize); */
|
||||
info.s_file_size.file_size = attr.fsize;
|
||||
|
||||
send_len = sizeof(info.s_file_size.file_size);//长度
|
||||
|
||||
/*小端格式*/
|
||||
buf[3] = (info.s_file_size.file_size >> 24) & 0xff;
|
||||
buf[2] = (info.s_file_size.file_size >> 16) & 0xff;
|
||||
buf[1] = (info.s_file_size.file_size >> 8) & 0xff;
|
||||
buf[0] = info.s_file_size.file_size & 0xff;
|
||||
|
||||
fclose(cfg_fp);
|
||||
break;
|
||||
case ONLINE_SUB_OP_QUERY_FILE_CONTENT:
|
||||
valid_cmd = 1;
|
||||
/* log_info("event_ONLINE_SUB_OP_QUERY_FILE_CONTENT\n"); */
|
||||
info.r_file_content.file_id = packet_combined(cfg_tool_dev->packet, 7);
|
||||
info.r_file_content.offset = packet_combined(cfg_tool_dev->packet, 11);
|
||||
info.r_file_content.size = packet_combined(cfg_tool_dev->packet, 15);
|
||||
|
||||
cfg_fp = cfg_open_file(info.r_file_content.file_id);
|
||||
|
||||
if (cfg_fp == NULL) {
|
||||
log_error("file open error!\n");
|
||||
goto _exit_;
|
||||
}
|
||||
fget_attrs(cfg_fp, &attr);
|
||||
|
||||
/* log_info("file addr:%x,file size:%d\n", attr.sclust, attr.fsize); */
|
||||
if (info.r_file_content.size > attr.fsize) {
|
||||
fclose(cfg_fp);
|
||||
log_error("reading size more than actual size!\n");
|
||||
break;
|
||||
}
|
||||
|
||||
/*逻辑地址转换成flash物理地址*/
|
||||
u32 flash_addr = sdfile_cpu_addr2flash_addr(attr.sclust);
|
||||
/* log_info("flash_addr:0x%x", flash_addr); */
|
||||
/*读取文件内容*/
|
||||
buf_temp = (char *)malloc(info.r_file_content.size);
|
||||
norflash_read(NULL, (void *)buf_temp, info.r_file_content.size, flash_addr + info.r_file_content.offset);
|
||||
/* printf_buf(buf_temp, info.r_file_content.size); */
|
||||
send_len = info.r_file_content.size;
|
||||
memcpy(buf, buf_temp, info.r_file_content.size);
|
||||
|
||||
if (buf_temp) {
|
||||
free(buf_temp);
|
||||
}
|
||||
fclose(cfg_fp);
|
||||
break;
|
||||
case ONLINE_SUB_OP_PREPARE_WRITE_FILE:
|
||||
valid_cmd = 1;
|
||||
/* log_info("event_ONLINE_SUB_OP_PREPARE_WRITE_FILE\n"); */
|
||||
info.r_prepare_write_file.file_id = packet_combined(cfg_tool_dev->packet, 7);
|
||||
info.r_prepare_write_file.size = packet_combined(cfg_tool_dev->packet, 11);
|
||||
|
||||
cfg_fp = cfg_open_file(info.r_prepare_write_file.file_id);
|
||||
if (cfg_fp == NULL) {
|
||||
log_error("file open error!\n");
|
||||
break;
|
||||
}
|
||||
fget_attrs(cfg_fp, &attr);
|
||||
|
||||
/* log_info("file addr:%x,file size:%d\n", attr.sclust, attr.fsize); */
|
||||
if (info.r_prepare_write_file.size > attr.fsize) {
|
||||
//fclose(cfg_fp);
|
||||
//log_error("preparing to write size more than actual size!\n");
|
||||
//break;
|
||||
}
|
||||
|
||||
info.s_prepare_write_file.file_size = attr.fsize;
|
||||
info.s_prepare_write_file.file_addr = sdfile_cpu_addr2flash_addr(attr.sclust);
|
||||
info.s_prepare_write_file.earse_unit = boot_info.vm.align * 256;
|
||||
|
||||
send_len = sizeof(info.s_prepare_write_file.file_size) * 3;
|
||||
|
||||
buf[3] = (info.s_prepare_write_file.file_addr >> 24) & 0xff;
|
||||
buf[2] = (info.s_prepare_write_file.file_addr >> 16) & 0xff;
|
||||
buf[1] = (info.s_prepare_write_file.file_addr >> 8) & 0xff;
|
||||
buf[0] = info.s_prepare_write_file.file_addr & 0xff;
|
||||
|
||||
buf[7] = (info.s_prepare_write_file.file_size >> 24) & 0xff;
|
||||
buf[6] = (info.s_prepare_write_file.file_size >> 16) & 0xff;
|
||||
buf[5] = (info.s_prepare_write_file.file_size >> 8) & 0xff;
|
||||
buf[4] = info.s_prepare_write_file.file_size & 0xff;
|
||||
|
||||
buf[11] = (info.s_prepare_write_file.earse_unit >> 24) & 0xff;
|
||||
buf[10] = (info.s_prepare_write_file.earse_unit >> 16) & 0xff;
|
||||
buf[9] = (info.s_prepare_write_file.earse_unit >> 8) & 0xff;
|
||||
buf[8] = info.s_prepare_write_file.earse_unit & 0xff;
|
||||
|
||||
fclose(cfg_fp);
|
||||
break;
|
||||
case ONLINE_SUB_OP_READ_ADDR_RANGE:
|
||||
valid_cmd = 1;
|
||||
/* log_info("event_ONLINE_SUB_OP_READ_ADDR_RANGE\n"); */
|
||||
info.r_read_addr_range.addr = packet_combined(cfg_tool_dev->packet, 7);
|
||||
/* log_info("reading flash addr:0x%x\n", info.r_read_addr_range.addr); */
|
||||
info.r_read_addr_range.size = packet_combined(cfg_tool_dev->packet, 11);
|
||||
/* log_info("reading size = %d\n", info.r_read_addr_range.size); */
|
||||
buf_temp = (char *)malloc(info.r_read_addr_range.size);
|
||||
norflash_read(NULL, (void *)buf_temp, info.r_read_addr_range.size, info.r_read_addr_range.addr);
|
||||
/* printf_buf(buf_temp, info.r_read_addr_range.size); */
|
||||
|
||||
send_len = info.r_read_addr_range.size;
|
||||
memcpy(buf, buf_temp, info.r_read_addr_range.size);
|
||||
|
||||
if (buf_temp) {
|
||||
free(buf_temp);
|
||||
}
|
||||
break;
|
||||
case ONLINE_SUB_OP_ERASE_ADDR_RANGE:
|
||||
valid_cmd = 1;
|
||||
/* log_info("event_ONLINE_SUB_OP_ERASE_ADDR_RANGE\n"); */
|
||||
info.r_erase_addr_range.addr = packet_combined(cfg_tool_dev->packet, 7);
|
||||
/* log_info("erasing flash start addr:0x%x\n", info.r_erase_addr_range.addr); */
|
||||
/*要擦除的大小,会保证按earse_unit对齐,即总是erase_unit的倍数*/
|
||||
info.r_erase_addr_range.size = packet_combined(cfg_tool_dev->packet, 11);
|
||||
/* log_info("erasing size = %d\n", info.r_erase_addr_range.size); */
|
||||
/* log_info("earse_unit = %d\n", info.s_prepare_write_file.earse_unit); */
|
||||
switch (info.s_prepare_write_file.earse_unit) {
|
||||
case 256:
|
||||
erase_cmd = IOCTL_ERASE_PAGE;
|
||||
break;
|
||||
case (4*1024):
|
||||
erase_cmd = IOCTL_ERASE_SECTOR;
|
||||
break;
|
||||
case (64*1024):
|
||||
erase_cmd = IOCTL_ERASE_BLOCK;
|
||||
break;
|
||||
defualt:
|
||||
memcpy(buf, error_return, sizeof(error_return));
|
||||
log_error("erase error!");
|
||||
break;
|
||||
}
|
||||
|
||||
for (u8 i = 0; i < (info.r_erase_addr_range.size / info.s_prepare_write_file.earse_unit); i ++) {
|
||||
u8 ret = norflash_erase(erase_cmd, info.r_erase_addr_range.addr + (i * info.s_prepare_write_file.earse_unit));
|
||||
if (ret) {
|
||||
memcpy(buf, error_return, sizeof(error_return));
|
||||
log_error("erase error!");
|
||||
} else {
|
||||
memcpy(buf, ok_return, sizeof(ok_return));
|
||||
log_info("erase success");
|
||||
}
|
||||
}
|
||||
|
||||
send_len = sizeof(error_return);
|
||||
break;
|
||||
case ONLINE_SUB_OP_WRITE_ADDR_RANGE:
|
||||
valid_cmd = 1;
|
||||
/* log_info("event_ONLINE_SUB_OP_WRITE_ADDR_RANGE\n"); */
|
||||
info.r_write_addr_range.addr = packet_combined(cfg_tool_dev->packet, 7);
|
||||
info.r_write_addr_range.size = packet_combined(cfg_tool_dev->packet, 11);
|
||||
/* log_info("writing flash start addr:0x%x\n", info.r_write_addr_range.addr); */
|
||||
/* log_info("writing size = %d\n", info.r_write_addr_range.size); */
|
||||
buf_temp = (char *)malloc(info.r_write_addr_range.size);
|
||||
memcpy(buf_temp, cfg_tool_dev->packet + 15, info.r_write_addr_range.size);
|
||||
/* printf_buf(buf_temp, info.r_write_addr_range.size); */
|
||||
|
||||
cfg_tool_encode_data_by_user_key(boot_info.chip_id, buf_temp, info.r_write_addr_range.size, info.r_write_addr_range.addr - boot_info.sfc.sfc_base_addr, 0x20);
|
||||
|
||||
write_len = norflash_write(NULL, buf_temp, info.r_write_addr_range.size, info.r_write_addr_range.addr);
|
||||
|
||||
/* norflash_read(NULL, buf_temp, info.r_write_addr_range.size, info.r_write_addr_range.addr); */
|
||||
/* printf_buf(buf_temp, info.r_write_addr_range.size); */
|
||||
|
||||
if (write_len != info.r_write_addr_range.size) {
|
||||
memcpy(buf, error_return, sizeof(error_return));
|
||||
log_error("write error!");
|
||||
} else {
|
||||
memcpy(buf, ok_return, sizeof(ok_return));
|
||||
}
|
||||
send_len = sizeof(error_return);
|
||||
|
||||
if (buf_temp) {
|
||||
free(buf_temp);
|
||||
}
|
||||
|
||||
if (info.r_prepare_write_file.file_id == CFG_TOOL_FILEID) {
|
||||
size_total_write += info.r_write_addr_range.size;
|
||||
/* log_info("size_total_write = %d\n", size_total_write); */
|
||||
/* log_info("erasing size = %d\n", info.r_erase_addr_range.size); */
|
||||
if (size_total_write >= info.r_erase_addr_range.size) {
|
||||
size_total_write = 0;
|
||||
log_info("cpu_reset\n");
|
||||
extern u16 sys_timeout_add(void *priv, void (*func)(void *priv), u32 msec);
|
||||
sys_timeout_add(NULL, delay_cpu_reset, 500);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ONLINE_SUB_OP_ENTER_UPGRADE_MODE:
|
||||
valid_cmd = 1;
|
||||
log_info("event_ONLINE_SUB_OP_ENTER_UPGRADE_MODE\n");
|
||||
cfg_tool_go_mask_usb_updata();
|
||||
break;
|
||||
default:
|
||||
valid_cmd = 0;
|
||||
log_error("invalid data\n");
|
||||
memcpy(buf, er_return, sizeof(er_return));//不认识的命令返回ER
|
||||
send_len = sizeof(er_return);
|
||||
break;
|
||||
_exit_:
|
||||
memcpy(buf, error_return, sizeof(error_return));//文件打开失败返回FA
|
||||
send_len = sizeof(error_return);
|
||||
break;
|
||||
}
|
||||
|
||||
all_assemble_package_send_to_pc(REPLY_STYLE, cfg_tool_dev->packet[2], buf, send_len);
|
||||
|
||||
free(buf_temp_0);
|
||||
free(buf);
|
||||
return (valid_cmd);
|
||||
}
|
||||
|
||||
void cfg_tool_event_to_user(u8 *packet, u32 type, u8 event, u8 size)
|
||||
{
|
||||
struct sys_event e;
|
||||
e.type = SYS_DEVICE_EVENT;
|
||||
if (packet != NULL) {
|
||||
if (size > sizeof(local_packet)) {
|
||||
return;
|
||||
}
|
||||
e.u.cfg_tool.packet = local_packet;
|
||||
memcpy(e.u.cfg_tool.packet, packet, size);
|
||||
}
|
||||
e.arg = (void *)type;
|
||||
e.u.cfg_tool.event = event;
|
||||
e.u.cfg_tool.size = size;
|
||||
sys_event_notify(&e);
|
||||
}
|
||||
|
||||
void app_cfg_tool_message_deal(u8 *buf, u32 len)
|
||||
{
|
||||
u8 cmd = buf[8];
|
||||
switch (cmd) {
|
||||
case ONLINE_SUB_OP_QUERY_BASIC_INFO:
|
||||
case ONLINE_SUB_OP_QUERY_FILE_SIZE:
|
||||
case ONLINE_SUB_OP_QUERY_FILE_CONTENT:
|
||||
case ONLINE_SUB_OP_PREPARE_WRITE_FILE:
|
||||
case ONLINE_SUB_OP_READ_ADDR_RANGE:
|
||||
case ONLINE_SUB_OP_ERASE_ADDR_RANGE:
|
||||
case ONLINE_SUB_OP_WRITE_ADDR_RANGE:
|
||||
case ONLINE_SUB_OP_ENTER_UPGRADE_MODE:
|
||||
cfg_tool_event_to_user(&buf[5], DEVICE_EVENT_FROM_CFG_TOOL, cmd, buf[5] + 1);
|
||||
break;
|
||||
default:
|
||||
cfg_tool_event_to_user(&buf[5], DEVICE_EVENT_FROM_CFG_TOOL, DEFAULT_ACTION, buf[5] + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void online_cfg_tool_data_deal(void *buf, u32 len)
|
||||
{
|
||||
u8 *data_buf = buf;
|
||||
u16 crc16_data;
|
||||
|
||||
/* printf_buf(buf, len); */
|
||||
|
||||
/*DATA前的固定字节包括 (5A AA A5 CRC L T SQ)共8个字节 */
|
||||
if (len < 8) {
|
||||
log_error("Data length is too short, receive an invalid message!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if ((data_buf[0] != 0x5a) || (data_buf[1] != 0xaa) || (data_buf[2] != 0xa5)) {
|
||||
log_error("Header check error, receive an invalid message!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/*CRC16校验,CRC16校验码位于数据包的buf[3]和buf[4]*/
|
||||
crc16_data = (data_buf[4] << 8) | data_buf[3];
|
||||
if (crc16_data != CRC16(data_buf + 5, len - 5)) {
|
||||
log_error("CRC16 check error, receive an invalid message!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
app_cfg_tool_message_deal(buf, len);
|
||||
}
|
||||
63
apps/common/debug/debug.c
Normal file
63
apps/common/debug/debug.c
Normal file
@ -0,0 +1,63 @@
|
||||
#include "app_config.h"
|
||||
#include "typedef.h"
|
||||
|
||||
|
||||
|
||||
#ifndef CONFIG_DEBUG_ENABLE
|
||||
|
||||
int putchar(int a)
|
||||
{
|
||||
return a;
|
||||
}
|
||||
|
||||
int puts(const char *out)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int printf(const char *format, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void put_buf(const u8 *buf, int len)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void put_u8hex(u8 dat)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void put_u16hex(u16 dat)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void put_u32hex(u32 dat)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void log_print(int level, const char *tag, const char *format, ...)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
#ifndef CONFIG_DEBUG_LITE_ENABLE
|
||||
void log_putbyte(char c)
|
||||
{
|
||||
|
||||
}
|
||||
#endif /* #ifndef CONFIG_DEBUG_LITE_ENABLE */
|
||||
|
||||
int assert_printf(const char *format, ...)
|
||||
{
|
||||
cpu_assert_debug();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
68
apps/common/debug/debug_lite.c
Normal file
68
apps/common/debug/debug_lite.c
Normal file
@ -0,0 +1,68 @@
|
||||
#include "app_config.h"
|
||||
#include "typedef.h"
|
||||
|
||||
#ifdef CONFIG_DEBUG_LITE_ENABLE
|
||||
|
||||
extern void putbyte(char a);
|
||||
|
||||
#define putbyte_lite putbyte
|
||||
|
||||
void log_putbyte(char c)
|
||||
{
|
||||
putbyte_lite(c);
|
||||
}
|
||||
|
||||
void puts_lite(const char *out)
|
||||
{
|
||||
while (*out != '\0') {
|
||||
putbyte_lite(*out);
|
||||
out++;
|
||||
}
|
||||
}
|
||||
|
||||
int printf_lite(const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, format);
|
||||
|
||||
return print(NULL, 0, format, args);
|
||||
}
|
||||
|
||||
void put_buf_lite(void *_buf, u32 len)
|
||||
{
|
||||
u8 *buf = (u8 *)_buf;
|
||||
printf_lite("\n0x%x\n", buf);
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (((i % 16) == 0) && (i != 0)) {
|
||||
putbyte_lite('\n');
|
||||
}
|
||||
printf_lite("%x", buf[i]);
|
||||
putbyte_lite(' ');
|
||||
}
|
||||
putbyte_lite('\n');
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
|
||||
void puts_lite(const char *out)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
void put_buf_lite(void *_buf, u32 len)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
int printf_lite(const char *format, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* #ifdef CONFIG_DEBUG_LITE_ENABLE */
|
||||
|
||||
|
||||
1128
apps/common/dev_manager/dev_manager.c
Normal file
1128
apps/common/dev_manager/dev_manager.c
Normal file
File diff suppressed because it is too large
Load Diff
93
apps/common/dev_manager/dev_manager.h
Normal file
93
apps/common/dev_manager/dev_manager.h
Normal file
@ -0,0 +1,93 @@
|
||||
#ifndef __DEV_MANAGER_H__
|
||||
#define __DEV_MANAGER_H__
|
||||
|
||||
#include "system/includes.h"
|
||||
#include "typedef.h"
|
||||
#include "system/fs/fs.h"
|
||||
|
||||
enum {
|
||||
DEV_MANAGER_ADD_OK = 0x0,
|
||||
DEV_MANAGER_ADD_IN_LIST_AREADY,
|
||||
DEV_MANAGER_ADD_ERR_PARM,
|
||||
DEV_MANAGER_ADD_ERR_NOMEM,
|
||||
DEV_MANAGER_ADD_ERR_NOT_FOUND,
|
||||
DEV_MANAGER_ADD_ERR_MOUNT_FAIL,
|
||||
};
|
||||
|
||||
|
||||
struct __dev;
|
||||
|
||||
struct __scan_callback {
|
||||
void (*enter)(struct __dev *dev);
|
||||
void (*exit)(struct __dev *dev);
|
||||
int (*scan_break)(void);
|
||||
};
|
||||
|
||||
//dev_manager增加设备节点
|
||||
int dev_manager_add(char *logo);
|
||||
//dev_manager删除设备节点
|
||||
int dev_manager_del(char *logo);
|
||||
//dev_manager获取设备总数
|
||||
u32 dev_manager_get_total(u8 valid);
|
||||
//dev_manager通过设备节点检查设备是否在设备链表中
|
||||
struct __dev *dev_manager_check(struct __dev *dev);
|
||||
//dev_manager通过逻辑盘符检查设备是否在设备链表中
|
||||
struct __dev *dev_manager_check_by_logo(char *logo);
|
||||
//dev_manager查找第一个设备
|
||||
struct __dev *dev_manager_find_first(u8 valid);
|
||||
//dev_manager查找最后一个设备
|
||||
struct __dev *dev_manager_find_last(u8 valid);
|
||||
//dev_manager查找参数设备的前一个设备
|
||||
struct __dev *dev_manager_find_prev(struct __dev *dev, u8 valid);
|
||||
//dev_manager查找参数设备的后一个设备
|
||||
struct __dev *dev_manager_find_next(struct __dev *dev, u8 valid);
|
||||
//dev_manager查找最后活动设备
|
||||
struct __dev *dev_manager_find_active(u8 valid);
|
||||
//dev_manager查找指定逻辑盘符对应的设备
|
||||
struct __dev *dev_manager_find_spec(char *logo, u8 valid);
|
||||
//dev_manager查找指定序号设备
|
||||
struct __dev *dev_manager_find_by_index(u32 index, u8 valid);
|
||||
//dev_manager扫盘句柄释放
|
||||
void dev_manager_scan_disk_release(struct vfscan *fsn);
|
||||
//dev_manager扫盘
|
||||
struct vfscan *dev_manager_scan_disk(struct __dev *dev, const char *path, const char *parm, u8 cycle_mode, struct __scan_callback *callback);
|
||||
//dev_manager设定指定设备节点设备有效
|
||||
void dev_manager_set_valid(struct __dev *dev, u8 flag);
|
||||
//dev_manager设定指定设备节点设备为最后活动设备
|
||||
void dev_manager_set_active(struct __dev *dev);
|
||||
//dev_manager设定指定逻辑盘符的设备有效
|
||||
void dev_manager_set_valid_by_logo(char *logo, u8 flag);
|
||||
//dev_manager设定指定逻辑盘符的设备为最后活动设备
|
||||
void dev_manager_set_active_by_logo(char *logo);
|
||||
//dev_manager获取指定设备节点的逻辑盘符
|
||||
char *dev_manager_get_logo(struct __dev *dev);
|
||||
//获取物理设备节点的逻辑盘符(去掉_rec后缀)
|
||||
char *dev_manager_get_phy_logo(struct __dev *dev);
|
||||
//获取录音文件夹设备节点的逻辑盘符(追加_rec后缀)
|
||||
char *dev_manager_get_rec_logo(struct __dev *dev);
|
||||
//dev_manager获取指定设备节点的文件系统根目录
|
||||
char *dev_manager_get_root_path(struct __dev *dev);
|
||||
//dev_manager获取指定逻辑盘符的设备的文件系统根目录
|
||||
char *dev_manager_get_root_path_by_logo(char *logo);
|
||||
//dev_manager通过设备节点获取设备mount信息
|
||||
struct imount *dev_manager_get_mount_hdl(struct __dev *dev);
|
||||
//dev_manager通过设备节点检查设备是否在线
|
||||
int dev_manager_online_check(struct __dev *dev, u8 valid);
|
||||
//dev_manager通过逻辑盘符检查设备是否在线
|
||||
int dev_manager_online_check_by_logo(char *logo, u8 valid);
|
||||
//通过逻辑盘符判断设备是否在设备链表中
|
||||
struct __dev *dev_manager_list_check_by_logo(char *logo);
|
||||
//检查链表中没有挂载的设备并重新挂载
|
||||
void dev_manager_list_check_mount(void);
|
||||
//设备挂载
|
||||
int dev_manager_mount(char *logo);
|
||||
//设备卸载
|
||||
int dev_manager_unmount(char *logo);
|
||||
|
||||
//dev_manager初始化
|
||||
void dev_manager_init(void);
|
||||
|
||||
void dev_manager_var_init();
|
||||
|
||||
#endif//__DEV_MANAGER_H__
|
||||
|
||||
173
apps/common/dev_manager/dev_reg.c
Normal file
173
apps/common/dev_manager/dev_reg.c
Normal file
@ -0,0 +1,173 @@
|
||||
#include "dev_reg.h"
|
||||
#include "app_config.h"
|
||||
|
||||
//*----------------------------------------------------------------------------*/
|
||||
/**@brief 设备配置表
|
||||
@param 具体配置项请看struct __dev_reg结构体描述
|
||||
@return
|
||||
@note 注意:
|
||||
例如logo逻辑盘符sd0_rec/sd1_rec/udisk_rec是做录音文件夹区分使用的,
|
||||
在定义新的设备逻辑盘发的时候, 注意避开"_rec"后缀作为设备逻辑盘符
|
||||
*/
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
const struct __dev_reg dev_reg[] = {
|
||||
#if SDFILE_STORAGE && TCFG_CODE_FLASH_ENABLE
|
||||
//内置flash
|
||||
{
|
||||
/*logo*/ SDFILE_DEV,
|
||||
/*name*/ NULL,
|
||||
/*storage_path*/ SDFILE_MOUNT_PATH,
|
||||
/*root_path*/ SDFILE_RES_ROOT_PATH,
|
||||
/*fs_type*/ "sdfile",
|
||||
},
|
||||
#endif
|
||||
#if FLASH_INSIDE_REC_ENABLE
|
||||
//内置录音
|
||||
{
|
||||
/*logo*/ "rec_sdfile",
|
||||
/*name*/ NULL,
|
||||
/*storage_path*/ "mnt/rec_sdfile",
|
||||
/*root_path*/ "mnt/rec_sdfile/C/",
|
||||
/*fs_type*/ "rec_sdfile",
|
||||
},
|
||||
#endif
|
||||
#if (TCFG_SD0_ENABLE)
|
||||
//sd0
|
||||
{
|
||||
/*logo*/ "sd0",
|
||||
/*name*/ "sd0",
|
||||
/*storage_path*/ "storage/sd0",
|
||||
/*root_path*/ "storage/sd0/C/",
|
||||
/*fs_type*/ "fat",
|
||||
},
|
||||
#endif
|
||||
#if (TCFG_SD1_ENABLE)
|
||||
//sd1
|
||||
{
|
||||
/*logo*/ "sd1",
|
||||
/*name*/ "sd1",
|
||||
/*storage_path*/ "storage/sd1",
|
||||
/*root_path*/ "storage/sd1/C/",
|
||||
/*fs_type*/ "fat",
|
||||
},
|
||||
#endif
|
||||
#if (TCFG_UDISK_ENABLE)
|
||||
//u盘
|
||||
{
|
||||
/*logo*/ "udisk0",
|
||||
/*name*/ "udisk0",
|
||||
/*storage_path*/ "storage/udisk0",
|
||||
/*root_path*/ "storage/udisk0/C/",
|
||||
/*fs_type*/ "fat",
|
||||
},
|
||||
#endif
|
||||
#if (TCFG_SD0_ENABLE && TCFG_RECORD_FOLDER_DEV_ENABLE)
|
||||
//sd0录音文件夹分区
|
||||
{
|
||||
/*logo*/ "sd0_rec",
|
||||
/*name*/ "sd0",
|
||||
/*storage_path*/ "storage/sd0",
|
||||
/*root_path*/ "storage/sd0/C/"REC_FOLDER_NAME,
|
||||
/*fs_type*/ "fat",
|
||||
},
|
||||
#endif
|
||||
#if (TCFG_SD1_ENABLE && TCFG_RECORD_FOLDER_DEV_ENABLE)
|
||||
//sd1录音文件夹分区
|
||||
{
|
||||
/*logo*/ "sd1_rec",
|
||||
/*name*/ "sd1",
|
||||
/*storage_path*/ "storage/sd1",
|
||||
/*root_path*/ "storage/sd1/C/"REC_FOLDER_NAME,
|
||||
/*fs_type*/ "fat",
|
||||
},
|
||||
#endif
|
||||
#if (TCFG_UDISK_ENABLE && TCFG_RECORD_FOLDER_DEV_ENABLE)
|
||||
//u盘录音文件夹分区
|
||||
{
|
||||
/*logo*/ "udisk0_rec",
|
||||
/*name*/ "udisk0",
|
||||
/*storage_path*/ "storage/udisk0",
|
||||
/*root_path*/ "storage/udisk0/C/"REC_FOLDER_NAME,
|
||||
/*fs_type*/ "fat",
|
||||
},
|
||||
#endif
|
||||
#if TCFG_NOR_FAT
|
||||
//外挂fat分区
|
||||
{
|
||||
/*logo*/ "fat_nor",
|
||||
/*name*/ "fat_nor",
|
||||
/*storage_path*/ "storage/fat_nor",
|
||||
/*root_path*/ "storage/fat_nor/C/",
|
||||
/*fs_type*/ "fat",
|
||||
},
|
||||
#endif
|
||||
#if TCFG_NOR_FS
|
||||
//外挂flash资源分区
|
||||
{
|
||||
/*logo*/ "res_nor",
|
||||
/*name*/ "res_nor",
|
||||
/*storage_path*/ "storage/res_nor",
|
||||
/*root_path*/ "storage/res_nor/C/",
|
||||
/*fs_type*/ "nor_sdfile",
|
||||
},
|
||||
#endif
|
||||
#if TCFG_NOR_REC
|
||||
///外挂录音分区
|
||||
{
|
||||
/*logo*/ "rec_nor",
|
||||
/*name*/ "rec_nor",
|
||||
/*storage_path*/ "storage/rec_nor",
|
||||
/*root_path*/ "storage/rec_nor/C/",
|
||||
/*fs_type*/ "rec_fs",
|
||||
},
|
||||
#endif
|
||||
{
|
||||
/*logo*/ "nor_ui",
|
||||
/*name*/ "nor_ui",
|
||||
/*storage_path*/ "storage/nor_ui",
|
||||
/*root_path*/ "storage/nor_ui/C/",
|
||||
/*fs_type*/ "nor_sdfile",
|
||||
},
|
||||
#if TCFG_VIR_UDISK_ENABLE
|
||||
// 虚拟U盘
|
||||
{
|
||||
/*logo*/ "vir_udisk0",
|
||||
/*name*/ "vir_udisk0",
|
||||
/*storage_path*/ "storage/vir_udisk0",
|
||||
/*root_path*/ "storage/vir_udisk0/C/",
|
||||
/*fs_type*/ "fat",
|
||||
},
|
||||
#endif
|
||||
#if TCFG_VIRFAT_FLASH_ENABLE
|
||||
//flash 虚拟fat
|
||||
{
|
||||
/*logo*/ "virfat_flash",
|
||||
/*name*/ "virfat_flash",
|
||||
/*storage_path*/ "storage/virfat_flash",
|
||||
/*root_path*/ "storage/virfat_flash/C/",
|
||||
/*fs_type*/ "sdfile_fat",
|
||||
},
|
||||
#endif
|
||||
#if TCFG_NANDFLASH_DEV_ENABLE
|
||||
{
|
||||
/*logo*/ "nandflash_ftl",
|
||||
/*name*/ "nandflash_ftl",
|
||||
/*storage_path*/ "storage/nandflash_ftl",
|
||||
/*root_path*/ "storage/nandflash_ftl/C/",
|
||||
/*fs_type*/ "fat",
|
||||
},
|
||||
#endif
|
||||
//<新加设备参数请在reg end前添加!!
|
||||
//<reg end
|
||||
{
|
||||
/*logo*/ NULL,
|
||||
/*name*/ NULL,
|
||||
/*storage_path*/ NULL,
|
||||
/*root_path*/ NULL,
|
||||
/*fs_type*/ NULL,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
21
apps/common/dev_manager/dev_reg.h
Normal file
21
apps/common/dev_manager/dev_reg.h
Normal file
@ -0,0 +1,21 @@
|
||||
#ifndef __DEV_REG_H__
|
||||
#define __DEV_REG_H__
|
||||
|
||||
#include "system/includes.h"
|
||||
#include "typedef.h"
|
||||
|
||||
///设备参数控制句柄
|
||||
struct __dev_reg {
|
||||
char *logo;//设备选择使用的逻辑盘符
|
||||
char *name;//设备名称,底层匹配设备节点使用
|
||||
char *storage_path;//设备路径,文件系统mount时使用
|
||||
char *root_path;//设备文件系统根目录
|
||||
char *fs_type;//文件系统类型,如:fat, sdfile
|
||||
};
|
||||
|
||||
|
||||
extern const struct __dev_reg dev_reg[];
|
||||
|
||||
#endif//__DEV_REG_H__
|
||||
|
||||
|
||||
327
apps/common/dev_manager/dev_update.c
Normal file
327
apps/common/dev_manager/dev_update.c
Normal file
@ -0,0 +1,327 @@
|
||||
#include "dev_update.h"
|
||||
#include "dev_manager.h"
|
||||
#include "update/update.h"
|
||||
#include "update/update_loader_download.h"
|
||||
#include "app_config.h"
|
||||
#include "btcontroller_modules.h"
|
||||
|
||||
#if defined(CONFIG_SD_UPDATE_ENABLE) || defined(CONFIG_USB_UPDATE_ENABLE)
|
||||
#define DEV_UPDATE_EN 1
|
||||
#else
|
||||
#define DEV_UPDATE_EN 0
|
||||
#endif
|
||||
|
||||
#ifdef DEV_UPDATE_SUPPORT_JUMP
|
||||
extern void __JUMP_TO_MASKROM();
|
||||
extern void save_spi_port();
|
||||
extern void update_close_hw(void *filter_name);
|
||||
extern void ram_protect_close(void);
|
||||
#endif //endif DEV_UPDATE_SUPPORT_JUMP
|
||||
|
||||
extern bool uart_update_send_update_ready(char *file_path);
|
||||
extern bool get_uart_update_sta(void);
|
||||
|
||||
static char update_path[48] = {0};
|
||||
extern const char updata_file_name[];
|
||||
|
||||
struct __update_dev_reg {
|
||||
char *logo;
|
||||
int type;
|
||||
union {
|
||||
UPDATA_SD sd;
|
||||
} u;
|
||||
};
|
||||
|
||||
|
||||
#if TCFG_SD0_ENABLE
|
||||
static const struct __update_dev_reg sd0_update = {
|
||||
.logo = "sd0",
|
||||
.type = SD0_UPDATA,
|
||||
.u.sd.control_type = SD_CONTROLLER_0,
|
||||
#ifdef TCFG_SD0_PORT_CMD
|
||||
.u.sd.control_io_clk = TCFG_SD0_PORT_CLK,
|
||||
.u.sd.control_io_cmd = TCFG_SD0_PORT_CMD,
|
||||
.u.sd.control_io_dat = TCFG_SD0_PORT_DA0,
|
||||
#else
|
||||
#if (TCFG_SD0_PORTS=='A')
|
||||
.u.sd.control_io = SD0_IO_A,
|
||||
#elif (TCFG_SD0_PORTS=='B')
|
||||
.u.sd.control_io = SD0_IO_B,
|
||||
#elif (TCFG_SD0_PORTS=='C')
|
||||
.u.sd.control_io = SD0_IO_C,
|
||||
#elif (TCFG_SD0_PORTS=='D')
|
||||
.u.sd.control_io = SD0_IO_D,
|
||||
#elif (TCFG_SD0_PORTS=='E')
|
||||
.u.sd.control_io = SD0_IO_E,
|
||||
#elif (TCFG_SD0_PORTS=='F')
|
||||
.u.sd.control_io = SD0_IO_F,
|
||||
#endif
|
||||
#endif
|
||||
.u.sd.power = 1,
|
||||
};
|
||||
#endif//TCFG_SD0_ENABLE
|
||||
|
||||
#if TCFG_SD1_ENABLE
|
||||
static const struct __update_dev_reg sd1_update = {
|
||||
.logo = "sd1",
|
||||
.type = SD1_UPDATA,
|
||||
.u.sd.control_type = SD_CONTROLLER_1,
|
||||
#if (TCFG_SD1_PORTS=='A')
|
||||
.u.sd.control_io = SD1_IO_A,
|
||||
#else
|
||||
.u.sd.control_io = SD1_IO_B,
|
||||
#endif
|
||||
.u.sd.power = 1,
|
||||
|
||||
};
|
||||
#endif//TCFG_SD1_ENABLE
|
||||
|
||||
#if TCFG_UDISK_ENABLE
|
||||
static const struct __update_dev_reg udisk_update = {
|
||||
.logo = "udisk0",
|
||||
.type = USB_UPDATA,
|
||||
};
|
||||
#endif//TCFG_UDISK_ENABLE
|
||||
|
||||
|
||||
static const struct __update_dev_reg *update_dev_list[] = {
|
||||
#if TCFG_UDISK_ENABLE
|
||||
&udisk_update,
|
||||
#endif//TCFG_UDISK_ENABLE
|
||||
#if TCFG_SD0_ENABLE
|
||||
&sd0_update,
|
||||
#endif//
|
||||
#if TCFG_SD1_ENABLE
|
||||
&sd1_update,
|
||||
#endif//TCFG_SD1_ENABLE
|
||||
};
|
||||
|
||||
void *dev_update_get_parm(int type)
|
||||
{
|
||||
struct __update_dev_reg *parm = NULL;
|
||||
for (int i = 0; i < ARRAY_SIZE(update_dev_list); i++) {
|
||||
if (update_dev_list[i]->type == type) {
|
||||
parm = (struct __update_dev_reg *)update_dev_list[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (parm == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
return (void *)&parm->u.sd;
|
||||
}
|
||||
|
||||
|
||||
struct strg_update {
|
||||
void *fd;
|
||||
char *update_path;
|
||||
};
|
||||
static struct strg_update strg_update = {0};
|
||||
#define __this (&strg_update)
|
||||
|
||||
static u16 strg_f_open(void)
|
||||
{
|
||||
if (!__this->update_path) {
|
||||
printf("file path err ");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (__this->fd) {
|
||||
return true;
|
||||
/* fclose(__this->fd);
|
||||
__this->fd = NULL; */
|
||||
}
|
||||
__this->fd = fopen(__this->update_path, "r");
|
||||
if (!__this->fd) {
|
||||
printf("file open err ");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static u16 strg_f_read(void *fp, u8 *buff, u16 len)
|
||||
{
|
||||
if (!__this->fd) {
|
||||
return (u16) - 1;
|
||||
}
|
||||
|
||||
len = fread(__this->fd, buff, len);
|
||||
return len;
|
||||
}
|
||||
|
||||
static int strg_f_seek(void *fp, u8 type, u32 offset)
|
||||
{
|
||||
if (!__this->fd) {
|
||||
return (int) - 1;
|
||||
}
|
||||
|
||||
int ret = fseek(__this->fd, offset, type);
|
||||
/* return 0; // 0k */
|
||||
return ret;
|
||||
}
|
||||
static u16 strg_f_stop(u8 err)
|
||||
{
|
||||
if (__this->fd) {
|
||||
fclose(__this->fd);
|
||||
__this->fd = NULL;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static int strg_update_set_file_path_and_hdl(char *update_path, void *fd)
|
||||
{
|
||||
__this->update_path = update_path;
|
||||
__this->fd = fd;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static const update_op_api_t strg_dev_update_op = {
|
||||
.f_open = strg_f_open,
|
||||
.f_read = strg_f_read,
|
||||
.f_seek = strg_f_seek,
|
||||
.f_stop = strg_f_stop,
|
||||
};
|
||||
|
||||
static void dev_update_param_private_handle(UPDATA_PARM *p)
|
||||
{
|
||||
u16 up_type = p->parm_type;
|
||||
|
||||
#ifdef CONFIG_SD_UPDATE_ENABLE
|
||||
if ((up_type == SD0_UPDATA) || (up_type == SD1_UPDATA)) {
|
||||
int sd_start = (u32)p->parm_priv;
|
||||
void *sd = NULL;
|
||||
sd = dev_update_get_parm(up_type);
|
||||
if (sd) {
|
||||
memcpy((void *)sd_start, sd, UPDATE_PRIV_PARAM_LEN);
|
||||
} else {
|
||||
memset((void *)sd_start, 0, UPDATE_PRIV_PARAM_LEN);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_UPDATE_ENABLE
|
||||
if (up_type == USB_UPDATA) {
|
||||
printf("usb updata ");
|
||||
int usb_start = (u32)p->parm_priv;
|
||||
memset((void *)usb_start, 0, UPDATE_PRIV_PARAM_LEN);
|
||||
}
|
||||
#endif
|
||||
memcpy(p->file_patch, updata_file_name, strlen(updata_file_name));
|
||||
}
|
||||
|
||||
|
||||
static void dev_update_before_jump_handle(u16 up_type)
|
||||
{
|
||||
#if (defined DEV_UPDATE_SUPPORT_JUMP) || (CONFIG_UPDATE_JUMP_TO_MASK)
|
||||
#if TCFG_BLUETOOTH_BACK_MODE //后台模式需要把蓝牙关掉
|
||||
if (BT_MODULES_IS_SUPPORT(BT_MODULE_LE)) {
|
||||
ll_hci_destory();
|
||||
}
|
||||
hci_controller_destory();
|
||||
#endif
|
||||
#if CONFIG_UPDATE_JUMP_TO_MASK
|
||||
y_printf(">>>[test]:latch reset update\n");
|
||||
latch_reset();
|
||||
|
||||
#if 0
|
||||
update_close_hw("null");
|
||||
ram_protect_close();
|
||||
save_spi_port();
|
||||
|
||||
extern void __BT_UPDATA_JUMP();
|
||||
y_printf("update jump to __BT_UPDATA ...\n");
|
||||
y_printf(">>>[test]:JL_IOMC = 0x%x\n", (JL_IOMAP->CON0 >> 16) & 0x3);
|
||||
/* clk_set("sys", 48 * 1000000L); */
|
||||
//跳转到uboot加载完,30ms左右(200410_yzb)
|
||||
__BT_UPDATA_JUMP();
|
||||
#endif
|
||||
#else
|
||||
printf("update jump to mask...\n");
|
||||
/* JL_UART0->CON0 = 0; */
|
||||
/* JL_UART1->CON0 = 0; */
|
||||
__JUMP_TO_MASKROM();
|
||||
#endif
|
||||
#else
|
||||
cpu_reset();
|
||||
#endif //DEV_UPDATE_SUPPORT_JUMP
|
||||
}
|
||||
|
||||
static void dev_update_state_cbk(int type, u32 state, void *priv)
|
||||
{
|
||||
update_ret_code_t *ret_code = (update_ret_code_t *)priv;
|
||||
|
||||
switch (state) {
|
||||
case UPDATE_CH_EXIT:
|
||||
if ((0 == ret_code->stu) && (0 == ret_code->err_code)) {
|
||||
update_mode_api_v2(type,
|
||||
dev_update_param_private_handle,
|
||||
dev_update_before_jump_handle);
|
||||
} else {
|
||||
printf("update fail, cpu reset!!!\n");
|
||||
cpu_reset();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
u16 dev_update_check(char *logo)
|
||||
{
|
||||
if (update_success_boot_check() == true) {
|
||||
return UPDATA_NON;
|
||||
}
|
||||
struct __dev *dev = dev_manager_find_spec(logo, 0);
|
||||
if (dev) {
|
||||
#if DEV_UPDATE_EN
|
||||
//<查找设备升级配置
|
||||
struct __update_dev_reg *parm = NULL;
|
||||
for (int i = 0; i < ARRAY_SIZE(update_dev_list); i++) {
|
||||
if (0 == strcmp(update_dev_list[i]->logo, logo)) {
|
||||
parm = (struct __update_dev_reg *)update_dev_list[i];
|
||||
}
|
||||
}
|
||||
if (parm == NULL) {
|
||||
printf("dev update without parm err!!!\n");
|
||||
return UPDATA_PARM_ERR;
|
||||
}
|
||||
//<尝试按照路径打开升级文件
|
||||
char *updata_file = (char *)updata_file_name;
|
||||
if (*updata_file == '/') {
|
||||
updata_file ++;
|
||||
}
|
||||
memset(update_path, 0, sizeof(update_path));
|
||||
sprintf(update_path, "%s%s", dev_manager_get_root_path(dev), updata_file);
|
||||
printf("update_path: %s\n", update_path);
|
||||
FILE *fd = fopen(update_path, "r");
|
||||
if (!fd) {
|
||||
///没有升级文件, 继续跑其他解码相关的流程
|
||||
printf("open update file err!!!\n");
|
||||
return UPDATA_DEV_ERR;
|
||||
}
|
||||
|
||||
#if(USER_UART_UPDATE_ENABLE) && (UART_UPDATE_ROLE == UART_UPDATE_MASTER)
|
||||
uart_update_send_update_ready(update_path);
|
||||
while (get_uart_update_sta()) {
|
||||
os_time_dly(10);
|
||||
}
|
||||
#else
|
||||
///进行升级
|
||||
|
||||
strg_update_set_file_path_and_hdl(update_path, (void *)fd);
|
||||
|
||||
update_mode_info_t info = {
|
||||
.type = parm->type,
|
||||
.state_cbk = dev_update_state_cbk,
|
||||
.p_op_api = &strg_dev_update_op,
|
||||
.task_en = 0,
|
||||
};
|
||||
app_active_update_task_init(&info);
|
||||
|
||||
#endif// USER_UART_UPDATE_ENABLE
|
||||
|
||||
#endif//DEV_UPDATE_EN
|
||||
}
|
||||
return UPDATA_READY;
|
||||
}
|
||||
|
||||
|
||||
|
||||
10
apps/common/dev_manager/dev_update.h
Normal file
10
apps/common/dev_manager/dev_update.h
Normal file
@ -0,0 +1,10 @@
|
||||
#ifndef __DEV_UPDATE_H__
|
||||
#define __DEV_UPDATE_H__
|
||||
|
||||
#include "typedef.h"
|
||||
#include "system/includes.h"
|
||||
|
||||
void *dev_update_get_parm(int type);
|
||||
u16 dev_update_check(char *logo);
|
||||
|
||||
#endif//__DEV_UPDATE_H__
|
||||
257
apps/common/device/gSensor/EPMotion.h
Normal file
257
apps/common/device/gSensor/EPMotion.h
Normal file
@ -0,0 +1,257 @@
|
||||
/*******************************************************************************/
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file EPMotion.h
|
||||
* @author ycwang@miramems.com
|
||||
* @version V2.0
|
||||
* @date 2019-01-31
|
||||
* @brief
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
|
||||
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
|
||||
* TIME. AS A RESULT, MiraMEMS SHALL NOT BE HELD LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
|
||||
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
|
||||
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
|
||||
*
|
||||
*/
|
||||
/*******************************************************************************/
|
||||
#ifndef __EPMOTION_h
|
||||
#define __EPMOTION_h
|
||||
|
||||
/*******************************************************************************
|
||||
Includes
|
||||
********************************************************************************/
|
||||
#include "mira_std.h"
|
||||
|
||||
/*******************************************************************************
|
||||
Macro definitions - Algorithm Build Options
|
||||
********************************************************************************/
|
||||
#define D_TAP_ENABLE 1
|
||||
#define M_TAP_ENABLE 1
|
||||
#define STEP_ENABLE 1
|
||||
|
||||
/*******************************************************************************
|
||||
Typedef definitions
|
||||
********************************************************************************/
|
||||
enum {
|
||||
DEBUG_ERR = 1,
|
||||
DEBUG_MSG = 1 << 1,
|
||||
DEBUG_DATA = 1 << 2,
|
||||
DEBUG_RAW = 1 << 3,
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
PIN_NONE,
|
||||
PIN_ONE,
|
||||
PIN_TWO
|
||||
} tPIN_NUM;
|
||||
|
||||
typedef enum {
|
||||
PIN_LEVEL_NONE,
|
||||
PIN_LEVEL_LOW,
|
||||
PIN_LEVEL_HIGH
|
||||
} tPIN_LEVEL;
|
||||
|
||||
typedef enum {
|
||||
NO_LATCHED,
|
||||
LATCHED_250MS,
|
||||
LATCHED_500MS,
|
||||
LATCHED_1S,
|
||||
LATCHED_2S,
|
||||
LATCHED_4S,
|
||||
LATCHED_8S,
|
||||
LATCHED_1MS = 10,
|
||||
LATCHED_2MS,
|
||||
LATCHED_25MS,
|
||||
LATCHED_50MS,
|
||||
LATCHED_100MS,
|
||||
LATCHED
|
||||
} tLATCH_MODE;
|
||||
|
||||
typedef enum {
|
||||
TEVENT_NONE,
|
||||
TEVENT_TAP_NOTIFY,
|
||||
} EPMotion_EVENT;
|
||||
|
||||
typedef enum {
|
||||
NONE_T,
|
||||
D_TAP_T,
|
||||
M_TAP_T,
|
||||
STEP_T,
|
||||
} tAlgorithm;
|
||||
|
||||
typedef enum {
|
||||
DISABLE_T,
|
||||
ENABLE_T
|
||||
} tSwitchCmd;
|
||||
|
||||
struct tInt_Pin_Config {
|
||||
tPIN_NUM num;
|
||||
tPIN_LEVEL level;
|
||||
};
|
||||
|
||||
struct tREG_Func {
|
||||
s8_m(*read)(u8_m addr, u8_m *data_m, u8_m len);
|
||||
s8_m(*write)(u8_m addr, u8_m data_m);
|
||||
};
|
||||
|
||||
struct tDEBUG_Func {
|
||||
s32_m(*myprintf)(const char *fmt, ...);
|
||||
};
|
||||
|
||||
struct EPMotion_op_s {
|
||||
struct tInt_Pin_Config pin;
|
||||
s8_m(*mir3da_event_handle)(EPMotion_EVENT event, u8_m data_m);
|
||||
struct tREG_Func reg;
|
||||
struct tDEBUG_Func debug;
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
Global variables and functions
|
||||
********************************************************************************/
|
||||
|
||||
/*******************************************************************************
|
||||
* Function Name: EPMotion_Init
|
||||
* Description : This function initializes the EPMotion.
|
||||
* Arguments : EPMotion_op_s *ops
|
||||
* Return Value : 0: OK; -1: Type Error; -2: OP Error; -3: Chip Error
|
||||
********************************************************************************/
|
||||
s8_m EPMotion_Init(struct EPMotion_op_s *ops);
|
||||
|
||||
/*******************************************************************************
|
||||
* Function Name: EPMotion_Tap_Set_Parma
|
||||
* Description : This function sets tap parmas.
|
||||
* Arguments :
|
||||
* threshold - set interrupt threshold 0~31 ,(threshold*125)mg
|
||||
* default is 21(2625mg)
|
||||
* latch_mode - set interrupt latched mode ,(tLATCH_MODE)
|
||||
* default is NO_LATCHED
|
||||
* duration - set interrupt duration 0~7(50~700)ms,
|
||||
* default is 0(50ms)
|
||||
* Return Value : None
|
||||
********************************************************************************/
|
||||
void EPMotion_Tap_Set_Parma(u8_m threshold, tLATCH_MODE latch_mode, u8_m duration);
|
||||
|
||||
#if D_TAP_ENABLE
|
||||
/*******************************************************************************
|
||||
* Function Name: EPMotion_Tap_Set_Filter
|
||||
* Description : This function sets filter.
|
||||
* Arguments :
|
||||
* level - set level of checking data 1~3 ,default is 1
|
||||
* ths - set the value of filter ,(ths*1)mg
|
||||
* Return Value : None
|
||||
********************************************************************************/
|
||||
void EPMotion_D_Tap_Set_Filter(u8_m level, u16_m ths);
|
||||
#endif
|
||||
|
||||
#if M_TAP_ENABLE
|
||||
/*******************************************************************************
|
||||
* Function Name: EPMotion_M_Tap_Set_Dur
|
||||
* Description : This function sets M tap duration.
|
||||
* Arguments :
|
||||
* m_dur_int - set interrupt duration 20~70,(m_dur_int*10)ms,
|
||||
* default is 50(500ms)
|
||||
* m_dur_event - set m tap event duration 20~6000,(m_dur_event*10)ms,
|
||||
* default is 100(1000ms)
|
||||
*EPMotion_M_Tap_Set_Dur第一个参数是设置两次敲击间隔的最大时间 第二参数是连续多次敲击总的有效时间
|
||||
* Return Value : None
|
||||
********************************************************************************/
|
||||
void EPMotion_M_Tap_Set_Dur(u8_m m_dur_int, u16_m m_dur_event);
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
* Function Name: EPMotion_Reset_Tap_INT
|
||||
* Description : This function reset tap INT.
|
||||
* Arguments : None
|
||||
* Return Value : None
|
||||
********************************************************************************/
|
||||
void EPMotion_Reset_Tap_INT(void);
|
||||
|
||||
/*******************************************************************************
|
||||
* Function Name: EPMotion_Resume_Tap_INT
|
||||
* Description : This function resume tap INT.
|
||||
* Arguments : None
|
||||
* Return Value : None
|
||||
********************************************************************************/
|
||||
void EPMotion_Resume_Tap_INT(void);
|
||||
|
||||
#if STEP_ENABLE
|
||||
/*******************************************************************************
|
||||
* Function Name: EPMotion_Reset_Step
|
||||
* Description : This function reset step counter.
|
||||
* Arguments : None
|
||||
* Return Value : None
|
||||
********************************************************************************/
|
||||
void EPMotion_Reset_Step(void);
|
||||
|
||||
/*******************************************************************************
|
||||
* Function Name: EPMotion_Get_Step
|
||||
* Description : This function gets the step.
|
||||
* Arguments : None
|
||||
* Return Value : step
|
||||
********************************************************************************/
|
||||
u16_m EPMotion_Get_Step(void);
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
* Function Name: EPMotion_Control
|
||||
* Description : This function initializes the xMotion.
|
||||
* Arguments : name - select which algorithm to control
|
||||
cmd - enable/disable
|
||||
* Return Value : 0->Success, -1->Init Fail£¬-2£¬No Supported
|
||||
********************************************************************************/
|
||||
s8_m EPMotion_Control(tAlgorithm name, tSwitchCmd cmd);
|
||||
|
||||
/*******************************************************************************
|
||||
* Function Name: EPMotion_Process_Data
|
||||
* Description : This function runs the EPMotion Algorithm.
|
||||
* Arguments : None
|
||||
* Return Value : None
|
||||
********************************************************************************/
|
||||
void EPMotion_Process_Data(s8_m int_active);
|
||||
|
||||
/*******************************************************************************
|
||||
* Function Name: EPMotion_Chip_Read_XYZ
|
||||
* Description : This function reads the chip xyz.
|
||||
* Arguments : x, y, z - acc data
|
||||
* Return Value : 0: OK; -1: Error
|
||||
********************************************************************************/
|
||||
s8_m EPMotion_Chip_Read_XYZ(s16_m *x, s16_m *y, s16_m *z);
|
||||
|
||||
/*******************************************************************************
|
||||
* Function Name: EPMotion_Get_Version
|
||||
* Description : This function gets EPMotion version.
|
||||
* Arguments : ver - EPMotion version Num
|
||||
* Return Value : None
|
||||
********************************************************************************/
|
||||
void EPMotion_Get_Version(u8_m *ver);
|
||||
|
||||
/*******************************************************************************
|
||||
* Function Name: EPMotion_Chip_Power_On
|
||||
* Description : This function enables the chip.
|
||||
* Arguments : None
|
||||
* Return Value : 0: OK; -1: Error
|
||||
********************************************************************************/
|
||||
s8_m EPMotion_Chip_Power_On(void);
|
||||
|
||||
/*******************************************************************************
|
||||
* Function Name: EPMotion_Chip_Power_Off
|
||||
* Description : This function disables on the chip.
|
||||
* Arguments : None
|
||||
* Return Value : 0: OK; -1: Error
|
||||
********************************************************************************/
|
||||
s8_m EPMotion_Chip_Power_Off(void);
|
||||
|
||||
/*******************************************************************************
|
||||
* Function Name: EPMotion_Set_Debug_level
|
||||
* Description : This function sets the debug log level
|
||||
* Arguments : Log level
|
||||
* Return Value : None
|
||||
********************************************************************************/
|
||||
void EPMotion_Set_Debug_level(u8_m level);
|
||||
#endif
|
||||
|
||||
|
||||
371
apps/common/device/gSensor/SC7A20.c
Normal file
371
apps/common/device/gSensor/SC7A20.c
Normal file
@ -0,0 +1,371 @@
|
||||
#include "gSensor/SC7A20.h"
|
||||
#include "gSensor/gSensor_manage.h"
|
||||
#include "app_config.h"
|
||||
|
||||
#include "gSensor/SC7A20.h"
|
||||
#include "math.h"
|
||||
|
||||
|
||||
#if TCFG_SC7A20_EN
|
||||
|
||||
u8 volatile sl_click_timer_en = 0;
|
||||
|
||||
#define INT_IO IO_PORTC_02
|
||||
#define SL_Sensor_Algo_Release_Enable 1
|
||||
|
||||
|
||||
u8 Click_time = 0X00;
|
||||
u8 Click_add_flag = 0X00;
|
||||
|
||||
|
||||
u32 SL_MEMS_i2cRead(u8 addr, u8 reg, u8 len, u8 *buf)
|
||||
{
|
||||
return _gravity_sensor_get_ndata(addr, reg, buf, len);
|
||||
}
|
||||
|
||||
u8 SL_MEMS_i2cWrite(u8 addr, u8 reg, u8 data)
|
||||
{
|
||||
gravity_sensor_command(addr, reg, data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
char SC7A20_Check()
|
||||
{
|
||||
u8 reg_value = 0;
|
||||
SL_MEMS_i2cRead(SC7A20_R_ADDR, SC7A20_WHO_AM_I, 1, ®_value);
|
||||
if (reg_value == 0x11) {
|
||||
return 0x01;
|
||||
} else {
|
||||
return 0x00;
|
||||
}
|
||||
}
|
||||
|
||||
u8 SC7A20_Config(void)
|
||||
{
|
||||
u8 Check_Flag = 0;
|
||||
u8 write_num = 0, i = 0;
|
||||
|
||||
u8 ODR = 0x6f; //400HZ/6f 200HZ
|
||||
u8 HP = 0x0c; //开启高通滤波
|
||||
u8 click_int = 0x04;//0x82 //将Click中断映射到INT1 OVERRUN
|
||||
u8 range = 0x90; //4g量程
|
||||
u8 fifo_en = 0x40; //使能fifo
|
||||
u8 fifo_mode = 0x9c; //0x9d //Stream模式,0-29(WTM30个)
|
||||
u8 click_mode = 0x15; //单击3轴触发
|
||||
|
||||
Check_Flag = SC7A20_Check();
|
||||
if (Check_Flag == 1) {
|
||||
SL_MEMS_i2cWrite(SC7A20_W_ADDR, SC7A20_CTRL_REG1, ODR);
|
||||
SL_MEMS_i2cWrite(SC7A20_W_ADDR, SC7A20_CTRL_REG2, HP);
|
||||
SL_MEMS_i2cWrite(SC7A20_W_ADDR, SC7A20_CTRL_REG3, click_int);// click int1
|
||||
SL_MEMS_i2cWrite(SC7A20_W_ADDR, SC7A20_CTRL_REG4, range);
|
||||
SL_MEMS_i2cWrite(SC7A20_W_ADDR, SC7A20_CTRL_REG5, fifo_en);
|
||||
SL_MEMS_i2cWrite(SC7A20_W_ADDR, SC7A20_FIFO_CTRL_REG, fifo_mode);
|
||||
/*
|
||||
SL_MEMS_i2cWrite(SC7A20_W_ADDR, SC7A20_CLICK_CFG, click_mode);//单Z轴
|
||||
SL_MEMS_i2cWrite(SC7A20_W_ADDR, SC7A20_CLICK_THS, SC7A20_CLICK_TH);//62.6mg(4g)*10
|
||||
SL_MEMS_i2cWrite(SC7A20_W_ADDR, SC7A20_TIME_LIMIT, SC7A20_CLICK_WINDOWS);
|
||||
SL_MEMS_i2cWrite(SC7A20_W_ADDR, SC7A20_TIME_LATENCY, SC7A20_CLICK_LATENCY);
|
||||
*/
|
||||
SL_MEMS_i2cWrite(SC7A20_W_ADDR, SC7A20_CTRL_REG6, SC7A20_INT_LEVEL);
|
||||
printf("check ok\n");
|
||||
return 0;
|
||||
} else {
|
||||
printf("check fail\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
u8 SC7A20_disable(void)
|
||||
{
|
||||
u8 Check_Flag = SC7A20_Check();
|
||||
if (Check_Flag == 1) {
|
||||
u8 ODR = 0x00;
|
||||
SL_MEMS_i2cWrite(SC7A20_W_ADDR, SC7A20_CTRL_REG1, ODR);
|
||||
printf("check ok\n");
|
||||
return 0;
|
||||
} else {
|
||||
printf("check fail\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#if SL_Sensor_Algo_Release_Enable==0
|
||||
extern signed short SL_DEBUG_DATA[10][128];
|
||||
extern u8 SL_DEBUG_DATA_LEN;
|
||||
#endif
|
||||
|
||||
u8 sl_pp_num = 0;
|
||||
|
||||
u8 SL_Get_CLICK_PP_CNT(u8 fun_flag)
|
||||
{
|
||||
if (fun_flag == 0) {
|
||||
sl_pp_num = 0;
|
||||
}
|
||||
return sl_pp_num;
|
||||
}
|
||||
|
||||
unsigned int SL_Click_Sqrt(unsigned int sqrt_data)
|
||||
{
|
||||
unsigned int SL_SQRT_LOW, SL_SQRT_UP, SL_SQRT_MID;
|
||||
u8 sl_sqrt_num = 0;
|
||||
|
||||
SL_SQRT_LOW = 0;
|
||||
SL_SQRT_UP = sqrt_data;
|
||||
SL_SQRT_MID = (SL_SQRT_UP + SL_SQRT_LOW) / 2;
|
||||
while (sl_sqrt_num < 200) {
|
||||
if (SL_SQRT_MID * SL_SQRT_MID > sqrt_data) {
|
||||
SL_SQRT_UP = SL_SQRT_MID;
|
||||
} else {
|
||||
SL_SQRT_LOW = SL_SQRT_MID;
|
||||
}
|
||||
if (SL_SQRT_UP - SL_SQRT_LOW == 1) {
|
||||
if (SL_SQRT_UP * SL_SQRT_UP - sqrt_data > sqrt_data - SL_SQRT_LOW * SL_SQRT_LOW) {
|
||||
return SL_SQRT_LOW;
|
||||
} else {
|
||||
return SL_SQRT_UP;
|
||||
}
|
||||
}
|
||||
SL_SQRT_MID = (SL_SQRT_UP + SL_SQRT_LOW) / 2;
|
||||
sl_sqrt_num++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
char SC7A20_Click_Read(int TH1, int TH2)
|
||||
{
|
||||
u8 i = 0, j = 0, k = 0;
|
||||
u8 click_num = 0;
|
||||
u8 fifo_len;
|
||||
unsigned int sc7a20_data = 0;
|
||||
unsigned int fifo_data_xyz[32];
|
||||
u8 click_result = 0x00;
|
||||
unsigned int click_sum = 0;
|
||||
u8 data1[6];
|
||||
signed char data[6];
|
||||
|
||||
g_printf("INT_HAPPEN!\r\n");
|
||||
|
||||
SL_MEMS_i2cRead(SC7A20_R_ADDR, SC7A20_SRC_REG, 1, &fifo_len);
|
||||
if ((fifo_len & 0x40) == 0x40) {
|
||||
fifo_len = 32;
|
||||
} else {
|
||||
fifo_len = fifo_len & 0x1f;
|
||||
}
|
||||
|
||||
for (i = 0; i < fifo_len; i++) {
|
||||
SL_MEMS_i2cRead(SC7A20_R_ADDR, 0xA8, 6, &data1[0]);
|
||||
data[1] = (signed char)data1[1];
|
||||
data[3] = (signed char)data1[3];
|
||||
data[5] = (signed char)data1[5];
|
||||
sc7a20_data = (data[1]) * (data[1]) + (data[3]) * (data[3]) + (data[5]) * (data[5]);
|
||||
sc7a20_data = SL_Click_Sqrt(sc7a20_data);
|
||||
fifo_data_xyz[i] = sc7a20_data;
|
||||
|
||||
#if SL_Sensor_Algo_Release_Enable==0
|
||||
SL_DEBUG_DATA[0][i] = data[1];
|
||||
SL_DEBUG_DATA[1][i] = data[3];
|
||||
SL_DEBUG_DATA[2][i] = data[5];
|
||||
SL_DEBUG_DATA[3][i] = fifo_data_xyz[i];
|
||||
SL_DEBUG_DATA_LEN = fifo_len;
|
||||
#endif
|
||||
}
|
||||
|
||||
k = 0;
|
||||
for (i = 1; i < fifo_len - 1; i++) {
|
||||
if ((fifo_data_xyz[i + 1] > TH1) && (fifo_data_xyz[i - 1] < 30)) {
|
||||
g_printf("in_th\r\n");
|
||||
if (click_num == 0) {
|
||||
click_sum = 0; //first peak
|
||||
for (j = 0; j < i - 1; j++) {
|
||||
if (fifo_data_xyz[j] > fifo_data_xyz[j + 1]) {
|
||||
click_sum += fifo_data_xyz[j] - fifo_data_xyz[j + 1];
|
||||
} else {
|
||||
click_sum += fifo_data_xyz[j + 1] - fifo_data_xyz[j];
|
||||
}
|
||||
}
|
||||
#if SL_Sensor_Algo_Release_Enable==0
|
||||
g_printf("click_sum:%d!\r\n", click_sum);
|
||||
#endif
|
||||
if (click_sum > TH2) {
|
||||
sl_pp_num++;
|
||||
break;
|
||||
}
|
||||
k = i;
|
||||
} else {
|
||||
k = i; //sencond peak
|
||||
}
|
||||
}
|
||||
|
||||
if (k != 0) {
|
||||
if (fifo_data_xyz[i - 1] - fifo_data_xyz[i + 1] > TH1 - 10) {
|
||||
if (i - k < 5) {
|
||||
click_num = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (click_num == 1) {
|
||||
click_result = 1;
|
||||
} else {
|
||||
click_result = 0;
|
||||
}
|
||||
|
||||
return click_result;
|
||||
}
|
||||
|
||||
//GPIO?????,??INT2
|
||||
//Service function in Int Function
|
||||
//u8 sl_click_timer_en =0;
|
||||
u8 sl_click_status = 0;
|
||||
unsigned short click_timer_cnt = 0;
|
||||
unsigned short click_timer_total_cnt = 0;
|
||||
u8 click_click_final_cnt = 0;
|
||||
|
||||
char SC7A20_Click_Alog(void)
|
||||
{
|
||||
u8 click_status = 0;
|
||||
|
||||
SL_MEMS_i2cWrite(SC7A20_W_ADDR, SC7A20_CTRL_REG3, 0x00);
|
||||
click_status = SC7A20_Click_Read(SC7A20_TH1, SC7A20_TH2); //40,50
|
||||
|
||||
g_printf("click_status = 0x%x\n", click_status);
|
||||
if (click_status == 1) {
|
||||
if (sl_click_timer_en == 0) {
|
||||
//set click timer flag
|
||||
sl_click_timer_en = 1;
|
||||
//clear click timer cnt value
|
||||
click_timer_cnt = 0;
|
||||
click_timer_total_cnt = 0;
|
||||
click_click_final_cnt = 0;
|
||||
}
|
||||
sl_click_status = 1;
|
||||
}
|
||||
SL_MEMS_i2cWrite(SC7A20_W_ADDR, SC7A20_CTRL_REG3, 0x82);
|
||||
return click_status;
|
||||
}
|
||||
|
||||
//This fuction is execute in 50ms timer when the timer is opened
|
||||
char SC7A20_click_status(void)
|
||||
{
|
||||
u8 click_e_cnt = 0;
|
||||
if (sl_click_timer_en == 1) {
|
||||
click_timer_cnt++;
|
||||
if ((click_timer_cnt < click_pp_num) && (sl_click_status == 1)) {
|
||||
g_printf("status:%d\r\n", sl_click_status);
|
||||
g_printf("fin_num:%d\r\n", click_click_final_cnt);
|
||||
sl_click_status = 0;
|
||||
click_timer_total_cnt = click_timer_total_cnt + click_timer_cnt;
|
||||
click_timer_cnt = 0;
|
||||
click_click_final_cnt++;
|
||||
}
|
||||
|
||||
click_e_cnt = SL_Get_CLICK_PP_CNT(1);
|
||||
|
||||
if ((((click_timer_cnt >= click_pp_num) || (click_timer_total_cnt >= click_max_num)) && (click_e_cnt < 1)) ||
|
||||
((click_timer_cnt >= click_pp_num) && (click_e_cnt > 0)))
|
||||
// if((click_timer_cnt>=click_pp_num)||(click_timer_total_cnt>=click_max_num))
|
||||
{
|
||||
//clear click timer flag
|
||||
sl_click_timer_en = 0;
|
||||
//clear click timer cnt value
|
||||
click_timer_cnt = 0;
|
||||
click_timer_total_cnt = 0;
|
||||
g_printf("fin_num:%d\r\n", click_click_final_cnt);
|
||||
if (click_e_cnt > 0) {
|
||||
click_e_cnt = SL_Get_CLICK_PP_CNT(0);
|
||||
return 0;
|
||||
} else {
|
||||
return click_click_final_cnt;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SC7A20_int_io_detect(u8 int_io_status)
|
||||
{
|
||||
static u8 int_io_status_old;
|
||||
/* u8 int_io_status = 0; */
|
||||
/* int_io_status = gpio_read(INT_IO); */
|
||||
if ((int_io_status) && (int_io_status_old == 0)) {
|
||||
log_e("sc7a20_int_io_detect\n");
|
||||
SC7A20_Click_Alog();
|
||||
} else {
|
||||
}
|
||||
int_io_status_old = int_io_status;
|
||||
}
|
||||
|
||||
void SC7A20_read_data(axis_info_t *sl_accel)
|
||||
{
|
||||
u8 data[6];
|
||||
u8 fifo_len = 0;
|
||||
SL_MEMS_i2cRead(SC7A20_R_ADDR, SC7A20_SRC_REG, 1, &fifo_len);
|
||||
if ((fifo_len & 0x40) == 0x40) {
|
||||
fifo_len = 32;
|
||||
} else {
|
||||
fifo_len = fifo_len & 0x1f;
|
||||
}
|
||||
for (u8 i = 0; i < fifo_len; i++) {
|
||||
SL_MEMS_i2cRead(SC7A20_R_ADDR, 0xA8, 6, data);
|
||||
sl_accel[i].x = (short)((data[1] << 8) | data[0]);
|
||||
// sl_accel[i].x = sl_accel[i].x >> 4;
|
||||
sl_accel[i].y = (short)((data[3] << 8) | data[2]);
|
||||
// sl_accel[i].y = sl_accel[i].y >> 4;
|
||||
sl_accel[i].z = (short)((data[5] << 8) | data[4]);
|
||||
// sl_accel[i].z = sl_accel[i].z >> 4;
|
||||
// printf("group:%2d,sl_accel_x:%5d, sl_accel_y:%5d, sl_accel_z:%5d\n", i, sl_accel[i].x, sl_accel[i].y, sl_accel[i].z);
|
||||
}
|
||||
}
|
||||
void SC7A20_ctl(u8 cmd, void *arg)
|
||||
{
|
||||
char res;
|
||||
switch (cmd) {
|
||||
case GSENSOR_DISABLE:
|
||||
res = SC7A20_disable();
|
||||
memcpy(arg, &res, 1);
|
||||
break;
|
||||
case GSENSOR_RESET_INT:
|
||||
res = SC7A20_Config();
|
||||
memcpy(arg, &res, 1);
|
||||
break;
|
||||
case GSENSOR_RESUME_INT:
|
||||
break;
|
||||
case GSENSOR_INT_DET:
|
||||
SC7A20_int_io_detect(*(u8 *)arg);
|
||||
break;
|
||||
case READ_GSENSOR_DATA:
|
||||
SC7A20_read_data((axis_info_t *)arg);
|
||||
break;
|
||||
case SEARCH_SENSOR:
|
||||
res = SC7A20_Check();
|
||||
memcpy(arg, &res, 1);
|
||||
break;
|
||||
default:
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static u8 sc7a20_idle_query(void)
|
||||
{
|
||||
return !sl_click_timer_en;
|
||||
}
|
||||
|
||||
REGISTER_GRAVITY_SENSOR(gSensor) = {
|
||||
.logo = "sc7a20",
|
||||
.gravity_sensor_init = SC7A20_Config,
|
||||
.gravity_sensor_check = SC7A20_click_status,
|
||||
.gravity_sensor_ctl = SC7A20_ctl,
|
||||
};
|
||||
|
||||
REGISTER_LP_TARGET(sc7a20_lp_target) = {
|
||||
.name = "sc7a20",
|
||||
.is_idle = sc7a20_idle_query,
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
116
apps/common/device/gSensor/SC7A20.h
Normal file
116
apps/common/device/gSensor/SC7A20.h
Normal file
@ -0,0 +1,116 @@
|
||||
/*
|
||||
Copyright (c) 2019 Silan MEMS. All Rights Reserved.
|
||||
*/
|
||||
#ifndef SC7A20_H
|
||||
#define SC7A20_H
|
||||
|
||||
/********添加IIC头文件******************/
|
||||
//#include "i2c.h"
|
||||
/***************************************/
|
||||
|
||||
|
||||
/***使用驱动前请根据实际接线情况配置(7bit)IIC地址******/
|
||||
/**SC7A20的SDO 脚接地: 0x18****************/
|
||||
/**SC7A20的SDO 脚接电源: 0x19****************/
|
||||
#define SC7A20_W_ADDR (0x19U << 1 | 0x0)
|
||||
#define SC7A20_R_ADDR (0x19U << 1 | 0x1)
|
||||
/*******************************************************/
|
||||
|
||||
#define SC7A20_CLICK_TH 0x38 //Click触发阈值,如果单次敲击无法触发中断,请将下面这个参数适当调小,如果单次敲击太过灵敏,请将下面这个参数适当调大
|
||||
#define SC7A20_CLICK_WINDOWS 0x05 //Click有效窗口
|
||||
#define SC7A20_CLICK_LATENCY 0x10 //Click中断持续时间,odr = 0x10时, 时间 = 16 * 2.5ms
|
||||
#define SC7A20_INT_LEVEL 0x02 //0x02为中断时低电平,0x0为高电平
|
||||
//如果中断能够触发,但是无法识别为单击,请调小如下函数中的参数 TH1
|
||||
//如果单击能够触发,摇晃都会触发多击,请调小如下函数中的参数 TH2
|
||||
//如果单击能够触发,多击功能比较难实现,请调大如下函数中的参数 TH2
|
||||
#define SC7A20_TH1 40
|
||||
#define SC7A20_TH2 50
|
||||
|
||||
#define click_pp_num (unsigned short)10*25 //10对应0.5s(不需要管后面的*25)
|
||||
#define click_max_num (unsigned short)60*25 // 60对应3s
|
||||
|
||||
|
||||
|
||||
/*************驱动初始化函数**************/
|
||||
unsigned char SC7A20_Config(void);
|
||||
/**SC7A20_Config 函数中, ODR 默认0x7f 400HZ/6f 200HZ ************/
|
||||
/**SC7A20_Config 函数中, HP 默认0xOC 开启高通滤波 ************/
|
||||
/**SC7A20_Config 函数中, click_int 默认0x80 将Click中断映射到INT1************/
|
||||
/**SC7A20_Config 函数中, range 默认0x90 4g量程************/
|
||||
/**SC7A20_Config 函数中, fifo_en 默认0x40 使能fifo************/
|
||||
/**SC7A20_Config 函数中, fifo_mode 默认0x80 Stream模式************/
|
||||
/**SC7A20_Config 函数中, click_mode 默认0x15 单击3轴触发************/
|
||||
/**SC7A20_Config 函数中, click_th 默认0x38 Click触发阈值************/
|
||||
/**SC7A20_Config 函数中, click_window 默认0x05 Click有效窗口************/
|
||||
/**SC7A20_Config 函数中, click_latency 默认0x10 Click中断持续时间************/
|
||||
|
||||
/*************返回数据情况如下*****************/
|
||||
/**return : 1 IIC通讯正常IC在线***************/
|
||||
/**return : 0; IIC通讯异常或IC不在线***************/
|
||||
|
||||
/*************单击状态检测**************/
|
||||
char SC7A20_Click_Read(int TH1, int TH2);
|
||||
/*************TH1 调节单击灵敏度,默认9000*****************/
|
||||
/*************TH2 默认6000*****************/
|
||||
/*************TH3 默认7000*****************/
|
||||
/*************返回数据情况如下*****************/
|
||||
/**return : 1 单次敲击有效***************/
|
||||
/**return : 0; 单次敲击无效***************/
|
||||
|
||||
|
||||
/*************外部中断调用Click敲击函数**************/
|
||||
char SC7A20_Click_Alog(void);
|
||||
/*************返回数据情况如下*****************/
|
||||
/**return : 1 单次敲击有效***************/
|
||||
/**return : 0; 单次敲击无效***************/
|
||||
|
||||
|
||||
/*************定时器中断调用Click状态函数**************/
|
||||
char SC7A20_click_status(void);
|
||||
/*************返回数据情况如下*****************/
|
||||
/**return : N N次敲击有效***************/
|
||||
|
||||
|
||||
/**reg map***************/
|
||||
#define SC7A20_OUT_TEMP_L 0x0C
|
||||
#define SC7A20_OUT_TEMP_H 0x0D
|
||||
#define SC7A20_WHO_AM_I 0x0F
|
||||
#define SC7A20_USER_CAL_START 0x13
|
||||
#define SC7A20_USER_CAL_END 0x1A
|
||||
#define SC7A20_NVM_WR 0x1E
|
||||
#define SC7A20_TEMP_CFG 0x1F
|
||||
#define SC7A20_CTRL_REG1 0x20
|
||||
#define SC7A20_CTRL_REG2 0x21
|
||||
#define SC7A20_CTRL_REG3 0x22
|
||||
#define SC7A20_CTRL_REG4 0x23
|
||||
#define SC7A20_CTRL_REG5 0x24
|
||||
#define SC7A20_CTRL_REG6 0x25
|
||||
#define SC7A20_REFERENCE 0x26
|
||||
#define SC7A20_STATUS_REG 0x27
|
||||
#define SC7A20_OUT_X_L 0x28
|
||||
#define SC7A20_OUT_X_H 0x29
|
||||
#define SC7A20_OUT_Y_L 0x2A
|
||||
#define SC7A20_OUT_Y_H 0x2B
|
||||
#define SC7A20_OUT_Z_L 0x2C
|
||||
#define SC7A20_OUT_Z_H 0x2D
|
||||
#define SC7A20_FIFO_CTRL_REG 0x2E
|
||||
#define SC7A20_SRC_REG 0x2F
|
||||
#define SC7A20_INT1_CFG 0x30
|
||||
#define SC7A20_INT1_SOURCE 0x31
|
||||
#define SC7A20_INT1_THS 0x32
|
||||
#define SC7A20_INT1_DURATION 0x33
|
||||
#define SC7A20_INT2_CFG 0x34
|
||||
#define SC7A20_INT2_SOURCE 0x35
|
||||
#define SC7A20_INT2_THS 0x36
|
||||
#define SC7A20_INT2_DURATION 0x37
|
||||
#define SC7A20_CLICK_CFG 0x38
|
||||
#define SC7A20_CLICK_SRC 0x39
|
||||
#define SC7A20_CLICK_THS 0x3A
|
||||
#define SC7A20_TIME_LIMIT 0x3B
|
||||
#define SC7A20_TIME_LATENCY 0x3C
|
||||
#define SC7A20_TIME_WINDOW 0x3D
|
||||
#define SC7A20_ACT_THS 0x3E
|
||||
#define SC7A20_ACT_DURATION 0x3F
|
||||
|
||||
#endif // SC7A20_H
|
||||
|
||||
141
apps/common/device/gSensor/STK8321.c
Normal file
141
apps/common/device/gSensor/STK8321.c
Normal file
@ -0,0 +1,141 @@
|
||||
#include "gSensor/STK8321.h"
|
||||
#include "gSensor/gSensor_manage.h"
|
||||
#include "app_config.h"
|
||||
|
||||
#if TCFG_STK8321_EN
|
||||
|
||||
static u8 stk8321_timeout_start = 0;
|
||||
|
||||
u8 STK8321_Read(u8 addr)
|
||||
{
|
||||
u8 data = 0;
|
||||
_gravity_sensor_get_ndata(I2C_ADDR_STK8321_R, addr, &data, 1);
|
||||
return data;
|
||||
}
|
||||
|
||||
void STK8321_Write(u8 addr, u8 data)
|
||||
{
|
||||
//g_sensor_write(G_SlaveAddr,addr,data);
|
||||
gravity_sensor_command(I2C_ADDR_STK8321_W, addr, data);
|
||||
}
|
||||
|
||||
u8 STK8321_init(void)
|
||||
{
|
||||
u8 k = 0, init_cnt = 10;
|
||||
u8 chip_id = 0;
|
||||
printf("\n###############>> [ init STK8321 start] <<################\n");
|
||||
|
||||
do {
|
||||
|
||||
chip_id = STK8321_Read(0x00);
|
||||
printf("\n STK8321 ID = [%x]\n", chip_id);
|
||||
init_cnt--;
|
||||
|
||||
} while ((chip_id != 0x86) && (init_cnt));
|
||||
|
||||
STK8321_Write(0x14, 0xB6); //software reset
|
||||
delay(1000);
|
||||
|
||||
if (chip_id != 0x86) {
|
||||
return -1;
|
||||
}
|
||||
STK8321_Write(0x14, 0xB6); //software reset
|
||||
delay(100);
|
||||
// mode settings
|
||||
STK8321_Write(0x11, 0x00); //active mode
|
||||
STK8321_Write(0x0F, 0x08); //range = +-8g
|
||||
STK8321_Write(0x10, 0x0D); //BW = 250Hz or ODR = 500Hz
|
||||
STK8321_Write(0x34, 0x04); //Enable I2C WatchDog
|
||||
// INT mode
|
||||
STK8321_Write(0x20, 0x00); //INT1 and INT2 active high
|
||||
STK8321_Write(0x21, 0x8F); //latched & clear
|
||||
// slope settings
|
||||
STK8321_Write(0x16, 0x04); // enable slope on Z-axis
|
||||
STK8321_Write(0x19, 0x01); // map sig-motion to INT 1
|
||||
STK8321_Write(0x27, 0x01); // The actual number of samples SLP_DUR[1:0]+1
|
||||
STK8321_Write(0x28, 0x25); // SLP_THD[7:0]*15.64_mg
|
||||
STK8321_Write(0x2A, 0x06); //Enable significant and any-motion interrupt
|
||||
STK8321_Write(0x29, 0x05); //skip_time 1LSB=20ms
|
||||
STK8321_Write(0x2B, 0x0A); //proof_time 1LSB=20ms
|
||||
printf("\n###############>> [ init STK8321 end ] <<################\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char STK8321_check_event()
|
||||
{
|
||||
static u16 timeout_cnt = 125; //需要等250ms
|
||||
u8 click_cnt = 0;
|
||||
if (stk8321_timeout_start) {
|
||||
if (timeout_cnt) {
|
||||
timeout_cnt --;
|
||||
} else {
|
||||
u8 RegReadValue = 0;
|
||||
g_printf("stk8321_timeout");
|
||||
RegReadValue = STK8321_Read(0x09);
|
||||
if ((RegReadValue & 0x04) == 0x00) {
|
||||
g_printf("Double Tap");
|
||||
click_cnt = 2;
|
||||
} else if ((RegReadValue & 0x04) == 0x04) {
|
||||
g_printf("Triple Tap");
|
||||
click_cnt = 3;
|
||||
} else {
|
||||
g_printf("NO Tap");
|
||||
click_cnt = 0;
|
||||
}
|
||||
STK8321_Write(0x2A, 0x02);
|
||||
STK8321_Write(0x21, 0x8F);
|
||||
stk8321_timeout_start = 0;
|
||||
timeout_cnt = 125;
|
||||
}
|
||||
}
|
||||
return click_cnt;
|
||||
}
|
||||
|
||||
void STK8321_int_io_detect(u8 int_io_status)
|
||||
{
|
||||
static u8 int_io_status_old;
|
||||
if (!stk8321_timeout_start) {
|
||||
if (!(int_io_status) && (int_io_status_old == 1)) {
|
||||
g_printf("STK8321_int_io_detect\n");
|
||||
stk8321_timeout_start = 1;
|
||||
STK8321_Write(0x2A, 0x04);
|
||||
STK8321_Write(0x21, 0x8F);
|
||||
}
|
||||
int_io_status_old = int_io_status;
|
||||
}
|
||||
}
|
||||
|
||||
void STK8321_ctl(u8 cmd, void *arg)
|
||||
{
|
||||
switch (cmd) {
|
||||
case GSENSOR_RESET_INT:
|
||||
break;
|
||||
case GSENSOR_RESUME_INT:
|
||||
break;
|
||||
case GSENSOR_INT_DET:
|
||||
STK8321_int_io_detect(*(u8 *)arg);
|
||||
break;
|
||||
default:
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static u8 STK8321_idle_query(void)
|
||||
{
|
||||
return !stk8321_timeout_start;
|
||||
}
|
||||
|
||||
REGISTER_GRAVITY_SENSOR(gSensor) = {
|
||||
.logo = "STK8321",
|
||||
.gravity_sensor_init = STK8321_init,
|
||||
.gravity_sensor_check = STK8321_check_event,
|
||||
.gravity_sensor_ctl = STK8321_ctl,
|
||||
};
|
||||
|
||||
REGISTER_LP_TARGET(da230_lp_target) = {
|
||||
.name = "STK8321",
|
||||
.is_idle = STK8321_idle_query,
|
||||
};
|
||||
#endif
|
||||
11
apps/common/device/gSensor/STK8321.h
Normal file
11
apps/common/device/gSensor/STK8321.h
Normal file
@ -0,0 +1,11 @@
|
||||
#ifndef __STK8321_H__
|
||||
#define __STK8321_H__
|
||||
|
||||
#include "typedef.h"
|
||||
|
||||
#define STK8321_ID 0x30
|
||||
|
||||
#define I2C_ADDR_STK8321_W (STK8321_ID | 0x0)
|
||||
#define I2C_ADDR_STK8321_R (STK8321_ID | 0x1)
|
||||
|
||||
#endif
|
||||
393
apps/common/device/gSensor/da230.c
Normal file
393
apps/common/device/gSensor/da230.c
Normal file
@ -0,0 +1,393 @@
|
||||
#include "gSensor/EPMotion.h"
|
||||
#include "gSensor/da230.h"
|
||||
#include "gSensor/gSensor_manage.h"
|
||||
#include "app_config.h"
|
||||
|
||||
#if TCFG_DA230_EN
|
||||
|
||||
#define LOG_TAG "[DA230]"
|
||||
#define LOG_ERROR_ENABLE
|
||||
#define LOG_DEBUG_ENABLE
|
||||
#define LOG_INFO_ENABLE
|
||||
/* #define LOG_DUMP_ENABLE */
|
||||
#define LOG_CLI_ENABLE
|
||||
#include "debug.h"
|
||||
|
||||
static u8 da230_init_ok = 0;
|
||||
static u8 tap_data = 0;
|
||||
static u8 tap_start = 0;
|
||||
static u8 event_ocur = 0;
|
||||
static u8 da230_is_idle = 1;
|
||||
|
||||
void da230_set_idle_flag(u8 flag)
|
||||
{
|
||||
da230_is_idle = flag;
|
||||
}
|
||||
|
||||
u32 da230_register_read(u8 addr, u8 *data)
|
||||
{
|
||||
_gravity_sensor_get_ndata(I2C_ADDR_DA230_R, addr, data, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
s8_m da230_register_write(u8_m addr, u8_m data)
|
||||
{
|
||||
gravity_sensor_command(I2C_ADDR_DA230_W, addr, data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
s8_m da230_read_nbyte_data(u8_m addr, u8_m *data, u8_m len)
|
||||
{
|
||||
_gravity_sensor_get_ndata(I2C_ADDR_DA230_R, addr, data, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
s8_m da230_register_mask_write(unsigned char addr, unsigned char mask, unsigned char data)
|
||||
{
|
||||
int res = 0;
|
||||
unsigned char tmp_data;
|
||||
|
||||
/* iic_readn(I2C_ADDR_DA230_R, addr, &tmp_data, 1); */
|
||||
da230_read_nbyte_data(addr, &tmp_data, 1);
|
||||
|
||||
tmp_data &= ~mask;
|
||||
tmp_data |= data & mask;
|
||||
/* iic_write(I2C_ADDR_DA230_W, addr, &tmp_data, 1); */
|
||||
da230_register_write(addr, tmp_data);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
s8_m handleEvent(EPMotion_EVENT event, u8 data)
|
||||
{
|
||||
event_ocur = 0;
|
||||
tap_start = 0;
|
||||
da230_set_idle_flag(1);
|
||||
log_info("da230_set_idle_flag:1");
|
||||
switch (event) {
|
||||
case TEVENT_TAP_NOTIFY: {
|
||||
tap_data = data;
|
||||
printf("*******DATA:%d \n", data);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 da230_register_write_bit(u8 addr, u8 start, u8 len, u8 data)
|
||||
{
|
||||
u32 res = 0;
|
||||
u8 tmp_data;
|
||||
|
||||
res = da230_register_read(addr, &tmp_data);
|
||||
if (res) {
|
||||
return res;
|
||||
}
|
||||
|
||||
SFR(tmp_data, start, len, data);
|
||||
|
||||
res = da230_register_write(addr, tmp_data);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
u32 da230_close_i2c_pullup(void)
|
||||
{
|
||||
u32 res = 0;
|
||||
|
||||
res |= da230_register_write(0x7f, 0x83);
|
||||
res |= da230_register_write(0x7f, 0x69);
|
||||
res |= da230_register_write(0x7f, 0xBD);
|
||||
|
||||
/**********将0x8f bit1写0,去掉da230内部i2c弱上拉*********/
|
||||
res |= da230_register_write_bit(0x8f, 1, 1, 0);
|
||||
|
||||
return res;
|
||||
}
|
||||
#if 0
|
||||
u32 da230_read_block_data(u8 base_addr, u8 count, u8 *data)
|
||||
{
|
||||
u32 i = 0;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
if (da230_register_read(base_addr + i, (data + i))) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
u32 da230_register_read_continuously(u8 addr, u8 count, u8 *data)
|
||||
{
|
||||
u32 res = 0;
|
||||
|
||||
res = (count == da230_read_block_data(addr, count, data)) ? 0 : 1;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
u32 da230_open_step_counter(void)
|
||||
{
|
||||
u32 res = 0;
|
||||
|
||||
res |= da230_register_write(NSA_REG_STEP_CONGIF1, 0x01);
|
||||
res |= da230_register_write(NSA_REG_STEP_CONGIF2, 0x62);
|
||||
res |= da230_register_write(NSA_REG_STEP_CONGIF3, 0x46);
|
||||
res |= da230_register_write(NSA_REG_STEP_CONGIF4, 0x32);
|
||||
res |= da230_register_write(NSA_REG_STEP_FILTER, 0xa2);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
u16 da230_get_step(void)
|
||||
{
|
||||
u8 tmp_data[4] = {0};
|
||||
u16 f_step = 0;
|
||||
|
||||
if (da230_register_read_continuously(NSA_REG_STEPS_MSB, 4, tmp_data) == 0) {
|
||||
if (0x40 == tmp_data[2] && 0x07 == tmp_data[3]) {
|
||||
f_step = ((tmp_data[0] << 8 | tmp_data[1])) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return (f_step);
|
||||
}
|
||||
|
||||
u32 da230_close_step_counter(void)
|
||||
{
|
||||
u32 res = 0;
|
||||
|
||||
res = da230_register_write(NSA_REG_STEP_FILTER, 0x22);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
u32 da230_register_write_bit(u8 addr, u8 start, u8 len, u8 data)
|
||||
{
|
||||
u32 res = 0;
|
||||
u8 tmp_data;
|
||||
|
||||
res = da230_register_read(addr, &tmp_data);
|
||||
if (res) {
|
||||
return res;
|
||||
}
|
||||
|
||||
SFR(tmp_data, start, len, data);
|
||||
|
||||
res = da230_register_write(addr, tmp_data);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
u32 da230_open_i2c_pullup(void)
|
||||
{
|
||||
u32 res = 0;
|
||||
|
||||
res |= da230_register_write(0x7f, 0x83);
|
||||
res |= da230_register_write(0x7f, 0x69);
|
||||
res |= da230_register_write(0x7f, 0xBD);
|
||||
|
||||
/**********将0x8f bit1写1,开启da230内部i2c弱上拉*********/
|
||||
res |= da230_register_write_bit(0x8f, 1, 1, 1);
|
||||
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct EPMotion_op_s ops_handle = {
|
||||
{PIN_ONE, PIN_LEVEL_LOW},
|
||||
handleEvent,
|
||||
{da230_read_nbyte_data, da230_register_write},
|
||||
printf
|
||||
};
|
||||
u8 da230_init(void)
|
||||
{
|
||||
u8 data = 0;
|
||||
|
||||
JL_PORTB->DIR &= ~BIT(2);
|
||||
JL_PORTB->DIE |= BIT(2);
|
||||
JL_PORTB->OUT |= BIT(2);
|
||||
da230_register_read(NSA_REG_WHO_AM_I, &data);
|
||||
|
||||
if (data != 0x13) {
|
||||
log_e("da230 init err1!!!!!!!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (EPMotion_Init(&ops_handle)) {
|
||||
log_e("da230 init err2!!!!!!!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
EPMotion_Set_Debug_level(DEBUG_ERR);
|
||||
EPMotion_Tap_Set_Parma(0x0d, LATCHED_100MS, 0x00); //0x05~0x1f
|
||||
//EPMotion_D_Tap_Set_Filter(1, 130);
|
||||
EPMotion_M_Tap_Set_Dur(70, 500);
|
||||
// EPMotion_M_Tap_Set_Dur(60,150);
|
||||
da230_register_mask_write(0x10, 0xe0, 0xc0);
|
||||
EPMotion_Control(M_TAP_T, ENABLE_T);
|
||||
// EPMotion_Tap_Set_Parma(0x08,LATCHED_25MS,0x00); //0x05~0x1f
|
||||
|
||||
|
||||
//close i2c pullup
|
||||
da230_close_i2c_pullup();
|
||||
da230_register_mask_write(0x8f, 0x02, 0x00);
|
||||
|
||||
da230_init_ok = 1;
|
||||
|
||||
log_info("da230 init success!!!\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 da230_set_enable(u8 enable)
|
||||
{
|
||||
u32 res = 0;
|
||||
|
||||
if (da230_init_ok) {
|
||||
|
||||
if (enable) {
|
||||
EPMotion_Chip_Power_On();
|
||||
} else {
|
||||
EPMotion_Chip_Power_Off();
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
void da230_read_XYZ(short *x, short *y, short *z)
|
||||
{
|
||||
if (da230_init_ok) {
|
||||
EPMotion_Chip_Read_XYZ(x, y, z);
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
u16 da230_open_interrupt(u16 num)
|
||||
{
|
||||
u16 res = 0;
|
||||
res = da230_register_write(NSA_REG_INTERRUPT_SETTINGS1, 0x87);
|
||||
res = da230_register_write(NSA_REG_ACTIVE_THRESHOLD, 0x05);
|
||||
switch (num) {
|
||||
case 0:
|
||||
res = da230_register_write(NSA_REG_INTERRUPT_MAPPING1, 0x04);
|
||||
break;
|
||||
case 1:
|
||||
res = da230_register_write(NSA_REG_INTERRUPT_MAPPING3, 0x04);
|
||||
break;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
|
||||
void da230_check_tap_int(void)
|
||||
{
|
||||
static int count = 0;
|
||||
if (tap_start) {
|
||||
if (event_ocur == 1) {
|
||||
count = 0;
|
||||
}
|
||||
if ((count % 5) == 0) {
|
||||
//printf("====process event %d\r\n",event_ocur);
|
||||
// gpio_direction_output(IO_PORT_DM, 1);
|
||||
EPMotion_Process_Data(event_ocur);
|
||||
// gpio_direction_output(IO_PORT_DM, 0);
|
||||
}
|
||||
count++;
|
||||
|
||||
if (count >= 300000) {
|
||||
count = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void da230_low_energy_mode(void)
|
||||
{
|
||||
da230_register_write(0x11, 0x04);
|
||||
}
|
||||
|
||||
void da230_int_io_detect(u8 int_io_status)
|
||||
{
|
||||
static u8 int_io_status_old = 0;
|
||||
/* u8 int_io_status = 0; */
|
||||
if (da230_init_ok) {
|
||||
/* int_io_status = gpio_read(INT_IO); */
|
||||
if ((int_io_status) && (int_io_status_old == 0)) {
|
||||
log_e("da230_int_io_detect\n");
|
||||
if (tap_start == 0) {
|
||||
tap_start = 1;
|
||||
da230_set_idle_flag(0);
|
||||
log_info("da230_set_idle_flag:0");
|
||||
}
|
||||
event_ocur = 1;
|
||||
putchar('A');
|
||||
} else {
|
||||
event_ocur = 0;
|
||||
}
|
||||
int_io_status_old = int_io_status;
|
||||
|
||||
da230_check_tap_int();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static char da230_check_event()
|
||||
{
|
||||
u8 tmp_tap_data = 0;
|
||||
tmp_tap_data = tap_data;
|
||||
if (tap_data) {
|
||||
tap_data = 0;
|
||||
printf("tmp_tap_data = %d\n", tmp_tap_data);
|
||||
}
|
||||
return tmp_tap_data;
|
||||
/* return EPMotion_Process_Data(); */
|
||||
}
|
||||
|
||||
void da230_ctl(u8 cmd, void *arg)
|
||||
{
|
||||
switch (cmd) {
|
||||
case GSENSOR_RESET_INT:
|
||||
EPMotion_Reset_Tap_INT();
|
||||
break;
|
||||
case GSENSOR_RESUME_INT:
|
||||
EPMotion_Resume_Tap_INT();
|
||||
break;
|
||||
case GSENSOR_INT_DET:
|
||||
da230_int_io_detect(*(u8 *)arg);
|
||||
break;
|
||||
default:
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static u8 da230_idle_query(void)
|
||||
{
|
||||
return da230_is_idle;
|
||||
}
|
||||
|
||||
REGISTER_GRAVITY_SENSOR(gSensor) = {
|
||||
.logo = "da230",
|
||||
.gravity_sensor_init = da230_init,
|
||||
.gravity_sensor_check = da230_check_event,
|
||||
.gravity_sensor_ctl = da230_ctl,
|
||||
};
|
||||
|
||||
REGISTER_LP_TARGET(da230_lp_target) = {
|
||||
.name = "da230",
|
||||
.is_idle = da230_idle_query,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
25
apps/common/device/gSensor/da230.h
Normal file
25
apps/common/device/gSensor/da230.h
Normal file
@ -0,0 +1,25 @@
|
||||
#ifndef __da230_h
|
||||
#define __da230_h
|
||||
|
||||
#include "typedef.h"
|
||||
#include "mira_std.h"
|
||||
|
||||
|
||||
|
||||
#define LATCHED_MODE LATCHED_1S //interrupt latched mode
|
||||
#define INTERRUPT_THRESHOLD 15 //interrupt threshold 0~31 ,(threshold*125)mg
|
||||
#define INTERRUPT_DURATION 5 //interrupt duration 0~7 ,(50~700)ms 0:50ms 1:100ms 2:150ms 3:200ms 4:250ms 5:375ms 6:500ms 7:700ms
|
||||
#define TAP_SAMPLE_LEVEL 1 //采样次数 = 25-TAP_SAMPLE_LEVEL*5
|
||||
#define TAP_FILTER 30 //噪声大小,大于TAP_FILTER认为是噪声
|
||||
|
||||
#define I2C_ADDR_DA230_W 0x4e
|
||||
#define I2C_ADDR_DA230_R 0x4f
|
||||
|
||||
extern u32 da230_register_read(u8 addr, u8 *data);
|
||||
extern s8_m da230_register_write(u8_m addr, u8_m data);
|
||||
extern u32 da230_register_write_bit(u8 addr, u8 start, u8 len, u8 data);
|
||||
|
||||
// extern u8 da230_int_event_detect(void);
|
||||
|
||||
#endif
|
||||
|
||||
409
apps/common/device/gSensor/gSensor_manage.c
Normal file
409
apps/common/device/gSensor/gSensor_manage.c
Normal file
@ -0,0 +1,409 @@
|
||||
#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
|
||||
|
||||
spinlock_t iic_lock;
|
||||
|
||||
#define LOG_TAG "[GSENSOR]"
|
||||
#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 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);
|
||||
//log_info("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) {
|
||||
log_info("GSENSOR_EVENT_CLICK\n");
|
||||
gSensor_event_to_user(KEY_EVENT_CLICK);
|
||||
} else if (det_result == 2) {
|
||||
log_info("GSENSOR_EVENT_DOUBLE_CLICK\n");
|
||||
gSensor_event_to_user(KEY_EVENT_DOUBLE_CLICK);
|
||||
} else if (det_result == 3) {
|
||||
log_info("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)
|
||||
{
|
||||
// printf("%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;
|
||||
// printf("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)
|
||||
{
|
||||
// printf("%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 {
|
||||
printf("%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) {
|
||||
// printf("%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++){
|
||||
printf("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++){ */
|
||||
/* printf("sour x=%06d y=%06d z=%06d",accel_data[i].x,accel_data[i].y,accel_data[i].z); */
|
||||
/* } */
|
||||
if (wlen == 0) {
|
||||
printf("data_w_cbuf_full");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// printf("%s ",__func__);
|
||||
return ;
|
||||
}
|
||||
}
|
||||
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;
|
||||
iic_start(gSensor_info->iic_hdl);
|
||||
if (0 == iic_tx_byte(gSensor_info->iic_hdl, w_chip_id)) {
|
||||
ret = 0;
|
||||
log_e("\n gsen iic wr err 0\n");
|
||||
goto __gcend;
|
||||
}
|
||||
|
||||
delay(gSensor_info->iic_delay);
|
||||
|
||||
if (0 == iic_tx_byte(gSensor_info->iic_hdl, register_address)) {
|
||||
ret = 0;
|
||||
log_e("\n gsen iic wr err 1\n");
|
||||
goto __gcend;
|
||||
}
|
||||
|
||||
delay(gSensor_info->iic_delay);
|
||||
|
||||
if (0 == iic_tx_byte(gSensor_info->iic_hdl, function_command)) {
|
||||
ret = 0;
|
||||
log_e("\n gsen iic wr err 2\n");
|
||||
goto __gcend;
|
||||
}
|
||||
|
||||
__gcend:
|
||||
iic_stop(gSensor_info->iic_hdl);
|
||||
spin_unlock(&sensor_iic);
|
||||
/* os_mutex_post(&SENSOR_IIC_MUTEX); */
|
||||
return ret;
|
||||
}
|
||||
|
||||
u8 _gravity_sensor_get_ndata(u8 r_chip_id, u8 register_address, u8 *buf, u8 data_len)
|
||||
{
|
||||
// printf("%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)) {
|
||||
log_e("\n gsen iic rd err 0\n");
|
||||
read_len = 0;
|
||||
goto __gdend;
|
||||
}
|
||||
|
||||
|
||||
delay(gSensor_info->iic_delay);
|
||||
if (0 == iic_tx_byte(gSensor_info->iic_hdl, register_address)) {
|
||||
log_e("\n gsen iic rd err 1\n");
|
||||
read_len = 0;
|
||||
goto __gdend;
|
||||
}
|
||||
|
||||
iic_start(gSensor_info->iic_hdl);
|
||||
if (0 == iic_tx_byte(gSensor_info->iic_hdl, r_chip_id)) {
|
||||
log_e("\n gsen iic rd err 2\n");
|
||||
read_len = 0;
|
||||
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 ++;
|
||||
|
||||
__gdend:
|
||||
|
||||
iic_stop(gSensor_info->iic_hdl);
|
||||
delay(gSensor_info->iic_delay);
|
||||
spin_unlock(&sensor_iic);
|
||||
|
||||
/* os_mutex_post(&SENSOR_IIC_MUTEX); */
|
||||
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);
|
||||
|
||||
log_e("\n gravity_sensor_init\n");
|
||||
|
||||
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_gsensor(gSensor_hdl) {
|
||||
if (!memcmp(gSensor_hdl->logo, platform_data->gSensor_name, strlen(platform_data->gSensor_name))) {
|
||||
retval = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (retval < 0) {
|
||||
log_e(">>>gSensor_hdl logo err\n");
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (gSensor_hdl->gravity_sensor_init()) {
|
||||
log_e(">>>>gSensor_Int ERROR\n");
|
||||
} else {
|
||||
log_info(">>>>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) {
|
||||
printf("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,使用时需要重新实现 */
|
||||
printf("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) {
|
||||
printf("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);
|
||||
printf("cbuf_init");
|
||||
//设置参数
|
||||
valid = 0;
|
||||
gSensor_hdl->gravity_sensor_ctl(GSENSOR_RESET_INT, &valid);
|
||||
|
||||
if (valid == -1) {
|
||||
return -1;
|
||||
}
|
||||
printf("gsensor_reset_succeed\n");
|
||||
return 0;
|
||||
}
|
||||
88
apps/common/device/gSensor/gSensor_manage.h
Normal file
88
apps/common/device/gSensor/gSensor_manage.h
Normal file
@ -0,0 +1,88 @@
|
||||
#ifndef _GSENSOR_MANAGE_H
|
||||
#define _GSENSOR_MANAGE_H
|
||||
#include "printf.h"
|
||||
#include "cpu.h"
|
||||
//#include "iic.h"
|
||||
#include "asm/iic_hw.h"
|
||||
#include "asm/iic_soft.h"
|
||||
#include "timer.h"
|
||||
#include "app_config.h"
|
||||
#include "event.h"
|
||||
#include "system/includes.h"
|
||||
|
||||
#define ACCEL_OF_GRAVITY 10
|
||||
#define ACCEL_DATA_GAIN 10
|
||||
|
||||
enum {
|
||||
GSENSOR_DISABLE = 0,
|
||||
GSENSOR_RESET_INT,
|
||||
GSENSOR_RESUME_INT,
|
||||
GSENSOR_INT_DET,
|
||||
READ_GSENSOR_DATA,
|
||||
GET_ACCEL_DATA,
|
||||
SEARCH_SENSOR,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
short x;
|
||||
short y;
|
||||
short z;
|
||||
} axis_info_t;
|
||||
|
||||
typedef struct {
|
||||
u8 logo[20];
|
||||
u8(*gravity_sensor_init)(void);
|
||||
char (*gravity_sensor_check)(void);
|
||||
void (*gravity_sensor_ctl)(u8 cmd, void *arg);
|
||||
} G_SENSOR_INTERFACE;
|
||||
|
||||
|
||||
struct gsensor_platform_data {
|
||||
u8 iic;
|
||||
char gSensor_name[20];
|
||||
u32 gSensor_int_io;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
u8 iic_hdl;
|
||||
u8 iic_delay; //这个延时并非影响iic的时钟频率,而是2Byte数据之间的延时
|
||||
u8 ctl_flag;
|
||||
int init_flag;
|
||||
int check_cnt;
|
||||
int check_timer_hdl;
|
||||
} G_SENSOR_INFO;
|
||||
|
||||
int gravity_sensor_init(void *_data);
|
||||
int gsensor_enable(void);
|
||||
int gsensor_disable(void);
|
||||
u8 gravity_sensor_command(u8 w_chip_id, u8 register_address, u8 function_command);
|
||||
u8 _gravity_sensor_get_ndata(u8 r_chip_id, u8 register_address, u8 *buf, u8 data_len);
|
||||
int get_gSensor_data(short *buf);
|
||||
int gSensor_read_data(u8 *buf, u8 buflen);
|
||||
int read_gsensor_buf(short *buf);
|
||||
int read_gsensor_nbuf(short *buf, short datalen);
|
||||
extern G_SENSOR_INTERFACE gsensor_dev_begin[];
|
||||
extern G_SENSOR_INTERFACE gsensor_dev_end[];
|
||||
|
||||
#define REGISTER_GRAVITY_SENSOR(gSensor) \
|
||||
static G_SENSOR_INTERFACE gSensor SEC_USED(.gsensor_dev)
|
||||
|
||||
#define list_for_each_gsensor(c) \
|
||||
for (c=gsensor_dev_begin; c<gsensor_dev_end; c++)
|
||||
|
||||
#define GSENSOR_PLATFORM_DATA_BEGIN(data) \
|
||||
static const struct gsensor_platform_data data = {
|
||||
|
||||
#define GSENSOR_PLATFORM_DATA_END() \
|
||||
};
|
||||
|
||||
/*
|
||||
enum {
|
||||
GSENSOR_EVENT_CLICK = 0,
|
||||
GSENSOR_EVENT_DOUBLE_CLICK,
|
||||
GSENSOR_EVENT_THREE_CLICK,
|
||||
};
|
||||
|
||||
#define DEVICE_EVENT_GSENSOR (('G' << 24) | ('S' << 16) | ('R' << 8) | '\0')
|
||||
*/
|
||||
#endif
|
||||
99
apps/common/device/gSensor/mira_std.h
Normal file
99
apps/common/device/gSensor/mira_std.h
Normal file
@ -0,0 +1,99 @@
|
||||
/*******************************************************************************/
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file mira_std.h
|
||||
* @author ycwang@miramems.com
|
||||
* @version V1.0
|
||||
* @date 26-Nov-2014
|
||||
* @brief
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
|
||||
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
|
||||
* TIME. AS A RESULT, MiraMEMS SHALL NOT BE HELD LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
|
||||
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
|
||||
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
|
||||
*
|
||||
* <h2><center>© COPYRIGHT 2014 MiraMEMS</center></h2>
|
||||
*/
|
||||
/*******************************************************************************/
|
||||
#ifndef __mira_std_h
|
||||
#define __mira_std_h
|
||||
|
||||
/*******************************************************************************
|
||||
Macro definitions - Register define for Gsensor asic
|
||||
********************************************************************************/
|
||||
#define NSA_REG_SPI_I2C 0x00
|
||||
#define NSA_REG_WHO_AM_I 0x01
|
||||
#define NSA_REG_ACC_X_LSB 0x02
|
||||
#define NSA_REG_ACC_X_MSB 0x03
|
||||
#define NSA_REG_ACC_Y_LSB 0x04
|
||||
#define NSA_REG_ACC_Y_MSB 0x05
|
||||
#define NSA_REG_ACC_Z_LSB 0x06
|
||||
#define NSA_REG_ACC_Z_MSB 0x07
|
||||
#define NSA_REG_MOTION_FLAG 0x09
|
||||
#define NSA_REG_G_RANGE 0x0f
|
||||
#define NSA_REG_ODR_AXIS_DISABLE 0x10
|
||||
#define NSA_REG_POWERMODE_BW 0x11
|
||||
#define NSA_REG_SWAP_POLARITY 0x12
|
||||
#define NSA_REG_FIFO_CTRL 0x14
|
||||
#define NSA_REG_INTERRUPT_SETTINGS0 0x15
|
||||
#define NSA_REG_INTERRUPT_SETTINGS1 0x16
|
||||
#define NSA_REG_INTERRUPT_SETTINGS2 0x17
|
||||
#define NSA_REG_INTERRUPT_MAPPING1 0x19
|
||||
#define NSA_REG_INTERRUPT_MAPPING2 0x1a
|
||||
#define NSA_REG_INTERRUPT_MAPPING3 0x1b
|
||||
#define NSA_REG_INT_PIN_CONFIG 0x20
|
||||
#define NSA_REG_INT_LATCH 0x21
|
||||
#define NSA_REG_ACTIVE_DURATION 0x27
|
||||
#define NSA_REG_ACTIVE_THRESHOLD 0x28
|
||||
#define NSA_REG_TAP_DURATION 0x2A
|
||||
#define NSA_REG_TAP_THRESHOLD 0x2B
|
||||
#define NSA_REG_ENGINEERING_MODE 0x7f
|
||||
#define NSA_REG_SENS_COMP 0x8c
|
||||
#define NSA_REG_MEMS_OPTION 0x8f
|
||||
#define NSA_REG_CHIP_INFO 0xc0
|
||||
|
||||
/*******************************************************************************
|
||||
Typedef definitions
|
||||
********************************************************************************/
|
||||
#define ARM_BIT_8 0
|
||||
|
||||
#if ARM_BIT_8
|
||||
//如下数据类型是在8位机上定义的,在其它平台(比如32位)可能存在差别,需要根据实际情况修改 。
|
||||
typedef unsigned char u8_m; /* 无符号8位整型变量*/
|
||||
typedef signed char s8_m; /* 有符号8位整型变量*/
|
||||
typedef unsigned int u16_m; /* 无符号16位整型变量*/
|
||||
typedef signed int s16_m; /* 有符号16位整型变量*/
|
||||
typedef unsigned long u32_m; /* 无符号32位整型变量*/
|
||||
typedef signed long s32_m; /* 有符号32位整型变量*/
|
||||
typedef float fp32_m; /* 单精度浮点数(32位长度)*/
|
||||
typedef double fp64_m; /* 双精度浮点数(64位长度)*/
|
||||
#else
|
||||
//如下数据类型是在32位机上定义的,在其它平台(比如8位)可能存在差别,需要根据实际情况修改 。
|
||||
typedef unsigned char u8_m; /* 无符号8位整型变量*/
|
||||
typedef signed char s8_m; /* 有符号8位整型变量*/
|
||||
typedef unsigned short u16_m; /* 无符号16位整型变量*/
|
||||
typedef signed short s16_m; /* 有符号16位整型变量*/
|
||||
typedef unsigned int u32_m; /* 无符号32位整型变量*/
|
||||
typedef signed int s32_m; /* 有符号32位整型变量*/
|
||||
typedef float fp32_m; /* 单精度浮点数(32位长度)*/
|
||||
typedef double fp64_m; /* 双精度浮点数(64位长度)*/
|
||||
#endif
|
||||
|
||||
typedef struct AccData_tag {
|
||||
s16_m ax; //加速度计原始数据结构体 数据格式 0 0 1024
|
||||
s16_m ay;
|
||||
s16_m az;
|
||||
|
||||
} AccData;
|
||||
|
||||
#define mir3da_abs(x) (((x) > 0) ? (x) : (-(x)))
|
||||
s32_m mir3da_sqrt(s32_m val);
|
||||
void mir3da_memset(void *dest, u8_m count);
|
||||
void *mir3da_memcpy(void *dest, void *source, u8_m count);
|
||||
#endif
|
||||
|
||||
|
||||
134
apps/common/device/gSensor/mpu6050.c
Normal file
134
apps/common/device/gSensor/mpu6050.c
Normal file
@ -0,0 +1,134 @@
|
||||
#include "gSensor/mpu6050.h"
|
||||
#include "gSensor/gSensor_manage.h"
|
||||
#include "app_config.h"
|
||||
#include "imuSensor_manage.h"
|
||||
|
||||
#if TCFG_MPU6050_EN
|
||||
|
||||
int gsensorlen = 32;
|
||||
OS_MUTEX SENSOR_IIC_MUTEX;
|
||||
spinlock_t sensor_iic;
|
||||
u8 sensor_iic_init_status = 0;
|
||||
|
||||
#define ACCEL_ONLY_LOW_POWER 0
|
||||
|
||||
u8 mpu6050_register_read(u8 addr, u8 *data)
|
||||
{
|
||||
_gravity_sensor_get_ndata(I2C_ADDR_MPU6050_R, addr, data, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
u8 mpu6050_register_write(u8 addr, u8 data)
|
||||
{
|
||||
gravity_sensor_command(I2C_ADDR_MPU6050_W, addr, data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
u8 mpu6050_read_nbyte_data(u8 addr, u8 *data, u8 len)
|
||||
{
|
||||
return _gravity_sensor_get_ndata(I2C_ADDR_MPU6050_R, addr, data, len);
|
||||
}
|
||||
|
||||
u8 mpu6050_get_xyz_data(u8 addr, void *xyz_data)
|
||||
{
|
||||
u8 buf[6], read_len;
|
||||
axis_info_t *data = (axis_info_t *)xyz_data;
|
||||
read_len = mpu6050_read_nbyte_data(addr, buf, 6);
|
||||
if (read_len == 6) {
|
||||
data->x = ((u16)buf[0] << 8) | buf[1];
|
||||
data->y = ((u16)buf[2] << 8) | buf[3];
|
||||
data->z = ((u16)buf[4] << 8) | buf[5];
|
||||
|
||||
data->x = 2 * ACCEL_OF_GRAVITY * ACCEL_DATA_GAIN * data->x / 32768;
|
||||
data->y = 2 * ACCEL_OF_GRAVITY * ACCEL_DATA_GAIN * data->y / 32768;
|
||||
data->z = 2 * ACCEL_OF_GRAVITY * ACCEL_DATA_GAIN * data->z / 32768;
|
||||
}
|
||||
return read_len;
|
||||
}
|
||||
|
||||
extern void step_cal_init();
|
||||
extern int step_cal();
|
||||
u8 mpu6050_init()
|
||||
{
|
||||
u8 res = 0;
|
||||
u8 data;
|
||||
res = mpu6050_register_read(MPU6050_RA_WHO_AM_I, &data); //读ID
|
||||
if (data == MPU_ADDR) {
|
||||
g_printf("read MPU6050 ID suss");
|
||||
} else {
|
||||
g_printf("read MPU6050 ID err");
|
||||
return -1;
|
||||
}
|
||||
|
||||
data = 0x80;
|
||||
mpu6050_register_write(MPU6050_RA_PWR_MGMT_1, data); //复位
|
||||
os_time_dly(10);
|
||||
|
||||
data = 0x00;
|
||||
data |= BIT(3); //关闭温度传感器
|
||||
#if ACCEL_ONLY_LOW_POWER
|
||||
data |= BIT(5); //设置accel-only低功耗模式
|
||||
#endif
|
||||
mpu6050_register_write(MPU6050_RA_PWR_MGMT_1, data); //退出休眠
|
||||
|
||||
data = 0x00;
|
||||
data |= (BIT(0) | BIT(1) | BIT(2)); //关闭陀螺仪
|
||||
#if ACCEL_ONLY_LOW_POWER
|
||||
data |= (3 << 6); //accel-only低功耗模式下,唤醒频率为40Hz
|
||||
#endif
|
||||
/*mpu6050_register_write(MPU6050_RA_PWR_MGMT_2, data);*/
|
||||
|
||||
data = ACCEL_RANGE_2G << 3;
|
||||
mpu6050_register_write(MPU6050_RA_ACCEL_CONFIG, data); //加速度计量程
|
||||
|
||||
#if (!ACCEL_ONLY_LOW_POWER)
|
||||
data = 0x06;
|
||||
mpu6050_register_write(MPU6050_RA_CONFIG, data); //设置陀螺仪输出速率
|
||||
|
||||
data = MPU6050_GYRO_OUT_RATE / MPU6050_SAMPLE_RATE - 1;
|
||||
mpu6050_register_write(MPU6050_RA_SMPLRT_DIV, data); //设置采样率, 采样率=陀螺仪输出速率/(1+SMPLRT_DIV)
|
||||
|
||||
data = 0x00;
|
||||
mpu6050_register_write(MPU6050_RA_INT_ENABLE, data); //关闭中断
|
||||
|
||||
data = 0x00;
|
||||
mpu6050_register_write(MPU6050_RA_USER_CTRL, data); //关闭主机IIC
|
||||
#endif
|
||||
|
||||
/*step_cal_init();*/
|
||||
/*sys_timer_add(NULL, step_cal, 50);*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mpu6050_ctl(u8 cmd, void *arg)
|
||||
{
|
||||
switch (cmd) {
|
||||
case GET_ACCEL_DATA:
|
||||
case IMU_GET_ACCEL_DATA:
|
||||
mpu6050_get_xyz_data(MPU6050_RA_ACCEL_XOUT_H, arg);
|
||||
break;
|
||||
case IMU_GET_GYRO_DATA:
|
||||
mpu6050_get_xyz_data(MPU6050_RA_GYRO_XOUT_H, arg);
|
||||
break;
|
||||
case READ_GSENSOR_DATA:
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
REGISTER_GRAVITY_SENSOR(gSensor) = {
|
||||
.logo = "mpu6050",
|
||||
.gravity_sensor_init = mpu6050_init,
|
||||
.gravity_sensor_check = NULL,
|
||||
.gravity_sensor_ctl = mpu6050_ctl,
|
||||
};
|
||||
|
||||
//未合到imu: init:gravity_sensor_init(&motion_sensor_data);
|
||||
REGISTER_IMU_SENSOR(mpu6050_sensor) = {
|
||||
.logo = "mpu6050",
|
||||
.imu_sensor_init = mpu6050_init,
|
||||
.imu_sensor_check = NULL,
|
||||
.imu_sensor_ctl = mpu6050_ctl,
|
||||
};
|
||||
|
||||
#endif //TCFG_MPU6050_EN
|
||||
16
apps/common/device/gSensor/mpu6050.h
Normal file
16
apps/common/device/gSensor/mpu6050.h
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef __MPU6050_H_
|
||||
#define __MPU6050_H_
|
||||
|
||||
#include "mpu6050_reg.h"
|
||||
|
||||
#define MPU6050_GYRO_OUT_RATE 1000 //1K或8K
|
||||
#define MPU6050_SAMPLE_RATE 125
|
||||
|
||||
enum {
|
||||
ACCEL_RANGE_2G,
|
||||
ACCEL_RANGE_4G,
|
||||
ACCEL_RANGE_8G,
|
||||
ACCEL_RANGE_16G,
|
||||
};
|
||||
|
||||
#endif
|
||||
598
apps/common/device/gSensor/mpu6050_reg.h
Normal file
598
apps/common/device/gSensor/mpu6050_reg.h
Normal file
@ -0,0 +1,598 @@
|
||||
#ifndef __MPU6050_REG_H_
|
||||
#define __MPU6050_REG_H_
|
||||
|
||||
#define MPU_ACK_WAIT_TIME 200 //us
|
||||
#define MPU6050_AD0_LOW
|
||||
|
||||
#ifdef MPU6050_AD0_LOW
|
||||
#define MPU_ADDR 0x68 //设备ID
|
||||
#else
|
||||
#define MPU_ADDR 0x69 //设备ID
|
||||
#endif
|
||||
|
||||
#define I2C_ADDR_MPU6050_W (MPU_ADDR<<1|0) // AD0为低的时候设备的写地址
|
||||
#define I2C_ADDR_MPU6050_R (MPU_ADDR<<1|1) // AD0为高的时候设备的写地址
|
||||
|
||||
|
||||
//技术文档未公布的寄存器 主要用于官方DMP操作
|
||||
#define MPU6050_RA_XG_OFFS_TC 0x00 //[bit7] PWR_MODE, [6:1] XG_OFFS_TC, [bit 0] OTP_BNK_VLD
|
||||
#define MPU6050_RA_YG_OFFS_TC 0x01 //[7] PWR_MODE, [6:1] YG_OFFS_TC, [0] OTP_BNK_VLD
|
||||
//bit7的定义,当设置为1,辅助I2C总线高电平是VDD。当设置为0,辅助I2C总线高电平是VLOGIC
|
||||
|
||||
#define MPU6050_RA_ZG_OFFS_TC 0x02 //[7] PWR_MODE, [6:1] ZG_OFFS_TC, [0] OTP_BNK_VLD
|
||||
#define MPU6050_RA_X_FINE_GAIN 0x03 //[7:0] X_FINE_GAIN
|
||||
#define MPU6050_RA_Y_FINE_GAIN 0x04 //[7:0] Y_FINE_GAIN
|
||||
#define MPU6050_RA_Z_FINE_GAIN 0x05 //[7:0] Z_FINE_GAIN
|
||||
|
||||
#define MPU6050_RA_XA_OFFS_H 0x06 //[15:0] XA_OFFS 两个寄存器合在一起
|
||||
#define MPU6050_RA_XA_OFFS_L_TC 0x07
|
||||
|
||||
#define MPU6050_RA_YA_OFFS_H 0x08 //[15:0] YA_OFFS 两个寄存器合在一起
|
||||
#define MPU6050_RA_YA_OFFS_L_TC 0x09
|
||||
|
||||
#define MPU6050_RA_ZA_OFFS_H 0x0A //[15:0] ZA_OFFS 两个寄存器合在一起
|
||||
#define MPU6050_RA_ZA_OFFS_L_TC 0x0B
|
||||
|
||||
#define MPU6050_RA_XG_OFFS_USRH 0x13 //[15:0] XG_OFFS_USR 两个寄存器合在一起
|
||||
#define MPU6050_RA_XG_OFFS_USRL 0x14
|
||||
|
||||
#define MPU6050_RA_YG_OFFS_USRH 0x15 //[15:0] YG_OFFS_USR 两个寄存器合在一起
|
||||
#define MPU6050_RA_YG_OFFS_USRL 0x16
|
||||
|
||||
#define MPU6050_RA_ZG_OFFS_USRH 0x17 //[15:0] ZG_OFFS_USR 两个寄存器合在一起
|
||||
#define MPU6050_RA_ZG_OFFS_USRL 0x18
|
||||
|
||||
/*陀螺仪的采样频率*/
|
||||
/*传感器的寄存器输出,FIFO输出,DMP采样、运动检测、
|
||||
*零运动检测和自由落体检测都是基于采样率。
|
||||
*通过SMPLRT_DIV把陀螺仪输出率分频即可得到采样率
|
||||
*采样率=陀螺仪输出率/ (1 + SMPLRT_DIV)
|
||||
*禁用DLPF的情况下(DLPF_CFG = 0或7) ,陀螺仪输出率= 8 khz
|
||||
*在启用DLPF(见寄存器26)时,陀螺仪输出率= 1 khz
|
||||
*加速度传感器输出率是1 khz。这意味着,采样率大于1 khz时,
|
||||
*同一个加速度传感器的样品可能会多次输入到FIFO、DMP和传感器寄存器*/
|
||||
#define MPU6050_RA_SMPLRT_DIV 0x19 //[0-7] 陀螺仪输出分频采样率
|
||||
|
||||
/*配置外部引脚采样和DLPF数字低通滤波器*/
|
||||
#define MPU6050_RA_CONFIG 0x1A
|
||||
//bit5-bit3 一个连接到FSYNC端口的外部信号可以通过配置EXT_SYNC_SET来采样
|
||||
// 也就是说,这里设置之后,FSYNC的电平0或1进入最终数据寄存器,具体如下
|
||||
// 0 不使用 1 FSYNC电平进入所有数据寄存器 2 FSYNC电平进入GYRO_XOUT_L 3 FSYNC电平进入GYRO_YOUT_L
|
||||
// 4 FSYNC电平进入GYRO_ZOUT_L 5 FSYNC电平进入ACCEL_XOUT_L 6 FSYNC电平进入ACCEL_YOUT_L
|
||||
// 7 FSYNC电平进入SYNC_ACCEL_ZOUT_L
|
||||
//bit2-bit0 数字低通滤波器 用于滤除高频干扰 高于这个频率的干扰被滤除掉
|
||||
/*对应关系如下
|
||||
* * | 加速度传感器 | 陀螺仪
|
||||
* * DLPF_CFG | 带宽 | 延迟 | 带宽 | 延迟 | 采样率
|
||||
* -------------+--------+-------+--------+------+-------------
|
||||
* 0 | 260Hz | 0ms | 256Hz | 0.98ms | 8kHz
|
||||
* 1 | 184Hz | 2.0ms | 188Hz | 1.9ms | 1kHz
|
||||
* 2 | 94Hz | 3.0ms | 98Hz | 2.8ms | 1kHz
|
||||
* 3 | 44Hz | 4.9ms | 42Hz | 4.8ms | 1kHz
|
||||
* 4 | 21Hz | 8.5ms | 20Hz | 8.3ms | 1kHz
|
||||
* 5 | 10Hz | 13.8ms | 10Hz | 13.4ms | 1kHz
|
||||
* 6 | 5Hz | 19.0ms | 5Hz | 18.6ms | 1kHz
|
||||
* 7 | Reserved | Reserved | Reserved
|
||||
* */
|
||||
|
||||
|
||||
/*陀螺仪的配置,主要是配置陀螺仪的量程与自检(通过相应的位7 6 5 开启自检)*/
|
||||
#define MPU6050_RA_GYRO_CONFIG 0x1B
|
||||
//bit4-bit3 量程设置如下
|
||||
// 0 = +/- 250 度/秒
|
||||
// 1 = +/- 500 度/秒
|
||||
// 2 = +/- 1000 度/秒
|
||||
// 3 = +/- 2000 度/秒*/
|
||||
|
||||
/*加速度计的配置,主要是配置加速度计的量程与自检(通过相应的位7 6 5 开启自检)
|
||||
*另外,还能配置系统的高通滤波器*/
|
||||
#define MPU6050_RA_ACCEL_CONFIG 0x1C
|
||||
//bit7 启动X自检 加速度计的自检
|
||||
//bit6 启动Y自检
|
||||
//bit5 启动Z自检
|
||||
//bit4-bit3 加速度传感器的量程配置
|
||||
// 0 = +/- 2g
|
||||
// 1 = +/- 4g
|
||||
// 2 = +/- 8g
|
||||
// 3 = +/- 16g*/
|
||||
//bit0到bit2 加速度传感器的高通滤波器
|
||||
/*DHPF是在路径中连接于运动探测器(自由落体,运动阈值,零运动)的一个滤波器模块。
|
||||
*高通滤波器的输出值不在数据寄存器中
|
||||
*高通滤波器有三种模式:
|
||||
*重置:在一个样本中将滤波器输出值设为零。这有效的禁用了高通滤波器。这种模式可以快速切换滤波器的设置模式。
|
||||
*开启:高通滤波器能通过高于截止频率的信号
|
||||
*持续:触发后,过滤器持续当前采样。过滤器输出值是输入样本和持续样本之间的差异
|
||||
*设置值如下所示
|
||||
* ACCEL_HPF | 高通滤波模式| 截止频率
|
||||
* ----------+-------------+------------------
|
||||
* 0 | Reset | None
|
||||
* 1 | On | 5Hz
|
||||
* 2 | On | 2.5Hz
|
||||
* 3 | On | 1.25Hz
|
||||
* 4 | On | 0.63Hz
|
||||
* 7 | Hold | None
|
||||
*/
|
||||
|
||||
#define MPU6050_RA_FF_THR 0x1D
|
||||
/*自由落体加速度的阈值
|
||||
*这个寄存器为自由落体的阈值检测进行配置。
|
||||
*FF_THR的单位是1LSB = 2mg。当加速度传感器测量而得的三个轴的绝对值
|
||||
*都小于检测阈值时,就可以测得自由落体值。这种情况下,(加速度计每次检测到就+1以下,所以还要依靠加速度采样率)
|
||||
*自由落体时间计数器计数一次 (寄存器30)。当自由落体时间计数器达到
|
||||
*FF_DUR中规定的时间时,自由落体被中断(或发生自由落体中断)
|
||||
**/
|
||||
|
||||
#define MPU6050_RA_FF_DUR 0x1E
|
||||
/*
|
||||
*自由落体加速度的时间阈值
|
||||
* 这个寄存器为自由落体时间阈值计数器进行配置。
|
||||
* 时间计数频率为1 khz,因此FF_DUR的单位是 1 LSB = 1毫秒。
|
||||
* 当加速度器测量而得的绝对值都小于检测阈值时,
|
||||
* 自由落体时间计数器计数一次。当自由落体时间计数器
|
||||
* 达到该寄存器的规定时间时,自由落体被中断。
|
||||
* (或发生自由落体中断)
|
||||
* */
|
||||
|
||||
#define MPU6050_RA_MOT_THR 0x1F
|
||||
/*
|
||||
*运动检测的加速度阈值
|
||||
*这个寄存器为运动中断的阈值检测进行配置。
|
||||
*MOT_THR的单位是 1LSB = 2mg。
|
||||
*当加速度器测量而得的绝对值都超过该运动检测的阈值时,
|
||||
*即可测得该运动。这一情况下,运动时间检测计数器计数一次。
|
||||
*当运动检测计数器达到MOT_DUR的规定时间时,运动检测被中断。
|
||||
* 运动中断表明了被检测的运动MOT_DETECT_STATUS (Register 97)的轴和极性。
|
||||
*/
|
||||
|
||||
#define MPU6050_RA_MOT_DUR 0x20
|
||||
/*
|
||||
*运动检测时间的阈值。
|
||||
*这个寄存器为运动中断的阈值检测进行配置。
|
||||
*时间计数器计数频率为1 kHz ,因此MOT_THR的单位是 1LSB = 1ms。
|
||||
*当加速度器测量而得的绝对值都超过该运动检测的阈值时(Register 31),
|
||||
*运动检测时间计数器计数一次。当运动检测计数器达到该寄存器规定的时间时,
|
||||
*运动检测被中断。
|
||||
**/
|
||||
|
||||
#define MPU6050_RA_ZRMOT_THR 0x21
|
||||
/*
|
||||
*零运动检测加速度阈值。
|
||||
* 这个寄存器为零运动中断检测进行配置。
|
||||
* ZRMOT_THR的单位是1LSB = 2mg。
|
||||
* 当加速度器测量而得的三个轴的绝对值都小于检测阈值时,
|
||||
* 就可以测得零运动。这种情况下,零运动时间计数器计数一次 (寄存器34)。
|
||||
* 当自零运动时间计数器达到ZRMOT_DUR (Register 34)中规定的时间时,零运动被中断。
|
||||
* 与自由落体或运动检测不同的是,当零运动首次检测到以及当零运动检测不到时,零运动检测都被中断。
|
||||
* 当零运动被检测到时,其状态将在MOT_DETECT_STATUS寄存器(寄存器97) 中显示出来。
|
||||
* 当运动状态变为零运动状态被检测到时,状态位设置为1。当零运动状态变为运动状态被检测到时,
|
||||
* 状态位设置为0。
|
||||
**/
|
||||
|
||||
#define MPU6050_RA_ZRMOT_DUR 0x22
|
||||
/*
|
||||
*零运动检测的时间阈值
|
||||
* 这个寄存器为零运动中断检测进行时间计数器的配置。
|
||||
* 时间计数器的计数频率为16 Hz,因此ZRMOT_DUR的单位是1 LSB = 64 ms。
|
||||
* 当加速度器测量而得的绝对值都小于检测器的阈值(Register 33)时,
|
||||
* 运动检测时间计数器计数一次。当零运动检测计数器达到该寄存器规定的时间时,
|
||||
* 零运动检测被中断。
|
||||
**/
|
||||
|
||||
|
||||
/*
|
||||
*设备的各种FIFO使能,包括温度 加速度 陀螺仪 从机
|
||||
*将相关的数据写入FIFO缓冲中
|
||||
**/
|
||||
#define MPU6050_RA_FIFO_EN 0x23
|
||||
//bit7 温度fifo使能
|
||||
//bit6 陀螺仪Xfifo使能
|
||||
//bit5 陀螺仪Yfifo使能
|
||||
//bit4 陀螺仪Zfifo使能
|
||||
//bit3 加速度传感器fifo使能
|
||||
//bit2 外部从设备2fifo使能
|
||||
//bit1 外部从设备1fifo使能
|
||||
//bit0 外部从设备0fifo使能
|
||||
|
||||
#define MPU6050_RA_I2C_MST_CTRL 0x24
|
||||
//配置单主机或者多主机下的IIC总线
|
||||
//bit7 监视从设备总线,看总线是否可用 MULT_MST_EN设置为1时,MPU-60X0的总线仲裁检测逻辑被打开
|
||||
//bit6 延迟数据就绪中断,直达从设备数据也进入主机再触发 相当于数据同步等待
|
||||
//bit5 当设置为1时,与Slave3 相连的外部传感器数据(寄存器73 到寄存器 96)写入FIFO缓冲中,每次都写入
|
||||
//bit4 主机读取一个从机到下一个从机读取之间的动作 为0 读取之间有一个restart,为1 下一次读取前会有一个重启,然后
|
||||
// 一直读取直到切换写入或者切换设备
|
||||
//bit3-bit0 配置MPU作为IIC主机时的时钟,基于MPU内部8M的分频
|
||||
/* I2C_MST_CLK | I2C 主时钟速度 | 8MHz 时钟分频器
|
||||
* ------------+------------------------+-------------------
|
||||
* 0 | 348kHz | 23
|
||||
* 1 | 333kHz | 24
|
||||
* 2 | 320kHz | 25
|
||||
* 3 | 308kHz | 26
|
||||
* 4 | 296kHz | 27
|
||||
* 5 | 286kHz | 28
|
||||
* 6 | 276kHz | 29
|
||||
* 7 | 267kHz | 30
|
||||
* 8 | 258kHz | 31
|
||||
* 9 | 500kHz | 16
|
||||
* 10 | 471kHz | 17
|
||||
* 11 | 444kHz | 18
|
||||
* 12 | 421kHz | 19
|
||||
* 13 | 400kHz | 20
|
||||
* 14 | 381kHz | 21
|
||||
* 15 | 364kHz | 22
|
||||
* */
|
||||
|
||||
|
||||
|
||||
/**************************MPU链接IIC从设备控制寄存器,没使用从机连接的基本不用考虑这些************************************/
|
||||
/*指定slave (0-3)的I2C地址
|
||||
* 注意Bit 7 (MSB)控制了读/写模式。如果设置了Bit 7,那么这是一个读取操作,
|
||||
* 如果将其清除,那么这是一个编写操作。其余位(6-0)是slave设备的7-bit设备地址。
|
||||
* 在读取模式中,读取结果是存储于最低可用的EXT_SENS_DATA寄存器中。
|
||||
* MPU-6050支持全5个slave,但Slave 4有其特殊功能(getSlave4* 和setSlave4*)。
|
||||
* 如寄存器25中所述,I2C数据转换通过采样率体现。用户负责确保I2C数据转换能够
|
||||
* 在一个采样率周期内完成。
|
||||
* I2C slave数据传输速率可根据采样率来减小。
|
||||
* 减小的传输速率是由I2C_MST_DLY(寄存器52)所决定的。
|
||||
* slave数据传输速率是否根据采样率来减小是由I2C_MST_DELAY_CTRL (寄存器103)所决定的。
|
||||
* slave的处理指令是固定的。Slave的处理顺序是Slave 1, Slave 2, Slave 3 和 Slave 4。
|
||||
* 如果某一个Slave被禁用了,那么它会被自动忽略。
|
||||
* 每个slave可按采样率或降低的采样率来读取。在有些slave以采样率读取有些以减小
|
||||
* 的采样率读取的情况下,slave的读取顺序依旧不变。然而,
|
||||
* 如果一些slave的读取速率不能在特定循环中进行读取,那么它们会被自动忽略
|
||||
* 更多降低的读取速率相关信息,请参阅寄存器52。
|
||||
* Slave是否按采样率或降低的采样率来读取由寄存器103得Delay Enable位来决定
|
||||
**/
|
||||
|
||||
//从机0设置相关
|
||||
#define MPU6050_RA_I2C_SLV0_ADDR 0x25
|
||||
//bit7 当前IIC 从设备0的操作,1为读取 0写入
|
||||
//bit6-bit0 从机设备的地址
|
||||
/* 要读取或者要写入的设备内部的寄存器地址,不管读取还是写入*/
|
||||
#define MPU6050_RA_I2C_SLV0_REG 0x26
|
||||
/*iic从机系统配置寄存器*/
|
||||
#define MPU6050_RA_I2C_SLV0_CTRL 0x27
|
||||
//bit7 启动或者禁止这个设备的IIC数据传送过程
|
||||
//bit6 当设置为1时,字节交换启用。当启用字节交换时,词对的高低字节即可交换
|
||||
//bit5 当 I2C_SLV0_REG_DIS 置 1,只能进行读取或者写入数据。当该位清 0,可以再读取
|
||||
// 或写入数据之前写入一个寄存器地址。当指定从机设备内部的寄存器地址进行发送或接收
|
||||
// 数据时,该位必须等于 0
|
||||
//bit4 指定从寄存器收到的字符对的分组顺序。当该位清 0,寄存器地址
|
||||
// 0和 1, 2 和 3 的字节是分别成对(甚至,奇数寄存器地址 ) ,作为一个字符对。当该位置 1,
|
||||
// 寄存器地址 1 和 2, 3 和 4 的字节是分别成对的,作为一个字符对
|
||||
//bit3-bit0 指定从机 0 发送字符的长度。由Slave 0转换而来和转换至Slave 0的字节数,(IIC一次传输的长度)
|
||||
// 该位清 0,I2C_SLV0_EN 位自动置 0.
|
||||
|
||||
/*IIC SLAVE1配置寄存器,与0相同*/
|
||||
|
||||
#define MPU6050_RA_I2C_SLV1_ADDR 0x28
|
||||
#define MPU6050_RA_I2C_SLV1_REG 0x29
|
||||
#define MPU6050_RA_I2C_SLV1_CTRL 0x2A
|
||||
|
||||
/*IIC SLAVE2配置寄存器,与0相同*/
|
||||
#define MPU6050_RA_I2C_SLV2_ADDR 0x2B
|
||||
#define MPU6050_RA_I2C_SLV2_REG 0x2C
|
||||
#define MPU6050_RA_I2C_SLV2_CTRL 0x2D
|
||||
|
||||
/*IIC SLAVE3配置寄存器,与0相同*/
|
||||
#define MPU6050_RA_I2C_SLV3_ADDR 0x2E
|
||||
#define MPU6050_RA_I2C_SLV3_REG 0x2F
|
||||
#define MPU6050_RA_I2C_SLV3_CTRL 0x30
|
||||
|
||||
/*slave4的I2C地址 IIC4与前几个的寄存器定义有所不同*/
|
||||
#define MPU6050_RA_I2C_SLV4_ADDR 0x31 //与IIC SLAVE1类似
|
||||
#define MPU6050_RA_I2C_SLV4_REG 0x32 /*slave4的当前内部寄存器*/
|
||||
#define MPU6050_RA_I2C_SLV4_DO 0x33
|
||||
/*写于slave4的新字节这一寄存器可储存写于slave4的数据。
|
||||
* 如果I2C_SLV4_RW设置为1(设置为读取模式),那么该寄存器无法执行操作*/
|
||||
#define MPU6050_RA_I2C_SLV4_CTRL 0x34
|
||||
//当设置为1时,此位启用了slave4的转换操作。当设置为0时,则禁用该操作
|
||||
#define MPU6050_I2C_SLV4_EN_BIT 7
|
||||
//当设置为1时,此位启用了slave4事务完成的中断信号的生成。
|
||||
// 当清除为0时,则禁用了该信号的生成。这一中断状态可在寄存器54中看到。
|
||||
#define MPU6050_I2C_SLV4_INT_EN_BIT 6
|
||||
//当设置为1时,只进行数据的读或写操作。当设置为0时,
|
||||
// 在读写数据之前将编写一个寄存器地址。当指定寄存器地址在slave设备中时
|
||||
// ,这应该等于0,而在该寄存器中会进行数据处理。
|
||||
#define MPU6050_I2C_SLV4_REG_DIS_BIT 5
|
||||
//采样率延迟,这为根据采样率减小的I2C slaves传输速率进行了配置。
|
||||
// 当一个slave的传输速率是根据采样率而降低的,那么该slave是以每1 / (1 + I2C_MST_DLY) 个样本进行传输。
|
||||
// 这一基本的采样率也是由SMPLRT_DIV (寄存器 25)和DLPF_CFG (寄存器26)所决定的的。
|
||||
// slave传输速率是否根据采样率来减小是由I2C_MST_DELAY_CTRL (寄存器103)所决定的
|
||||
#define MPU6050_I2C_SLV4_MST_DLY_BIT 4 //[4:0]
|
||||
#define MPU6050_I2C_SLV4_MST_DLY_LENGTH 5
|
||||
/*slave4中可读取的最后可用字节*/
|
||||
#define MPU6050_RA_I2C_SLV4_DI 0x35
|
||||
|
||||
/*
|
||||
* IIC辅助从机系统中断状态
|
||||
**/
|
||||
#define MPU6050_RA_I2C_MST_STATUS 0x36
|
||||
//bit7 此位反映了一个与MPU-60X0相连的外部设备的FSYNC中断状态。
|
||||
// 当设置为1且在INT_PIN_CFG(寄存器55)中断言FSYNC_INT_EN时,中断产生。
|
||||
//bit6 当slave4事务完成时,设备会自动设置为1 如果定义了INT_ENABLE中的I2C_MST_INT_EN则产生中断
|
||||
//bit5 I2C主机失去辅助I2C总线(一个错误状态)的仲裁,此位自动设置为1.如果断言了INT_ENABLE寄存器
|
||||
// (寄存器56)中的I2C_MST_INT_EN位,则中断产生
|
||||
//bit4 slave4的NACK状态
|
||||
//bit3 slave3的NACK状态
|
||||
//bit2 slave2的NACK状态
|
||||
//bit1 slave1的NACK状态
|
||||
//bit0 slave0的NACK状态
|
||||
|
||||
|
||||
/*中断引脚配置寄存器*/
|
||||
#define MPU6050_RA_INT_PIN_CFG 0x37
|
||||
//bit7 中断的逻辑电平模式,高电平时,设置为0;低电平时,设置为1
|
||||
//bit6 中断驱动模式,推拉模式设置为0,开漏模式设置为1.
|
||||
//bit5 中断锁存模式.50us-pulse模式设置为0,latch-until-int-cleared模式设置为1
|
||||
//bit4 中断锁存清除模式 status-read-only状态设置为0,any-register-read状态设置为1.
|
||||
//bit3 FSYNC中断逻辑电平模式 0=active-high, 1=active-low
|
||||
//bit2 FSYNC端口中断启用设置设置为0时禁用,设置为1时启用
|
||||
//bit1 I2C支路启用状态,此位等于1且I2C_MST_EN (寄存器 106 位[5])等于0时,主机应用程序处理器能够直接访问MPU-60X0的辅助I2C总线
|
||||
// 否则无论如何都不能直接访问
|
||||
//bit0 当此位为1时,CLKOUT端口可以输出参考时钟。当此位为0时,输出禁用
|
||||
|
||||
|
||||
/*部分中断使能*/
|
||||
#define MPU6050_RA_INT_ENABLE 0x38
|
||||
//bit7 自由落体中断使能
|
||||
//bit6 运动检测中断使能
|
||||
//bit5 零运动检测中断使能
|
||||
//bit4 FIFO溢出中断使能
|
||||
//bit3 IIC主机所有中断源使能
|
||||
//bit0 数据就绪中断使能
|
||||
|
||||
|
||||
/*DMP中断使能*/
|
||||
#define MPU6050_RA_DMP_INT_STATUS 0x39
|
||||
//不知道这些位的具体作用是什么,官方语焉不详,但是的确存在
|
||||
#define MPU6050_DMPINT_4_BIT 4
|
||||
#define MPU6050_DMPINT_3_BIT 3
|
||||
#define MPU6050_DMPINT_2_BIT 2
|
||||
#define MPU6050_DMPINT_1_BIT 1
|
||||
#define MPU6050_DMPINT_0_BIT 0
|
||||
|
||||
/*DMP中断配置*/
|
||||
#define MPU6050_RA_INT_STATUS 0x3A
|
||||
//DMP中断位之一使能
|
||||
#define MPU6050_INTERRUPT_PLL_RDY_INT_BIT 2
|
||||
//DMP中断位之二使能
|
||||
#define MPU6050_INTERRUPT_DMP_INT_BIT 1
|
||||
|
||||
/*加速度X输出*/
|
||||
#define MPU6050_RA_ACCEL_XOUT_H 0x3B
|
||||
#define MPU6050_RA_ACCEL_XOUT_L 0x3C
|
||||
|
||||
/*加速度Y输出*/
|
||||
#define MPU6050_RA_ACCEL_YOUT_H 0x3D
|
||||
#define MPU6050_RA_ACCEL_YOUT_L 0x3E
|
||||
|
||||
/*加速度Z输出*/
|
||||
#define MPU6050_RA_ACCEL_ZOUT_H 0x3F
|
||||
#define MPU6050_RA_ACCEL_ZOUT_L 0x40
|
||||
|
||||
/*温度值输出*/
|
||||
#define MPU6050_RA_TEMP_OUT_H 0x41
|
||||
#define MPU6050_RA_TEMP_OUT_L 0x42
|
||||
|
||||
/*陀螺仪X输出*/
|
||||
#define MPU6050_RA_GYRO_XOUT_H 0x43
|
||||
#define MPU6050_RA_GYRO_XOUT_L 0x44
|
||||
|
||||
/*陀螺仪Y输出*/
|
||||
#define MPU6050_RA_GYRO_YOUT_H 0x45
|
||||
#define MPU6050_RA_GYRO_YOUT_L 0x46
|
||||
|
||||
/*陀螺仪Z输出*/
|
||||
#define MPU6050_RA_GYRO_ZOUT_H 0x47
|
||||
#define MPU6050_RA_GYRO_ZOUT_L 0x48
|
||||
|
||||
/*从IIC从机上获取到的数据*/
|
||||
#define MPU6050_RA_EXT_SENS_DATA_00 0x49
|
||||
#define MPU6050_RA_EXT_SENS_DATA_01 0x4A
|
||||
#define MPU6050_RA_EXT_SENS_DATA_02 0x4B
|
||||
#define MPU6050_RA_EXT_SENS_DATA_03 0x4C
|
||||
#define MPU6050_RA_EXT_SENS_DATA_04 0x4D
|
||||
#define MPU6050_RA_EXT_SENS_DATA_05 0x4E
|
||||
#define MPU6050_RA_EXT_SENS_DATA_06 0x4F
|
||||
#define MPU6050_RA_EXT_SENS_DATA_07 0x50
|
||||
#define MPU6050_RA_EXT_SENS_DATA_08 0x51
|
||||
#define MPU6050_RA_EXT_SENS_DATA_09 0x52
|
||||
#define MPU6050_RA_EXT_SENS_DATA_10 0x53
|
||||
#define MPU6050_RA_EXT_SENS_DATA_11 0x54
|
||||
#define MPU6050_RA_EXT_SENS_DATA_12 0x55
|
||||
#define MPU6050_RA_EXT_SENS_DATA_13 0x56
|
||||
#define MPU6050_RA_EXT_SENS_DATA_14 0x57
|
||||
#define MPU6050_RA_EXT_SENS_DATA_15 0x58
|
||||
#define MPU6050_RA_EXT_SENS_DATA_16 0x59
|
||||
#define MPU6050_RA_EXT_SENS_DATA_17 0x5A
|
||||
#define MPU6050_RA_EXT_SENS_DATA_18 0x5B
|
||||
#define MPU6050_RA_EXT_SENS_DATA_19 0x5C
|
||||
#define MPU6050_RA_EXT_SENS_DATA_20 0x5D
|
||||
#define MPU6050_RA_EXT_SENS_DATA_21 0x5E
|
||||
#define MPU6050_RA_EXT_SENS_DATA_22 0x5F
|
||||
#define MPU6050_RA_EXT_SENS_DATA_23 0x60
|
||||
|
||||
//运动检测的状态
|
||||
#define MPU6050_RA_MOT_DETECT_STATUS 0x61
|
||||
//bit7 x轴反向运动检测中断状态
|
||||
//bit6 x轴正向运动检测中断状态
|
||||
//bit5 Y轴反向运动检测中断状态
|
||||
//bit4 Y轴正向运动检测中断状态
|
||||
//bit3 Z轴反向运动检测中断状态
|
||||
//bit2 Z轴正向运动检测中断状态
|
||||
//bit1
|
||||
//bit0 零运动检测中断状态
|
||||
//
|
||||
|
||||
|
||||
/*写入到IIC从机中的数据,指定的slv数据输出容器*/
|
||||
#define MPU6050_RA_I2C_SLV0_DO 0x63
|
||||
#define MPU6050_RA_I2C_SLV1_DO 0x64
|
||||
#define MPU6050_RA_I2C_SLV2_DO 0x65
|
||||
#define MPU6050_RA_I2C_SLV3_DO 0x66
|
||||
|
||||
/*外部影子寄存器的配置,这个寄存器用于指定外部传感器数据影子的时间
|
||||
*当启用了某一特定的slave,其传输速率就会减小。
|
||||
*当一个slave的传输速率是根据采样率而降低的,那么该slave是以
|
||||
*每1 / (1 + I2C_MST_DLY) 个样本进行传输。
|
||||
* 1 / (1 + I2C_MST_DLY) Samples
|
||||
* 这一基本的采样率也是由SMPLRT_DIV (寄存器 25)和DLPF_CFG (寄存器26)所决定的的。*/
|
||||
#define MPU6050_RA_I2C_MST_DELAY_CTRL 0x67
|
||||
//DELAY_ES_SHADOW设置为1,跟随外部传感器数据影子将会延迟到所有的数据接收完毕。
|
||||
#define MPU6050_DELAYCTRL_DELAY_ES_SHADOW_BIT 7
|
||||
//slv4-0的配置
|
||||
#define MPU6050_DELAYCTRL_I2C_SLV4_DLY_EN_BIT 4
|
||||
#define MPU6050_DELAYCTRL_I2C_SLV3_DLY_EN_BIT 3
|
||||
#define MPU6050_DELAYCTRL_I2C_SLV2_DLY_EN_BIT 2
|
||||
#define MPU6050_DELAYCTRL_I2C_SLV1_DLY_EN_BIT 1
|
||||
#define MPU6050_DELAYCTRL_I2C_SLV0_DLY_EN_BIT 0
|
||||
|
||||
/*用于陀螺仪,加速度计,温度传感器的模拟和数字信号通道的复位。
|
||||
复位会还原模数转换信号通道和清除他们的上电配置*/
|
||||
#define MPU6050_RA_SIGNAL_PATH_RESET 0x68
|
||||
//bit2 重置陀螺仪的信号路径
|
||||
//bit1 重置加速度传感器的信号路径
|
||||
//bit0 重置温度传感器的信号路径
|
||||
|
||||
|
||||
/*获取加速度传感器启动延迟 还有滤波器的一些配置
|
||||
* 加速度传感器数据路径为传感器寄存器、运动检测、
|
||||
* 零运动检测和自由落体检测模块提供样本。在检测模块开始操作之前,
|
||||
* 包含过滤器的信号路径必须用新样本来启用。
|
||||
* 默认的4毫秒唤醒延迟时间可以加长3毫秒以上。在ACCEL_ON_DELAY中规定
|
||||
* 这个延迟以1 LSB = 1 毫秒为单位。除非InvenSense另行指示,
|
||||
* 用户可以选择任何大于零的值。*/
|
||||
#define MPU6050_RA_MOT_DETECT_CTRL 0x69
|
||||
//具体的有效控制位
|
||||
//bit5-bit4 [5:4]1-4ms 延时时间1-4ms选择
|
||||
//bit3-bit2 自由落体检测计数器的减量配置。
|
||||
// 当指定数量的样本的加速度测量都满足其各自的阈值条件时,
|
||||
// 检测结果存储于自由落体检测模块中。当满足阈值条件时,
|
||||
// 相应的检测计数器递增1。用户可通过FF_COUNT配置不满足阈值条件来减量。
|
||||
// 减量率可根据下表进行设置:
|
||||
/* FF_COUNT | 计数器减量
|
||||
* ---------+------------------
|
||||
* 0 | 重置
|
||||
* 1 | 1
|
||||
* 2 | 2
|
||||
* 3 | 4
|
||||
* 当FF_COUNT配置为0(复位)时,任何不合格的样品都将计数器重置为0*/
|
||||
//bit1-bit0 运动检测计数器的减量配置。
|
||||
// 当指定数量的样本的加速度测量都满足其各自的阈值条件时,
|
||||
// 检测结果存储于运动检测模块中。当满足阈值条件时,相应的检测计数器递增1。
|
||||
// 用户可通过MOT_COUNT配置不满足阈值条件来减量。减量率可根据下表进行设置:
|
||||
// MOT_COUNT | 计数器减量
|
||||
/* ----------+------------------
|
||||
* 0 | 重置
|
||||
* 1 | 1
|
||||
* 2 | 2
|
||||
* 3 | 4
|
||||
* 当MOT_COUNT配置为0(复位)时,任何不合格的样品都将计数器重置为0*/
|
||||
|
||||
|
||||
/*这个寄存器允许用户使能或使能 FIFO 缓冲区,
|
||||
*I2C 主机模式和主要 I2C 接口。FIFO 缓冲
|
||||
区,I2C 主机,传感器信号通道和传感器寄存器也可以使用这个寄存器复位*/
|
||||
#define MPU6050_RA_USER_CTRL 0x6A
|
||||
//bit7 DMP禁止
|
||||
//bit6 当此位设置为0,FIFO缓冲是禁用的
|
||||
//bit5 当这个模式被启用,MPU-60X0即成为辅助I2C总线上的外部传感器slave设备的I2C主机
|
||||
// 当此位被清除为0时,辅助I2C总线线路(AUX_DA and AUX_CL)理论上是由I2C总线
|
||||
// (SDA和SCL)驱动的。这是启用旁路模式的一个前提
|
||||
//bit4 I2C转换至SPI模式(只允许MPU-6000)
|
||||
//bit3 重置DMP模式,官方文档未说明的寄存器
|
||||
//bit2 重置FIFO当设置为1时,此位将重置FIFO缓冲区,此时FIFO_EN等于0。触发重置后,此位将自动清为0
|
||||
//bit1 重置I2C主机当设置为1时,此位将重置I2C主机,此时I2C_MST_EN等于0。触发重置后,此位将自动清为0
|
||||
//bit0 重置所有传感器寄存器和信号路径 如果只重置信号路径(不重置传感器寄存器),请使用寄存器104
|
||||
|
||||
|
||||
/*允许用户配置电源模式和时钟源。还提供了复位整个设备和禁用温度传感器的位*/
|
||||
#define MPU6050_RA_PWR_MGMT_1 0x6B
|
||||
//bit7 触发一个设备的完整重置。 触发重置后,一个~ 50 毫秒的小延迟是合理的
|
||||
//bit6 寄存器的SLEEP位设置使设备处于非常低功率的休眠模式。
|
||||
//bit5 唤醒周期启用状态当此位设为1且SLEEP禁用时.在休眠模式和唤醒模式间循环,以此从活跃的传感器中获取数据样本
|
||||
//bit3 温度传感器启用状态控制内部温度传感器的使用
|
||||
//bit2-bit0 设定时钟源设置,一个频率为8 mhz的内部振荡器,基于陀螺仪的时钟或外部信息源都可以被选为MPU-60X0的时钟源
|
||||
/* CLK_SEL | 时钟源
|
||||
* --------+--------------------------------------
|
||||
* 0 | 内部振荡器
|
||||
* 1 | PLL with X Gyro reference
|
||||
* 2 | PLL with Y Gyro reference
|
||||
* 3 | PLL with Z Gyro reference
|
||||
* 4 | PLL with external 32.768kHz reference
|
||||
* 5 | PLL with external 19.2MHz reference
|
||||
* 6 | Reserved
|
||||
* 7 | Stops the clock and keeps the timing generator in reset
|
||||
* */
|
||||
|
||||
|
||||
/*这个寄存器允许用户配置加速度计在低功耗模式下唤起的频率。也允许用户让加速度计和
|
||||
陀螺仪的个别轴进入待机模式。*/
|
||||
#define MPU6050_RA_PWR_MGMT_2 0x6C
|
||||
//bit7-bit6 Accel-Only低电量模式下的唤醒频率
|
||||
/* 通过把Power Management 1寄存器(寄存器107)中的PWRSEL设为1,
|
||||
* MPU-60X0可以处于Accerlerometer Only的低电量模式。在这种模式下,
|
||||
设备将关闭除了原I2C接口以外的所有设备,只留下accelerometer以固定时间
|
||||
间隔醒来进行测量。唤醒频率可用LP_WAKE_CTRL进行配置,如下表所示:
|
||||
* LP_WAKE_CTRL | 唤醒频率
|
||||
* -------------+------------------
|
||||
* 0 | 1.25 Hz
|
||||
* 1 | 5 Hz
|
||||
* 2 | 20 Hz
|
||||
* 3 | 40 Hz
|
||||
* */
|
||||
//bit5 备用的x轴加速度传感器启用状态,也就是进入待机模式
|
||||
//bit4 备用的Y轴加速度传感器启用状态
|
||||
//bit3 备用的Z轴加速度传感器启用状态
|
||||
//bit2 备用的x轴陀螺仪启用状态
|
||||
//bit1 备用的Y轴陀螺仪启用状态
|
||||
//bit0 备用的Z轴陀螺仪启用状态
|
||||
|
||||
/*设定DMP模式下的bank*/
|
||||
#define MPU6050_RA_BANK_SEL 0x6D
|
||||
//DMP内存配置
|
||||
#define MPU6050_BANKSEL_PRFTCH_EN_BIT 6
|
||||
#define MPU6050_BANKSEL_CFG_USER_BANK_BIT 5
|
||||
#define MPU6050_BANKSEL_MEM_SEL_BIT 4
|
||||
#define MPU6050_BANKSEL_MEM_SEL_LENGTH 5
|
||||
//dmp内存地址设置
|
||||
#define MPU6050_DMP_MEMORY_BANKS 8
|
||||
#define MPU6050_DMP_MEMORY_BANK_SIZE 256
|
||||
#define MPU6050_DMP_MEMORY_CHUNK_SIZE 16
|
||||
|
||||
/*设定DMP模式下的起始地址*/
|
||||
#define MPU6050_RA_MEM_START_ADDR 0x6E
|
||||
/*一个字节的dmp数据缓存*/
|
||||
#define MPU6050_RA_MEM_R_W 0x6F
|
||||
/*DMP配置寄存器1*/
|
||||
#define MPU6050_RA_DMP_CFG_1 0x70
|
||||
/*DMP配置寄存器2*/
|
||||
#define MPU6050_RA_DMP_CFG_2 0x71
|
||||
|
||||
/*当前FIFO缓冲区大小
|
||||
* 这个值表明了存储于FIFO缓冲区的字节数。
|
||||
* 而这个数字也是能从FIFO缓冲区读取的字节数,
|
||||
* 它与存储在FIFO(寄存器35和36)中的传感器数据组所提供的可用样本数成正比。
|
||||
* 两个寄存器一起构成一个16位数据*/
|
||||
#define MPU6050_RA_FIFO_COUNTH 0x72
|
||||
#define MPU6050_RA_FIFO_COUNTL 0x73
|
||||
|
||||
/*这个寄存器用于从FIFO缓冲区中读取和编写数据。数据在寄存器编号(从低到高)的指
|
||||
*令下编写入数据写入FIFO。如果所有的FIFO启用标志(见下文)都被启用了且
|
||||
*所有外部传感器数据寄存器(寄存器73至寄存器96)都与一个slave设备相连
|
||||
*,那么寄存器59到寄存器96的内容都将在采样率的指令下编写。
|
||||
* 当传感器数据寄存器(寄存器59到寄存器96)的相关FIFO启用标志在FIFO_EN 寄存
|
||||
* 器35)中都设为1时,它们的内容将被写入FIFO缓冲区。在I2C_MST_CTRL (寄存器 36)
|
||||
* 中能找到一个与I2C Slave 3相连的额外的传感器数据寄存器标志。
|
||||
* 如果FIFO缓冲区溢出,状态位FIFO_OFLOW_INT自动设置为1。
|
||||
* 此位位于INT_STATUS (寄存器58)中。当FIFO缓冲区溢出时,最早的数据将会丢失
|
||||
* 而新数据将被写入FIFO。如果FIFO缓冲区为空, 读取将返回原来从FIFO中读取的
|
||||
* 最后一个字节,直到有可用的新数据。用户应检查FIFO_COUNT,以确保不在FIFO缓冲为空时读取。*/
|
||||
#define MPU6050_RA_FIFO_R_W 0x74
|
||||
|
||||
/*寄存器是用来验证设备的身份的 默认值是0X34*/
|
||||
#define MPU6050_RA_WHO_AM_I 0x75
|
||||
//bit6-bit1 设备身份验证 0x34 最高位和最低位都剔除掉
|
||||
|
||||
|
||||
#endif
|
||||
418
apps/common/device/gx8002_npu/gx8002_enc/gx8002_enc.c
Normal file
418
apps/common/device/gx8002_npu/gx8002_enc/gx8002_enc.c
Normal file
@ -0,0 +1,418 @@
|
||||
#include "includes.h"
|
||||
#include "app_config.h"
|
||||
#include "gx8002_enc.h"
|
||||
|
||||
#if TCFG_GX8002_ENC_ENABLE
|
||||
|
||||
#define GX8002_DEBUG_ENABLE 1
|
||||
|
||||
#define gx8002_info printf
|
||||
#if GX8002_DEBUG_ENABLE
|
||||
#define gx8002_debug printf
|
||||
#define gx8002_put_buf put_buf
|
||||
#else
|
||||
#define gx8002_debug(...)
|
||||
#define gx8002_put_buf(...)
|
||||
#endif /* #if GX8002_DEBUG_ENABLE */
|
||||
|
||||
|
||||
//====================================================================//
|
||||
// AC897N GX8002 ENC模型 //
|
||||
/*
|
||||
________ ________
|
||||
| | PCM 2CH | |
|
||||
| TX|----------------->|RX |
|
||||
| UART | | UART |
|
||||
| | PCM 1CH | |
|
||||
| RX|<-----------------|TX |
|
||||
|________| |________|
|
||||
BT_CHIP GX8002
|
||||
|
||||
NOTE:
|
||||
*/
|
||||
|
||||
//====================================================================//
|
||||
#define UART_RX_BUF_POINTS (256 * 4) // buf_len = UART_RX_BUF_POINTS x sizeof(16)
|
||||
#define UART_RX_BUF_FRAME_LEN (256 * sizeof(s16) * 2) // buf_len = UART_RX_BUF_FRAME_LEN
|
||||
#define UART_TX_BUF_POINTS (256 * 2) //buf_len = UART_TX_BUF_POINTS x sizeof(16)
|
||||
#define UART_TRANSPORT_BUAD 1000000 //发送波特率
|
||||
|
||||
#define THIS_TASK_NAME "gx8002_enc"
|
||||
|
||||
struct gx8002_enc_t {
|
||||
u8 task_init;
|
||||
u8 state;
|
||||
const uart_bus_t *uart_bus;
|
||||
OS_SEM rx_sem;
|
||||
int uart_rxbuf[(UART_RX_BUF_POINTS * sizeof(s16)) / sizeof(int)]; //uart硬件RX dma缓存, 要求buf长度为2的n次幂, 4字节对齐
|
||||
int uart_txbuf[(UART_TX_BUF_POINTS * sizeof(s16)) / sizeof(int)]; //uart硬件TX dma缓存, 要求buf4字节对齐
|
||||
int uart_rx_frame_buf[UART_RX_BUF_FRAME_LEN / sizeof(int)]; //用于读取Rx缓存中的数据, 临时buf
|
||||
};
|
||||
|
||||
enum {
|
||||
GX8002_ENC_STATE_CLOSE = 0,
|
||||
GX8002_ENC_STATE_OPEN,
|
||||
GX8002_ENC_STATE_RUN,
|
||||
};
|
||||
|
||||
|
||||
static struct gx8002_enc_t *gx8002_enc = NULL;
|
||||
|
||||
//============== extern function =================//
|
||||
/* extern void gx8002_vddio_power_ctrl(u8 on); */
|
||||
/* extern void gx8002_core_vdd_power_ctrl(u8 on); */
|
||||
|
||||
//for make
|
||||
__attribute__((weak))
|
||||
void gx8002_board_port_suspend(void)
|
||||
{
|
||||
}
|
||||
|
||||
__attribute__((weak))
|
||||
void gx8002_vddio_power_ctrl(u8 on)
|
||||
{
|
||||
}
|
||||
|
||||
__attribute__((weak))
|
||||
void gx8002_core_vdd_power_ctrl(u8 on)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
static void gx8002_device_power_on(void)
|
||||
{
|
||||
gx8002_vddio_power_ctrl(1);
|
||||
os_time_dly(2); //vddio先上电 --> wait 20ms --> core_vdd上电
|
||||
gx8002_core_vdd_power_ctrl(1);
|
||||
}
|
||||
|
||||
static void gx8002_device_power_off(void)
|
||||
{
|
||||
gx8002_vddio_power_ctrl(0);
|
||||
gx8002_core_vdd_power_ctrl(0);
|
||||
}
|
||||
|
||||
static void gx8002_enc_data_output(void)
|
||||
{
|
||||
int ret = 0;
|
||||
s16 *rxbuf = NULL;
|
||||
s16 magic_code = 0;
|
||||
static u8 cnt = 0;
|
||||
if (gx8002_enc && (gx8002_enc->state == GX8002_ENC_STATE_RUN)) {
|
||||
if (gx8002_enc->uart_bus && gx8002_enc->uart_bus->read) {
|
||||
rxbuf = (s16 *)(gx8002_enc->uart_rx_frame_buf);
|
||||
putchar('r');
|
||||
ret = gx8002_enc->uart_bus->read((u8 *)rxbuf, UART_RX_BUF_FRAME_LEN, 0);
|
||||
#if 1
|
||||
//数据校验
|
||||
magic_code = rxbuf[0];
|
||||
for (int i = 1; i < ret / sizeof(s16); i++) {
|
||||
if (rxbuf[i] != magic_code) {
|
||||
if (rxbuf[i] != (magic_code + 1)) {
|
||||
gx8002_debug("data err: magic_code = 0x%x, rxbuf[%d] = 0x%x", magic_code, i, rxbuf[i]);
|
||||
printf("buf_in = %d", gx8002_enc->uart_bus->kfifo.buf_in);
|
||||
printf("buf_out = %d", gx8002_enc->uart_bus->kfifo.buf_out);
|
||||
put_buf(gx8002_enc->uart_bus->kfifo.buffer, gx8002_enc->uart_bus->kfifo.buf_size);
|
||||
ASSERT(0);
|
||||
break;
|
||||
wdt_clear();
|
||||
} else {
|
||||
magic_code++;
|
||||
gx8002_debug("increase: 0x%x", magic_code);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void gx8002_enc_uart_isr_hook(void *arg, u32 status)
|
||||
{
|
||||
if (status != UT_TX) {
|
||||
//RX pending
|
||||
os_sem_post(&(gx8002_enc->rx_sem));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void gx8002_enc_uart_porting_config(u32 baud)
|
||||
{
|
||||
struct uart_platform_data_t u_arg = {0};
|
||||
|
||||
u_arg.tx_pin = TCFG_GX8002_ENC_UART_TX_PORT;
|
||||
u_arg.rx_pin = TCFG_GX8002_ENC_UART_RX_PORT;
|
||||
u_arg.rx_cbuf = gx8002_enc->uart_rxbuf;
|
||||
u_arg.rx_cbuf_size = sizeof(gx8002_enc->uart_rxbuf);
|
||||
u_arg.frame_length = UART_RX_BUF_FRAME_LEN;
|
||||
u_arg.rx_timeout = 100;
|
||||
u_arg.isr_cbfun = gx8002_enc_uart_isr_hook;
|
||||
u_arg.baud = baud;
|
||||
u_arg.is_9bit = 0;
|
||||
|
||||
gx8002_enc->uart_bus = uart_dev_open(&u_arg);
|
||||
|
||||
if (gx8002_enc->uart_bus) {
|
||||
gx8002_info("gx8002 uart init succ");
|
||||
} else {
|
||||
gx8002_info("gx8002 uart init fail");
|
||||
ASSERT(gx8002_enc->uart_bus);
|
||||
}
|
||||
}
|
||||
|
||||
static void gx8002_enc_uart_porting_close(void)
|
||||
{
|
||||
if (gx8002_enc && gx8002_enc->uart_bus) {
|
||||
uart_dev_close((uart_bus_t *)(gx8002_enc->uart_bus));
|
||||
gx8002_board_port_suspend();
|
||||
gx8002_enc->uart_bus = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void __gx8002_enc_run(void)
|
||||
{
|
||||
//TODO: add gx8002 post start msg
|
||||
gx8002_debug("%s", __func__);
|
||||
|
||||
while (1) {
|
||||
os_sem_pend(&(gx8002_enc->rx_sem), 0);
|
||||
|
||||
if (gx8002_enc->state != GX8002_ENC_STATE_RUN) {
|
||||
break;
|
||||
}
|
||||
|
||||
gx8002_enc_data_output();
|
||||
}
|
||||
}
|
||||
|
||||
static void __gx8002_enc_close(int priv)
|
||||
{
|
||||
if (gx8002_enc) {
|
||||
if (gx8002_enc->state == GX8002_ENC_STATE_CLOSE) {
|
||||
gx8002_device_power_off();
|
||||
gx8002_enc_uart_porting_close();
|
||||
if (priv) {
|
||||
os_sem_post((OS_SEM *)priv);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void gx8002_enc_task(void *priv)
|
||||
{
|
||||
int msg[16];
|
||||
int res;
|
||||
|
||||
os_sem_create(&(gx8002_enc->rx_sem), 0);
|
||||
|
||||
gx8002_enc_uart_porting_config(UART_TRANSPORT_BUAD);
|
||||
gx8002_device_power_on();
|
||||
|
||||
gx8002_enc->state = GX8002_ENC_STATE_OPEN;
|
||||
|
||||
if (priv) {
|
||||
os_sem_post((OS_SEM *)priv);
|
||||
}
|
||||
|
||||
while (1) {
|
||||
res = os_taskq_pend(NULL, msg, ARRAY_SIZE(msg));
|
||||
if (res == OS_TASKQ) {
|
||||
switch (msg[1]) {
|
||||
case GX8002_ENC_MSG_RUN:
|
||||
__gx8002_enc_run();
|
||||
break;
|
||||
case GX8002_ENC_MSG_CLOSE:
|
||||
__gx8002_enc_close(msg[2]);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//====================================================================//
|
||||
// GX8002 ENC API //
|
||||
//====================================================================//
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/**@brief 打开gx8002_enc流程, 创建gx8002线程
|
||||
@param void
|
||||
@return void
|
||||
@note 不能在中断中调用, 需要在线程中调用;
|
||||
*/
|
||||
/*----------------------------------------------------------------------------*/
|
||||
void gx8002_enc_open(void)
|
||||
{
|
||||
gx8002_debug("%s", __func__);
|
||||
|
||||
if (gx8002_enc == NULL) {
|
||||
gx8002_enc = zalloc(sizeof(struct gx8002_enc_t));
|
||||
if (gx8002_enc == NULL) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
OS_SEM sem_wait;
|
||||
os_sem_create(&sem_wait, 0);
|
||||
gx8002_enc->task_init = 1;
|
||||
task_create(gx8002_enc_task, (void *)&sem_wait, THIS_TASK_NAME);
|
||||
|
||||
os_sem_pend(&sem_wait, 0);
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/**@brief 启动gx8002_enc流程
|
||||
@param void
|
||||
@return void
|
||||
@note
|
||||
*/
|
||||
/*----------------------------------------------------------------------------*/
|
||||
void gx8002_enc_start(void)
|
||||
{
|
||||
gx8002_debug("%s", __func__);
|
||||
|
||||
if (gx8002_enc && (gx8002_enc->state == GX8002_ENC_STATE_OPEN)) {
|
||||
gx8002_enc->state = GX8002_ENC_STATE_RUN;
|
||||
os_taskq_post_msg(THIS_TASK_NAME, 1, GX8002_ENC_MSG_RUN);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/**@brief 关闭gx8002_enc流程, 释放资源
|
||||
@param void
|
||||
@return void
|
||||
@note 不能在中断中调用, 需要在线程中调用;
|
||||
*/
|
||||
/*----------------------------------------------------------------------------*/
|
||||
void gx8002_enc_close(void)
|
||||
{
|
||||
OS_SEM sem_wait;
|
||||
|
||||
gx8002_debug("%s", __func__);
|
||||
if (gx8002_enc) {
|
||||
if (gx8002_enc->task_init) {
|
||||
os_sem_create(&sem_wait, 0);
|
||||
gx8002_enc->state = GX8002_ENC_STATE_CLOSE;
|
||||
os_sem_post(&(gx8002_enc->rx_sem));
|
||||
os_taskq_post_msg(THIS_TASK_NAME, 2, GX8002_ENC_MSG_CLOSE, (u32)&sem_wait);
|
||||
os_sem_pend(&sem_wait, 0);
|
||||
gx8002_enc->task_init = 0;
|
||||
task_kill(THIS_TASK_NAME);
|
||||
}
|
||||
|
||||
free(gx8002_enc);
|
||||
gx8002_enc = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/**@brief gx8002_enc数据输入, 支持1~2通道数据输入
|
||||
@param ch0_buf: 通道0数据buf
|
||||
@param ch1_buf: 通道1数据buf
|
||||
@param points: ch0和ch1 buf中点数
|
||||
@return
|
||||
@note 1)不能在中断中调用, 需要在线程中调用;
|
||||
@note 2)如果只有1通道数据, 把ch0_buf/ch1_buf传参为NULL即可;
|
||||
@note 3)ch0_buf和ch1_buf数据宽度为16bit;
|
||||
*/
|
||||
/*----------------------------------------------------------------------------*/
|
||||
u32 gx8002_enc_data_input(s16 *ch0_buf, s16 *ch1_buf, u32 points)
|
||||
{
|
||||
u32 send_points = 0;
|
||||
s16 *txbuf = NULL;
|
||||
u32 remain_points = points;
|
||||
u32 txbuf_points = 0;
|
||||
u8 ch_num = 0;
|
||||
|
||||
if (gx8002_enc && (gx8002_enc->state == GX8002_ENC_STATE_RUN)) {
|
||||
if (gx8002_enc->uart_bus && gx8002_enc->uart_bus->write) {
|
||||
if (ch0_buf && ch1_buf) {
|
||||
//2ch
|
||||
ch_num = 2;
|
||||
txbuf_points = (sizeof(gx8002_enc->uart_txbuf) / sizeof(s16) / 2);
|
||||
} else {
|
||||
ch_num = 1;
|
||||
if (ch0_buf == NULL) {
|
||||
ch0_buf = ch1_buf;
|
||||
}
|
||||
txbuf_points = (sizeof(gx8002_enc->uart_txbuf) / sizeof(s16));
|
||||
}
|
||||
|
||||
txbuf = (s16 *)(gx8002_enc->uart_txbuf);
|
||||
while (remain_points) {
|
||||
send_points = remain_points <= txbuf_points ? remain_points : txbuf_points;
|
||||
//gx8002_debug("send_points: %d", send_points);
|
||||
if (ch_num == 2) {
|
||||
for (int i = 0; i < send_points; i++) {
|
||||
txbuf[2 * i] = ch0_buf[i];
|
||||
txbuf[2 * i + 1] = ch1_buf[i];
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < send_points; i++) {
|
||||
txbuf[i] = ch0_buf[i];
|
||||
}
|
||||
}
|
||||
|
||||
gx8002_enc->uart_bus->write((const u8 *)txbuf, send_points * sizeof(s16) * ch_num);
|
||||
remain_points -= send_points;
|
||||
}
|
||||
|
||||
return points * sizeof(s16) * ch_num;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//====================================================================//
|
||||
// GX8002 ENC TEST //
|
||||
//====================================================================//
|
||||
|
||||
static void gx8002_enc_input_test(void *priv)
|
||||
{
|
||||
|
||||
if (gx8002_enc == NULL) {
|
||||
putchar('i');
|
||||
return;
|
||||
}
|
||||
#define BUF_TEST_POINTS 300
|
||||
static s16 cnt = 0x0;
|
||||
s16 tmp_buf[BUF_TEST_POINTS];
|
||||
putchar('w');
|
||||
cnt++;
|
||||
for (int i = 0; i < ARRAY_SIZE(tmp_buf); i++) {
|
||||
tmp_buf[i] = cnt;
|
||||
}
|
||||
//gx8002_enc_data_input(tmp_buf, NULL, BUF_TEST_POINTS); //1ch data
|
||||
gx8002_enc_data_input(tmp_buf, tmp_buf, BUF_TEST_POINTS); //two ch data
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
static void gx8002_enc_close_test(void *priv)
|
||||
{
|
||||
gx8002_enc_close();
|
||||
}
|
||||
|
||||
static int gx8002_enc_test(void)
|
||||
{
|
||||
gx8002_enc_open();
|
||||
gx8002_enc_start();
|
||||
|
||||
sys_timer_add(NULL, gx8002_enc_input_test, 50);
|
||||
sys_timer_add(NULL, gx8002_enc_close_test, 1000 * 60 * 3);
|
||||
|
||||
return 0;
|
||||
}
|
||||
//late_initcall(gx8002_enc_test);
|
||||
|
||||
|
||||
#endif /* #if TCFG_GX8002_ENC_ENABLE */
|
||||
10
apps/common/device/gx8002_npu/gx8002_enc/gx8002_enc.h
Normal file
10
apps/common/device/gx8002_npu/gx8002_enc/gx8002_enc.h
Normal file
@ -0,0 +1,10 @@
|
||||
#ifndef __GX8002_NPU_H__
|
||||
#define __GX8002_NPU_H__
|
||||
|
||||
enum GX8002_MSG {
|
||||
GX8002_ENC_MSG_RUN = ('G' << 24) | ('E' << 16) | ('N' << 8) | ('C' << 0),
|
||||
GX8002_ENC_MSG_CLOSE,
|
||||
};
|
||||
|
||||
|
||||
#endif /* #ifndef __GX8002_NPU_H__ */
|
||||
921
apps/common/device/gx8002_npu/gx8002_npu.c
Normal file
921
apps/common/device/gx8002_npu/gx8002_npu.c
Normal file
@ -0,0 +1,921 @@
|
||||
#include "includes.h"
|
||||
#include "app_config.h"
|
||||
#include "gx8002_npu.h"
|
||||
#include "gx8002_npu_api.h"
|
||||
#include "asm/pwm_led.h"
|
||||
#include "btstack/avctp_user.h"
|
||||
|
||||
#if TCFG_GX8002_NPU_ENABLE
|
||||
|
||||
#define GX8002_DEBUG_ENABLE 0
|
||||
|
||||
#define gx8002_info g_printf
|
||||
#if GX8002_DEBUG_ENABLE
|
||||
#define gx8002_debug g_printf
|
||||
#define gx8002_put_buf put_buf
|
||||
#else
|
||||
#define gx8002_debug(...)
|
||||
#define gx8002_put_buf(...)
|
||||
#endif /* #if GX8002_DEBUG_ENABLE */
|
||||
|
||||
|
||||
|
||||
//===========================================================//
|
||||
// GX8002 NPU LOGIC LAYER //
|
||||
//===========================================================//
|
||||
///// 分配内存 /////
|
||||
#define OS_MALLOC malloc
|
||||
|
||||
///// 释放内存 /////
|
||||
#define OS_FREE free
|
||||
|
||||
static const char msg_rcv_magic[MSG_MAGIC_LEN] = {
|
||||
MSG_RCV_MAGIC0, MSG_RCV_MAGIC1,
|
||||
MSG_RCV_MAGIC2, MSG_RCV_MAGIC3
|
||||
};
|
||||
|
||||
static unsigned char msg_seq = 0;
|
||||
static unsigned char initialized = 0;
|
||||
static struct message prev_snd_msg;
|
||||
static struct message prev_rcv_msg;
|
||||
static STREAM_READ stream_read = NULL;
|
||||
static STREAM_WRITE stream_write = NULL;
|
||||
static STREAM_EMPTY stream_is_empty = NULL;
|
||||
|
||||
struct msg_header {
|
||||
unsigned int magic;
|
||||
unsigned short cmd;
|
||||
unsigned char seq;
|
||||
unsigned char flags;
|
||||
unsigned short length;
|
||||
unsigned int crc32;
|
||||
} __attribute__((packed));
|
||||
|
||||
static const unsigned int crc32tab[] = {
|
||||
0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL,
|
||||
0x076dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L,
|
||||
0x0edb8832L, 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L,
|
||||
0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 0x90bf1d91L,
|
||||
0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
|
||||
0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L,
|
||||
0x136c9856L, 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL,
|
||||
0x14015c4fL, 0x63066cd9L, 0xfa0f3d63L, 0x8d080df5L,
|
||||
0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 0xa2677172L,
|
||||
0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
|
||||
0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L,
|
||||
0x32d86ce3L, 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L,
|
||||
0x26d930acL, 0x51de003aL, 0xc8d75180L, 0xbfd06116L,
|
||||
0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 0xb8bda50fL,
|
||||
0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
|
||||
0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL,
|
||||
0x76dc4190L, 0x01db7106L, 0x98d220bcL, 0xefd5102aL,
|
||||
0x71b18589L, 0x06b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L,
|
||||
0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 0xe10e9818L,
|
||||
0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
|
||||
0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL,
|
||||
0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L,
|
||||
0x65b0d9c6L, 0x12b7e950L, 0x8bbeb8eaL, 0xfcb9887cL,
|
||||
0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L,
|
||||
0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
|
||||
0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL,
|
||||
0x4369e96aL, 0x346ed9fcL, 0xad678846L, 0xda60b8d0L,
|
||||
0x44042d73L, 0x33031de5L, 0xaa0a4c5fL, 0xdd0d7cc9L,
|
||||
0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L,
|
||||
0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
|
||||
0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L,
|
||||
0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL,
|
||||
0xedb88320L, 0x9abfb3b6L, 0x03b6e20cL, 0x74b1d29aL,
|
||||
0xead54739L, 0x9dd277afL, 0x04db2615L, 0x73dc1683L,
|
||||
0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
|
||||
0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L,
|
||||
0xf00f9344L, 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL,
|
||||
0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L,
|
||||
0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 0x67dd4accL,
|
||||
0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
|
||||
0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L,
|
||||
0xd1bb67f1L, 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL,
|
||||
0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L, 0x41047a60L,
|
||||
0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 0x4669be79L,
|
||||
0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
|
||||
0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL,
|
||||
0xc5ba3bbeL, 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L,
|
||||
0xc2d7ffa7L, 0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL,
|
||||
0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 0x026d930aL,
|
||||
0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
|
||||
0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L,
|
||||
0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L,
|
||||
0x86d3d2d4L, 0xf1d4e242L, 0x68ddb3f8L, 0x1fda836eL,
|
||||
0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 0x18b74777L,
|
||||
0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
|
||||
0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L,
|
||||
0xa00ae278L, 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L,
|
||||
0xa7672661L, 0xd06016f7L, 0x4969474dL, 0x3e6e77dbL,
|
||||
0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 0x37d83bf0L,
|
||||
0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
|
||||
0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L,
|
||||
0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL,
|
||||
0xb3667a2eL, 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L,
|
||||
0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 0x2d02ef8dL
|
||||
};
|
||||
|
||||
static unsigned int crc32(const unsigned char *buf, unsigned int size)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned int crc = 0xFFFFFFFF;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
crc = crc32tab[(crc ^ buf[i]) & 0xff] ^ (crc >> 8);
|
||||
}
|
||||
|
||||
return crc ^ 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
static inline int stream_getc(char *ch)
|
||||
{
|
||||
int ret = stream_read((unsigned char *)ch, 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int msg_byte_match(char c)
|
||||
{
|
||||
char ch = 0;
|
||||
|
||||
return (stream_getc(&ch) && (ch == c));
|
||||
}
|
||||
|
||||
static int msg_find_magic(void)
|
||||
{
|
||||
int i;
|
||||
int offset = 0;
|
||||
|
||||
while (offset < MSG_LEN_MAX) {
|
||||
for (i = 0; i < MSG_MAGIC_LEN; i++) {
|
||||
offset++;
|
||||
if (!msg_byte_match(msg_rcv_magic[i])) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ((i + 1) == MSG_MAGIC_LEN) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static unsigned char msg_get_new_seq(unsigned char seq)
|
||||
{
|
||||
unsigned char next_seq;
|
||||
|
||||
next_seq = (seq + 1) % MSG_SEQ_MAX;
|
||||
|
||||
return next_seq == 0 ? next_seq + 1 : next_seq;
|
||||
}
|
||||
|
||||
static int nc_message_receive(struct message *msg)
|
||||
{
|
||||
struct msg_header msg_header;
|
||||
unsigned int newcrc32 = 0;
|
||||
unsigned int oldcrc32 = 0;
|
||||
unsigned short bodylen;
|
||||
unsigned char *pheader = (unsigned char *)&msg_header;
|
||||
|
||||
if (!msg || !initialized) {
|
||||
line_inf;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (stream_is_empty()) {
|
||||
line_inf;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Read stream until find mseeage magic */
|
||||
if (msg_find_magic() != 0) {
|
||||
line_inf;
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&msg_header, 0, sizeof(struct msg_header));
|
||||
msg_header.magic = MSG_MAGIC;
|
||||
|
||||
/* Read the rest of message header */
|
||||
stream_read(pheader + MSG_MAGIC_LEN,
|
||||
sizeof(struct msg_header) - MSG_MAGIC_LEN);
|
||||
|
||||
/* Check message header integrity */
|
||||
newcrc32 = crc32((unsigned char *)&msg_header,
|
||||
sizeof(struct msg_header) - MSG_HEAD_CHECK_LEN);
|
||||
if (newcrc32 != msg_header.crc32) {
|
||||
line_inf;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Read message body */
|
||||
if (msg_header.length > 0) {
|
||||
|
||||
msg->body = OS_MALLOC(msg_header.length);
|
||||
if (msg->body == NULL) {
|
||||
line_inf;
|
||||
return -1;
|
||||
}
|
||||
|
||||
stream_read(msg->body, msg_header.length);
|
||||
if (MSG_NEED_BCHECK(msg_header.flags)) {
|
||||
bodylen = msg_header.length - MSG_BODY_CHECK_LEN;
|
||||
newcrc32 = crc32(msg->body, bodylen);
|
||||
memcpy(&oldcrc32, msg->body + bodylen, MSG_BODY_CHECK_LEN);
|
||||
|
||||
if (oldcrc32 != newcrc32) {
|
||||
line_inf;
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
bodylen = msg_header.length;
|
||||
}
|
||||
} else {
|
||||
bodylen = 0;
|
||||
}
|
||||
|
||||
msg->cmd = msg_header.cmd;
|
||||
msg->seq = msg_header.seq;
|
||||
msg->flags = msg_header.flags;
|
||||
msg->bodylen = bodylen;
|
||||
|
||||
prev_rcv_msg.cmd = msg->cmd;
|
||||
prev_rcv_msg.seq = msg->seq;
|
||||
|
||||
return bodylen;
|
||||
}
|
||||
|
||||
static int nc_message_send(struct message *msg)
|
||||
{
|
||||
struct msg_header msg_header;
|
||||
unsigned int body_crc32 = 0;
|
||||
|
||||
if (!msg || !initialized) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&msg_header, 0, sizeof(struct msg_header));
|
||||
|
||||
msg_header.magic = MSG_MAGIC;
|
||||
msg_header.cmd = msg->cmd;
|
||||
msg_header.flags = msg->flags;
|
||||
|
||||
if ((msg->cmd == prev_snd_msg.cmd) &&
|
||||
(msg->seq == prev_snd_msg.seq) &&
|
||||
(MSG_TYPE(msg->cmd)) == MSG_TYPE_REQ) {
|
||||
msg_seq = prev_snd_msg.seq;
|
||||
} else {
|
||||
msg_seq = msg_get_new_seq(msg_seq);
|
||||
}
|
||||
|
||||
msg_header.seq = msg_seq;
|
||||
|
||||
if (!msg->body) {
|
||||
msg_header.length = 0;
|
||||
} else {
|
||||
if (MSG_NEED_BCHECK(msg->flags)) {
|
||||
body_crc32 = crc32((unsigned char *)msg->body, msg->bodylen);
|
||||
msg_header.length = msg->bodylen + MSG_BODY_CHECK_LEN;
|
||||
} else {
|
||||
msg_header.length = msg->bodylen;
|
||||
}
|
||||
}
|
||||
|
||||
msg_header.crc32 = crc32((unsigned char *)&msg_header,
|
||||
sizeof(struct msg_header) - MSG_BODY_CHECK_LEN);
|
||||
|
||||
stream_write((unsigned char *)&msg_header, sizeof(struct msg_header));
|
||||
|
||||
if (msg->body) {
|
||||
stream_write(msg->body, msg->bodylen);
|
||||
if (MSG_NEED_BCHECK(msg->flags)) {
|
||||
stream_write((unsigned char *)&body_crc32, MSG_BODY_CHECK_LEN);
|
||||
}
|
||||
}
|
||||
|
||||
prev_snd_msg.cmd = msg->cmd;
|
||||
prev_snd_msg.seq = msg_seq;
|
||||
msg->seq = msg_seq;
|
||||
|
||||
return msg->bodylen;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int nc_message_init(STREAM_READ read, STREAM_WRITE write, STREAM_EMPTY is_empty)
|
||||
{
|
||||
if (!read || !write || !is_empty) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
stream_read = read;
|
||||
stream_write = write;
|
||||
stream_is_empty = is_empty;
|
||||
|
||||
msg_seq = 0;
|
||||
memset(&prev_rcv_msg, 0xFF, sizeof(prev_rcv_msg));
|
||||
memset(&prev_snd_msg, 0xFF, sizeof(prev_snd_msg));
|
||||
initialized = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gx8002_uart_agent_query_event(unsigned short cmd)
|
||||
{
|
||||
struct message snd_msg = {0};
|
||||
gx8002_info("gx8002 task query msg");
|
||||
|
||||
//snd_msg.cmd = MSG_REQ_VOICE_EVENT;
|
||||
snd_msg.cmd = cmd;
|
||||
snd_msg.flags = 0;
|
||||
snd_msg.body = NULL;
|
||||
snd_msg.bodylen = 0;
|
||||
|
||||
return nc_message_send(&snd_msg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//===========================================================//
|
||||
// GX8002 NPU PORT LAYER //
|
||||
//===========================================================//
|
||||
|
||||
#define THIS_TASK_NAME "gx8002"
|
||||
|
||||
enum GX8002_STATE {
|
||||
GX8002_STATE_WORKING = 1,
|
||||
GX8002_STATE_SUSPEND,
|
||||
GX8002_STATE_UPGRADING,
|
||||
};
|
||||
|
||||
|
||||
struct gx8002_handle {
|
||||
u8 state;
|
||||
u8 idle; //0: busy, 1: idle
|
||||
OS_SEM rx_sem;
|
||||
const uart_bus_t *uart_bus;
|
||||
};
|
||||
|
||||
static struct gx8002_handle hdl;
|
||||
|
||||
#define __this (&hdl)
|
||||
static u8 uart_cbuf[32] __attribute__((aligned(4)));
|
||||
u8 gx_self_info[6] = {0, 0, 0, 0, //version
|
||||
0, //mic status
|
||||
0
|
||||
}; //gsensor status
|
||||
|
||||
//============== extern function =================//
|
||||
extern void gx8002_board_port_resumed(void);
|
||||
extern void gx8002_board_port_suspend(void);
|
||||
extern void gx8002_vddio_power_ctrl(u8 on);
|
||||
extern void gx8002_core_vdd_power_ctrl(u8 on);
|
||||
|
||||
static void gx8002_uart_isr_hook(void *arg, u32 status)
|
||||
{
|
||||
if (status != UT_TX) {
|
||||
gx8002_info("gx8002 uart RX pnding");
|
||||
if (__this->state == GX8002_STATE_WORKING) {
|
||||
os_sem_post(&(__this->rx_sem));
|
||||
__this->idle = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void gx8002_uart_porting_config(u32 baud)
|
||||
{
|
||||
struct uart_platform_data_t u_arg = {0};
|
||||
|
||||
if (__this->uart_bus) {
|
||||
gx8002_info("gx8002 uart have init");
|
||||
return;
|
||||
}
|
||||
u_arg.tx_pin = TCFG_GX8002_NPU_UART_TX_PORT;
|
||||
u_arg.rx_pin = TCFG_GX8002_NPU_UART_RX_PORT;
|
||||
u_arg.rx_cbuf = uart_cbuf;
|
||||
u_arg.rx_cbuf_size = sizeof(uart_cbuf);
|
||||
u_arg.frame_length = 0xFFFF;
|
||||
u_arg.rx_timeout = 100;
|
||||
u_arg.isr_cbfun = gx8002_uart_isr_hook;
|
||||
u_arg.baud = baud;
|
||||
u_arg.is_9bit = 0;
|
||||
|
||||
__this->uart_bus = uart_dev_open(&u_arg);
|
||||
if (__this->uart_bus) {
|
||||
gx8002_info("gx8002 uart init succ");
|
||||
} else {
|
||||
gx8002_info("gx8002 uart init fail");
|
||||
ASSERT(__this->uart_bus);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void gx8002_uart_porting_close(void)
|
||||
{
|
||||
if (__this->uart_bus) {
|
||||
uart_dev_close(__this->uart_bus);
|
||||
gpio_disable_fun_output_port(TCFG_GX8002_NPU_UART_TX_PORT);
|
||||
gx8002_board_port_suspend();
|
||||
__this->uart_bus = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int gx8002_uart_stream_read(unsigned char *buf, int len)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ASSERT(__this->uart_bus && __this->uart_bus->read);
|
||||
if (__this->uart_bus && __this->uart_bus->read) {
|
||||
ret = __this->uart_bus->read(buf, len, 1000);
|
||||
gx8002_debug("stream read len %d", len);
|
||||
gx8002_put_buf(buf, len);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int gx8002_uart_stream_write(const unsigned char *buf, int len)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ASSERT(__this->uart_bus && __this->uart_bus->write);
|
||||
if (__this->uart_bus && __this->uart_bus->write) {
|
||||
__this->uart_bus->write(buf, len);
|
||||
ret = len;
|
||||
gx8002_debug("stream write len %d", len);
|
||||
gx8002_put_buf(buf, len);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int gx8002_uart_stream_is_empty(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gx8002_uart_porting_poll(u32 timeout)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static void gx8002_power_off(void)
|
||||
{
|
||||
//由板级提供
|
||||
gx8002_board_port_suspend();
|
||||
gx8002_vddio_power_ctrl(0);
|
||||
gx8002_core_vdd_power_ctrl(0);
|
||||
}
|
||||
|
||||
static void gx8002_power_off_keep_vddio(void)
|
||||
{
|
||||
//由板级提供
|
||||
gx8002_board_port_suspend();
|
||||
//gx8002_vddio_power_ctrl(0); //通话是会影响mic配置, 不关MIC_LDO
|
||||
gx8002_core_vdd_power_ctrl(0);
|
||||
}
|
||||
|
||||
//======================================//
|
||||
// GX8002上电注意事项:
|
||||
// 1) 正常上电需要先将uart IO初始化为确认电平, 否则gx8002会进入升级模式;
|
||||
// 2) vddio先上电, core_vdd需要等vddio上电后之后3ms后上电;
|
||||
//======================================//
|
||||
static void gx8002_normal_power_on(void)
|
||||
{
|
||||
gx8002_board_port_resumed();
|
||||
//由板级提供
|
||||
//gx8002_core_vdd_power_ctrl(0);
|
||||
gx8002_vddio_power_ctrl(1);
|
||||
os_time_dly(2);
|
||||
gx8002_core_vdd_power_ctrl(1);
|
||||
}
|
||||
|
||||
//进升级模式
|
||||
static void gx8002_upgrade_power_on(void)
|
||||
{
|
||||
//由板级提供
|
||||
//gx8002_core_vdd_power_ctrl(0);
|
||||
gx8002_vddio_power_ctrl(1);
|
||||
os_time_dly(2);
|
||||
gx8002_core_vdd_power_ctrl(1);
|
||||
gx8002_board_port_resumed();
|
||||
}
|
||||
|
||||
static void gx8002_first_power_on(void)
|
||||
{
|
||||
//由板级提供
|
||||
//gx8002_core_vdd_power_ctrl(0);
|
||||
gx8002_vddio_power_ctrl(1);
|
||||
os_time_dly(10);
|
||||
gx8002_core_vdd_power_ctrl(1);
|
||||
|
||||
//gx8002_board_port_resumed();
|
||||
}
|
||||
|
||||
|
||||
static void __gx8002_module_suspend(u8 keep_vddio)
|
||||
{
|
||||
gx8002_info("%s", __func__);
|
||||
if (keep_vddio) {
|
||||
gx8002_power_off_keep_vddio();
|
||||
} else {
|
||||
gx8002_power_off();
|
||||
}
|
||||
|
||||
if (__this->state == GX8002_STATE_UPGRADING) {
|
||||
return;
|
||||
}
|
||||
__this->state = GX8002_STATE_SUSPEND;
|
||||
}
|
||||
|
||||
static void __gx8002_module_resumed()
|
||||
{
|
||||
gx8002_info("%s", __func__);
|
||||
gx8002_normal_power_on();
|
||||
|
||||
if (__this->state == GX8002_STATE_UPGRADING) {
|
||||
return;
|
||||
}
|
||||
__this->state = GX8002_STATE_WORKING;
|
||||
}
|
||||
|
||||
void gx8002_module_suspend(u8 keep_vddio)
|
||||
{
|
||||
os_taskq_post_msg(THIS_TASK_NAME, 2, GX8002_MSG_SUSPEND, keep_vddio);
|
||||
}
|
||||
|
||||
void gx8002_module_resumed()
|
||||
{
|
||||
os_taskq_post_msg(THIS_TASK_NAME, 1, GX8002_MSG_RESUMED);
|
||||
}
|
||||
|
||||
void gx8002_normal_cold_reset(void)
|
||||
{
|
||||
gx8002_power_off();
|
||||
os_time_dly(50);
|
||||
gx8002_normal_power_on();
|
||||
}
|
||||
|
||||
void gx8002_upgrade_cold_reset(void)
|
||||
{
|
||||
gx8002_power_off();
|
||||
os_time_dly(50);
|
||||
gx8002_upgrade_power_on();
|
||||
}
|
||||
|
||||
int gx8002_uart_spp_ota_init(void);
|
||||
static void gx8002_app_event_handler(struct sys_event *event)
|
||||
{
|
||||
gx8002_info("%s", __func__);
|
||||
struct bt_event *bt = &(event->u.bt);
|
||||
switch (event->type) {
|
||||
case SYS_BT_EVENT:
|
||||
if ((u32)event->arg == SYS_BT_EVENT_TYPE_CON_STATUS) {
|
||||
switch (bt->event) {
|
||||
case BT_STATUS_FIRST_CONNECTED:
|
||||
#if GX8002_UPGRADE_SPP_TOGGLE
|
||||
gx8002_uart_spp_ota_init();
|
||||
#endif /* #if GX8002_UPGRADE_SPP_TOGGLE */
|
||||
break;
|
||||
#if 0
|
||||
case BT_STATUS_SCO_STATUS_CHANGE:
|
||||
if (bt->value != 0xff) {
|
||||
gx8002_module_suspend();
|
||||
} else {
|
||||
gx8002_module_resumed();
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int gx8002_wakeup_handle(unsigned short cmd)
|
||||
{
|
||||
int err;
|
||||
struct message recv_msg = {0};
|
||||
unsigned short event;
|
||||
int ret = 0;
|
||||
|
||||
if (__this->state != GX8002_STATE_WORKING) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (gx8002_uart_porting_poll(1000) > 0) {
|
||||
os_sem_set(&(__this->rx_sem), 0);
|
||||
gx8002_uart_agent_query_event(cmd);
|
||||
|
||||
err = os_sem_pend(&(__this->rx_sem), 100);
|
||||
if (err != OS_NO_ERR) {
|
||||
gx8002_info("rx sem err: %d", err);
|
||||
__this->idle = 1;
|
||||
return -1;
|
||||
}
|
||||
gx8002_info("gx8002 task receive >>>>");
|
||||
// 有串口数据
|
||||
memset(&recv_msg, 0, sizeof(recv_msg));
|
||||
if (nc_message_receive(&recv_msg) < 0) {
|
||||
if (recv_msg.body) {
|
||||
OS_FREE(recv_msg.body);
|
||||
}
|
||||
gx8002_info("recv_msg NULL\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (recv_msg.cmd) {
|
||||
case MSG_RSP_VOICE_EVENT:
|
||||
//语音事件
|
||||
event = recv_msg.body[1] << 8 | recv_msg.body[0];
|
||||
//处理语音事件
|
||||
ret = event;
|
||||
gx8002_event_state_update(event);
|
||||
break;
|
||||
|
||||
case MSG_RSP_MIC_EVENT:
|
||||
event = recv_msg.body[1] << 8 | recv_msg.body[0];
|
||||
ret = event;
|
||||
break;
|
||||
case MSG_RSP_GSENSOR_EVENT:
|
||||
event = recv_msg.body[1] << 8 | recv_msg.body[0];
|
||||
ret = event;
|
||||
break;
|
||||
|
||||
case MSG_RSP_VERSION_EVENT:
|
||||
gx8002_info(">> gx version");
|
||||
memcpy(gx_self_info, recv_msg.body, recv_msg.bodylen);
|
||||
put_buf(gx_self_info, sizeof(gx_self_info));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (recv_msg.body) {
|
||||
OS_FREE(recv_msg.body);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void gx8002_self_test_handle()
|
||||
{
|
||||
int ret = 0;
|
||||
int mic_test_cnt = 0;
|
||||
int gsensor_test_cnt = 0;
|
||||
|
||||
//int self_test_result = 0;
|
||||
|
||||
gx8002_info("gx8002 self test start >>>>");
|
||||
__gsensor_test_retry:
|
||||
__this->idle = 0;
|
||||
gx8002_info("gsensor_test_cnt = %d", gsensor_test_cnt);
|
||||
ret = gx8002_wakeup_handle(MSG_REQ_GSENSOR_EVENT);
|
||||
if (ret == 0) {
|
||||
gx8002_info("gx8002 gsensor test OK");
|
||||
//self_test_result |= (0xA << 4);
|
||||
gx_self_info[5] = 0xA;
|
||||
} else {
|
||||
gsensor_test_cnt++;
|
||||
if (gsensor_test_cnt < 10) {
|
||||
gx8002_info("gx8002 gsensor no OK try again");
|
||||
os_time_dly(500 / 10);
|
||||
goto __gsensor_test_retry;
|
||||
}
|
||||
gx_self_info[5] = 1;
|
||||
}
|
||||
|
||||
//MIC状态查询
|
||||
__mic_test_retry:
|
||||
__this->idle = 0;
|
||||
gx8002_info("mic_test_cnt = %d", mic_test_cnt);
|
||||
ret = gx8002_wakeup_handle(MSG_REQ_MIC_EVENT);
|
||||
if (ret == 0) {
|
||||
gx8002_info("gx8002 mic test OK");
|
||||
//self_test_result |= 0xA;
|
||||
gx_self_info[4] = 0xA;
|
||||
} else {
|
||||
mic_test_cnt++;
|
||||
if (mic_test_cnt < 10) {
|
||||
gx8002_info("gx8002 mic no OK try again");
|
||||
os_time_dly(500 / 10);
|
||||
goto __mic_test_retry;
|
||||
}
|
||||
gx_self_info[4] = 1;
|
||||
}
|
||||
|
||||
__this->idle = 1;
|
||||
|
||||
//put_buf(gx_self_info,sizeof(gx_self_info));
|
||||
gx8002_info("gx_self_info[mic]:%x,gx_self_info[g]:%x", gx_self_info[4], gx_self_info[5]);
|
||||
}
|
||||
|
||||
|
||||
static void gx8002_sdfile_update_timer(void *priv)
|
||||
{
|
||||
gx8002_info("gx8002 post update msg >>>>");
|
||||
os_taskq_post_msg(THIS_TASK_NAME, 2, GX8002_MSG_UPDATE, GX8002_UPDATE_TYPE_SDFILE);
|
||||
}
|
||||
|
||||
void gx8002_update_end_post_msg(u8 flag)
|
||||
{
|
||||
os_taskq_post_msg(THIS_TASK_NAME, 2, GX8002_MSG_UPDATE_END, flag);
|
||||
}
|
||||
|
||||
|
||||
static void gx8002_upgrade_start(int update_type)
|
||||
{
|
||||
#if GX8002_UPGRADE_TOGGLE
|
||||
gx8002_uart_porting_close();
|
||||
__this->state = GX8002_STATE_UPGRADING;
|
||||
|
||||
switch (update_type) {
|
||||
case GX8002_UPDATE_TYPE_SDFILE:
|
||||
gx8002_uart_sdfile_ota_init();
|
||||
break;
|
||||
case GX8002_UPDATE_TYPE_SPP:
|
||||
gx8002_uart_spp_ota_init();
|
||||
break;
|
||||
case GX8002_UPDATE_TYPE_APP:
|
||||
gx8002_uart_app_ota_init();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#endif /* #if GX8002_UPGRADE_TOGGLE */
|
||||
}
|
||||
|
||||
static void gx8002_upgrade_end(u8 flag)
|
||||
{
|
||||
gx8002_uart_porting_config(115200);
|
||||
gx8002_normal_power_on();
|
||||
__this->state = GX8002_STATE_WORKING;
|
||||
}
|
||||
|
||||
void gx8002_voice_event_post_msg(u8 msg)
|
||||
{
|
||||
os_taskq_post_msg(THIS_TASK_NAME, 2, GX8002_MSG_VOICE_EVENT, msg);
|
||||
}
|
||||
|
||||
void gx8002_npu_version_check(void *priv)
|
||||
{
|
||||
if (__this->state == GX8002_STATE_WORKING) {
|
||||
__this->idle = 0;
|
||||
os_taskq_post_msg(THIS_TASK_NAME, 1, GX8002_MSG_GET_VERSION);
|
||||
} else {
|
||||
__this->idle = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void gx8002_uart_recv_task(void *param)
|
||||
{
|
||||
int msg[16];
|
||||
int res;
|
||||
|
||||
gx8002_info("gx8002 task init");
|
||||
#if 1
|
||||
//串口初始化
|
||||
gx8002_uart_porting_config(115200);
|
||||
|
||||
gx8002_first_power_on();
|
||||
|
||||
// 设置回调
|
||||
nc_message_init(gx8002_uart_stream_read, gx8002_uart_stream_write, gx8002_uart_stream_is_empty);
|
||||
#endif
|
||||
|
||||
os_sem_create(&(__this->rx_sem), 0);
|
||||
|
||||
__this->state = GX8002_STATE_WORKING;
|
||||
__this->idle = 1;
|
||||
#if GX8002_UPGRADE_SPP_TOGGLE
|
||||
register_sys_event_handler(SYS_BT_EVENT, 0, 0, gx8002_app_event_handler);
|
||||
#endif /* #if GX8002_UPGRADE_SPP_TOGGLE */
|
||||
|
||||
/* if (GX8002_UPGRADE_SDFILE_TOGGLE) { */
|
||||
/* sys_timeout_add(NULL, gx8002_sdfile_update_timer, 10000); */
|
||||
/* } */
|
||||
|
||||
#if GX8002_UPGRADE_APP_TOGGLE
|
||||
gx8002_uart_app_ota_update_register_handle();
|
||||
#endif /* #if GX8002_UPGRADE_APP_TOGGLE */
|
||||
|
||||
//gx版本查询
|
||||
sys_timeout_add(NULL, gx8002_npu_version_check, 1000);
|
||||
|
||||
while (1) {
|
||||
res = os_taskq_pend(NULL, msg, ARRAY_SIZE(msg));
|
||||
if (res == OS_TASKQ) {
|
||||
switch (msg[1]) {
|
||||
case GX8002_MSG_WAKEUP:
|
||||
gx8002_wakeup_handle(MSG_REQ_VOICE_EVENT);
|
||||
break;
|
||||
case GX8002_MSG_VOICE_EVENT:
|
||||
gx8002_voice_event_handle(msg[2]);
|
||||
break;
|
||||
case GX8002_MSG_UPDATE:
|
||||
gx8002_upgrade_start(msg[2]);
|
||||
break;
|
||||
case GX8002_MSG_UPDATE_END:
|
||||
gx8002_upgrade_end(msg[2]);
|
||||
break;
|
||||
case GX8002_MSG_SUSPEND:
|
||||
__gx8002_module_suspend(msg[2]);
|
||||
break;
|
||||
case GX8002_MSG_RESUMED:
|
||||
__gx8002_module_resumed();
|
||||
break;
|
||||
case GX8002_MSG_SELF_TEST:
|
||||
gx8002_self_test_handle();
|
||||
break;
|
||||
case GX8002_MSG_GET_VERSION:
|
||||
gx8002_wakeup_handle(MSG_REQ_VERSION_EVENT);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int gx8002_npu_init(void)
|
||||
{
|
||||
#if 0 //升级GX8002固件
|
||||
gpio_set_pull_down(TCFG_GX8002_NPU_UART_TX_PORT, 0);
|
||||
gpio_set_pull_up(TCFG_GX8002_NPU_UART_TX_PORT, 0);
|
||||
gpio_set_die(TCFG_GX8002_NPU_UART_TX_PORT, 0);
|
||||
gpio_set_dieh(TCFG_GX8002_NPU_UART_TX_PORT, 0);
|
||||
gpio_set_direction(TCFG_GX8002_NPU_UART_TX_PORT, 1);
|
||||
|
||||
gpio_set_pull_down(TCFG_GX8002_NPU_UART_RX_PORT, 0);
|
||||
gpio_set_pull_up(TCFG_GX8002_NPU_UART_RX_PORT, 0);
|
||||
gpio_set_die(TCFG_GX8002_NPU_UART_RX_PORT, 0);
|
||||
gpio_set_dieh(TCFG_GX8002_NPU_UART_RX_PORT, 0);
|
||||
gpio_set_direction(TCFG_GX8002_NPU_UART_RX_PORT, 1);
|
||||
return 0;
|
||||
#endif
|
||||
//创建recv任务
|
||||
task_create(gx8002_uart_recv_task, 0, THIS_TASK_NAME);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void gx8002_npu_int_edge_wakeup_handle(u8 index, u8 gpio)
|
||||
{
|
||||
gx8002_info("gx8002 wakeup, cut_state: %d", __this->state);
|
||||
if (__this->state == GX8002_STATE_WORKING) {
|
||||
__this->idle = 0;
|
||||
os_taskq_post_msg(THIS_TASK_NAME, 1, GX8002_MSG_WAKEUP);
|
||||
} else {
|
||||
__this->idle = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void gx8002_npu_mic_gsensor_self_test(void)
|
||||
{
|
||||
gx8002_info("gx8002 self test %d", __this->state);
|
||||
if (__this->state == GX8002_STATE_WORKING) {
|
||||
__this->idle = 0;
|
||||
os_taskq_post_msg(THIS_TASK_NAME, 1, GX8002_MSG_SELF_TEST);
|
||||
} else {
|
||||
__this->idle = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static u8 gx8002_npu_idle_query(void)
|
||||
{
|
||||
//gx8002_debug("__this->idle = %d", __this->idle);
|
||||
//return 1;
|
||||
if (__this->state == GX8002_STATE_UPGRADING) {
|
||||
return 0;
|
||||
}
|
||||
return __this->idle;
|
||||
}
|
||||
|
||||
static enum LOW_POWER_LEVEL gx8002_npu_level_query(void)
|
||||
{
|
||||
if (__this->state != GX8002_STATE_SUSPEND) {
|
||||
return LOW_POWER_MODE_LIGHT_SLEEP;
|
||||
} else {
|
||||
return LOW_POWER_MODE_DEEP_SLEEP;
|
||||
}
|
||||
}
|
||||
|
||||
REGISTER_LP_TARGET(gx8002_lp_target) = {
|
||||
.name = "gx8002",
|
||||
.level = gx8002_npu_level_query,
|
||||
.is_idle = gx8002_npu_idle_query,
|
||||
};
|
||||
|
||||
#endif /* #if TCFG_GX8002_NPU_ENABLE */
|
||||
95
apps/common/device/gx8002_npu/gx8002_npu.h
Normal file
95
apps/common/device/gx8002_npu/gx8002_npu.h
Normal file
@ -0,0 +1,95 @@
|
||||
#ifndef __GX8002_NPU_H__
|
||||
#define __GX8002_NPU_H__
|
||||
|
||||
/*
|
||||
* Message command
|
||||
*/
|
||||
#define MSG_TYPEBITS 8
|
||||
#define MSG_NRBITS 8
|
||||
|
||||
#define MSG_NRMASK ((1 << MSG_NRBITS) - 1)
|
||||
#define MSG_TYPEMASK ((1 << MSG_TYPEBITS) - 1)
|
||||
|
||||
#define MSG_NRSHIFT 0
|
||||
#define MSG_TYPESHIFT (MSG_NRSHIFT + MSG_NRBITS)
|
||||
|
||||
/* Create new message */
|
||||
#define NEW_MSG(type, nr) \
|
||||
(((type) << MSG_TYPESHIFT) | \
|
||||
((nr) << MSG_NRSHIFT))
|
||||
|
||||
/* Get message type */
|
||||
#define MSG_TYPE(cmd) (((cmd) >> MSG_TYPESHIFT) & MSG_TYPEMASK)
|
||||
|
||||
/* Get message nr */
|
||||
#define MSG_NR(cmd) (((cmd) >> MSG_NRSHIFT) & MSG_NRMASK)
|
||||
|
||||
/*
|
||||
* Message flags
|
||||
*/
|
||||
#define MSG_FLAG_BCHECK (1 << 0)
|
||||
#define MSG_FLAG_BCHECK_BITS 1
|
||||
#define MSG_FLAG_BCHECK_MASK ((1 << MSG_FLAG_BCHECK_BITS) - 1)
|
||||
#define MSG_FLAG_BCHECK_SHIFT 0
|
||||
|
||||
/* Check if need message body crc32 */
|
||||
#define MSG_NEED_BCHECK(flags) (((flags) >> MSG_FLAG_BCHECK_SHIFT) & MSG_FLAG_BCHECK_MASK)
|
||||
|
||||
|
||||
#define MSG_HEAD_LEN 14 /* Message header length */
|
||||
#define MSG_HEAD_CHECK_LEN 4 /* Message header crc32 length */
|
||||
#define MSG_MAGIC_LEN 4 /* Message magic length */
|
||||
#define MSG_BODY_LEN_MAX 3072 /* Message body maximun length */
|
||||
#define MSG_BODY_CHECK_LEN 4 /* Message body crc32 length */
|
||||
|
||||
#define MSG_SEQ_MAX 255 /* Message sequence maximum count */
|
||||
#define MSG_LEN_MAX (MSG_HEAD_LEN + MSG_BODY_LEN_MAX) /* Message maximun length */
|
||||
|
||||
#define MSG_MAGIC 0x58585542
|
||||
|
||||
#define MSG_RCV_MAGIC0 (((MSG_MAGIC) & 0x000000FF) >> 0 )
|
||||
#define MSG_RCV_MAGIC1 (((MSG_MAGIC) & 0x0000FF00) >> 8 )
|
||||
#define MSG_RCV_MAGIC2 (((MSG_MAGIC) & 0x00FF0000) >> 16)
|
||||
#define MSG_RCV_MAGIC3 (((MSG_MAGIC) & 0xFF000000) >> 24)
|
||||
|
||||
typedef enum {
|
||||
MSG_TYPE_REQ = 0x1,
|
||||
MSG_TYPE_RSP = 0x2,
|
||||
MSG_TYPE_NTF = 0x3,
|
||||
} MSG_TYPE;
|
||||
|
||||
struct message {
|
||||
unsigned short cmd;
|
||||
unsigned char seq;
|
||||
unsigned char flags;
|
||||
unsigned char *body;
|
||||
unsigned short bodylen;
|
||||
} __attribute__((packed));
|
||||
|
||||
typedef enum {
|
||||
MSG_REQ_VOICE_EVENT = NEW_MSG(MSG_TYPE_REQ, 0x0C),
|
||||
MSG_RSP_VOICE_EVENT = NEW_MSG(MSG_TYPE_RSP, 0x0C),
|
||||
|
||||
//查询gx固件版本
|
||||
MSG_REQ_VERSION_EVENT = NEW_MSG(MSG_TYPE_REQ, 0x02),
|
||||
MSG_RSP_VERSION_EVENT = NEW_MSG(MSG_TYPE_RSP, 0x02),
|
||||
|
||||
//查询MIC状态
|
||||
MSG_REQ_MIC_EVENT = NEW_MSG(MSG_TYPE_REQ, 0x70),
|
||||
MSG_RSP_MIC_EVENT = NEW_MSG(MSG_TYPE_RSP, 0x70),
|
||||
|
||||
//查询Gsensor状态
|
||||
MSG_REQ_GSENSOR_EVENT = NEW_MSG(MSG_TYPE_REQ, 0x71),
|
||||
MSG_RSP_GSENSOR_EVENT = NEW_MSG(MSG_TYPE_RSP, 0x71),
|
||||
} UART_MSG_ID;
|
||||
/* Stream read callback */
|
||||
typedef int (*STREAM_READ)(unsigned char *buf, int len);
|
||||
|
||||
/* Stream write callback */
|
||||
typedef int (*STREAM_WRITE)(const unsigned char *buf, int len);
|
||||
|
||||
/* Stream is empty callback */
|
||||
typedef int (*STREAM_EMPTY)(void);
|
||||
|
||||
|
||||
#endif /* #ifndef __GX8002_NPU_H__ */
|
||||
71
apps/common/device/gx8002_npu/gx8002_npu_api.h
Normal file
71
apps/common/device/gx8002_npu/gx8002_npu_api.h
Normal file
@ -0,0 +1,71 @@
|
||||
#ifndef __GX8002_NPU_API_H__
|
||||
#define __GX8002_NPU_API_H__
|
||||
|
||||
#include "app_config.h"
|
||||
#include "update_loader_download.h"
|
||||
|
||||
#if TCFG_GX8002_NPU_ENABLE
|
||||
|
||||
#define GX8002_UPGRADE_TOGGLE 1
|
||||
|
||||
#if GX8002_UPGRADE_TOGGLE
|
||||
#define GX8002_UPGRADE_SDFILE_TOGGLE 0 //for test, 升级文件存内置flash升级gx8002
|
||||
#define GX8002_UPGRADE_SPP_TOGGLE 0 //使用spp协议升级gx8002
|
||||
|
||||
#define GX8002_UPGRADE_APP_TOGGLE 1 //使用测试盒/手机APP传输数据, 通过ota流程升级gx8002
|
||||
#if CONFIG_DOUBLE_BANK_ENABLE
|
||||
#define GX8002_UPGRADE_APP_TWS_TOGGLE 1 //TWS同步升级使能
|
||||
#endif /* #if CONFIG_DOUBLE_BANK_ENABLE */
|
||||
#endif
|
||||
|
||||
#endif /* #if TCFG_GX8002_NPU_ENABLE */
|
||||
|
||||
//语音事件列表
|
||||
enum gx8002_voice_event {
|
||||
MAIN_WAKEUP_VOICE_EVENT = 100, //"小度小度", "天猫精灵", "小爱同学"
|
||||
MUSIC_PAUSE_VOICE_EVENT = 102, //"暂停播放"
|
||||
MUSIC_STOP_VOICE_EVENT = 103, //"停止播放"
|
||||
MUSIC_PLAY_VOICE_EVENT = 104, //"播放音乐"
|
||||
VOLUME_UP_VOICE_EVENT = 105, //"增大音量"
|
||||
VOLUME_DOWN_VOICE_EVENT = 106, //"减小音量"
|
||||
MUSIC_PREV_VOICE_EVENT = 112, //"播放上一首"
|
||||
MUSIC_NEXT_VOICE_EVENT = 113, //"播放下一首"
|
||||
CALL_ANSWER_VOICE_EVENT = 114, //"接听电话"
|
||||
CALL_HANG_UP_VOICE_EVENT = 115, //"挂掉电话"
|
||||
};
|
||||
|
||||
enum GX8002_MSG {
|
||||
GX8002_MSG_BEGIN = ('8' << 24) | ('0' << 16) | ('0' << 8) | ('2' << 0),
|
||||
GX8002_MSG_WAKEUP,
|
||||
GX8002_MSG_VOICE_EVENT,
|
||||
GX8002_MSG_UPDATE,
|
||||
GX8002_MSG_UPDATE_END,
|
||||
GX8002_MSG_SUSPEND,
|
||||
GX8002_MSG_RESUMED,
|
||||
GX8002_MSG_SELF_TEST,
|
||||
GX8002_MSG_GET_VERSION,
|
||||
};
|
||||
|
||||
enum GX8002_UPDATE_TYPE {
|
||||
GX8002_UPDATE_TYPE_SDFILE = 0x5A,
|
||||
GX8002_UPDATE_TYPE_SPP,
|
||||
GX8002_UPDATE_TYPE_APP,
|
||||
};
|
||||
|
||||
void gx8002_npu_int_edge_wakeup_handle(u8 index, u8 gpio);
|
||||
int gx8002_npu_init(void);
|
||||
void gx8002_event_state_update(u8 voice_event);
|
||||
//int gx8002_uart_ota_init(void);
|
||||
int gx8002_uart_sdfile_ota_init(void);
|
||||
int gx8002_uart_spp_ota_init(void);
|
||||
int gx8002_uart_app_ota_init(void);
|
||||
void gx8002_voice_event_handle(u8 voice_event);
|
||||
void gx8002_uart_app_ota_update_register_handle(void);
|
||||
|
||||
void gx8002_cold_reset(void);
|
||||
void gx8002_normal_cold_reset(void);
|
||||
void gx8002_upgrade_cold_reset(void);
|
||||
void gx8002_update_end_post_msg(u8 flag);
|
||||
void gx8002_voice_event_post_msg(u8 msg);
|
||||
|
||||
#endif /* #ifndef __GX8002_NPU_API_H__ */
|
||||
193
apps/common/device/gx8002_npu/gx8002_npu_event_deal.c
Normal file
193
apps/common/device/gx8002_npu/gx8002_npu_event_deal.c
Normal file
@ -0,0 +1,193 @@
|
||||
#include "includes.h"
|
||||
#include "app_config.h"
|
||||
#include "gx8002_npu.h"
|
||||
#include "gx8002_npu_api.h"
|
||||
#include "btstack/avctp_user.h"
|
||||
#include "tone_player.h"
|
||||
|
||||
#if TCFG_USER_TWS_ENABLE
|
||||
#include "bt_tws.h"
|
||||
#endif /* #if TCFG_USER_TWS_ENABLE */
|
||||
|
||||
#if TCFG_GX8002_NPU_ENABLE
|
||||
|
||||
#define gx8002_event_info printf
|
||||
|
||||
bool get_tws_sibling_connect_state(void);
|
||||
|
||||
#define TWS_FUNC_ID_VOICE_EVENT_SYNC TWS_FUNC_ID('V', 'O', 'I', 'C')
|
||||
|
||||
struct gx8002_event_hdl {
|
||||
u8 last_event;
|
||||
u32 last_event_jiffies;
|
||||
};
|
||||
|
||||
static struct gx8002_event_hdl hdl = {0};
|
||||
|
||||
#define __this (&hdl)
|
||||
|
||||
__attribute__((weak))
|
||||
void volume_down(u8 dec)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
__attribute__((weak))
|
||||
void volume_up(u8 inc)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
__attribute__((weak))
|
||||
int app_case_voice_event_handle(u8 voice_event)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gx8002_recognize_tone_play(void)
|
||||
{
|
||||
if (get_tws_sibling_connect_state() == TRUE) {
|
||||
if (tws_api_get_role() == TWS_ROLE_MASTER) {
|
||||
bt_tws_play_tone_at_same_time(SYNC_TONE_VOICE_RECOGNIZE, 200);
|
||||
}
|
||||
} else {
|
||||
tone_play(TONE_NORMAL, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void gx8002_event_handle(u8 voice_event)
|
||||
{
|
||||
u32 cur_jiffies = jiffies;
|
||||
u8 a2dp_state;
|
||||
u8 call_state;
|
||||
|
||||
if (voice_event == __this->last_event) {
|
||||
if (jiffies_to_msecs(cur_jiffies - __this->last_event_jiffies) < 1000) {
|
||||
gx8002_event_info("voice event %d same, ignore", voice_event);
|
||||
__this->last_event_jiffies = cur_jiffies;
|
||||
return;
|
||||
}
|
||||
}
|
||||
__this->last_event_jiffies = cur_jiffies;
|
||||
__this->last_event = voice_event;
|
||||
|
||||
gx8002_event_info("%s: %d", __func__, voice_event);
|
||||
|
||||
if (app_case_voice_event_handle(voice_event)) {
|
||||
return;
|
||||
}
|
||||
|
||||
//播放提示音
|
||||
if ((voice_event != VOLUME_UP_VOICE_EVENT) && (voice_event != VOLUME_DOWN_VOICE_EVENT)) {
|
||||
//gx8002_recognize_tone_play();
|
||||
}
|
||||
|
||||
switch (voice_event) {
|
||||
case MAIN_WAKEUP_VOICE_EVENT:
|
||||
gx8002_event_info("send SIRI cmd");
|
||||
user_send_cmd_prepare(USER_CTRL_HFP_GET_SIRI_OPEN, 0, NULL);
|
||||
break;
|
||||
case MUSIC_PAUSE_VOICE_EVENT:
|
||||
case MUSIC_STOP_VOICE_EVENT:
|
||||
case MUSIC_PLAY_VOICE_EVENT:
|
||||
call_state = get_call_status();
|
||||
if ((call_state == BT_CALL_OUTGOING) ||
|
||||
(call_state == BT_CALL_ALERT)) {
|
||||
//user_send_cmd_prepare(USER_CTRL_HFP_CALL_HANGUP, 0, NULL);
|
||||
} else if (call_state == BT_CALL_INCOMING) {
|
||||
//user_send_cmd_prepare(USER_CTRL_HFP_CALL_ANSWER, 0, NULL);
|
||||
} else if (call_state == BT_CALL_ACTIVE) {
|
||||
//user_send_cmd_prepare(USER_CTRL_HFP_CALL_HANGUP, 0, NULL);
|
||||
} else {
|
||||
a2dp_state = a2dp_get_status();
|
||||
if (a2dp_state == BT_MUSIC_STATUS_STARTING) {
|
||||
if (voice_event == MUSIC_PAUSE_VOICE_EVENT) {
|
||||
gx8002_event_info("send PAUSE cmd");
|
||||
user_send_cmd_prepare(USER_CTRL_AVCTP_OPID_PAUSE, 0, NULL);
|
||||
} else if (voice_event == MUSIC_STOP_VOICE_EVENT) {
|
||||
gx8002_event_info("send STOP cmd");
|
||||
user_send_cmd_prepare(USER_CTRL_AVCTP_OPID_STOP, 0, NULL);
|
||||
}
|
||||
} else {
|
||||
if (voice_event == MUSIC_PLAY_VOICE_EVENT) {
|
||||
gx8002_event_info("send PLAY cmd");
|
||||
user_send_cmd_prepare(USER_CTRL_AVCTP_OPID_PLAY, 0, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case VOLUME_UP_VOICE_EVENT:
|
||||
gx8002_event_info("volume up");
|
||||
volume_up(4); //music: 0 ~ 16, call: 0 ~ 15, step: 25%
|
||||
//gx8002_recognize_tone_play();
|
||||
break;
|
||||
case VOLUME_DOWN_VOICE_EVENT:
|
||||
gx8002_event_info("volume down");
|
||||
volume_down(4); //music: 0 ~ 16, call: 0 ~ 15, step: 25%
|
||||
//gx8002_recognize_tone_play();
|
||||
break;
|
||||
case MUSIC_PREV_VOICE_EVENT:
|
||||
gx8002_event_info("volume PREV cmd");
|
||||
user_send_cmd_prepare(USER_CTRL_AVCTP_OPID_PREV, 0, NULL);
|
||||
break;
|
||||
case MUSIC_NEXT_VOICE_EVENT:
|
||||
gx8002_event_info("volume NEXT cmd");
|
||||
user_send_cmd_prepare(USER_CTRL_AVCTP_OPID_NEXT, 0, NULL);
|
||||
break;
|
||||
case CALL_ANSWER_VOICE_EVENT:
|
||||
if (get_call_status() == BT_CALL_INCOMING) {
|
||||
gx8002_event_info("volume ANSWER cmd");
|
||||
user_send_cmd_prepare(USER_CTRL_HFP_CALL_ANSWER, 0, NULL);
|
||||
}
|
||||
break;
|
||||
case CALL_HANG_UP_VOICE_EVENT:
|
||||
gx8002_event_info("volume HANG UP cmd");
|
||||
if ((get_call_status() >= BT_CALL_INCOMING) && (get_call_status() <= BT_CALL_ALERT)) {
|
||||
user_send_cmd_prepare(USER_CTRL_HFP_CALL_HANGUP, 0, NULL);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void gx8002_event_sync_tws_state_deal(void *_data, u16 len, bool rx)
|
||||
{
|
||||
u8 *data = (u8 *)_data;
|
||||
u8 voice_event = data[0];
|
||||
//if (rx) {
|
||||
gx8002_event_info("tws event rx sync: %d", voice_event);
|
||||
//gx8002_event_handle(voice_event);
|
||||
gx8002_voice_event_post_msg(voice_event);
|
||||
//}
|
||||
}
|
||||
|
||||
static void gx8002_sync_tws_event(u8 voice_event)
|
||||
{
|
||||
if (get_tws_sibling_connect_state() == TRUE) {
|
||||
tws_api_send_data_to_sibling(&voice_event, 1, TWS_FUNC_ID_VOICE_EVENT_SYNC);
|
||||
}
|
||||
}
|
||||
|
||||
void gx8002_event_state_update(u8 voice_event)
|
||||
{
|
||||
//tone_play(TONE_NORMAL, 1);
|
||||
if (get_tws_sibling_connect_state() == TRUE) {
|
||||
gx8002_sync_tws_event(voice_event);
|
||||
} else {
|
||||
gx8002_event_handle(voice_event);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void gx8002_voice_event_handle(u8 voice_event)
|
||||
{
|
||||
gx8002_event_handle(voice_event);
|
||||
}
|
||||
|
||||
REGISTER_TWS_FUNC_STUB(gx8002_voice_event_sync) = {
|
||||
.func_id = TWS_FUNC_ID_VOICE_EVENT_SYNC,
|
||||
.func = gx8002_event_sync_tws_state_deal,
|
||||
};
|
||||
|
||||
#endif /* #if TCFG_GX8002_NPU_ENABLE */
|
||||
@ -0,0 +1,736 @@
|
||||
#include "includes.h"
|
||||
#include "../gx_uart_upgrade.h"
|
||||
#include "../../gx8002_npu_api.h"
|
||||
#include "../gx_uart_upgrade_porting.h"
|
||||
//#include "../utils/gx_fifo.h"
|
||||
|
||||
#if GX8002_UPGRADE_APP_TOGGLE
|
||||
|
||||
typedef struct _gx8002_file_head_t {
|
||||
u16 head_crc;
|
||||
u16 data_crc;
|
||||
u32 addr;
|
||||
u32 len;
|
||||
u8 attr;
|
||||
u8 res;
|
||||
u16 index;
|
||||
char name[16];
|
||||
} gx8002_file_head_t;
|
||||
|
||||
struct app_ota_info {
|
||||
int update_result;
|
||||
u32 ufw_addr;
|
||||
u8 cur_seek_file;
|
||||
u8 update_role;
|
||||
OS_SEM ota_sem;
|
||||
OS_SEM rx_sem;
|
||||
cbuffer_t *cbuf_handle;
|
||||
update_op_api_t *file_ops;
|
||||
gx8002_file_head_t file_boot_head;
|
||||
gx8002_file_head_t file_bin_head;
|
||||
int packet_buf[UPGRADE_PACKET_SIZE / sizeof(int)];
|
||||
};
|
||||
|
||||
|
||||
enum GX_APP_UPDATE_ERR {
|
||||
GX_APP_UPDATE_ERR_NONE = 0,
|
||||
GX_APP_UPDATE_ERR_NOMEM = -100,
|
||||
GX_APP_UPDATE_ERR_FILE_READ,
|
||||
GX_APP_UPDATE_ERR_FILE_DIR_VERIFY,
|
||||
GX_APP_UPDATE_ERR_FILE_HEAD_VERIFY,
|
||||
GX_APP_UPDATE_ERR_FILE_DATA_VERIFY,
|
||||
|
||||
GX_APP_UPDATE_ERR_UPDATE_LOOP,
|
||||
GX_APP_UPDATE_ERR_UPDATE_STATE,
|
||||
};
|
||||
|
||||
enum GX8002_UPDATE_ROLE {
|
||||
GX8002_UPDATE_ROLE_NORMAL = 0,
|
||||
GX8002_UPDATE_ROLE_TWS_MASTER,
|
||||
GX8002_UPDATE_ROLE_TWS_SLAVE,
|
||||
};
|
||||
|
||||
static struct app_ota_info *ota_upgrade = NULL;
|
||||
#define __this ota_upgrade
|
||||
|
||||
#define GX8002_UFW_VERIFY_BUF_LEN 512
|
||||
#define GX8002_UFW_FILE_DATA_VERIFY_ENABLE 0
|
||||
|
||||
#define GX8002_OTA_UPGRADE_DEBUG_ENABLE 1
|
||||
|
||||
#define ota_upgrade_info printf
|
||||
|
||||
#if GX8002_OTA_UPGRADE_DEBUG_ENABLE
|
||||
#define ota_upgrade_debug printf
|
||||
#define ota_upgrade_put_buf put_buf
|
||||
#else
|
||||
#define ota_upgrade_debug(...)
|
||||
#define ota_upgrade_put_buf(...)
|
||||
#endif /* #if GX8002_DEBUG_ENABLE */
|
||||
|
||||
//=================================================================//
|
||||
// tws同步升级接口 //
|
||||
//=================================================================//
|
||||
extern void gx8002_uart_app_ota_tws_update_register_handle(void);
|
||||
extern int gx8002_uart_app_ota_tws_update_init(void *priv);
|
||||
extern int gx8002_uart_app_ota_tws_update_sync_start(u8 *buf, u16 len);
|
||||
extern int gx8002_uart_app_ota_tws_update_sync_pend(void);
|
||||
extern int gx8002_uart_app_ota_tws_update_sync_post(void);
|
||||
extern int gx8002_uart_app_ota_tws_update_sync_data(u8 *buf, u16 len);
|
||||
extern int gx8002_uart_app_ota_tws_update_sync_respond(void);
|
||||
extern int gx8002_uart_app_ota_tws_update_close(void);
|
||||
extern int gx8002_uart_app_ota_tws_update_sync_result(int result);
|
||||
extern int gx8002_uart_app_ota_tws_update_sync_result_get(void);
|
||||
|
||||
//=================================================================//
|
||||
// 使用fifo作数据缓存 //
|
||||
//=================================================================//
|
||||
////////////// FW Stream Porting //////////////////
|
||||
static u32 fw_stream_get_file_addr(u32 addr)
|
||||
{
|
||||
return __this->ufw_addr + addr;
|
||||
}
|
||||
|
||||
#define STREAM_FIFO_BLOCK_TOTAL 16
|
||||
#define STREAM_FIFO_TIMEOUT_MS (5000)
|
||||
|
||||
static int fw_stream_open(FW_IMAGE_TYPE img_type)
|
||||
{
|
||||
if (__this->cbuf_handle == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fw_stream_close(FW_IMAGE_TYPE img_type)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
//gx8002线程同步数据
|
||||
static int fw_stream_read(FW_IMAGE_TYPE img_type, unsigned char *buf, unsigned int len)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
static u32 read_cnt = 0;
|
||||
|
||||
if (__this->cbuf_handle) {
|
||||
if (cbuf_get_data_len(__this->cbuf_handle) < len) {
|
||||
os_sem_set(&(__this->rx_sem), 0);
|
||||
os_sem_pend(&(__this->rx_sem), msecs_to_jiffies(STREAM_FIFO_TIMEOUT_MS));
|
||||
}
|
||||
ret = cbuf_read(__this->cbuf_handle, buf, len);
|
||||
if (ret < len) {
|
||||
ota_upgrade_info("read errm ret = 0x%x, len = 0x%x", ret, len);
|
||||
return -1;
|
||||
}
|
||||
if (__this->update_role == GX8002_UPDATE_ROLE_TWS_MASTER) {
|
||||
//TODO: tws sync data
|
||||
gx8002_uart_app_ota_tws_update_sync_data(buf, (u16)len);
|
||||
if (gx8002_uart_app_ota_tws_update_sync_pend()) {
|
||||
ota_upgrade_info("read timeout");
|
||||
ret = -1;
|
||||
}
|
||||
} else if (__this->update_role == GX8002_UPDATE_ROLE_TWS_SLAVE) {
|
||||
//TODO: tws respond
|
||||
gx8002_uart_app_ota_tws_update_sync_respond();
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fw_stream_get_flash_img_info(flash_img_info_t *info)
|
||||
{
|
||||
if (info == NULL) {
|
||||
return -1;
|
||||
}
|
||||
info->img_size = __this->file_bin_head.len;
|
||||
|
||||
ota_upgrade_debug("%s, img_size = 0x%x", __func__, info->img_size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gx8002_ota_data_receive(u8 *data, u32 size)
|
||||
{
|
||||
gx8002_file_head_t *file_receive_table[] = {
|
||||
&(__this->file_boot_head),
|
||||
&(__this->file_bin_head)
|
||||
};
|
||||
|
||||
u32 file_addr = 0;
|
||||
u32 remain_len = 0;
|
||||
u32 rlen = 0;
|
||||
u16 ret = 0;
|
||||
|
||||
for (u32 i = 0; i < ARRAY_SIZE(file_receive_table); i++) {
|
||||
file_addr = fw_stream_get_file_addr((file_receive_table[i])->addr);
|
||||
__this->file_ops->f_seek(NULL, SEEK_SET, file_addr);
|
||||
remain_len = (file_receive_table[i])->len;
|
||||
ota_upgrade_debug("receive %s data, len = 0x%x", (file_receive_table[i])->name, remain_len);
|
||||
while (remain_len) {
|
||||
if (__this->update_result != GX_APP_UPDATE_ERR_NONE) {
|
||||
return __this->update_result;
|
||||
}
|
||||
rlen = (remain_len > size) ? size : remain_len;
|
||||
ret = __this->file_ops->f_read(NULL, data, rlen);
|
||||
|
||||
if ((u16) - 1 == ret) {
|
||||
ota_upgrade_debug("f_read %s err", (file_receive_table[i])->name);
|
||||
return GX_APP_UPDATE_ERR_FILE_READ;
|
||||
}
|
||||
//TODO: TWS send data sync
|
||||
while (cbuf_is_write_able(__this->cbuf_handle, rlen) < rlen) {
|
||||
/* ota_upgrade_debug("aaa"); */
|
||||
os_time_dly(2);
|
||||
/* ota_upgrade_debug("bbb"); */
|
||||
if (__this->update_result != GX_APP_UPDATE_ERR_NONE) {
|
||||
return __this->update_result;
|
||||
}
|
||||
}
|
||||
if (cbuf_write(__this->cbuf_handle, data, rlen) != rlen) {
|
||||
ota_upgrade_debug("cbuf full !!!");
|
||||
}
|
||||
os_sem_post(&(__this->rx_sem));
|
||||
|
||||
remain_len -= rlen;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int gx8002_ota_data_passive_receive(u8 *data, u32 size)
|
||||
{
|
||||
int ret = 0;
|
||||
if ((__this == NULL) || (__this->cbuf_handle == NULL)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (__this->update_role != GX8002_UPDATE_ROLE_TWS_SLAVE) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (cbuf_is_write_able(__this->cbuf_handle, size) < size) {
|
||||
ota_upgrade_info("passive receive cbuf full !!!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = cbuf_write(__this->cbuf_handle, data, size);
|
||||
os_sem_post(&(__this->rx_sem));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int __gx8002_ufw_file_data_verify(u32 file_addr, u32 file_len, u16 target_crc, u16(*func_read)(void *fp, u8 *buff, u16 len))
|
||||
{
|
||||
u8 *rbuf = malloc(GX8002_UFW_VERIFY_BUF_LEN);
|
||||
u16 crc_interval = 0;
|
||||
u16 r_len = 0;
|
||||
int ret = GX_APP_UPDATE_ERR_NONE;
|
||||
|
||||
if (rbuf == NULL) {
|
||||
return GX_APP_UPDATE_ERR_NOMEM;
|
||||
}
|
||||
|
||||
while (file_len) {
|
||||
r_len = (file_len > GX8002_UFW_VERIFY_BUF_LEN) ? GX8002_UFW_VERIFY_BUF_LEN : file_len;
|
||||
if (func_read) {
|
||||
func_read(NULL, rbuf, r_len);
|
||||
}
|
||||
|
||||
crc_interval = CRC16_with_initval(rbuf, r_len, crc_interval);
|
||||
|
||||
file_addr += r_len;
|
||||
file_len -= r_len;
|
||||
}
|
||||
|
||||
if (crc_interval != target_crc) {
|
||||
ret = GX_APP_UPDATE_ERR_FILE_DATA_VERIFY;
|
||||
}
|
||||
|
||||
_file_data_verify_end:
|
||||
if (rbuf) {
|
||||
free(rbuf);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __gx8002_ufw_file_head_verify(gx8002_file_head_t *file_head)
|
||||
{
|
||||
int ret = GX_APP_UPDATE_ERR_NONE;
|
||||
u16 calc_crc = CRC16(&(file_head->data_crc), sizeof(gx8002_file_head_t) - 2);
|
||||
|
||||
if (calc_crc != file_head->head_crc) {
|
||||
ret = GX_APP_UPDATE_ERR_FILE_DATA_VERIFY;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int gx8002_ufw_file_verify(u32 ufw_addr, update_op_api_t *file_ops)
|
||||
{
|
||||
int ret = 0;
|
||||
u16 r_len = 0;
|
||||
u8 file_cnt = 0;
|
||||
gx8002_file_head_t *file_head;
|
||||
u8 *rbuf = (u8 *)malloc(GX8002_UFW_VERIFY_BUF_LEN);
|
||||
if (rbuf == NULL) {
|
||||
ret = GX_APP_UPDATE_ERR_NOMEM;
|
||||
goto _verify_end;
|
||||
}
|
||||
|
||||
file_ops->f_seek(NULL, SEEK_SET, ufw_addr);
|
||||
r_len = file_ops->f_read(NULL, rbuf, GX8002_UFW_VERIFY_BUF_LEN);
|
||||
|
||||
if ((u16) - 1 == r_len) {
|
||||
ret = GX_APP_UPDATE_ERR_FILE_READ;
|
||||
ota_upgrade_debug("f_read err");
|
||||
goto _verify_end;
|
||||
}
|
||||
|
||||
file_head = (gx8002_file_head_t *)rbuf;
|
||||
ret = __gx8002_ufw_file_head_verify(file_head);
|
||||
if (ret != GX_APP_UPDATE_ERR_NONE) {
|
||||
ota_upgrade_debug("gx8002 ufw file head verify err");
|
||||
goto _verify_end;
|
||||
}
|
||||
|
||||
if (strcmp(file_head->name, "gx8002")) {
|
||||
ret = GX_APP_UPDATE_ERR_FILE_HEAD_VERIFY;
|
||||
ota_upgrade_debug("gx8002 ufw file head name err");
|
||||
goto _verify_end;
|
||||
}
|
||||
|
||||
ota_upgrade_info("find: %s", file_head->name);
|
||||
do {
|
||||
file_head++;
|
||||
ret = __gx8002_ufw_file_head_verify(file_head);
|
||||
if (ret != GX_APP_UPDATE_ERR_NONE) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcmp(file_head->name, "gx8002.boot") == 0) {
|
||||
ota_upgrade_info("find: %s", file_head->name);
|
||||
memcpy(&(__this->file_boot_head), file_head, sizeof(gx8002_file_head_t));
|
||||
#if GX8002_UFW_FILE_DATA_VERIFY_ENABLE
|
||||
file_ops->f_seek(NULL, SEEK_SET, __this->ufw_addr + file_head->addr);
|
||||
ret = __gx8002_ufw_file_data_verify(__this->ufw_addr + file_head->addr, file_head->len, file_head->data_crc, file_ops->f_read);
|
||||
if (ret == GX_APP_UPDATE_ERR_NONE) {
|
||||
file_cnt++;
|
||||
} else {
|
||||
ota_upgrade_debug("gx8002.boot file head verify err");
|
||||
break;
|
||||
}
|
||||
#else
|
||||
file_cnt++;
|
||||
#endif /* #if GX8002_UFW_FILE_DATA_VERIFY_ENABLE */
|
||||
}
|
||||
if (strcmp(file_head->name, "mcu_nor.bin") == 0) {
|
||||
ota_upgrade_info("find: %s", file_head->name);
|
||||
memcpy(&(__this->file_bin_head), file_head, sizeof(gx8002_file_head_t));
|
||||
#if GX8002_UFW_FILE_DATA_VERIFY_ENABLE
|
||||
file_ops->f_seek(NULL, SEEK_SET, __this->ufw_addr + file_head->addr);
|
||||
ret = __gx8002_ufw_file_data_verify(__this->ufw_addr + file_head->addr, file_head->len, file_head->data_crc, file_ops->f_read);
|
||||
if (ret == GX_APP_UPDATE_ERR_NONE) {
|
||||
file_cnt++;
|
||||
} else {
|
||||
ota_upgrade_debug("mcu_nor.bin file head verify err");
|
||||
break;
|
||||
}
|
||||
#else
|
||||
file_cnt++;
|
||||
#endif /* #if GX8002_UFW_FILE_DATA_VERIFY_ENABLE */
|
||||
}
|
||||
} while (file_head->index == 0);
|
||||
|
||||
if ((ret != GX_APP_UPDATE_ERR_NONE) && (file_cnt != 2)) {
|
||||
ret = GX_APP_UPDATE_ERR_FILE_DATA_VERIFY;
|
||||
ota_upgrade_debug("file_cnt: %d err", file_cnt);
|
||||
goto _verify_end;
|
||||
}
|
||||
|
||||
ota_upgrade_info("find file_cnt: %d, verify ok", file_cnt);
|
||||
|
||||
_verify_end:
|
||||
if (rbuf) {
|
||||
free(rbuf);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
///////// status info /////////////
|
||||
static const char *status_info_str[UPGRADE_STAGE_NONE][UPGRADE_STATUS_NONE] = {
|
||||
// UPGRADE_STAGE_HANDSHAKE
|
||||
{"handshake start\n", NULL, "handshake ok\n", "handshake err\n"},
|
||||
// UPGRADE_STAGE_BOOT_HEADER
|
||||
{"boot header start\n", NULL, "boot header ok\n", "boot header err\n"},
|
||||
// UPGRADE_STAGE_BOOT_S1
|
||||
{"boot stage1 start\n", "boot stage1 downloading\n", "boot stage1 ok\n", "boot stage1 err\n"},
|
||||
// UPGRADE_STAGE_BOOT_S2
|
||||
{"boot stage2 start\n", "boot stage2 downloading\n", "boot stage2 ok\n", "boot stage2 err\n"},
|
||||
// UPGRADE_STAGE_FLASH_IMG
|
||||
{"flash img start\n", "flash img downloading\n", "flash img ok\n", "flash img err\n"},
|
||||
};
|
||||
|
||||
static void gx8002_upgrade_status_cb(upgrade_stage_e stage, upgrade_status_e status)
|
||||
{
|
||||
const char *reply_str = status_info_str[stage][status];
|
||||
if (reply_str != NULL) {
|
||||
ota_upgrade_info("status info: %s\n", reply_str);
|
||||
}
|
||||
}
|
||||
|
||||
static int gx8002_upgrade_task(void *param)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ota_upgrade_info("---- gx8002 ota start ----");
|
||||
gx8002_upgrade_cold_reset();
|
||||
|
||||
ret = gx_uart_upgrade_proc();
|
||||
|
||||
gx8002_normal_cold_reset();
|
||||
ota_upgrade_info("---- gx8002 ota over ----");
|
||||
|
||||
if (ret < 0) {
|
||||
gx8002_update_end_post_msg(0);
|
||||
} else {
|
||||
gx8002_update_end_post_msg(1);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
//===================================================================//
|
||||
/*
|
||||
@breif: ota流程回调: 初始化函数, 公共流程
|
||||
@parma: addr: 访问外置芯片固件地址
|
||||
@parma: file_ops: 访问外置芯片固件文件操作接口
|
||||
@return: 1) GX_APP_UPDATE_ERR_NONE = 0: 初始化成功
|
||||
2) < 0: 初始化失败
|
||||
*/
|
||||
//===================================================================//
|
||||
int gx8002_app_ota_start(int (*complete_callback)(void))
|
||||
{
|
||||
int ret = GX_APP_UPDATE_ERR_NONE;
|
||||
|
||||
ota_upgrade_debug("%s", __func__);
|
||||
|
||||
if (__this->cbuf_handle == NULL) {
|
||||
__this->cbuf_handle = (cbuffer_t *)malloc(sizeof(cbuffer_t) + (UPGRADE_PACKET_SIZE * STREAM_FIFO_BLOCK_TOTAL));
|
||||
if (__this->cbuf_handle == NULL) {
|
||||
ret = GX_APP_UPDATE_ERR_NOMEM;
|
||||
return ret;
|
||||
}
|
||||
cbuf_init(__this->cbuf_handle, __this->cbuf_handle + 1, (UPGRADE_PACKET_SIZE * STREAM_FIFO_BLOCK_TOTAL));
|
||||
}
|
||||
|
||||
os_sem_create(&(__this->rx_sem), 0);
|
||||
|
||||
os_taskq_post_msg("gx8002", 2, GX8002_MSG_UPDATE, GX8002_UPDATE_TYPE_APP);
|
||||
|
||||
if (complete_callback) {
|
||||
if (complete_callback()) {
|
||||
return GX_APP_UPDATE_ERR_UPDATE_LOOP;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
//===================================================================//
|
||||
/*
|
||||
@breif: ota流程回调: 释放资源
|
||||
@parma: void
|
||||
@return: 1) GX_APP_UPDATE_ERR_NONE = 0: 初始化成功
|
||||
2) < 0: 初始化失败
|
||||
*/
|
||||
//===================================================================//
|
||||
static int gx8002_app_ota_close(void)
|
||||
{
|
||||
if (__this->update_role == GX8002_UPDATE_ROLE_TWS_SLAVE) {
|
||||
//从机出口
|
||||
gx8002_uart_app_ota_tws_update_sync_result(__this->update_result);
|
||||
|
||||
if (__this->cbuf_handle) {
|
||||
free(__this->cbuf_handle);
|
||||
__this->cbuf_handle = NULL;
|
||||
}
|
||||
|
||||
if (__this) {
|
||||
free(__this);
|
||||
__this = NULL;
|
||||
}
|
||||
gx8002_uart_app_ota_tws_update_close();
|
||||
} else {
|
||||
os_sem_post(&(__this->ota_sem));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//===================================================================//
|
||||
/*
|
||||
@breif: 从机升级开始
|
||||
@parma: void
|
||||
@return: 1) GX_APP_UPDATE_ERR_NONE = 0: 初始化成功
|
||||
2) < 0: 初始化失败
|
||||
*/
|
||||
//===================================================================//
|
||||
int gx8002_app_ota_passive_start(int (*complete_callback)(void), u8 *ota_data, u16 len)
|
||||
{
|
||||
int ret = GX_APP_UPDATE_ERR_NONE;
|
||||
|
||||
ota_upgrade_debug("%s", __func__);
|
||||
if (__this) {
|
||||
return GX_APP_UPDATE_ERR_UPDATE_STATE;
|
||||
}
|
||||
|
||||
__this = zalloc(sizeof(struct app_ota_info));
|
||||
if (__this == NULL) {
|
||||
return GX_APP_UPDATE_ERR_NOMEM;
|
||||
}
|
||||
|
||||
ASSERT(len == sizeof(gx8002_file_head_t));
|
||||
|
||||
memcpy((u8 *) & (__this->file_bin_head), ota_data, sizeof(gx8002_file_head_t));
|
||||
|
||||
__this->update_role = GX8002_UPDATE_ROLE_TWS_SLAVE;
|
||||
|
||||
ret = gx8002_app_ota_start(complete_callback);
|
||||
|
||||
if (ret) {
|
||||
gx8002_app_ota_close();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
//===================================================================//
|
||||
/*
|
||||
@breif: ota流程回调: 初始化函数, 主机流程
|
||||
@parma: priv: 访问外置芯片固件地址
|
||||
@parma: file_ops: 访问外置芯片固件文件操作接口
|
||||
@return: 1) GX_APP_UPDATE_ERR_NONE = 0: 初始化成功
|
||||
2) < 0: 初始化失败
|
||||
*/
|
||||
//===================================================================//
|
||||
static int gx8002_chip_update_init(void *priv, update_op_api_t *file_ops)
|
||||
{
|
||||
int ret = GX_APP_UPDATE_ERR_NONE;
|
||||
|
||||
if (__this) {
|
||||
return GX_APP_UPDATE_ERR_UPDATE_STATE;
|
||||
}
|
||||
|
||||
user_chip_update_info_t *update_info = (user_chip_update_info_t *)priv;
|
||||
|
||||
__this = zalloc(sizeof(struct app_ota_info));
|
||||
if (__this == NULL) {
|
||||
return GX_APP_UPDATE_ERR_NOMEM;
|
||||
}
|
||||
|
||||
__this->ufw_addr = update_info->addr;
|
||||
__this->file_ops = file_ops;
|
||||
__this->update_role = GX8002_UPDATE_ROLE_NORMAL;
|
||||
__this->update_result = GX_APP_UPDATE_ERR_NONE;
|
||||
|
||||
__this->cur_seek_file = FW_FLASH_MAX;
|
||||
|
||||
ota_upgrade_info("%s: ufw_addr = 0x%x", __func__, __this->ufw_addr);
|
||||
|
||||
ret = gx8002_ufw_file_verify(__this->ufw_addr, file_ops);
|
||||
|
||||
ota_upgrade_info("%s, ret = %d", __func__, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
//===================================================================//
|
||||
/*
|
||||
@breif: ota流程回调: 获取升级问文件长度, 用于计算升级进度, 主机调用
|
||||
@parma: void
|
||||
@return: 1) 升级长度(int)
|
||||
2) = 0: 升级状态出错
|
||||
*/
|
||||
//===================================================================//
|
||||
static int gx8002_chip_update_get_len(void)
|
||||
{
|
||||
int update_len = 0;
|
||||
|
||||
if (__this == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
update_len = __this->file_boot_head.len + __this->file_bin_head.len;
|
||||
ota_upgrade_info("%s: boot_len = 0x%x, bin_len = 0x%x, update_len = 0x%x", __func__, __this->file_boot_head.len, __this->file_bin_head.len, update_len);
|
||||
|
||||
return update_len;
|
||||
}
|
||||
|
||||
//===================================================================//
|
||||
/*
|
||||
@breif: ota流程回调: 升级主流程, 主机调用
|
||||
@parma: void *priv 用于tws同步升级接口(update_op_tws_api_t), 非tws同步升级设置未NULL即可
|
||||
@return: 1) = 0: 升级成功
|
||||
2) < 0: 升级失败
|
||||
*/
|
||||
//===================================================================//
|
||||
static int gx8002_chip_update_loop(void *priv)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (__this == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ota_upgrade_debug("%s", __func__);
|
||||
|
||||
int (*start_callback)(void) = NULL;
|
||||
|
||||
if (priv) {
|
||||
__this->update_role = GX8002_UPDATE_ROLE_TWS_MASTER;
|
||||
|
||||
ret = gx8002_uart_app_ota_tws_update_init(priv);
|
||||
if (ret) {
|
||||
goto __update_end;
|
||||
}
|
||||
gx8002_uart_app_ota_tws_update_sync_start((u8 *) & (__this->file_bin_head), sizeof(gx8002_file_head_t));
|
||||
|
||||
start_callback = gx8002_uart_app_ota_tws_update_sync_pend;
|
||||
}
|
||||
|
||||
os_sem_create(&(__this->ota_sem), 0);
|
||||
|
||||
ret = gx8002_app_ota_start(start_callback);
|
||||
if (ret != GX_APP_UPDATE_ERR_NONE) {
|
||||
goto __update_end;
|
||||
}
|
||||
|
||||
//update 线程接收数据
|
||||
ret = gx8002_ota_data_receive((u8 *)(__this->packet_buf), sizeof(__this->packet_buf));
|
||||
if (ret != GX_APP_UPDATE_ERR_NONE) {
|
||||
goto __update_end;
|
||||
}
|
||||
|
||||
//等待升级完成
|
||||
os_sem_pend(&(__this->ota_sem), 0);
|
||||
|
||||
if (__this->update_result != GX_APP_UPDATE_ERR_NONE) {
|
||||
ota_upgrade_info("gx8002 update failed.");
|
||||
} else {
|
||||
ota_upgrade_info("gx8002 update succ.");
|
||||
}
|
||||
|
||||
ret = __this->update_result;
|
||||
|
||||
__update_end:
|
||||
if (priv) {
|
||||
ret |= gx8002_uart_app_ota_tws_update_sync_result_get();
|
||||
gx8002_uart_app_ota_tws_update_close();
|
||||
}
|
||||
if (__this->cbuf_handle) {
|
||||
free(__this->cbuf_handle);
|
||||
__this->cbuf_handle = NULL;
|
||||
}
|
||||
if (__this) {
|
||||
free(__this);
|
||||
__this = NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
//===================================================================//
|
||||
/*
|
||||
@breif: 需要升级流程提供注册接口
|
||||
@parma: user_chip_update_file_name: 外置芯片升级文件名, 包含在update.ufw文件中
|
||||
@parma: user_update_handle: 当update.ufw存在升级文件时回调该函数升级外置芯片固件
|
||||
@parma: addr: 外置芯片固件在update.ufw升级文件中地址
|
||||
@parma: file_ops: 访问外置芯片固件文件操作接口
|
||||
*/
|
||||
//===================================================================//
|
||||
static const user_chip_update_t gx8002_user_chip_update_instance = {
|
||||
.file_name = "gx8002.bin",
|
||||
.update_init = gx8002_chip_update_init,
|
||||
.update_get_len = gx8002_chip_update_get_len,
|
||||
.update_loop = gx8002_chip_update_loop,
|
||||
};
|
||||
|
||||
//===================================================================//
|
||||
/*
|
||||
@breif: 注册ota流程回调, 提供给gx8002线程调用
|
||||
@parma: void
|
||||
@return: void
|
||||
*/
|
||||
//===================================================================//
|
||||
void gx8002_uart_app_ota_update_register_handle(void)
|
||||
{
|
||||
register_user_chip_update_handle(&gx8002_user_chip_update_instance);
|
||||
|
||||
#if GX8002_UPGRADE_APP_TWS_TOGGLE
|
||||
gx8002_uart_app_ota_tws_update_register_handle();
|
||||
#endif /* #if GX8002_UPGRADE_APP_TWS_TOGGLE */
|
||||
}
|
||||
|
||||
//===================================================================//
|
||||
/*
|
||||
@breif: 外置芯片启动升级流程, 提供给gx8002线程调用
|
||||
@parma: void
|
||||
@return: 1) 0: 升级成功
|
||||
2) -1: 升级失败
|
||||
*/
|
||||
//===================================================================//
|
||||
int gx8002_uart_app_ota_init(void)
|
||||
{
|
||||
int ret = 0;
|
||||
upgrade_uart_t uart_ops;
|
||||
|
||||
ota_upgrade_info("gx8002_uart_app_ota start >>>>");
|
||||
|
||||
uart_ops.open = gx_upgrade_uart_porting_open;
|
||||
uart_ops.close = gx_upgrade_uart_porting_close;
|
||||
uart_ops.send = gx_upgrade_uart_porting_write;
|
||||
uart_ops.wait_reply = gx_uart_upgrade_porting_wait_reply;
|
||||
|
||||
fw_stream_t fw_stream_ops;
|
||||
fw_stream_ops.open = fw_stream_open;
|
||||
fw_stream_ops.close = fw_stream_close;
|
||||
fw_stream_ops.read = fw_stream_read;
|
||||
fw_stream_ops.get_flash_img_info = fw_stream_get_flash_img_info;
|
||||
|
||||
gx_uart_upgrade_init(&uart_ops, &fw_stream_ops, gx8002_upgrade_status_cb);
|
||||
|
||||
ret = gx8002_upgrade_task(NULL);
|
||||
|
||||
if (ret < 0) {
|
||||
__this->update_result = GX_APP_UPDATE_ERR_UPDATE_LOOP;
|
||||
} else {
|
||||
__this->update_result = GX_APP_UPDATE_ERR_NONE;
|
||||
}
|
||||
|
||||
gx8002_app_ota_close();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#else /* #if GX8002_UPGRADE_APP_TOGGLE */
|
||||
|
||||
int gx8002_uart_app_ota_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* #if GX8002_UPGRADE_APP_TOGGLE */
|
||||
|
||||
@ -0,0 +1,265 @@
|
||||
#include "includes.h"
|
||||
#include "../gx_uart_upgrade.h"
|
||||
#include "../../gx8002_npu_api.h"
|
||||
#include "../gx_uart_upgrade_porting.h"
|
||||
//#include "../utils/gx_fifo.h"
|
||||
|
||||
#if (GX8002_UPGRADE_APP_TWS_TOGGLE && OTA_TWS_SAME_TIME_ENABLE)
|
||||
|
||||
struct gx8002_tws_update {
|
||||
update_op_tws_api_t *tws_handle;
|
||||
OS_SEM tws_sync_sem;
|
||||
u8 slave_result;
|
||||
};
|
||||
|
||||
enum GX8002_TWS_UPDATE_CMD {
|
||||
GX8002_TWS_UPDATE_CMD_START = 'G',
|
||||
GX8002_TWS_UPDATE_CMD_UFW_DATA,
|
||||
GX8002_TWS_UPDATE_CMD_RESPOND,
|
||||
GX8002_TWS_UPDATE_CMD_RESULT,
|
||||
};
|
||||
|
||||
static struct gx8002_tws_update *tws_update = NULL;
|
||||
|
||||
#define GX8002_OTA_UPGRADE_DEBUG_ENABLE 0
|
||||
|
||||
#define ota_upgrade_info printf
|
||||
|
||||
#if GX8002_OTA_UPGRADE_DEBUG_ENABLE
|
||||
#define ota_upgrade_debug printf
|
||||
#define ota_upgrade_put_buf put_buf
|
||||
#else
|
||||
#define ota_upgrade_debug(...)
|
||||
#define ota_upgrade_put_buf(...)
|
||||
#endif /* #if GX8002_DEBUG_ENABLE */
|
||||
|
||||
#define GX8002_TWS_SYNC_TIMEOUT 300
|
||||
|
||||
|
||||
extern int gx8002_ota_data_passive_receive(u8 *data, u32 size);
|
||||
extern int gx8002_app_ota_passive_start(int (*complete_callback)(void), u8 *ota_data, u16 len);
|
||||
extern update_op_tws_api_t *get_tws_update_api(void);
|
||||
extern void tws_update_register_user_chip_update_handle(void (*update_handle)(void *data, u32 len));
|
||||
|
||||
int gx8002_uart_app_ota_tws_update_sync_pend(void)
|
||||
{
|
||||
ota_upgrade_debug("%s", __func__);
|
||||
if (tws_update) {
|
||||
if (os_sem_pend(&(tws_update->tws_sync_sem), GX8002_TWS_SYNC_TIMEOUT) == OS_TIMEOUT) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gx8002_uart_app_ota_tws_update_sync_post(void)
|
||||
{
|
||||
ota_upgrade_debug("%s", __func__);
|
||||
if (tws_update) {
|
||||
os_sem_post(&(tws_update->tws_sync_sem));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gx8002_uart_app_ota_tws_update_sync_result(int result)
|
||||
{
|
||||
ota_upgrade_info("%s: result: 0x%x", __func__, result);
|
||||
if (tws_update) {
|
||||
if (result) {
|
||||
tws_update->slave_result = 'N';
|
||||
} else {
|
||||
tws_update->slave_result = 'O';
|
||||
}
|
||||
if (tws_update->tws_handle) {
|
||||
tws_update->tws_handle->tws_ota_user_chip_update_send(GX8002_TWS_UPDATE_CMD_RESULT, &(tws_update->slave_result), 1);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gx8002_uart_app_ota_tws_update_sync_result_get(void)
|
||||
{
|
||||
if (tws_update) {
|
||||
if (gx8002_uart_app_ota_tws_update_sync_pend()) {
|
||||
ota_upgrade_info("%s timeout", __func__);
|
||||
return -1;
|
||||
}
|
||||
if (tws_update->slave_result == 'O') {
|
||||
ota_upgrade_info("%s, get: O", __func__);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
ota_upgrade_info("%s state err", __func__);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int gx8002_uart_app_ota_tws_update_sync_respond(void)
|
||||
{
|
||||
ota_upgrade_debug("%s", __func__);
|
||||
if (tws_update) {
|
||||
if (tws_update->tws_handle) {
|
||||
tws_update->tws_handle->tws_ota_user_chip_update_send(GX8002_TWS_UPDATE_CMD_RESPOND, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gx8002_uart_app_ota_tws_update_sync_start(u8 *buf, u16 len)
|
||||
{
|
||||
if (tws_update) {
|
||||
if (tws_update->tws_handle) {
|
||||
tws_update->tws_handle->tws_ota_user_chip_update_send(GX8002_TWS_UPDATE_CMD_START, buf, len);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gx8002_uart_app_ota_tws_update_sync_data(u8 *buf, u16 len)
|
||||
{
|
||||
if (tws_update) {
|
||||
if (tws_update->tws_handle) {
|
||||
tws_update->tws_handle->tws_ota_user_chip_update_send(GX8002_TWS_UPDATE_CMD_UFW_DATA, buf, len);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gx8002_uart_app_ota_tws_update_init(void *priv)
|
||||
{
|
||||
ota_upgrade_info("%s", __func__);
|
||||
|
||||
if (tws_update) {
|
||||
free(tws_update);
|
||||
}
|
||||
|
||||
if (priv == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
tws_update = zalloc(sizeof(struct gx8002_tws_update));
|
||||
if (tws_update == NULL) {
|
||||
return -1;
|
||||
}
|
||||
tws_update->tws_handle = priv;
|
||||
|
||||
os_sem_create(&(tws_update->tws_sync_sem), 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int gx8002_uart_app_ota_tws_update_close(void)
|
||||
{
|
||||
if (tws_update) {
|
||||
free(tws_update);
|
||||
|
||||
tws_update = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gx8002_uart_app_ota_tws_update_handle(void *data, u32 len)
|
||||
{
|
||||
u8 *rx_packet = (u8 *)data;
|
||||
int ret = 0;
|
||||
|
||||
ota_upgrade_debug("receive cmd 0x%x, data len = 0x%x", rx_packet[0], len - 1);
|
||||
|
||||
switch (rx_packet[0]) {
|
||||
case GX8002_TWS_UPDATE_CMD_START:
|
||||
gx8002_uart_app_ota_tws_update_init(get_tws_update_api());
|
||||
ret = gx8002_app_ota_passive_start(gx8002_uart_app_ota_tws_update_sync_respond, rx_packet + 1, len - 1);
|
||||
if (ret) {
|
||||
gx8002_uart_app_ota_tws_update_close();
|
||||
}
|
||||
break;
|
||||
|
||||
case GX8002_TWS_UPDATE_CMD_UFW_DATA:
|
||||
gx8002_ota_data_passive_receive(rx_packet + 1, len - 1);
|
||||
break;
|
||||
|
||||
case GX8002_TWS_UPDATE_CMD_RESPOND:
|
||||
gx8002_uart_app_ota_tws_update_sync_post();
|
||||
break;
|
||||
|
||||
case GX8002_TWS_UPDATE_CMD_RESULT:
|
||||
ota_upgrade_info("result: 0x%x", rx_packet[1]);
|
||||
if (tws_update) {
|
||||
tws_update->slave_result = rx_packet[1];
|
||||
}
|
||||
gx8002_uart_app_ota_tws_update_sync_post();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void gx8002_uart_app_ota_tws_update_register_handle(void)
|
||||
{
|
||||
tws_update_register_user_chip_update_handle(gx8002_uart_app_ota_tws_update_handle);
|
||||
}
|
||||
|
||||
#else /* #if (GX8002_UPGRADE_APP_TWS_TOGGLE && OTA_TWS_SAME_TIME_ENABLE) */
|
||||
|
||||
void gx8002_uart_app_ota_tws_update_register_handle(void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int gx8002_uart_app_ota_tws_update_init(void *priv)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gx8002_uart_app_ota_tws_update_sync_pend(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gx8002_uart_app_ota_tws_update_sync_post(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gx8002_uart_app_ota_tws_update_sync_data(u8 *buf, u16 len)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gx8002_uart_app_ota_tws_update_sync_respond(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gx8002_uart_app_ota_tws_update_close(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gx8002_uart_app_ota_tws_update_sync_start(u8 *buf, u16 len)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gx8002_uart_app_ota_tws_update_sync_result(int result)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int gx8002_uart_app_ota_tws_update_sync_result_get(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* #if (GX8002_UPGRADE_APP_TWS_TOGGLE && OTA_TWS_SAME_TIME_ENABLE) */
|
||||
|
||||
482
apps/common/device/gx8002_npu/gx8002_upgrade/gx_uart_upgrade.c
Normal file
482
apps/common/device/gx8002_npu/gx8002_upgrade/gx_uart_upgrade.c
Normal file
@ -0,0 +1,482 @@
|
||||
#include "includes.h"
|
||||
#include "gx_uart_upgrade.h"
|
||||
#include "../gx8002_npu_api.h"
|
||||
|
||||
#if GX8002_UPGRADE_TOGGLE
|
||||
|
||||
#define GX_UPGRADE_DEBUG 0
|
||||
#if GX_UPGRADE_DEBUG
|
||||
//#define upgrade_debug(fmt, ...) y_printf("[gx_uart_upgrade]: " fmt, ##__VA_ARGS__)
|
||||
#define upgrade_debug printf
|
||||
#else
|
||||
#define upgrade_debug(fmt, ...)
|
||||
#endif
|
||||
|
||||
#define HANDSHAKE_BAUDRATE 576000
|
||||
#define UART_REPLY_TIMEOUT_MS 5000
|
||||
|
||||
static upgrade_uart_t uart_ops;
|
||||
static fw_stream_t fw_stream_ops;
|
||||
static upgrade_status_cb status_callback;
|
||||
|
||||
typedef struct {
|
||||
unsigned short chip_id;
|
||||
unsigned char chip_type;
|
||||
unsigned char chip_version;
|
||||
|
||||
unsigned short boot_delay;
|
||||
unsigned char baud_rate;
|
||||
unsigned char reserved_1;
|
||||
|
||||
unsigned int stage1_size;
|
||||
unsigned int stage2_baud_rate;
|
||||
unsigned int stage2_size;
|
||||
unsigned int stage2_checksum;
|
||||
unsigned char reserved[8];
|
||||
} __attribute__((packed)) boot_header_t;
|
||||
|
||||
static boot_header_t boot_header;
|
||||
static unsigned char data_buf[UPGRADE_PACKET_SIZE];
|
||||
static upgrade_stage_e current_stage;
|
||||
static int upgrade_initialized = 0;
|
||||
|
||||
static inline void set_upgrade_stage(upgrade_stage_e stage)
|
||||
{
|
||||
current_stage = stage;
|
||||
}
|
||||
|
||||
static inline upgrade_stage_e get_upgrade_stage(void)
|
||||
{
|
||||
return current_stage;
|
||||
}
|
||||
|
||||
static void status_report(upgrade_status_e status)
|
||||
{
|
||||
if (status_callback) {
|
||||
status_callback(get_upgrade_stage(), status);
|
||||
}
|
||||
}
|
||||
|
||||
static int upgrade_handshake(unsigned int timeout_ms, unsigned int retry_times)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
upgrade_debug("start upgrade_handshake, timeout_ms: %d, retry_times: %d\n", timeout_ms, retry_times);
|
||||
|
||||
set_upgrade_stage(UPGRADE_STAGE_HANDSHAKE);
|
||||
status_report(UPGRADE_STATUS_START);
|
||||
|
||||
upgrade_debug("waiting 'M' ...\n");
|
||||
while (retry_times--) {
|
||||
upgrade_debug("handshake retry_times: %d", retry_times);
|
||||
unsigned char c = 0xef;
|
||||
uart_ops.send(&c, 1);
|
||||
if (!uart_ops.wait_reply((const unsigned char *)"M", 1, timeout_ms)) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
upgrade_debug("get 'M' !\n");
|
||||
status_report(UPGRADE_STATUS_OK);
|
||||
} else {
|
||||
upgrade_debug("wait 'M' err !\n");
|
||||
status_report(UPGRADE_STATUS_ERR);
|
||||
}
|
||||
|
||||
upgrade_debug("upgrade_handshake over, ret: %d\n ", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int is_little_endian(void)
|
||||
{
|
||||
int a = 0x11223344;
|
||||
unsigned char *p = (unsigned char *)&a;
|
||||
|
||||
return (*p == 0x44) ? 1 : 0;
|
||||
}
|
||||
|
||||
static unsigned int switch_endian(unsigned int v)
|
||||
{
|
||||
return (((v >> 0) & 0xff) << 24) | (((v >> 8) & 0xff) << 16) | (((v >> 16) & 0xff) << 8) | (((v >> 24) & 0xff) << 0);
|
||||
}
|
||||
|
||||
static unsigned int be32_to_cpu(unsigned int v)
|
||||
{
|
||||
if (is_little_endian()) {
|
||||
return switch_endian(v);
|
||||
} else {
|
||||
return v;
|
||||
}
|
||||
}
|
||||
|
||||
static int boot_info_baudrate[] = {300, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200};
|
||||
static void print_bootheader(const boot_header_t *header)
|
||||
{
|
||||
upgrade_debug("chip_id %x\n", header->chip_id);
|
||||
upgrade_debug("chip_type %x\n", header->chip_type);
|
||||
upgrade_debug("chip_version %x\n", header->chip_version);
|
||||
upgrade_debug("boot_delay %x\n", header->boot_delay);
|
||||
upgrade_debug("baud_rate %d\n", boot_info_baudrate[header->baud_rate]);
|
||||
upgrade_debug("stage1_size %d\n", header->stage1_size);
|
||||
upgrade_debug("stage2_baud_rate %d\n", header->stage2_baud_rate);
|
||||
upgrade_debug("stage2_size %d\n", header->stage2_size);
|
||||
upgrade_debug("stage2_checksum %d\n", header->stage2_checksum);
|
||||
}
|
||||
|
||||
int parse_bootimg_header(void)
|
||||
{
|
||||
upgrade_debug("reading boot header ...\n");
|
||||
|
||||
set_upgrade_stage(UPGRADE_STAGE_BOOT_HEADER);
|
||||
status_report(UPGRADE_STATUS_START);
|
||||
|
||||
int ret = fw_stream_ops.read(FW_BOOT_IMAGE, (unsigned char *)&boot_header, sizeof(boot_header));
|
||||
if (ret < sizeof(boot_header)) {
|
||||
upgrade_debug("read boot header err !\n");
|
||||
goto header_err;
|
||||
}
|
||||
|
||||
boot_header.stage1_size = be32_to_cpu(boot_header.stage1_size);
|
||||
boot_header.stage2_baud_rate = be32_to_cpu(boot_header.stage2_baud_rate);
|
||||
boot_header.stage2_size = be32_to_cpu(boot_header.stage2_size);
|
||||
boot_header.stage2_checksum = be32_to_cpu(boot_header.stage2_checksum);
|
||||
|
||||
print_bootheader(&boot_header);
|
||||
status_report(UPGRADE_STATUS_OK);
|
||||
return 0;
|
||||
|
||||
header_err:
|
||||
status_report(UPGRADE_STATUS_ERR);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int download_bootimg_stage1(void)
|
||||
{
|
||||
int wsize = 0;
|
||||
int len = 0;
|
||||
int size = 0;
|
||||
|
||||
upgrade_debug("start boot stage1 ...\n");
|
||||
|
||||
set_upgrade_stage(UPGRADE_STAGE_BOOT_S1);
|
||||
status_report(UPGRADE_STATUS_START);
|
||||
|
||||
size = boot_header.stage1_size;
|
||||
size = size / 4;
|
||||
data_buf[0] = 'Y';
|
||||
data_buf[1] = (size >> 0) & 0xFF;
|
||||
data_buf[2] = (size >> 8) & 0xFF;
|
||||
data_buf[3] = (size >> 16) & 0xFF;
|
||||
data_buf[4] = (size >> 24) & 0xFF;
|
||||
uart_ops.send(data_buf, 5);
|
||||
|
||||
if (boot_header.chip_type == 0x01) {
|
||||
size = size * 4;
|
||||
}
|
||||
|
||||
upgrade_debug("download boot stage1 ...\n");
|
||||
while (wsize < size) {
|
||||
if (wsize % UPGRADE_BLOCK_SIZE == 0) {
|
||||
status_report(UPGRADE_STATUS_DOWNLOADING);
|
||||
}
|
||||
len = (boot_header.stage1_size - wsize >= UPGRADE_PACKET_SIZE) ? UPGRADE_PACKET_SIZE : (boot_header.stage1_size - wsize);
|
||||
len = fw_stream_ops.read(FW_BOOT_IMAGE, data_buf, len);
|
||||
if (len <= 0) {
|
||||
upgrade_debug("read data err !\n");
|
||||
goto stage1_err;
|
||||
}
|
||||
len = uart_ops.send(data_buf, len);
|
||||
if (len <= 0) {
|
||||
upgrade_debug("send data err !\n");
|
||||
goto stage1_err;
|
||||
}
|
||||
|
||||
wsize += len;
|
||||
}
|
||||
|
||||
upgrade_debug("download size: %d, waiting 'F' ...\n", wsize);
|
||||
if (uart_ops.wait_reply((const unsigned char *)"F", 1, UART_REPLY_TIMEOUT_MS)) {
|
||||
upgrade_debug("wait 'F' err !\n");
|
||||
goto stage1_err;
|
||||
}
|
||||
upgrade_debug("get 'F' !\n");
|
||||
|
||||
///// stage1 running, change baudrate /////
|
||||
upgrade_debug("change baudrate: %d\n", boot_header.stage2_baud_rate);
|
||||
|
||||
uart_ops.close();
|
||||
uart_ops.open(boot_header.stage2_baud_rate, 8, 1, 0);
|
||||
|
||||
upgrade_debug("wait \"GET\" ...\n");
|
||||
if (uart_ops.wait_reply((const unsigned char *)"GET", 3, UART_REPLY_TIMEOUT_MS)) {
|
||||
upgrade_debug("wait 'GET' err !\n");
|
||||
goto stage1_err;
|
||||
}
|
||||
upgrade_debug("get \"GET\" !\n");
|
||||
|
||||
data_buf[0] = 'O';
|
||||
data_buf[1] = 'K';
|
||||
uart_ops.send(data_buf, 2);
|
||||
|
||||
status_report(UPGRADE_STATUS_OK);
|
||||
upgrade_debug("boot stage1 ok !\n");
|
||||
|
||||
return 0;
|
||||
|
||||
stage1_err:
|
||||
status_report(UPGRADE_STATUS_ERR);
|
||||
upgrade_debug("boot stage1 err !\n");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int download_bootimg_stage2(void)
|
||||
{
|
||||
unsigned int checksum = 0;
|
||||
unsigned int stage2_size = 0;
|
||||
int len = 0;
|
||||
int wsize = 0;
|
||||
|
||||
upgrade_debug("start boot stage2 ...\n");
|
||||
|
||||
set_upgrade_stage(UPGRADE_STAGE_BOOT_S2);
|
||||
status_report(UPGRADE_STATUS_START);
|
||||
|
||||
stage2_size = boot_header.stage2_size;
|
||||
checksum = boot_header.stage2_checksum;
|
||||
upgrade_debug("stage2_size = %u, checksum = %u\n", stage2_size, checksum);
|
||||
|
||||
if (checksum == 0 || stage2_size == 0) {
|
||||
upgrade_debug("stage2_size or checksum err !\n");
|
||||
goto stage2_err;
|
||||
}
|
||||
|
||||
data_buf[0] = 'S';
|
||||
uart_ops.send(data_buf, 1);
|
||||
uart_ops.send((const unsigned char *)&checksum, 4);
|
||||
uart_ops.send((const unsigned char *)&stage2_size, 4);
|
||||
|
||||
upgrade_debug("waiting \"ready\" ...\n");
|
||||
if (uart_ops.wait_reply((const unsigned char *)"ready", 5, UART_REPLY_TIMEOUT_MS)) {
|
||||
upgrade_debug("wait ready error !\n");
|
||||
goto stage2_err;
|
||||
}
|
||||
upgrade_debug("get \"ready\"\n");
|
||||
|
||||
upgrade_debug("download boot stage2 ...\n");
|
||||
while (wsize < stage2_size) {
|
||||
if (wsize % UPGRADE_BLOCK_SIZE == 0) {
|
||||
status_report(UPGRADE_STATUS_DOWNLOADING);
|
||||
}
|
||||
len = (stage2_size - wsize >= UPGRADE_PACKET_SIZE) ? UPGRADE_PACKET_SIZE : (stage2_size - wsize);
|
||||
len = fw_stream_ops.read(FW_BOOT_IMAGE, data_buf, len);
|
||||
if (len <= 0) {
|
||||
upgrade_debug("read data err !\n");
|
||||
goto stage2_err;
|
||||
}
|
||||
|
||||
len = uart_ops.send(data_buf, len);
|
||||
if (len <= 0) {
|
||||
upgrade_debug("send data err !\n");
|
||||
goto stage2_err;
|
||||
}
|
||||
|
||||
wsize += len;
|
||||
}
|
||||
|
||||
upgrade_debug("download size: %d, waiting 'O' ...\n", wsize);
|
||||
if (uart_ops.wait_reply((const unsigned char *)"O", 1, UART_REPLY_TIMEOUT_MS)) {
|
||||
upgrade_debug("wait 'O' err !\n");
|
||||
goto stage2_err;
|
||||
}
|
||||
upgrade_debug("get 'O' !\n");
|
||||
|
||||
upgrade_debug("waiting \"boot>\" ...\n");
|
||||
|
||||
if (uart_ops.wait_reply((const unsigned char *)"boot>", 5, UART_REPLY_TIMEOUT_MS)) {
|
||||
upgrade_debug("wait \"boot>\" err !\n");
|
||||
goto stage2_err;
|
||||
}
|
||||
upgrade_debug("get \"boot>\" !\n");
|
||||
|
||||
status_report(UPGRADE_STATUS_OK);
|
||||
upgrade_debug("boot stage2 ok !\n");
|
||||
|
||||
return 0;
|
||||
|
||||
stage2_err:
|
||||
status_report(UPGRADE_STATUS_ERR);
|
||||
upgrade_debug("boot stage2 err !\n");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int download_bootimg(void)
|
||||
{
|
||||
if (parse_bootimg_header() != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (download_bootimg_stage1() != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (download_bootimg_stage2() != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int download_flashimg(void)
|
||||
{
|
||||
int wsize = 0;
|
||||
int len = 0;
|
||||
flash_img_info_t info = {0};
|
||||
|
||||
upgrade_debug("start flash image ...\n");
|
||||
|
||||
set_upgrade_stage(UPGRADE_STAGE_FLASH_IMG);
|
||||
status_report(UPGRADE_STATUS_START);
|
||||
fw_stream_ops.get_flash_img_info(&info);
|
||||
upgrade_debug("flash image size = %d\n", info.img_size);
|
||||
|
||||
if (info.img_size == 0) {
|
||||
upgrade_debug("flash image size err !\n");
|
||||
goto flash_err;
|
||||
}
|
||||
|
||||
memset(data_buf, 0, UPGRADE_PACKET_SIZE);
|
||||
len = sprintf((char *)data_buf, "serialdown %d %d %d\n", 0, info.img_size, UPGRADE_FLASH_BLOCK_SIZE);
|
||||
uart_ops.send(data_buf, len);
|
||||
|
||||
upgrade_debug("waiting \"~sta~\" ...\n");
|
||||
if (uart_ops.wait_reply((const unsigned char *)"~sta~", 5, UART_REPLY_TIMEOUT_MS)) {
|
||||
upgrade_debug("wait ~sta~ err !\n");
|
||||
goto flash_err;
|
||||
}
|
||||
upgrade_debug("get \"~sta~\" !\n");
|
||||
|
||||
upgrade_debug("download flash image ...\n");
|
||||
|
||||
while (wsize < info.img_size) {
|
||||
if (wsize % UPGRADE_BLOCK_SIZE == 0) {
|
||||
status_report(UPGRADE_STATUS_DOWNLOADING);
|
||||
}
|
||||
|
||||
len = (info.img_size - wsize >= UPGRADE_PACKET_SIZE) ? UPGRADE_PACKET_SIZE : (info.img_size - wsize);
|
||||
len = fw_stream_ops.read(FW_FLASH_IMAGE, data_buf, len);
|
||||
if (len <= 0) {
|
||||
upgrade_debug("read data err !\n");
|
||||
goto flash_err;
|
||||
}
|
||||
|
||||
len = uart_ops.send(data_buf, len);
|
||||
if (len <= 0) {
|
||||
upgrade_debug("send data err !\n");
|
||||
goto flash_err;
|
||||
}
|
||||
wsize += len;
|
||||
|
||||
if ((wsize % UPGRADE_FLASH_BLOCK_SIZE) == 0) {
|
||||
upgrade_debug("waiting \"~sta~\" ...\n");
|
||||
if (uart_ops.wait_reply((const unsigned char *)"~sta~", 5, UART_REPLY_TIMEOUT_MS)) {
|
||||
upgrade_debug("wait \"~sta~\" err !\n");
|
||||
goto flash_err;
|
||||
}
|
||||
upgrade_debug("get \"~sta~\" !\n");
|
||||
}
|
||||
}
|
||||
|
||||
upgrade_debug("download size: %d, waiting \"~fin~\" ...\n", wsize);
|
||||
if (uart_ops.wait_reply((const unsigned char *)"~fin~", 5, UART_REPLY_TIMEOUT_MS)) {
|
||||
upgrade_debug("wait \"~fin~\" err !\n");
|
||||
goto flash_err;
|
||||
}
|
||||
upgrade_debug("get \"~fin~\" !\n");
|
||||
|
||||
status_report(UPGRADE_STATUS_OK);
|
||||
upgrade_debug("flash image ok !\n");
|
||||
return 0;
|
||||
|
||||
flash_err:
|
||||
status_report(UPGRADE_STATUS_ERR);
|
||||
upgrade_debug("flash image err !\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int gx_uart_upgrade_proc(void)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
if (!upgrade_initialized) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
set_upgrade_stage(UPGRADE_STAGE_NONE);
|
||||
|
||||
if (uart_ops.open(HANDSHAKE_BAUDRATE, 8, 1, 0) < 0) {
|
||||
upgrade_debug("open uart err !\n");
|
||||
goto upgrade_done;
|
||||
}
|
||||
|
||||
if (fw_stream_ops.open(FW_BOOT_IMAGE) < 0) {
|
||||
upgrade_debug("open boot img stream err !\n");
|
||||
goto upgrade_done;
|
||||
}
|
||||
|
||||
if (fw_stream_ops.open(FW_FLASH_IMAGE) < 0) {
|
||||
upgrade_debug("open flash img stream err !\n");
|
||||
goto upgrade_done;
|
||||
}
|
||||
|
||||
/* JL_PORTA->DIR &= ~BIT(4); */
|
||||
/* JL_PORTA->OUT |= BIT(4); */
|
||||
if (upgrade_handshake(10, 100) < 0) {
|
||||
goto upgrade_done;
|
||||
}
|
||||
|
||||
if (download_bootimg() < 0) {
|
||||
goto upgrade_done;
|
||||
}
|
||||
|
||||
if (download_flashimg() < 0) {
|
||||
goto upgrade_done;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
upgrade_done:
|
||||
uart_ops.close();
|
||||
fw_stream_ops.close(FW_BOOT_IMAGE);
|
||||
fw_stream_ops.close(FW_FLASH_IMAGE);
|
||||
set_upgrade_stage(UPGRADE_STAGE_NONE);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int gx_uart_upgrade_init(upgrade_uart_t *uart, fw_stream_t *fw_stream, upgrade_status_cb status_cb)
|
||||
{
|
||||
if ((uart == NULL) || (fw_stream == NULL)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(&uart_ops, uart, sizeof(upgrade_uart_t));
|
||||
memcpy(&fw_stream_ops, fw_stream, sizeof(fw_stream_t));
|
||||
|
||||
status_callback = status_cb;
|
||||
|
||||
upgrade_initialized = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gx_uart_upgrade_deinit(void)
|
||||
{
|
||||
upgrade_initialized = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* #if GX8002_UPGRADE_TOGGLE */
|
||||
@ -0,0 +1,17 @@
|
||||
#ifndef __GX_URAT_UPGRADE_H__
|
||||
#define __GX_URAT_UPGRADE_H__
|
||||
|
||||
#include "gx_upgrade_def.h"
|
||||
|
||||
typedef struct {
|
||||
int (*open)(int baud, int databits, int stopbits, int parity);
|
||||
int (*close)(void);
|
||||
int (*wait_reply)(const unsigned char *buf, unsigned int len, unsigned int timeout);
|
||||
int (*send)(const unsigned char *buf, unsigned int len);
|
||||
} upgrade_uart_t;
|
||||
|
||||
int gx_uart_upgrade_init(upgrade_uart_t *uart, fw_stream_t *fw_stream, upgrade_status_cb status_cb);
|
||||
int gx_uart_upgrade_deinit(void);
|
||||
int gx_uart_upgrade_proc(void);
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,136 @@
|
||||
#include "includes.h"
|
||||
#include "asm/uart_dev.h"
|
||||
#include "gx_uart_upgrade_porting.h"
|
||||
#include "../gx8002_npu_api.h"
|
||||
#include "app_config.h"
|
||||
|
||||
#if GX8002_UPGRADE_TOGGLE
|
||||
|
||||
#define GX_UART_UPGRADE_PORT_DEBUG 1
|
||||
|
||||
#ifdef GX_UART_UPGRADE_PORT_DEBUG
|
||||
//#define upgrade_debug(fmt, ...) y_printf("[gx_uart_upgrade]: " fmt, ##__VA_ARGS__)
|
||||
#define gx_uart_upgrade_port_debug y_printf
|
||||
#else
|
||||
#define gx_uart_upgrade_port_debug(fmt, ...)
|
||||
#endif
|
||||
|
||||
struct gx_upgrade_uart_port {
|
||||
const uart_bus_t *uart_bus;
|
||||
u32 cur_baud;
|
||||
};
|
||||
|
||||
static u8 uart_upgrade_cbuf[512] __attribute__((aligned(4)));
|
||||
|
||||
static struct gx_upgrade_uart_port uart_port = {0};
|
||||
|
||||
#define __this (&uart_port)
|
||||
|
||||
static void gx8002_upgrade_uart_isr_hook(void *arg, u32 status)
|
||||
{
|
||||
if (status != UT_TX) {
|
||||
//gx_uart_upgrade_port_debug("UT_RX_OT pending");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int gx_upgrade_uart_porting_open(int baud, int databits, int stopbits, int parity)
|
||||
{
|
||||
int ret = -1;
|
||||
struct uart_platform_data_t u_arg = {0};
|
||||
|
||||
if (__this->uart_bus) {
|
||||
gx_uart_upgrade_port_debug("gx8002 uart upgrade have open");
|
||||
return 0;
|
||||
}
|
||||
|
||||
u_arg.tx_pin = TCFG_GX8002_NPU_UART_TX_PORT;
|
||||
u_arg.rx_pin = TCFG_GX8002_NPU_UART_RX_PORT;
|
||||
u_arg.rx_cbuf = uart_upgrade_cbuf;
|
||||
u_arg.rx_cbuf_size = sizeof(uart_upgrade_cbuf);
|
||||
u_arg.frame_length = 0xFFFF;
|
||||
u_arg.rx_timeout = 5;
|
||||
u_arg.isr_cbfun = gx8002_upgrade_uart_isr_hook;
|
||||
u_arg.baud = baud;
|
||||
u_arg.is_9bit = 0;
|
||||
|
||||
__this->uart_bus = uart_dev_open(&u_arg);
|
||||
if (__this->uart_bus != NULL) {
|
||||
gx_uart_upgrade_port_debug("gx8002 uart upgrade open: baud: %d", baud);
|
||||
ret = 0;
|
||||
} else {
|
||||
gx_uart_upgrade_port_debug("gx8002 uart upgrade open fail");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int gx_upgrade_uart_porting_close(void)
|
||||
{
|
||||
if (__this->uart_bus) {
|
||||
uart_dev_close(__this->uart_bus);
|
||||
gpio_disable_fun_output_port(TCFG_GX8002_NPU_UART_TX_PORT);
|
||||
__this->uart_bus = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gx_upgrade_uart_porting_read(unsigned char *buf, unsigned int len, unsigned int timeout_ms)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
if (__this->uart_bus && __this->uart_bus->read) {
|
||||
ret = __this->uart_bus->read(buf, len, timeout_ms);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
//int gx_upgrade_uart_porting_write(const unsigned char *buf, unsigned int len, unsigned int timeout_ms)
|
||||
int gx_upgrade_uart_porting_write(const unsigned char *buf, unsigned int len)
|
||||
{
|
||||
int ret = len;
|
||||
|
||||
if (__this->uart_bus && __this->uart_bus->write) {
|
||||
__this->uart_bus->write(buf, len);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int gx_uart_upgrade_porting_wait_reply(const unsigned char *buf, unsigned int len, unsigned int timeout_ms)
|
||||
{
|
||||
int index = 0;
|
||||
unsigned char ch;
|
||||
|
||||
while (gx_upgrade_uart_porting_read(&ch, 1, timeout_ms) > 0) {
|
||||
//gx_uart_upgrade_port_debug("`0x%02x`\n", ch);
|
||||
if (ch == (unsigned char)buf[index]) {
|
||||
index++;
|
||||
}
|
||||
if (index == len) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void uart_clock_critical_enter(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static void uart_clock_critical_exit(void)
|
||||
{
|
||||
if (__this->uart_bus && __this->uart_bus->set_baud) {
|
||||
gx_uart_upgrade_port_debug("clock critical uart set_baud: %d", __this->cur_baud);
|
||||
__this->uart_bus->set_baud(__this->cur_baud);
|
||||
}
|
||||
}
|
||||
CLOCK_CRITICAL_HANDLE_REG(gx8002, uart_clock_critical_enter, uart_clock_critical_exit)
|
||||
|
||||
|
||||
#endif /* #if GX8002_UPGRADE_TOGGLE */
|
||||
@ -0,0 +1,16 @@
|
||||
#ifndef _GX_UART_UPGRADE_UPGRADE_PORT_
|
||||
#define _GX_UART_UPGRADE_UPGRADE_PORT_
|
||||
|
||||
|
||||
int gx_upgrade_uart_porting_open(int baud, int databits, int stopbits, int parity);
|
||||
|
||||
int gx_upgrade_uart_porting_close(void);
|
||||
|
||||
int gx_upgrade_uart_porting_read(unsigned char *buf, unsigned int len, unsigned int timeout_ms);
|
||||
|
||||
//int gx_upgrade_uart_porting_write(const unsigned char *buf, unsigned int len, unsigned int timeout_ms);
|
||||
int gx_upgrade_uart_porting_write(const unsigned char *buf, unsigned int len);
|
||||
|
||||
int gx_uart_upgrade_porting_wait_reply(const unsigned char *buf, unsigned int len, unsigned int timeout_ms);
|
||||
|
||||
#endif /* #ifndef _GX_UART_UPGRADE_UPGRADE_PORT_ */
|
||||
@ -0,0 +1,47 @@
|
||||
#ifndef __GX_UPGRADE_DEF_H__
|
||||
#define __GX_UPGRADE_DEF_H__
|
||||
|
||||
#define UPGRADE_DATA_BLOCK_SIZE 256
|
||||
|
||||
#define UPGRADE_PACKET_SIZE 256
|
||||
#define UPGRADE_BLOCK_SIZE (1024 * 4)
|
||||
#define UPGRADE_FLASH_BLOCK_SIZE (1024 * 56) //56K
|
||||
|
||||
typedef enum {
|
||||
UPGRADE_STAGE_HANDSHAKE = 0,
|
||||
UPGRADE_STAGE_BOOT_HEADER,
|
||||
UPGRADE_STAGE_BOOT_S1,
|
||||
UPGRADE_STAGE_BOOT_S2,
|
||||
UPGRADE_STAGE_FLASH_IMG,
|
||||
UPGRADE_STAGE_NONE
|
||||
} upgrade_stage_e;
|
||||
|
||||
typedef enum {
|
||||
UPGRADE_STATUS_START = 0,
|
||||
UPGRADE_STATUS_DOWNLOADING,
|
||||
UPGRADE_STATUS_OK,
|
||||
UPGRADE_STATUS_ERR,
|
||||
UPGRADE_STATUS_NONE
|
||||
} upgrade_status_e;
|
||||
|
||||
typedef void (*upgrade_status_cb)(upgrade_stage_e stage, upgrade_status_e status);
|
||||
|
||||
typedef enum {
|
||||
FW_BOOT_IMAGE = 0, //"gx8002.boot"
|
||||
FW_FLASH_IMAGE, //"mcu_nor.bin"
|
||||
|
||||
FW_FLASH_MAX,
|
||||
} FW_IMAGE_TYPE;
|
||||
|
||||
typedef struct {
|
||||
unsigned int img_size;
|
||||
} flash_img_info_t;
|
||||
|
||||
typedef struct {
|
||||
int (*open)(FW_IMAGE_TYPE img_type);
|
||||
int (*close)(FW_IMAGE_TYPE img_type);
|
||||
int (*read)(FW_IMAGE_TYPE img_type, unsigned char *buf, unsigned int len);
|
||||
int (*get_flash_img_info)(flash_img_info_t *info);
|
||||
} fw_stream_t;
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,189 @@
|
||||
#include "includes.h"
|
||||
#include "../gx_uart_upgrade.h"
|
||||
#include "../../gx8002_npu_api.h"
|
||||
#include "../gx_uart_upgrade_porting.h"
|
||||
|
||||
#if GX8002_UPGRADE_SDFILE_TOGGLE
|
||||
|
||||
#define STREAM_FIFO_BLOCK_TOTAL 20
|
||||
#define STREAM_FIFO_TIMEOUT_MS 7000
|
||||
|
||||
typedef int (*reply)(unsigned char *data, int size);
|
||||
static int ota_start = 0;
|
||||
|
||||
struct sdfile_fifo {
|
||||
FILE *boot_fp;
|
||||
FILE *bin_fp;
|
||||
};
|
||||
|
||||
static struct sdfile_fifo sdfile_upgrade = {0};
|
||||
#define __this (&sdfile_upgrade)
|
||||
|
||||
#define GX8002_SDFILE_UPGRADE_DEBUG_ENABLE 1
|
||||
|
||||
#define sdfile_upgrade_info g_printf
|
||||
|
||||
#if GX8002_SDFILE_UPGRADE_DEBUG_ENABLE
|
||||
#define sdfile_upgrade_debug r_printf
|
||||
#define sdfile_upgrade_put_buf put_buf
|
||||
#else
|
||||
#define sdfile_upgrade_debug(...)
|
||||
#define sdfile_upgrade_put_buf(...)
|
||||
#endif /* #if GX8002_DEBUG_ENABLE */
|
||||
|
||||
////////////// FW Stream Porting //////////////////
|
||||
static int fw_stream_open(FW_IMAGE_TYPE img_type)
|
||||
{
|
||||
#define BOOT_IMAGE_PATH SDFILE_RES_ROOT_PATH"gx8002.boot"
|
||||
#define BIN_IMAGE_PATH SDFILE_RES_ROOT_PATH"mcu_nor.bin"
|
||||
FILE *fp = NULL;
|
||||
if (img_type == FW_BOOT_IMAGE) {
|
||||
fp = fopen(BOOT_IMAGE_PATH, "r");
|
||||
if (fp) {
|
||||
sdfile_upgrade_info("open %s succ", BOOT_IMAGE_PATH);
|
||||
__this->boot_fp = fp;
|
||||
} else {
|
||||
sdfile_upgrade_info("open %s failed!", BOOT_IMAGE_PATH);
|
||||
return -1;
|
||||
}
|
||||
} else if (img_type == FW_FLASH_IMAGE) {
|
||||
fp = fopen(BIN_IMAGE_PATH, "r");
|
||||
if (fp) {
|
||||
sdfile_upgrade_info("open %s succ", BIN_IMAGE_PATH);
|
||||
__this->bin_fp = fp;
|
||||
} else {
|
||||
sdfile_upgrade_info("open %s failed!", BIN_IMAGE_PATH);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fw_stream_close(FW_IMAGE_TYPE img_type)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (img_type == FW_BOOT_IMAGE) {
|
||||
if (__this->boot_fp) {
|
||||
fclose(__this->boot_fp);
|
||||
__this->boot_fp = NULL;
|
||||
}
|
||||
} else if (img_type == FW_FLASH_IMAGE) {
|
||||
if (__this->bin_fp) {
|
||||
fclose(__this->bin_fp);
|
||||
__this->bin_fp = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fw_stream_read(FW_IMAGE_TYPE img_type, unsigned char *buf, unsigned int len)
|
||||
{
|
||||
int ret = 0;
|
||||
FILE *fp = NULL;
|
||||
|
||||
if (img_type == FW_BOOT_IMAGE) {
|
||||
fp = __this->boot_fp;
|
||||
} else if (img_type == FW_FLASH_IMAGE) {
|
||||
fp = __this->bin_fp;
|
||||
}
|
||||
|
||||
if (fp) {
|
||||
ret = fread(fp, buf, len);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fw_stream_get_flash_img_info(flash_img_info_t *info)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (info == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (__this->bin_fp) {
|
||||
info->img_size = flen(__this->bin_fp);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
///////// status info /////////////
|
||||
static const char *status_info_str[UPGRADE_STAGE_NONE][UPGRADE_STATUS_NONE] = {
|
||||
// UPGRADE_STAGE_HANDSHAKE
|
||||
{"handshake start\n", NULL, "handshake ok\n", "handshake err\n"},
|
||||
// UPGRADE_STAGE_BOOT_HEADER
|
||||
{"boot header start\n", NULL, "boot header ok\n", "boot header err\n"},
|
||||
// UPGRADE_STAGE_BOOT_S1
|
||||
{"boot stage1 start\n", "boot stage1 downloading\n", "boot stage1 ok\n", "boot stage1 err\n"},
|
||||
// UPGRADE_STAGE_BOOT_S2
|
||||
{"boot stage2 start\n", "boot stage2 downloading\n", "boot stage2 ok\n", "boot stage2 err\n"},
|
||||
// UPGRADE_STAGE_FLASH_IMG
|
||||
{"flash img start\n", "flash img downloading\n", "flash img ok\n", "flash img err\n"},
|
||||
};
|
||||
|
||||
static void gx8002_upgrade_status_cb(upgrade_stage_e stage, upgrade_status_e status)
|
||||
{
|
||||
const char *reply_str = status_info_str[stage][status];
|
||||
if (reply_str != NULL) {
|
||||
sdfile_upgrade_info("status info: %s\n", reply_str);
|
||||
}
|
||||
}
|
||||
|
||||
static int gx8002_upgrade_task(void *param)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
sdfile_upgrade_info("---- gx8002 ota start ----");
|
||||
gx8002_upgrade_cold_reset();
|
||||
|
||||
ret = gx_uart_upgrade_proc();
|
||||
|
||||
gx8002_normal_cold_reset();
|
||||
sdfile_upgrade_info("---- gx8002 ota over ----");
|
||||
|
||||
if (ret < 0) {
|
||||
gx8002_update_end_post_msg(0);
|
||||
} else {
|
||||
gx8002_update_end_post_msg(1);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int gx8002_uart_sdfile_ota_init(void)
|
||||
{
|
||||
upgrade_uart_t uart_ops;
|
||||
|
||||
uart_ops.open = gx_upgrade_uart_porting_open;
|
||||
uart_ops.close = gx_upgrade_uart_porting_close;
|
||||
uart_ops.send = gx_upgrade_uart_porting_write;
|
||||
uart_ops.wait_reply = gx_uart_upgrade_porting_wait_reply;
|
||||
|
||||
fw_stream_t fw_stream_ops;
|
||||
fw_stream_ops.open = fw_stream_open;
|
||||
fw_stream_ops.close = fw_stream_close;
|
||||
fw_stream_ops.read = fw_stream_read;
|
||||
fw_stream_ops.get_flash_img_info = fw_stream_get_flash_img_info;
|
||||
|
||||
gx_uart_upgrade_init(&uart_ops, &fw_stream_ops, gx8002_upgrade_status_cb);
|
||||
|
||||
gx8002_upgrade_task(NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else /* #if GX8002_UPGRADE_SDFILE_TOGGLE */
|
||||
|
||||
int gx8002_uart_sdfile_ota_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* #if GX8002_UPGRADE_SDFILE_TOGGLE */
|
||||
|
||||
@ -0,0 +1,239 @@
|
||||
#include "includes.h"
|
||||
#include "gx_fifo.h"
|
||||
|
||||
#define os_mutex_t OS_MUTEX *
|
||||
#define gx_os_mutex_lock os_mutex_pend
|
||||
#define gx_os_mutex_unlock os_mutex_post
|
||||
|
||||
#define os_sem_t OS_SEM *
|
||||
#define gx_os_sem_post os_sem_post
|
||||
#define gx_os_sem_wait os_sem_pend
|
||||
|
||||
typedef struct {
|
||||
char *data;
|
||||
unsigned int length;
|
||||
} fifoBlock;
|
||||
|
||||
typedef struct {
|
||||
int fifo_head;
|
||||
int fifo_tail;
|
||||
int block_num;
|
||||
int block_total;
|
||||
int block_size;
|
||||
fifoBlock *fifo_block;
|
||||
os_mutex_t fifo_mutex;
|
||||
os_sem_t fifo_sem;
|
||||
} GxFIFO;
|
||||
|
||||
|
||||
//======================== OS porting ======================================//
|
||||
static void *gx_os_calloc(u32 nmemb, u32 size)
|
||||
{
|
||||
return zalloc(nmemb * size);
|
||||
}
|
||||
|
||||
static void gx_os_free(void *p)
|
||||
{
|
||||
if (p) {
|
||||
free(p);
|
||||
}
|
||||
}
|
||||
|
||||
static os_mutex_t gx_os_mutex_create()
|
||||
{
|
||||
os_mutex_t mutex;
|
||||
mutex = (os_mutex_t)gx_os_calloc((sizeof(*mutex)), 1);
|
||||
|
||||
ASSERT(mutex, "mutex alloc err");
|
||||
|
||||
os_mutex_create(mutex);
|
||||
|
||||
return mutex;
|
||||
}
|
||||
|
||||
static void gx_os_mutex_destroy(os_mutex_t mutex)
|
||||
{
|
||||
if (mutex) {
|
||||
os_mutex_del(mutex, 0);
|
||||
gx_os_free(mutex);
|
||||
}
|
||||
}
|
||||
|
||||
static os_sem_t gx_os_sem_create(u32 cnt)
|
||||
{
|
||||
os_sem_t sem;
|
||||
sem = (os_mutex_t)gx_os_calloc((sizeof(*sem)), 1);
|
||||
|
||||
ASSERT(sem, "sem alloc err");
|
||||
|
||||
os_sem_create(sem, cnt);
|
||||
|
||||
return sem;
|
||||
}
|
||||
|
||||
static void gx_os_sem_destroy(os_sem_t sem)
|
||||
{
|
||||
if (sem) {
|
||||
os_sem_del(sem, 0);
|
||||
gx_os_free(sem);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//==============================================================//
|
||||
|
||||
int gx_fifo_destroy(fifo_handle_t fifo)
|
||||
{
|
||||
GxFIFO *temp_fifo = (GxFIFO *)fifo;
|
||||
int i = 0;
|
||||
|
||||
if (temp_fifo == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
gx_os_mutex_lock(temp_fifo->fifo_mutex, 0);
|
||||
if (temp_fifo->fifo_block != NULL) {
|
||||
for (i = 0; i < temp_fifo->block_total; i++) {
|
||||
if (temp_fifo->fifo_block[i].data != NULL) {
|
||||
gx_os_free(temp_fifo->fifo_block[i].data);
|
||||
temp_fifo->fifo_block[i].data = NULL;
|
||||
}
|
||||
}
|
||||
gx_os_free(temp_fifo->fifo_block);
|
||||
temp_fifo->fifo_block = NULL;
|
||||
}
|
||||
|
||||
gx_os_sem_destroy(temp_fifo->fifo_sem);
|
||||
gx_os_mutex_destroy(temp_fifo->fifo_mutex);
|
||||
|
||||
gx_os_free(temp_fifo);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
fifo_handle_t gx_fifo_create(int block_size, int block_num)
|
||||
{
|
||||
GxFIFO *temp_fifo = NULL;
|
||||
int i = 0;
|
||||
|
||||
if ((block_size == 0) || (block_num == 0)) {
|
||||
goto fifo_failed;
|
||||
}
|
||||
|
||||
if ((temp_fifo = (GxFIFO *)gx_os_calloc(sizeof(GxFIFO), 1)) == NULL) {
|
||||
goto fifo_failed;
|
||||
}
|
||||
|
||||
if ((temp_fifo->fifo_block = (fifoBlock *)gx_os_calloc(block_num * sizeof(fifoBlock), 1)) == NULL) {
|
||||
goto fifo_failed;
|
||||
}
|
||||
|
||||
temp_fifo->fifo_mutex = gx_os_mutex_create();
|
||||
temp_fifo->fifo_sem = gx_os_sem_create(0);
|
||||
|
||||
for (i = 0; i < block_num; i++) {
|
||||
if ((temp_fifo->fifo_block[i].data = (char *)gx_os_calloc(block_size, 1)) == NULL) {
|
||||
goto fifo_failed;
|
||||
}
|
||||
}
|
||||
|
||||
temp_fifo->block_total = block_num;
|
||||
temp_fifo->block_size = block_size;
|
||||
temp_fifo->fifo_head = 0;
|
||||
temp_fifo->fifo_tail = -1;
|
||||
|
||||
return (fifo_handle_t)temp_fifo;
|
||||
|
||||
fifo_failed:
|
||||
gx_fifo_destroy((fifo_handle_t)temp_fifo);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gx_fifo_write(fifo_handle_t fifo, const char *write_data, int write_size)
|
||||
{
|
||||
GxFIFO *temp_fifo = (GxFIFO *)fifo;
|
||||
int cp_size = 0;
|
||||
|
||||
if ((temp_fifo == NULL) || (write_data == NULL) || (write_size == 0)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
gx_os_mutex_lock(temp_fifo->fifo_mutex, 0);
|
||||
if (temp_fifo->block_num >= temp_fifo->block_total) {
|
||||
printf("[%s]%d: fifo full!!!\n", __func__, __LINE__);
|
||||
gx_os_mutex_unlock(temp_fifo->fifo_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
temp_fifo->fifo_tail++;
|
||||
if (temp_fifo->fifo_tail >= temp_fifo->block_total) {
|
||||
temp_fifo->fifo_tail = 0;
|
||||
}
|
||||
|
||||
(write_size >= temp_fifo->block_size)
|
||||
? (cp_size = temp_fifo->block_size) : (cp_size = write_size);
|
||||
memcpy(temp_fifo->fifo_block[temp_fifo->fifo_tail].data, write_data, cp_size);
|
||||
temp_fifo->fifo_block[temp_fifo->fifo_tail].length = cp_size;
|
||||
#if 1
|
||||
if (temp_fifo->block_num == 0) {
|
||||
//printf("[%s]%d new data: %d!!!\n", __func__, __LINE__, os_sem_query(temp_fifo->fifo_sem));
|
||||
gx_os_sem_post(temp_fifo->fifo_sem);
|
||||
}
|
||||
#endif
|
||||
temp_fifo->block_num++;
|
||||
|
||||
// gx_os_sem_post(temp_fifo->fifo_sem);
|
||||
gx_os_mutex_unlock(temp_fifo->fifo_mutex);
|
||||
|
||||
return cp_size;
|
||||
}
|
||||
|
||||
int gx_fifo_read(fifo_handle_t fifo, char *read_data, int read_size, int timeout)
|
||||
{
|
||||
GxFIFO *temp_fifo = (GxFIFO *)fifo;
|
||||
int cp_size = 0;
|
||||
|
||||
if ((temp_fifo == NULL) || (read_data == NULL) || (read_size == 0)) {
|
||||
return 0;
|
||||
}
|
||||
#if 0
|
||||
int ret = gx_os_sem_wait(temp_fifo->fifo_sem, timeout);
|
||||
if (ret != 0) {
|
||||
printf("[%s]%d: wait data timeout: %d !!!!!!!\n", __func__, __LINE__, ret);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
gx_os_mutex_lock(temp_fifo->fifo_mutex, 0);
|
||||
|
||||
while (temp_fifo->block_num == 0) {
|
||||
//printf("[%s]%d: fifo empty: %d!!!\n", __func__, __LINE__, gx_os_sem_query(temp_fifo->fifo_sem));
|
||||
gx_os_mutex_unlock(temp_fifo->fifo_mutex);
|
||||
|
||||
if (gx_os_sem_wait(temp_fifo->fifo_sem, timeout) != 0) {
|
||||
printf("[%s]%d: wait data timeout !!!!!!!\n", __func__, __LINE__);
|
||||
return 0;
|
||||
}
|
||||
//os_sem_pend(&temp_fifo->fifo_sem, 0);
|
||||
//os_mutex_pend(&temp_fifo->fifo_mutex, 0);
|
||||
gx_os_mutex_lock(temp_fifo->fifo_mutex, 0);
|
||||
//printf("[%s]%d, fifo has data: %d!!!\n", __func__, __LINE__, os_sem_query(&temp_fifo->fifo_sem));
|
||||
//return 0;
|
||||
}
|
||||
|
||||
(read_size >= temp_fifo->fifo_block[temp_fifo->fifo_head].length)
|
||||
? (cp_size = temp_fifo->fifo_block[temp_fifo->fifo_head].length) : (cp_size = read_size);
|
||||
memcpy(read_data, temp_fifo->fifo_block[temp_fifo->fifo_head].data, cp_size);
|
||||
read_size = temp_fifo->fifo_block[temp_fifo->fifo_head].length;
|
||||
|
||||
temp_fifo->fifo_head++;
|
||||
if (temp_fifo->fifo_head >= temp_fifo->block_total) {
|
||||
temp_fifo->fifo_head = 0;
|
||||
}
|
||||
|
||||
temp_fifo->block_num--;
|
||||
|
||||
gx_os_mutex_unlock(temp_fifo->fifo_mutex);
|
||||
|
||||
return cp_size;
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
#ifndef __GX_FIFO_H__
|
||||
#define __GX_FIFO_H__
|
||||
|
||||
typedef int fifo_handle_t;
|
||||
fifo_handle_t gx_fifo_create(int block_size, int block_num);
|
||||
int gx_fifo_destroy(fifo_handle_t fifo);
|
||||
int gx_fifo_write(fifo_handle_t fifo, const char *write_data, int write_size);
|
||||
int gx_fifo_read(fifo_handle_t fifo, char *read_data, int read_size, int timeout);
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,249 @@
|
||||
#include "includes.h"
|
||||
#include "../gx_uart_upgrade.h"
|
||||
#include "../../gx8002_npu_api.h"
|
||||
#include "../gx_uart_upgrade_porting.h"
|
||||
#include "btstack/avctp_user.h"
|
||||
#include "classic/hci_lmp.h"
|
||||
#include "gx_fifo.h"
|
||||
|
||||
#if GX8002_UPGRADE_SPP_TOGGLE
|
||||
|
||||
#define spp_upgrade_info g_printf
|
||||
|
||||
//=============== SPP Porting ================//
|
||||
int gx8002_ota_recv(unsigned char *data, int size);
|
||||
static void gx8002_spp_data_handler(u8 packet_type, u16 ch, u8 *packet, u16 size)
|
||||
{
|
||||
switch (packet_type) {
|
||||
case 1:
|
||||
/* cbuf_init(&spp_buf_hdl, spp_buf, sizeof(spp_buf)); */
|
||||
/* spp_timer = sys_timer_add(NULL, spp_send_data_timer, 50); */
|
||||
/* spp_printf("spp connect\n"); */
|
||||
spp_upgrade_info("gx8002 spp connect\n");
|
||||
break;
|
||||
case 2:
|
||||
spp_upgrade_info("gx8002 spp disconnect\n");
|
||||
/* if (spp_timer) { */
|
||||
/* sys_timer_del(spp_timer); */
|
||||
/* spp_timer = 0; */
|
||||
/* } */
|
||||
break;
|
||||
case 7:
|
||||
//spp_upgrade_info("gx8002 spp_rx: %d", size);
|
||||
//put_buf(packet,size);
|
||||
gx8002_ota_recv(packet, size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void gx8002_spp_send_data(u8 *data, u32 size)
|
||||
{
|
||||
user_send_cmd_prepare(USER_CTRL_SPP_SEND_DATA, size, data);
|
||||
}
|
||||
|
||||
|
||||
void gx8002_spp_ota_init(void)
|
||||
{
|
||||
spp_data_deal_handle_register(gx8002_spp_data_handler);
|
||||
}
|
||||
|
||||
////////////// FW Stream Porting //////////////////
|
||||
#define STREAM_FIFO_BLOCK_TOTAL 16
|
||||
#define STREAM_FIFO_TIMEOUT_MS (5000 / 10)
|
||||
|
||||
/* typedef int (*reply)(unsigned char *data, int size); */
|
||||
static int ota_start = 0;
|
||||
//static os_sem_t ota_sem;
|
||||
static fifo_handle_t fw_fifo;
|
||||
|
||||
static int gx8002_ota_start(void)
|
||||
{
|
||||
if (!ota_start) {
|
||||
os_taskq_post_msg("gx8002", 2, GX8002_MSG_UPDATE, GX8002_UPDATE_TYPE_SPP);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_gx8002_ota_start(void)
|
||||
{
|
||||
return ota_start;
|
||||
}
|
||||
|
||||
int gx8002_ota_recv(unsigned char *data, int size)
|
||||
{
|
||||
int i;
|
||||
|
||||
if ((data == NULL) || (size == 0)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (strncmp((char *)data, "startupgrade", strlen("startupgrade")) == 0) {
|
||||
gx8002_ota_start();
|
||||
} else {
|
||||
if (ota_start) {
|
||||
if (fw_fifo > 0) {
|
||||
int cnt = size / UPGRADE_PACKET_SIZE;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < cnt; i++) {
|
||||
gx_fifo_write(fw_fifo, (const char *)&data[UPGRADE_PACKET_SIZE * i], UPGRADE_PACKET_SIZE);
|
||||
}
|
||||
|
||||
if (size % UPGRADE_PACKET_SIZE) {
|
||||
gx_fifo_write(fw_fifo, (const char *)&data[UPGRADE_PACKET_SIZE * i], size % UPGRADE_PACKET_SIZE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int fw_stream_open(FW_IMAGE_TYPE img_type)
|
||||
{
|
||||
if (fw_fifo == 0) {
|
||||
if ((fw_fifo = gx_fifo_create(UPGRADE_PACKET_SIZE, STREAM_FIFO_BLOCK_TOTAL)) == 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fw_stream_close(FW_IMAGE_TYPE img_type)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (fw_fifo > 0) {
|
||||
ret = gx_fifo_destroy(fw_fifo);
|
||||
fw_fifo = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fw_stream_read(FW_IMAGE_TYPE img_type, unsigned char *buf, unsigned int len)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (fw_fifo > 0) {
|
||||
ret = gx_fifo_read(fw_fifo, (char *)buf, len, STREAM_FIFO_TIMEOUT_MS);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fw_stream_get_flash_img_info(flash_img_info_t *info)
|
||||
{
|
||||
unsigned int size = 0;
|
||||
|
||||
if (info == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fw_fifo == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ret = gx_fifo_read(fw_fifo, (char *)info, sizeof(flash_img_info_t), STREAM_FIFO_TIMEOUT_MS);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
///////// status info /////////////
|
||||
static const char *status_info_str[UPGRADE_STAGE_NONE][UPGRADE_STATUS_NONE] = {
|
||||
// UPGRADE_STAGE_HANDSHAKE
|
||||
{"handshake start\n", NULL, "handshake ok\n", "handshake err\n"},
|
||||
// UPGRADE_STAGE_BOOT_HEADER
|
||||
{"boot header start\n", NULL, "boot header ok\n", "boot header err\n"},
|
||||
// UPGRADE_STAGE_BOOT_S1
|
||||
{"boot stage1 start\n", "boot stage1 downloading\n", "boot stage1 ok\n", "boot stage1 err\n"},
|
||||
// UPGRADE_STAGE_BOOT_S2
|
||||
{"boot stage2 start\n", "boot stage2 downloading\n", "boot stage2 ok\n", "boot stage2 err\n"},
|
||||
// UPGRADE_STAGE_FLASH_IMG
|
||||
{"flash img start\n", "flash img downloading\n", "flash img ok\n", "flash img err\n"},
|
||||
};
|
||||
|
||||
static void gx8002_upgrade_status_cb(upgrade_stage_e stage, upgrade_status_e status)
|
||||
{
|
||||
//printf("---- [%s]: stage: %d, status: %d ----\n", __func__, stage, status);
|
||||
const char *reply_str = status_info_str[stage][status];
|
||||
if (reply_str != NULL) {
|
||||
spp_upgrade_info("status info: %s\n", reply_str);
|
||||
//user_spp_send_data((unsigned char *)reply_str, strlen(reply_str));
|
||||
gx8002_spp_send_data((u8 *)reply_str, strlen(reply_str));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int gx8002_upgrade_task(void *param)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
spp_upgrade_info("---- gx8002 ota start ----");
|
||||
gx8002_upgrade_cold_reset();
|
||||
|
||||
ret = gx_uart_upgrade_proc();
|
||||
|
||||
gx8002_normal_cold_reset();
|
||||
spp_upgrade_info("---- gx8002 ota over ----");
|
||||
|
||||
ota_start = 0;
|
||||
|
||||
if (ret < 0) {
|
||||
gx8002_update_end_post_msg(0);
|
||||
} else {
|
||||
gx8002_update_end_post_msg(1);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int gx8002_uart_spp_ota_init(void)
|
||||
{
|
||||
upgrade_uart_t uart_ops;
|
||||
fw_stream_t fw_stream_ops;
|
||||
|
||||
uart_ops.open = gx_upgrade_uart_porting_open;
|
||||
uart_ops.close = gx_upgrade_uart_porting_close;
|
||||
uart_ops.send = gx_upgrade_uart_porting_write;
|
||||
uart_ops.wait_reply = gx_uart_upgrade_porting_wait_reply;
|
||||
|
||||
|
||||
fw_stream_ops.open = fw_stream_open;
|
||||
fw_stream_ops.close = fw_stream_close;
|
||||
fw_stream_ops.read = fw_stream_read;
|
||||
fw_stream_ops.get_flash_img_info = fw_stream_get_flash_img_info;
|
||||
|
||||
gx_uart_upgrade_init(&uart_ops, &fw_stream_ops, gx8002_upgrade_status_cb);
|
||||
|
||||
ota_start = 1;
|
||||
|
||||
gx8002_upgrade_task(NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else /* #if GX8002_UPGRADE_SPP_TOGGLE */
|
||||
|
||||
int gx8002_uart_spp_ota_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int get_gx8002_ota_start(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gx8002_ota_recv(unsigned char *data, int size)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* #if GX8002_UPGRADE_SPP_TOGGLE */
|
||||
64
apps/common/device/imu_sensor/icm_42670p/InvError.h
Normal file
64
apps/common/device/imu_sensor/icm_42670p/InvError.h
Normal file
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* ________________________________________________________________________________________________________
|
||||
* Copyright (c) 2015-2015 InvenSense Inc. All rights reserved.
|
||||
*
|
||||
* This software, related documentation and any modifications thereto (collectively “Software”) is subject
|
||||
* to InvenSense and its licensors' intellectual property rights under U.S. and international copyright
|
||||
* and other intellectual property rights laws.
|
||||
*
|
||||
* InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software
|
||||
* and any use, reproduction, disclosure or distribution of the Software without an express license agreement
|
||||
* from InvenSense is strictly prohibited.
|
||||
*
|
||||
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, THE SOFTWARE IS
|
||||
* PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
|
||||
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, IN NO EVENT SHALL
|
||||
* INVENSENSE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY
|
||||
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
||||
* OF THE SOFTWARE.
|
||||
* ________________________________________________________________________________________________________
|
||||
*/
|
||||
|
||||
/** @defgroup InvError Error code
|
||||
* @brief Common error code
|
||||
*
|
||||
* @ingroup EmbUtils
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _INV_ERROR_H_
|
||||
#define _INV_ERROR_H_
|
||||
|
||||
/** @brief Common error code definition
|
||||
*/
|
||||
enum inv_error {
|
||||
INV_ERROR_SUCCESS = 0, /**< no error */
|
||||
INV_ERROR = -1, /**< unspecified error */
|
||||
INV_ERROR_NIMPL = -2, /**< function not implemented for given
|
||||
arguments */
|
||||
INV_ERROR_TRANSPORT = -3, /**< error occurred at transport level */
|
||||
INV_ERROR_TIMEOUT = -4, /**< action did not complete in the expected
|
||||
time window */
|
||||
INV_ERROR_SIZE = -5, /**< size/length of given arguments is not
|
||||
suitable to complete requested action */
|
||||
INV_ERROR_OS = -6, /**< error related to OS */
|
||||
INV_ERROR_IO = -7, /**< error related to IO operation */
|
||||
INV_ERROR_MEM = -9, /**< not enough memory to complete requested
|
||||
action */
|
||||
INV_ERROR_HW = -10, /**< error at HW level */
|
||||
INV_ERROR_BAD_ARG = -11, /**< provided arguments are not good to
|
||||
perform requested action */
|
||||
INV_ERROR_UNEXPECTED = -12, /**< something unexpected happened */
|
||||
INV_ERROR_FILE = -13, /**< cannot access file or unexpected format */
|
||||
INV_ERROR_PATH = -14, /**< invalid file path */
|
||||
INV_ERROR_IMAGE_TYPE = -15, /**< error when image type is not managed */
|
||||
INV_ERROR_WATCHDOG = -16, /**< error when device doesn't respond
|
||||
to ping */
|
||||
};
|
||||
|
||||
#endif /* _INV_ERROR_H_ */
|
||||
|
||||
/** @} */
|
||||
|
||||
1037
apps/common/device/imu_sensor/icm_42670p/icm_42670p.c
Normal file
1037
apps/common/device/imu_sensor/icm_42670p/icm_42670p.c
Normal file
File diff suppressed because it is too large
Load Diff
129
apps/common/device/imu_sensor/icm_42670p/icm_42670p.h
Normal file
129
apps/common/device/imu_sensor/icm_42670p/icm_42670p.h
Normal file
@ -0,0 +1,129 @@
|
||||
#ifndef _ICM_42670P_H_
|
||||
#define _ICM_42670P_H_
|
||||
#include "typedef.h"
|
||||
|
||||
|
||||
|
||||
#define ICM42670P
|
||||
|
||||
#if TCFG_ICM42670P_ENABLE
|
||||
|
||||
/*打开这个宏后,fifo读到的数据为
|
||||
(6(acc[s16])+6(gyro[s16]))
|
||||
*/
|
||||
#define ICM42670P_FIFO_DATA_FIT 1
|
||||
|
||||
|
||||
/******************************************************************
|
||||
* user config ICM42670P Macro Definition
|
||||
******************************************************************/
|
||||
#define ICM42670P_USE_I2C 0 /*IIC.(<=1MHz) */
|
||||
#define ICM42670P_USE_SPI 1 /*SPI.(<=24MHz) */
|
||||
#define ICM42670P_USER_INTERFACE TCFG_ICM42670P_INTERFACE_TYPE//ICM42670P_USE_I2C
|
||||
// #define ICM42670P_USER_INTERFACE ICM42670P_USE_SPI
|
||||
#define ICM42670P_SA0_IIC_ADDR 1 //1:iic模式SA0接VCC, 0:iic模式SA0接GND
|
||||
//int io config
|
||||
// #define ICM42670P_INT_IO1 IO_PORTB_03//TCFG_IOKEY_POWER_ONE_PORT //
|
||||
// #define ICM42670P_INT_IO1 IO_PORTA_06 //
|
||||
// #define ICM42670P_INT_READ_IO1() gpio_read(ICM42670P_INT_IO1)
|
||||
|
||||
|
||||
// #define ICM42670P_USE_FIFO_EN 1 //0:disable fifo 1:enable fifo(fifo size:512 bytes)
|
||||
#define ICM42670P_USE_INT_EN 0 //0:disable //中断方式不成功,疑硬件问题
|
||||
// #define ICM42670P_USE_WOM_EN 0 //0:disable
|
||||
// #define ICM42670P_USE_FSYNC_EN 0 //0:disable
|
||||
|
||||
#define SCALED_DATA_G_DPS 0 //1:output decode data; 0:Output raw data
|
||||
//解码后数据: 8(timer[u64])+12(acc[float])+12(gyro[float])+4(temp[float])
|
||||
//原始数据 : 8(timer[u64])+12(acc[int32])+12(gyro[int32])+2(temp[int16])
|
||||
/******************************************************************
|
||||
* ICM42670P I2C address Macro Definition
|
||||
* (7bit): (0x37)011 0111@SDO=1; (0x36)011 0110@SDO=0;
|
||||
******************************************************************/
|
||||
#if ICM42670P_SA0_IIC_ADDR
|
||||
#define ICM42670P_SLAVE_ADDRESS (0x69<<1)//0XD0
|
||||
#else
|
||||
#define ICM42670P_SLAVE_ADDRESS (0x68<<1)//0XD2
|
||||
#endif
|
||||
|
||||
typedef u32(*IMU_read)(unsigned char devAddr,
|
||||
unsigned char regAddr,
|
||||
unsigned char *readBuf,
|
||||
u32 readLen);
|
||||
typedef u32(*IMU_write)(unsigned char devAddr,
|
||||
unsigned char regAddr,
|
||||
unsigned char *writeBuf,
|
||||
u32 writeLen);
|
||||
|
||||
typedef struct {
|
||||
// u8 comms; //0:IIC; 1:SPI //改为宏控制
|
||||
#if (ICM42670P_USER_INTERFACE==ICM42670P_USE_I2C)
|
||||
u8 iic_hdl;
|
||||
u8 iic_delay; //这个延时并非影响iic的时钟频率,而是2Byte数据之间的延时
|
||||
// u8 iic_clk; //iic_clk: <=400kHz
|
||||
#elif (ICM42670P_USER_INTERFACE==ICM42670P_USE_SPI)
|
||||
u8 spi_hdl; //SPIx (role:master)
|
||||
u8 spi_cs_pin; //
|
||||
//u8 spi_work_mode;//icm42670p only suspport 4wire(SPI_MODE_BIDIR_1BIT) (与spi结构体一样)
|
||||
// u8 port; //SPIx group:A,B,C,D (spi结构体)
|
||||
// U8 spi_clk; //spi_clk: <=8MHz (spi结构体)
|
||||
|
||||
#endif
|
||||
} icm42670p_param;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Select communication link between SmartMotion and IMU
|
||||
*/
|
||||
#if (ICM42670P_USER_INTERFACE==ICM42670P_USE_I2C)
|
||||
#define SERIF_TYPE UI_I2C
|
||||
#elif (ICM42670P_USER_INTERFACE==ICM42670P_USE_SPI)
|
||||
#define SERIF_TYPE UI_SPI4
|
||||
// #define SERIF_TYPE UI_SPI3
|
||||
#endif
|
||||
/*
|
||||
* Set power mode flag
|
||||
* Set this flag to run example in low-noise mode.
|
||||
* Reset this flag to run example in low-power mode.
|
||||
* Note: low-noise mode is not available with sensor data frequencies less than 12.5Hz.
|
||||
*/
|
||||
#define USE_LOW_NOISE_MODE 1
|
||||
/*
|
||||
* Select Fifo resolution Mode (default is low resolution mode)
|
||||
* Low resolution mode: 16 bits data format
|
||||
* High resolution mode: 20 bits data format
|
||||
* Warning: Enabling High Res mode will force FSR to 16g and 2000dps
|
||||
*/
|
||||
#define USE_HIGH_RES_MODE 0
|
||||
/*
|
||||
* Select to use FIFO or to read data from registers
|
||||
*/
|
||||
#define USE_FIFO 1
|
||||
|
||||
enum inv_msg_level {
|
||||
INV_MSG_LEVEL_OFF = 0,
|
||||
INV_MSG_LEVEL_ERROR,
|
||||
INV_MSG_LEVEL_WARNING,
|
||||
INV_MSG_LEVEL_INFO,
|
||||
INV_MSG_LEVEL_VERBOSE,
|
||||
INV_MSG_LEVEL_DEBUG,
|
||||
INV_MSG_LEVEL_MAX
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif /*TCFG_ICM42670P_ENABLE*/
|
||||
#endif /*_ICM_42670P_H_*/
|
||||
|
||||
374
apps/common/device/imu_sensor/icm_42670p/inv_imu_apex.c
Normal file
374
apps/common/device/imu_sensor/icm_42670p/inv_imu_apex.c
Normal file
@ -0,0 +1,374 @@
|
||||
/*
|
||||
* ________________________________________________________________________________________________________
|
||||
* Copyright (c) 2017 InvenSense Inc. All rights reserved.
|
||||
*
|
||||
* This software, related documentation and any modifications thereto (collectively "Software") is subject
|
||||
* to InvenSense and its licensors' intellectual property rights under U.S. and international copyright
|
||||
* and other intellectual property rights laws.
|
||||
*
|
||||
* InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software
|
||||
* and any use, reproduction, disclosure or distribution of the Software without an express license agreement
|
||||
* from InvenSense is strictly prohibited.
|
||||
*
|
||||
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, THE SOFTWARE IS
|
||||
* PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
|
||||
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, IN NO EVENT SHALL
|
||||
* INVENSENSE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY
|
||||
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
||||
* OF THE SOFTWARE.
|
||||
* ________________________________________________________________________________________________________
|
||||
*/
|
||||
|
||||
#include "inv_imu_defs.h"
|
||||
#include "inv_imu_extfunc.h"
|
||||
#include "inv_imu_driver.h"
|
||||
#include "inv_imu_apex.h"
|
||||
|
||||
int inv_imu_apex_enable_ff(struct inv_imu_device *s)
|
||||
{
|
||||
int status = 0;
|
||||
uint8_t value;
|
||||
|
||||
status |= inv_imu_start_dmp(s);
|
||||
|
||||
status |= inv_imu_read_reg(s, APEX_CONFIG1, 1, &value);
|
||||
value &= ~APEX_CONFIG1_FF_ENABLE_MASK;
|
||||
value |= (uint8_t)APEX_CONFIG1_FF_ENABLE_EN;
|
||||
status |= inv_imu_write_reg(s, APEX_CONFIG1, 1, &value);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int inv_imu_apex_disable_ff(struct inv_imu_device *s)
|
||||
{
|
||||
int status = 0;
|
||||
uint8_t value;
|
||||
|
||||
status |= inv_imu_read_reg(s, APEX_CONFIG1, 1, &value);
|
||||
value &= ~APEX_CONFIG1_FF_ENABLE_MASK;
|
||||
value |= (uint8_t)APEX_CONFIG1_FF_ENABLE_DIS;
|
||||
status |= inv_imu_write_reg(s, APEX_CONFIG1, 1, &value);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int inv_imu_apex_enable_smd(struct inv_imu_device *s)
|
||||
{
|
||||
int status = 0;
|
||||
uint8_t value;
|
||||
|
||||
status |= inv_imu_start_dmp(s);
|
||||
|
||||
status |= inv_imu_read_reg(s, APEX_CONFIG1, 1, &value);
|
||||
value &= ~APEX_CONFIG1_SMD_ENABLE_MASK;
|
||||
value |= (uint8_t)APEX_CONFIG1_SMD_ENABLE_EN;
|
||||
status |= inv_imu_write_reg(s, APEX_CONFIG1, 1, &value);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int inv_imu_apex_disable_smd(struct inv_imu_device *s)
|
||||
{
|
||||
int status = 0;
|
||||
uint8_t value;
|
||||
|
||||
status |= inv_imu_read_reg(s, APEX_CONFIG1, 1, &value);
|
||||
value &= ~APEX_CONFIG1_SMD_ENABLE_MASK;
|
||||
value |= (uint8_t)APEX_CONFIG1_SMD_ENABLE_DIS;
|
||||
status |= inv_imu_write_reg(s, APEX_CONFIG1, 1, &value);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int inv_imu_apex_init_parameters_struct(struct inv_imu_device *s, inv_imu_apex_parameters_t *apex_inputs)
|
||||
{
|
||||
int status = 0;
|
||||
(void)s;
|
||||
|
||||
/* Default parameters at POR */
|
||||
apex_inputs->pedo_amp_th = APEX_CONFIG3_PEDO_AMP_TH_62_MG;
|
||||
apex_inputs->pedo_step_cnt_th = 0x5;
|
||||
apex_inputs->pedo_step_det_th = 0x2;
|
||||
apex_inputs->pedo_sb_timer_th = APEX_CONFIG4_PEDO_SB_TIMER_TH_150_SAMPLES;
|
||||
apex_inputs->pedo_hi_enrgy_th = APEX_CONFIG4_PEDO_HI_ENRGY_TH_104_MG;
|
||||
apex_inputs->tilt_wait_time = APEX_CONFIG5_TILT_WAIT_TIME_4_S;
|
||||
apex_inputs->power_save_time = APEX_CONFIG2_DMP_POWER_SAVE_TIME_SEL_8_S;
|
||||
apex_inputs->power_save = APEX_CONFIG0_DMP_POWER_SAVE_EN;
|
||||
apex_inputs->sensitivity_mode = APEX_CONFIG9_SENSITIVITY_MODE_NORMAL;
|
||||
apex_inputs->low_energy_amp_th = APEX_CONFIG2_LOW_ENERGY_AMP_TH_SEL_80_MG;
|
||||
apex_inputs->smd_sensitivity = APEX_CONFIG9_SMD_SENSITIVITY_0;
|
||||
apex_inputs->ff_debounce_duration = APEX_CONFIG9_FF_DEBOUNCE_DURATION_2000_MS;
|
||||
apex_inputs->ff_max_duration_cm = APEX_CONFIG12_FF_MAX_DURATION_204_CM;
|
||||
apex_inputs->ff_min_duration_cm = APEX_CONFIG12_FF_MIN_DURATION_10_CM;
|
||||
apex_inputs->lowg_peak_th = APEX_CONFIG10_LOWG_PEAK_TH_563_MG;
|
||||
apex_inputs->lowg_peak_hyst = APEX_CONFIG5_LOWG_PEAK_TH_HYST_156_MG;
|
||||
apex_inputs->lowg_samples_th = APEX_CONFIG10_LOWG_TIME_TH_1_SAMPLE;
|
||||
apex_inputs->highg_peak_th = APEX_CONFIG11_HIGHG_PEAK_TH_2500_MG;
|
||||
apex_inputs->highg_peak_hyst = APEX_CONFIG5_HIGHG_PEAK_TH_HYST_156_MG;
|
||||
apex_inputs->highg_samples_th = APEX_CONFIG11_HIGHG_TIME_TH_1_SAMPLE;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int inv_imu_apex_configure_parameters(struct inv_imu_device *s, const inv_imu_apex_parameters_t *apex_inputs)
|
||||
{
|
||||
int status = 0;
|
||||
uint8_t data;
|
||||
uint8_t apexConfig[7];
|
||||
APEX_CONFIG1_PED_ENABLE_t pedo_state;
|
||||
APEX_CONFIG1_TILT_ENABLE_t tilt_state;
|
||||
APEX_CONFIG1_FF_ENABLE_t ff_state;
|
||||
APEX_CONFIG1_SMD_ENABLE_t smd_state;
|
||||
|
||||
/* DMP cannot be configured if it is running, hence make sure all APEX algorithms are off */
|
||||
status |= inv_imu_read_reg(s, APEX_CONFIG1, 1, &data);
|
||||
pedo_state = (APEX_CONFIG1_PED_ENABLE_t)(data & APEX_CONFIG1_PED_ENABLE_MASK);
|
||||
tilt_state = (APEX_CONFIG1_TILT_ENABLE_t)(data & APEX_CONFIG1_TILT_ENABLE_MASK);
|
||||
ff_state = (APEX_CONFIG1_FF_ENABLE_t)(data & APEX_CONFIG1_FF_ENABLE_MASK);
|
||||
smd_state = (APEX_CONFIG1_SMD_ENABLE_t)(data & APEX_CONFIG1_SMD_ENABLE_MASK);
|
||||
if (pedo_state == APEX_CONFIG1_PED_ENABLE_EN) {
|
||||
return INV_ERROR;
|
||||
}
|
||||
if (tilt_state == APEX_CONFIG1_TILT_ENABLE_EN) {
|
||||
return INV_ERROR;
|
||||
}
|
||||
if (ff_state == APEX_CONFIG1_FF_ENABLE_EN) {
|
||||
return INV_ERROR;
|
||||
}
|
||||
if (smd_state == APEX_CONFIG1_SMD_ENABLE_EN) {
|
||||
return INV_ERROR;
|
||||
}
|
||||
|
||||
|
||||
status |= inv_imu_switch_on_mclk(s);
|
||||
|
||||
/* Power Save mode and low energy amplitude threshold (for Pedometer in Slow Walk mode) */
|
||||
/* APEX_CONFIG2_MREG1 */
|
||||
apexConfig[0] = (uint8_t)apex_inputs->power_save_time
|
||||
| (uint8_t)apex_inputs->low_energy_amp_th;
|
||||
|
||||
/* Pedometer parameters */
|
||||
/* APEX_CONFIG3_MREG1 */
|
||||
apexConfig[1] = (uint8_t)apex_inputs->pedo_amp_th
|
||||
| (apex_inputs->pedo_step_cnt_th & APEX_CONFIG3_PED_STEP_CNT_TH_SEL_MASK);
|
||||
|
||||
/* APEX_CONFIG4_MREG1 */
|
||||
apexConfig[2] = ((apex_inputs->pedo_step_det_th << APEX_CONFIG4_PED_STEP_DET_TH_SEL_POS)
|
||||
& APEX_CONFIG4_PED_STEP_DET_TH_SEL_MASK)
|
||||
| (uint8_t)apex_inputs->pedo_sb_timer_th
|
||||
| (uint8_t)apex_inputs->pedo_hi_enrgy_th;
|
||||
|
||||
/* Tilt, Lowg and highg parameters */
|
||||
/* APEX_CONFIG5_MREG1 */
|
||||
apexConfig[3] = (uint8_t)apex_inputs->tilt_wait_time
|
||||
| (uint8_t)apex_inputs->lowg_peak_hyst
|
||||
| (uint8_t)apex_inputs->highg_peak_hyst;
|
||||
|
||||
status |= inv_imu_write_reg(s, APEX_CONFIG2_MREG1, 4, &apexConfig[0]);
|
||||
|
||||
|
||||
/* APEX_CONFIG0 */
|
||||
status |= inv_imu_read_reg(s, APEX_CONFIG0, 1, &apexConfig[0]);
|
||||
apexConfig[0] &= ~APEX_CONFIG0_DMP_POWER_SAVE_EN_MASK;
|
||||
apexConfig[0] |= apex_inputs->power_save;
|
||||
status |= inv_imu_write_reg(s, APEX_CONFIG0, 1, &apexConfig[0]);
|
||||
|
||||
/* free fall parameter, SMD parameter and parameters for Pedometer in Slow Walk mode */
|
||||
/* APEX_CONFIG9_MREG1 */
|
||||
apexConfig[0] = (uint8_t)apex_inputs->ff_debounce_duration
|
||||
| (uint8_t)apex_inputs->smd_sensitivity
|
||||
| (uint8_t)apex_inputs->sensitivity_mode;
|
||||
|
||||
/* Lowg and highg parameters and free fall parameters */
|
||||
/* APEX_CONFIG10_MREG1 */
|
||||
apexConfig[1] = (uint8_t)apex_inputs->lowg_peak_th
|
||||
| (uint8_t)apex_inputs->lowg_samples_th;
|
||||
|
||||
/* APEX_CONFIG11_MREG1 */
|
||||
apexConfig[2] = (uint8_t)apex_inputs->highg_peak_th
|
||||
| (uint8_t)apex_inputs->highg_samples_th;
|
||||
|
||||
status |= inv_imu_write_reg(s, APEX_CONFIG9_MREG1, 3, &apexConfig[0]);
|
||||
|
||||
|
||||
/* APEX_CONFIG12_MREG1 */
|
||||
apexConfig[0] = (uint8_t)apex_inputs->ff_max_duration_cm
|
||||
| (uint8_t)apex_inputs->ff_min_duration_cm;
|
||||
|
||||
status |= inv_imu_write_reg(s, APEX_CONFIG12_MREG1, 1, &apexConfig[0]);
|
||||
|
||||
status |= inv_imu_switch_off_mclk(s);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int inv_imu_apex_get_parameters(struct inv_imu_device *s, inv_imu_apex_parameters_t *apex_params)
|
||||
{
|
||||
int status = 0;
|
||||
uint8_t data[7];
|
||||
uint8_t value;
|
||||
|
||||
status |= inv_imu_read_reg(s, APEX_CONFIG0, 1, &value);
|
||||
apex_params->power_save = (APEX_CONFIG0_DMP_POWER_SAVE_t)(value & APEX_CONFIG0_DMP_POWER_SAVE_EN_MASK);
|
||||
|
||||
/* Access continuous config registers (CONFIG2-CONFIG11) */
|
||||
status |= inv_imu_read_reg(s, APEX_CONFIG2_MREG1, sizeof(data), &data[0]);
|
||||
|
||||
/* Get params from apex_config2 : dmp_power_save_time and low_energy_amp_th */
|
||||
apex_params->power_save_time = (APEX_CONFIG2_DMP_POWER_SAVE_TIME_t)
|
||||
(data[0] & APEX_CONFIG2_DMP_POWER_SAVE_TIME_SEL_MASK);
|
||||
apex_params->low_energy_amp_th = (APEX_CONFIG2_LOW_ENERGY_AMP_TH_t)
|
||||
(data[0] & APEX_CONFIG2_LOW_ENERGY_AMP_TH_SEL_MASK);
|
||||
|
||||
/* Get params from apex_config3 : pedo_amp_th and pedo_step_cnt_th */
|
||||
apex_params->pedo_amp_th = (APEX_CONFIG3_PEDO_AMP_TH_t)
|
||||
(data[1] & APEX_CONFIG3_PED_AMP_TH_SEL_MASK);
|
||||
apex_params->pedo_step_cnt_th = (data[1] & APEX_CONFIG3_PED_STEP_CNT_TH_SEL_MASK)
|
||||
>> APEX_CONFIG3_PED_STEP_CNT_TH_SEL_POS;
|
||||
|
||||
/* Get params from apex_config4 : pedo_step_det_th, pedo_sb_timer_th and pedo_hi_enrgy_th */
|
||||
apex_params->pedo_step_det_th = (data[2] & APEX_CONFIG4_PED_STEP_DET_TH_SEL_MASK)
|
||||
>> APEX_CONFIG4_PED_STEP_DET_TH_SEL_POS;
|
||||
apex_params->pedo_sb_timer_th = (APEX_CONFIG4_PEDO_SB_TIMER_TH_t)
|
||||
(data[2] & APEX_CONFIG4_PED_SB_TIMER_TH_SEL_MASK);
|
||||
apex_params->pedo_hi_enrgy_th = (APEX_CONFIG4_PEDO_HI_ENRGY_TH_t)
|
||||
(data[2] & APEX_CONFIG4_PED_HI_EN_TH_SEL_MASK);
|
||||
|
||||
/* Get params from apex_config5 : tilt_wait_time, lowg_peak_hyst and highg_peak_hyst */
|
||||
apex_params->tilt_wait_time = (APEX_CONFIG5_TILT_WAIT_TIME_t)
|
||||
(data[3] & APEX_CONFIG5_TILT_WAIT_TIME_SEL_MASK);
|
||||
apex_params->lowg_peak_hyst = (APEX_CONFIG5_LOWG_PEAK_TH_HYST_t)
|
||||
(data[3] & APEX_CONFIG5_LOWG_PEAK_TH_HYST_SEL_MASK);
|
||||
apex_params->highg_peak_hyst = (APEX_CONFIG5_HIGHG_PEAK_TH_HYST_t)
|
||||
(data[3] & APEX_CONFIG5_HIGHG_PEAK_TH_HYST_SEL_MASK);
|
||||
|
||||
/* Get params from apex_config9 : ff_debounce_duration, smd_sensitivity and sensitivity_mode */
|
||||
apex_params->ff_debounce_duration = (APEX_CONFIG9_FF_DEBOUNCE_DURATION_t)
|
||||
(data[4] & APEX_CONFIG9_FF_DEBOUNCE_DURATION_SEL_MASK);
|
||||
apex_params->smd_sensitivity = (APEX_CONFIG9_SMD_SENSITIVITY_t)
|
||||
(data[4] & APEX_CONFIG9_SMD_SENSITIVITY_SEL_MASK);
|
||||
apex_params->sensitivity_mode = (APEX_CONFIG9_SENSITIVITY_MODE_t)
|
||||
(data[4] & APEX_CONFIG9_SENSITIVITY_MODE_MASK);
|
||||
|
||||
/* Get params from apex_config10 : lowg_peak_th and lowg_samples_th */
|
||||
apex_params->lowg_peak_th = (APEX_CONFIG10_LOWG_PEAK_TH_t)
|
||||
(data[5] & APEX_CONFIG10_LOWG_PEAK_TH_SEL_MASK);
|
||||
apex_params->lowg_samples_th = (APEX_CONFIG10_LOWG_TIME_TH_SAMPLES_t)
|
||||
(data[5] & APEX_CONFIG10_LOWG_TIME_TH_SEL_MASK);
|
||||
|
||||
/* Get params from apex_config11 : highg_peak_th and highg_samples_th */
|
||||
apex_params->highg_peak_th = (APEX_CONFIG11_HIGHG_PEAK_TH_t)
|
||||
(data[6] & APEX_CONFIG11_HIGHG_PEAK_TH_SEL_MASK);
|
||||
apex_params->highg_samples_th = (APEX_CONFIG11_HIGHG_TIME_TH_SAMPLES_t)
|
||||
(data[6] & APEX_CONFIG11_HIGHG_TIME_TH_SEL_MASK);
|
||||
|
||||
/* Access apex reg 12 */
|
||||
status |= inv_imu_read_reg(s, APEX_CONFIG12_MREG1, 1, &data[0]);
|
||||
|
||||
/* Get params from apex_config12 : ff_max_duration_cm and ff_min_duration_cm */
|
||||
apex_params->ff_max_duration_cm = (APEX_CONFIG12_FF_MAX_DURATION_t)
|
||||
(data[0] & APEX_CONFIG12_FF_MAX_DURATION_SEL_MASK);
|
||||
apex_params->ff_min_duration_cm = (APEX_CONFIG12_FF_MIN_DURATION_t)
|
||||
(data[0] & APEX_CONFIG12_FF_MIN_DURATION_SEL_MASK);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int inv_imu_apex_set_frequency(struct inv_imu_device *s, const APEX_CONFIG1_DMP_ODR_t frequency)
|
||||
{
|
||||
uint8_t value;
|
||||
int status = 0;
|
||||
|
||||
status |= inv_imu_read_reg(s, APEX_CONFIG1, 1, &value);
|
||||
|
||||
value &= ~APEX_CONFIG1_DMP_ODR_MASK;
|
||||
value |= frequency;
|
||||
|
||||
status |= inv_imu_write_reg(s, APEX_CONFIG1, 1, &value);
|
||||
return status;
|
||||
}
|
||||
|
||||
int inv_imu_apex_enable_pedometer(struct inv_imu_device *s)
|
||||
{
|
||||
int status = 0;
|
||||
uint8_t value;
|
||||
|
||||
status |= inv_imu_start_dmp(s);
|
||||
|
||||
/* Enable Pedometer */
|
||||
status |= inv_imu_read_reg(s, APEX_CONFIG1, 1, &value);
|
||||
value &= ~APEX_CONFIG1_PED_ENABLE_MASK;
|
||||
value |= (uint8_t)APEX_CONFIG1_PED_ENABLE_EN;
|
||||
status |= inv_imu_write_reg(s, APEX_CONFIG1, 1, &value);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int inv_imu_apex_disable_pedometer(struct inv_imu_device *s)
|
||||
{
|
||||
int status = 0;
|
||||
uint8_t value;
|
||||
|
||||
/* Disable Pedometer */
|
||||
status |= inv_imu_read_reg(s, APEX_CONFIG1, 1, &value);
|
||||
value &= ~APEX_CONFIG1_PED_ENABLE_MASK;
|
||||
value |= (uint8_t)APEX_CONFIG1_PED_ENABLE_DIS;
|
||||
status |= inv_imu_write_reg(s, APEX_CONFIG1, 1, &value);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int inv_imu_apex_enable_tilt(struct inv_imu_device *s)
|
||||
{
|
||||
int status = 0;
|
||||
uint8_t value;
|
||||
|
||||
status |= inv_imu_start_dmp(s);
|
||||
|
||||
/* Enable Tilt */
|
||||
status |= inv_imu_read_reg(s, APEX_CONFIG1, 1, &value);
|
||||
value &= ~APEX_CONFIG1_TILT_ENABLE_MASK;
|
||||
value |= (uint8_t)APEX_CONFIG1_TILT_ENABLE_EN;
|
||||
status |= inv_imu_write_reg(s, APEX_CONFIG1, 1, &value);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int inv_imu_apex_disable_tilt(struct inv_imu_device *s)
|
||||
{
|
||||
int status = 0;
|
||||
uint8_t value;
|
||||
|
||||
/* Disable Tilt */
|
||||
status |= inv_imu_read_reg(s, APEX_CONFIG1, 1, &value);
|
||||
value &= ~APEX_CONFIG1_TILT_ENABLE_MASK;
|
||||
value |= (uint8_t)APEX_CONFIG1_TILT_ENABLE_DIS;
|
||||
status |= inv_imu_write_reg(s, APEX_CONFIG1, 1, &value);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int inv_imu_apex_get_data_activity(struct inv_imu_device *s, inv_imu_apex_step_activity_t *apex_activity)
|
||||
{
|
||||
uint8_t data[4];
|
||||
int status = inv_imu_read_reg(s, APEX_DATA0, 4, data);
|
||||
|
||||
apex_activity->step_cnt = data[1] << 8 | data[0];
|
||||
apex_activity->step_cadence = data[2];
|
||||
apex_activity->activity_class = data[3] & APEX_DATA3_ACTIVITY_CLASS_MASK;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int inv_imu_apex_get_data_free_fall(struct inv_imu_device *s, uint16_t *freefall_duration)
|
||||
{
|
||||
uint8_t data[2];
|
||||
int status = inv_imu_read_reg(s, APEX_DATA4, 2, &data[0]);
|
||||
|
||||
*freefall_duration = (data[1] << 8) | data[0];
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
186
apps/common/device/imu_sensor/icm_42670p/inv_imu_apex.h
Normal file
186
apps/common/device/imu_sensor/icm_42670p/inv_imu_apex.h
Normal file
@ -0,0 +1,186 @@
|
||||
/*
|
||||
* ________________________________________________________________________________________________________
|
||||
* Copyright (c) 2017 InvenSense Inc. All rights reserved.
|
||||
*
|
||||
* This software, related documentation and any modifications thereto (collectively "Software") is subject
|
||||
* to InvenSense and its licensors' intellectual property rights under U.S. and international copyright
|
||||
* and other intellectual property rights laws.
|
||||
*
|
||||
* InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software
|
||||
* and any use, reproduction, disclosure or distribution of the Software without an express license agreement
|
||||
* from InvenSense is strictly prohibited.
|
||||
*
|
||||
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, THE SOFTWARE IS
|
||||
* PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
|
||||
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, IN NO EVENT SHALL
|
||||
* INVENSENSE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY
|
||||
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
||||
* OF THE SOFTWARE.
|
||||
* ________________________________________________________________________________________________________
|
||||
*/
|
||||
|
||||
/** @defgroup DriverApex IMU driver high level functions related to APEX and the DMP
|
||||
* @brief High-level function to setup an IMU device
|
||||
* @ingroup Driver
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @file inv_imu_apex.h
|
||||
* High-level function to setup an IMU device
|
||||
*/
|
||||
|
||||
#ifndef _INV_IMU_APEX_H_
|
||||
#define _INV_IMU_APEX_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "inv_imu_defs.h"
|
||||
|
||||
#include "InvError.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
/* Forward declarations */
|
||||
struct inv_imu_device;
|
||||
|
||||
/** @brief IMU APEX inputs parameters definition
|
||||
*/
|
||||
typedef struct {
|
||||
APEX_CONFIG3_PEDO_AMP_TH_t pedo_amp_th;
|
||||
uint8_t pedo_step_cnt_th;
|
||||
uint8_t pedo_step_det_th;
|
||||
APEX_CONFIG4_PEDO_SB_TIMER_TH_t pedo_sb_timer_th;
|
||||
APEX_CONFIG4_PEDO_HI_ENRGY_TH_t pedo_hi_enrgy_th;
|
||||
APEX_CONFIG5_TILT_WAIT_TIME_t tilt_wait_time;
|
||||
APEX_CONFIG2_DMP_POWER_SAVE_TIME_t power_save_time;
|
||||
APEX_CONFIG0_DMP_POWER_SAVE_t power_save;
|
||||
APEX_CONFIG9_SENSITIVITY_MODE_t sensitivity_mode;
|
||||
APEX_CONFIG2_LOW_ENERGY_AMP_TH_t low_energy_amp_th;
|
||||
APEX_CONFIG9_SMD_SENSITIVITY_t smd_sensitivity;
|
||||
APEX_CONFIG9_FF_DEBOUNCE_DURATION_t ff_debounce_duration;
|
||||
APEX_CONFIG12_FF_MAX_DURATION_t ff_max_duration_cm;
|
||||
APEX_CONFIG12_FF_MIN_DURATION_t ff_min_duration_cm;
|
||||
APEX_CONFIG10_LOWG_PEAK_TH_t lowg_peak_th;
|
||||
APEX_CONFIG5_LOWG_PEAK_TH_HYST_t lowg_peak_hyst;
|
||||
APEX_CONFIG10_LOWG_TIME_TH_SAMPLES_t lowg_samples_th;
|
||||
APEX_CONFIG11_HIGHG_PEAK_TH_t highg_peak_th;
|
||||
APEX_CONFIG5_HIGHG_PEAK_TH_HYST_t highg_peak_hyst;
|
||||
APEX_CONFIG11_HIGHG_TIME_TH_SAMPLES_t highg_samples_th;
|
||||
} inv_imu_apex_parameters_t;
|
||||
|
||||
/** @brief APEX pedometer outputs
|
||||
*/
|
||||
typedef struct inv_imu_apex_step_activity {
|
||||
uint16_t step_cnt; /**< Number of steps taken */
|
||||
uint8_t step_cadence; /**< Walk/run cadence in number of samples.
|
||||
Format is u6.2. E.g, At 50Hz and 2Hz walk frequency, if the cadency is 25 samples.
|
||||
The register will output 100. */
|
||||
uint8_t activity_class; /**< Detected activity unknown (0), walk (1) or run (2) */
|
||||
} inv_imu_apex_step_activity_t;
|
||||
|
||||
/** @brief Enable Free Fall.
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_apex_enable_ff(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Disable Free Fall.
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_apex_disable_ff(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Enable Significant Motion Detection.
|
||||
* note : SMD requests to have the accelerometer enabled to work.
|
||||
* To have good performance, it's recommended to set accelerometer ODR (Output Data Rate) to 20ms
|
||||
* and the accelerometer in Low Power Mode.
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_apex_enable_smd(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Disable Significant Motion Detection.
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_apex_disable_smd(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Fill the APEX parameters structure with all the default parameters for APEX algorithms (pedometer, tilt)
|
||||
* @param[out] apex_inputs Default input parameters. See @sa inv_imu_apex_parameters_t
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_apex_init_parameters_struct(struct inv_imu_device *s, inv_imu_apex_parameters_t *apex_inputs);
|
||||
|
||||
/** @brief Configures DMP parameters for APEX algorithms (pedometer, tilt, lowg, highg).
|
||||
* This programmable parameters will be decoded and propagate to the SRAM to be executed at DMP start.
|
||||
* @param[in] apex_inputs The requested input parameters. See @sa inv_imu_apex_parameters_t
|
||||
* @warning APEX inputs can't change on the fly, this API should be called before enabling any APEX features.
|
||||
* @warning APEX configuration can't be done too frequently, but only once every 10ms.
|
||||
* Otherwise it can create unknown behavior.
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_apex_configure_parameters(struct inv_imu_device *s, const inv_imu_apex_parameters_t *apex_inputs);
|
||||
|
||||
/** @brief Returns current DMP parameters for APEX algorithms (pedometer, tilt).
|
||||
* @param[out] apex_params The current parameter, fetched from registers. See @sa inv_imu_apex_parameters_t
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_apex_get_parameters(struct inv_imu_device *s, inv_imu_apex_parameters_t *apex_params);
|
||||
|
||||
/** @brief Configure DMP Output Data Rate for APEX algorithms (pedometer, tilt)
|
||||
* @param[in] frequency The requested frequency.
|
||||
* @sa APEX_CONFIG1_DMP_ODR_t
|
||||
* @warning DMP_ODR can change on the fly, and the DMP code will accommodate necessary modifications
|
||||
* @warning The user needs to take care to set Accel frequency >= DMP frequency. This is a hard constraint
|
||||
since HW will not handle incorrect setting.
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_apex_set_frequency(struct inv_imu_device *s, const APEX_CONFIG1_DMP_ODR_t frequency);
|
||||
|
||||
/** @brief Enable APEX algorithm Pedometer.
|
||||
* note : Pedometer request to have the accelerometer enabled to works
|
||||
* with accelerometer frequency less than dmp frequency.
|
||||
* @return 0 on success, negative value on error.
|
||||
* @warning Pedometer must be turned OFF to reconfigure it
|
||||
*/
|
||||
int inv_imu_apex_enable_pedometer(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Disable APEX algorithm Pedometer.
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_apex_disable_pedometer(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Enable APEX algorithm Tilt.
|
||||
* note : Tilt request to have the accelerometer enabled to works
|
||||
* with accelerometer frequency less than dmp frequency.
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_apex_enable_tilt(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Disable APEX algorithm Tilt.
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_apex_disable_tilt(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Retrieve APEX pedometer outputs and format them
|
||||
* @param[out] apex_activity Apex step and activity data value.
|
||||
* @return 0 in case of success, negative value on error. See enum inv_error
|
||||
*/
|
||||
int inv_imu_apex_get_data_activity(struct inv_imu_device *s, inv_imu_apex_step_activity_t *apex_activity);
|
||||
|
||||
/** @brief Retrieve APEX free fall outputs and format them
|
||||
* @param[out] Free fall duration in number of sample.
|
||||
* @return 0 in case of success, negative value on error. See enum inv_error
|
||||
*/
|
||||
int inv_imu_apex_get_data_free_fall(struct inv_imu_device *s, uint16_t *freefall_duration);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _INV_IMU_APEX_H_ */
|
||||
|
||||
/** @} */
|
||||
|
||||
1014
apps/common/device/imu_sensor/icm_42670p/inv_imu_defs.h
Normal file
1014
apps/common/device/imu_sensor/icm_42670p/inv_imu_defs.h
Normal file
File diff suppressed because it is too large
Load Diff
1722
apps/common/device/imu_sensor/icm_42670p/inv_imu_driver.c
Normal file
1722
apps/common/device/imu_sensor/icm_42670p/inv_imu_driver.c
Normal file
File diff suppressed because it is too large
Load Diff
533
apps/common/device/imu_sensor/icm_42670p/inv_imu_driver.h
Normal file
533
apps/common/device/imu_sensor/icm_42670p/inv_imu_driver.h
Normal file
@ -0,0 +1,533 @@
|
||||
/*
|
||||
* ________________________________________________________________________________________________________
|
||||
* Copyright (c) 2017 InvenSense Inc. All rights reserved.
|
||||
*
|
||||
* This software, related documentation and any modifications thereto (collectively "Software") is subject
|
||||
* to InvenSense and its licensors' intellectual property rights under U.S. and international copyright
|
||||
* and other intellectual property rights laws.
|
||||
*
|
||||
* InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software
|
||||
* and any use, reproduction, disclosure or distribution of the Software without an express license agreement
|
||||
* from InvenSense is strictly prohibited.
|
||||
*
|
||||
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, THE SOFTWARE IS
|
||||
* PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
|
||||
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, IN NO EVENT SHALL
|
||||
* INVENSENSE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY
|
||||
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
||||
* OF THE SOFTWARE.
|
||||
* ________________________________________________________________________________________________________
|
||||
*/
|
||||
|
||||
/** @defgroup Driver IMU driver high level functions
|
||||
* @brief High-level function to setup an IMU device
|
||||
* @ingroup DriverIcm
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @file inv_imu_driver.h
|
||||
* High-level function to setup an IMU device
|
||||
*/
|
||||
|
||||
#ifndef _INV_IMU_DRIVER_H_
|
||||
#define _INV_IMU_DRIVER_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "inv_imu_defs.h"
|
||||
#include "inv_imu_transport.h"
|
||||
|
||||
#include "InvError.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
/** @brief IMU max FSR values for accel and gyro
|
||||
* Dependent on chip
|
||||
*/
|
||||
#define ACCEL_CONFIG0_FS_SEL_MAX ACCEL_CONFIG0_FS_SEL_16g
|
||||
#define GYRO_CONFIG0_FS_SEL_MAX GYRO_CONFIG0_FS_SEL_2000dps
|
||||
|
||||
#define ACCEL_OFFUSER_MAX_MG 1000
|
||||
#define GYRO_OFFUSER_MAX_DPS 64
|
||||
|
||||
/** @brief IMU maximum buffer size mirrored from FIFO at polling time
|
||||
* @warning fifo_idx type variable must be large enough to parse the FIFO_MIRRORING_SIZE
|
||||
*/
|
||||
#define FIFO_MIRRORING_SIZE 16 * 258 // packet size * max_count = 4kB
|
||||
|
||||
/** @brief IMU Accelerometer start-up time before having correct data
|
||||
*/
|
||||
#define ACC_STARTUP_TIME_US 10000
|
||||
|
||||
/** @brief IMU Gyroscope start-up time before having correct data
|
||||
*/
|
||||
#define GYR_STARTUP_TIME_US 70000
|
||||
|
||||
/** @brief IMU Gyroscope power off to power on duration
|
||||
*/
|
||||
#define GYR_POWER_OFF_DUR_US 20000
|
||||
|
||||
/** @brief Sensor identifier for UI control function
|
||||
*/
|
||||
enum inv_imu_sensor {
|
||||
INV_SENSOR_ACCEL, /**< Accelerometer */
|
||||
INV_SENSOR_GYRO, /**< Gyroscope */
|
||||
INV_SENSOR_FSYNC_EVENT, /**< FSYNC */
|
||||
INV_SENSOR_TEMPERATURE, /**< Chip temperature */
|
||||
INV_SENSOR_DMP_PEDOMETER_EVENT, /**< Pedometer: step detected */
|
||||
INV_SENSOR_DMP_PEDOMETER_COUNT, /**< Pedometer: step counter */
|
||||
INV_SENSOR_DMP_TILT, /**< Tilt */
|
||||
INV_SENSOR_DMP_FF, /**< FreeFall */
|
||||
INV_SENSOR_DMP_LOWG, /**< Low G */
|
||||
INV_SENSOR_DMP_SMD, /**< Significant Motion Detection */
|
||||
INV_SENSOR_MAX
|
||||
};
|
||||
|
||||
/** @brief Configure Fifo usage
|
||||
*/
|
||||
typedef enum {
|
||||
INV_IMU_FIFO_DISABLED = 0, /**< Fifo is disabled and data source is sensors registers */
|
||||
INV_IMU_FIFO_ENABLED = 1, /**< Fifo is used as data source */
|
||||
} INV_IMU_FIFO_CONFIG_t;
|
||||
|
||||
/** @brief Sensor event structure definition
|
||||
*/
|
||||
typedef struct {
|
||||
int sensor_mask;
|
||||
uint16_t timestamp_fsync;
|
||||
int16_t accel[3];
|
||||
int16_t gyro[3];
|
||||
int16_t temperature;
|
||||
int8_t accel_high_res[3];
|
||||
int8_t gyro_high_res[3];
|
||||
} inv_imu_sensor_event_t;
|
||||
|
||||
/** @brief IMU driver states definition
|
||||
*/
|
||||
struct inv_imu_device {
|
||||
struct inv_imu_transport transport; /**< Transport layer
|
||||
Must be the first one of struct inv_imu_device */
|
||||
void (*sensor_event_cb)(inv_imu_sensor_event_t *event); /**< callback executed by:
|
||||
inv_imu_get_data_from_fifo (if FIFO is used)
|
||||
inv_imu_get_data_from_registers (if FIFO isn't used)
|
||||
May be NULL if above API are not used by application */
|
||||
uint8_t fifo_data[FIFO_MIRRORING_SIZE]; /**< FIFO mirroring memory area */
|
||||
uint8_t dmp_is_on; /**< DMP started status */
|
||||
uint8_t endianness_data; /**< Data endianness configuration */
|
||||
uint8_t fifo_highres_enabled; /**< Highres mode configuration */
|
||||
INV_IMU_FIFO_CONFIG_t fifo_is_used; /**< FIFO configuration */
|
||||
uint64_t gyro_start_time_us; /**< Gyro start time used to discard first samples */
|
||||
uint64_t accel_start_time_us; /**< Accel start time used to discard first samples */
|
||||
uint64_t gyro_power_off_tmst; /**< Gyro power off time */
|
||||
};
|
||||
|
||||
|
||||
/* Interrupt enum state for INT1, INT2, and IBI */
|
||||
typedef enum {
|
||||
INV_IMU_DISABLE = 0,
|
||||
INV_IMU_ENABLE
|
||||
} inv_imu_interrupt_value;
|
||||
|
||||
/** @brief Interrupt definition
|
||||
*/
|
||||
typedef struct {
|
||||
inv_imu_interrupt_value INV_UI_FSYNC;
|
||||
inv_imu_interrupt_value INV_UI_DRDY;
|
||||
inv_imu_interrupt_value INV_FIFO_THS;
|
||||
inv_imu_interrupt_value INV_FIFO_FULL;
|
||||
inv_imu_interrupt_value INV_SMD;
|
||||
inv_imu_interrupt_value INV_WOM_X;
|
||||
inv_imu_interrupt_value INV_WOM_Y;
|
||||
inv_imu_interrupt_value INV_WOM_Z;
|
||||
inv_imu_interrupt_value INV_FF;
|
||||
inv_imu_interrupt_value INV_LOWG;
|
||||
inv_imu_interrupt_value INV_STEP_DET;
|
||||
inv_imu_interrupt_value INV_STEP_CNT_OVFL;
|
||||
inv_imu_interrupt_value INV_TILT_DET;
|
||||
} inv_imu_interrupt_parameter_t;
|
||||
|
||||
|
||||
/** @brief Configure the serial interface used to access the device and execute hardware initialization.
|
||||
*
|
||||
* This functions first configures serial interface passed in parameter to make sure device
|
||||
* is accessible both in read and write. Thus no serial access should be done before
|
||||
* successfully executing the present function.
|
||||
*
|
||||
* Then if requested serial interface is a primary interface (aka UI interface or AP
|
||||
* interface), this function initializes the device using the following hardware settings:
|
||||
* - set timestamp resolution to 16us
|
||||
* - enable FIFO mechanism with the following configuration:
|
||||
* - FIFO record mode i.e FIFO count unit is packet
|
||||
* - FIFO snapshot mode i.e drop the data when the FIFO overflows
|
||||
* - Timestamp is logged in FIFO
|
||||
* - Little Endian fifo_count and fifo_data
|
||||
* - generate FIFO threshold interrupt when packet count reaches FIFO watermark
|
||||
* - set FIFO watermark to 1 packet
|
||||
* - enable temperature and timestamp data to go to FIFO
|
||||
*
|
||||
*
|
||||
* @param[in] s driver structure. Note that first field of this structure MUST be a struct
|
||||
* inv_imu_serif.
|
||||
*
|
||||
* @param[in] serif pointer on serial interface structure to be used to access inv_device.
|
||||
*
|
||||
* @param[in] sensor_event_cb callback executed by inv_imu_get_data_from_fifo function
|
||||
* each time it extracts some valid data from fifo. Or inv_imu_get_data_from_registers read data
|
||||
* from register. Thus this parameter is optional as long
|
||||
* as inv_imu_get_data_from_fifo/inv_imu_get_data_from_registers function is not used.
|
||||
*
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_init(struct inv_imu_device *s,
|
||||
struct inv_imu_serif *serif,
|
||||
void (*sensor_event_cb)(inv_imu_sensor_event_t *event));
|
||||
|
||||
/** @brief Perform a soft reset of the device
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_device_reset(struct inv_imu_device *s);
|
||||
|
||||
/** @brief return WHOAMI value
|
||||
* @param[out] who_am_i WHOAMI for device
|
||||
* @return 0 on success, negative value on error
|
||||
*/
|
||||
int inv_imu_get_who_am_i(struct inv_imu_device *s, uint8_t *who_am_i);
|
||||
|
||||
/** @brief Enable/put accel in low power mode
|
||||
* @return 0 on success, negative value on error.
|
||||
* @details
|
||||
* It enables accel and gyro data in the FIFO (so
|
||||
* the packet format is 16 bytes). If called first,
|
||||
* the configuration will be applied, otherwise it
|
||||
* will be ignored if the FIFO is not empty (but since
|
||||
* the new configuration is identical it is not a issue).
|
||||
* @warning inv_device::register_cache::pwr_mgmt0_reg is modified by this function
|
||||
*/
|
||||
int inv_imu_enable_accel_low_power_mode(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Enable/put accel in low noise mode
|
||||
* @return 0 on success, negative value on error.
|
||||
* @details
|
||||
* It enables accel and gyro data in the FIFO (so
|
||||
* the packet format is 16 bytes). If called first,
|
||||
* the configuration will be applied, otherwise it
|
||||
* will be ignored if the FIFO is not empty (but since
|
||||
* the new configuration is identical it is not a issue).
|
||||
* @warning inv_device::register_cache::pwr_mgmt0_reg is modified by this function
|
||||
*/
|
||||
int inv_imu_enable_accel_low_noise_mode(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Disable all 3 axes of accel
|
||||
* @return 0 on success, negative value on error.
|
||||
* @details
|
||||
* If both accel and gyro are turned off as a result of this
|
||||
* function, they will also be removed from the FIFO and a
|
||||
* FIFO reset will be performed (to guarantee no side effects
|
||||
* until the next enable sensor call)
|
||||
* @warning inv_device::register_cache::pwr_mgmt0_reg is modified by this function
|
||||
*/
|
||||
int inv_imu_disable_accel(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Enable/put gyro in low noise mode
|
||||
* @return 0 on success, negative value on error.
|
||||
* @details
|
||||
* It enables gyro and accel data in the FIFO (so
|
||||
* the packet format is 16 bytes). If called first,
|
||||
* the configuration will be applied, otherwise it
|
||||
* will be ignored if the FIFO is not empty (but since
|
||||
* the new configuration is identical it is not a issue).
|
||||
* @warning inv_device::register_cache::pwr_mgmt0_reg is modified by this function
|
||||
*/
|
||||
int inv_imu_enable_gyro_low_noise_mode(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Disable all 3 axes of gyro
|
||||
* @return 0 on success, negative value on error.
|
||||
* @details
|
||||
* If both accel and gyro are turned off as a result of this
|
||||
* function, they will also be removed from the FIFO and a
|
||||
* FIFO reset will be performed (to guarantee no side effects
|
||||
* until the next enable sensor call)
|
||||
* @warning inv_device::register_cache::pwr_mgmt0_reg is modified by this function
|
||||
*/
|
||||
int inv_imu_disable_gyro(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Enable fsync tagging functionality.
|
||||
* In details it:
|
||||
* - enables fsync
|
||||
* - enables timestamp to registers. Once fsync is enabled fsync counter is pushed to
|
||||
* fifo instead of timestamp. So timestamp is made available in registers. Note that
|
||||
* this increase power consumption.
|
||||
* - enables fsync related interrupt
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_enable_fsync(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Disable fsync tagging functionality.
|
||||
* In details it:
|
||||
* - disables fsync
|
||||
* - disables timestamp to registers. Once fsync is disabled timestamp is pushed to fifo
|
||||
* instead of fsync counter. So in order to decrease power consumption, timestamp is no
|
||||
* more available in registers.
|
||||
* - disables fsync related interrupt
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_disable_fsync(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Configure which interrupt source can trigger INT1.
|
||||
* @param[in] interrupt_to_configure structure with the corresponding state to manage INT1.
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_set_config_int1(struct inv_imu_device *s,
|
||||
inv_imu_interrupt_parameter_t *interrupt_to_configure);
|
||||
|
||||
/** @brief Retrieve interrupts configuration.
|
||||
* @param[in] interrupt_to_configure structure with the corresponding state to manage INT1.
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_get_config_int1(struct inv_imu_device *s,
|
||||
inv_imu_interrupt_parameter_t *interrupt_to_configure);
|
||||
|
||||
/** @brief Configure which interrupt source can trigger INT2.
|
||||
* @param[in] interrupt_to_configure structure with the corresponding state to INT2.
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_set_config_int2(struct inv_imu_device *s,
|
||||
inv_imu_interrupt_parameter_t *interrupt_to_configure);
|
||||
|
||||
/** @brief Retrieve interrupts configuration.
|
||||
* @param[in] interrupt_to_configure structure with the corresponding state to manage INT2.
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_get_config_int2(struct inv_imu_device *s,
|
||||
inv_imu_interrupt_parameter_t *interrupt_to_configure);
|
||||
|
||||
/** @brief Read all registers containing data (temperature, accelerometer and gyroscope). Then it calls
|
||||
* sensor_event_cb function passed in parameter of inv_imu_init function for each packet
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_get_data_from_registers(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Read all available packets from the FIFO. For each packet function builds a
|
||||
* sensor event containing packet data and validity information. Then it calls
|
||||
* sensor_event_cb funtion passed in parameter of inv_imu_init function for each
|
||||
* packet.
|
||||
* @return number of valid packets read on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_get_data_from_fifo(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Converts ACCEL_CONFIG0_ODR_t or GYRO_CONFIG0_ODR_t enums to period expressed in us
|
||||
* @param[in] odr_bitfield An ACCEL_CONFIG0_ODR_t or GYRO_CONFIG0_ODR_t enum
|
||||
* @return The corresponding period expressed in us
|
||||
*/
|
||||
uint32_t inv_imu_convert_odr_bitfield_to_us(uint32_t odr_bitfield);
|
||||
|
||||
/** @brief Configure accel Output Data Rate
|
||||
* @param[in] frequency The requested frequency.
|
||||
* @sa ACCEL_CONFIG0_ODR_t
|
||||
* @return 0 on success, negative value on error.
|
||||
* @warning inv_device::register_cache::accel_config0_reg is modified by this function
|
||||
*/
|
||||
int inv_imu_set_accel_frequency(struct inv_imu_device *s,
|
||||
const ACCEL_CONFIG0_ODR_t frequency);
|
||||
|
||||
/** @brief Configure gyro Output Data Rate
|
||||
* @param[in] frequency The requested frequency.
|
||||
* @sa GYRO_CONFIG0_ODR_t
|
||||
* @return 0 on success, negative value on error.
|
||||
* @warning inv_device::register_cache::gyro_config0_reg is modified by this function
|
||||
*/
|
||||
int inv_imu_set_gyro_frequency(struct inv_imu_device *s,
|
||||
const GYRO_CONFIG0_ODR_t frequency);
|
||||
|
||||
/** @brief Set accel full scale range
|
||||
* @param[in] accel_fsr_g requested full scale range.
|
||||
* @sa ACCEL_CONFIG0_FS_SEL_t.
|
||||
* @return 0 on success, negative value on error.
|
||||
* @warning inv_device::register_cache::accel_config0_reg is modified by this function
|
||||
*/
|
||||
int inv_imu_set_accel_fsr(struct inv_imu_device *s,
|
||||
ACCEL_CONFIG0_FS_SEL_t accel_fsr_g);
|
||||
|
||||
/** @brief Access accel full scale range
|
||||
* @param[out] accel_fsr_g current full scale range.
|
||||
* @sa ACCEL_CONFIG0_FS_SEL_t.
|
||||
* @return 0 on success, negative value on error.
|
||||
* @warning inv_device::register_cache::accel_config0_reg is relied upon by this function
|
||||
*/
|
||||
int inv_imu_get_accel_fsr(struct inv_imu_device *s,
|
||||
ACCEL_CONFIG0_FS_SEL_t *accel_fsr_g);
|
||||
|
||||
/** @brief Set gyro full scale range
|
||||
* @param[in] gyro_fsr_dps requested full scale range.
|
||||
* @sa GYRO_CONFIG0_FS_SEL_t.
|
||||
* @return 0 on success, negative value on error.
|
||||
* @warning inv_device::register_cache::gyro_config0_reg is modified by this function
|
||||
*/
|
||||
int inv_imu_set_gyro_fsr(struct inv_imu_device *s,
|
||||
GYRO_CONFIG0_FS_SEL_t gyro_fsr_dps);
|
||||
|
||||
/** @brief Access gyro full scale range
|
||||
* @param[out] gyro_fsr_dps current full scale range.
|
||||
* @sa GYRO_CONFIG0_FS_SEL_t.
|
||||
* @return 0 on success, negative value on error.
|
||||
* @warning inv_device::register_cache::gyro_config0_reg is relied upon by this function
|
||||
*/
|
||||
int inv_imu_get_gyro_fsr(struct inv_imu_device *s,
|
||||
GYRO_CONFIG0_FS_SEL_t *gyro_fsr_dps);
|
||||
|
||||
/** @brief Set accel Low-Power averaging value
|
||||
* @param[in] acc_avg requested averaging value
|
||||
* @sa ACCEL_CONFIG1_ACCEL_FILT_AVG_t
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_set_accel_lp_avg(struct inv_imu_device *s,
|
||||
ACCEL_CONFIG1_ACCEL_FILT_AVG_t acc_avg);
|
||||
|
||||
/** @brief Set accel Low-Noise bandwidth value
|
||||
* @param[in] acc_bw requested averaging value
|
||||
* @sa ACCEL_CONFIG1_ACCEL_FILT_BW_t
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_set_accel_ln_bw(struct inv_imu_device *s,
|
||||
ACCEL_CONFIG1_ACCEL_FILT_BW_t acc_bw);
|
||||
|
||||
/** @brief Set gyro Low-Noise bandwidth value
|
||||
* @param[in] gyr_bw requested averaging value
|
||||
* @sa GYRO_CONFIG1_GYRO_FILT_BW_t
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_set_gyro_ln_bw(struct inv_imu_device *s,
|
||||
GYRO_CONFIG1_GYRO_FILT_BW_t gyr_bw);
|
||||
|
||||
/** @brief Set timestamp resolution
|
||||
* @param[in] timestamp_resol requested timestamp resolution
|
||||
* @sa TMST_CONFIG1_RESOL_t
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_set_timestamp_resolution(struct inv_imu_device *s,
|
||||
const TMST_CONFIG1_RESOL_t timestamp_resol);
|
||||
|
||||
/** @brief reset IMU fifo
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_reset_fifo(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Enable 20 bits raw acc and raw gyr data in fifo.
|
||||
* @return 0 on success, negative return code otherwise
|
||||
*/
|
||||
int inv_imu_enable_high_resolution_fifo(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Disable 20 bits raw acc and raw gyr data in fifo.
|
||||
* @return 0 on success, negative return code otherwise
|
||||
*/
|
||||
int inv_imu_disable_high_resolution_fifo(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Configure Fifo
|
||||
* @param[in] fifo_config Fifo configuration method :
|
||||
* if FIFO is enabled, data are pushed to FIFO and FIFO THS interrupt is set
|
||||
* if FIFO is disabled, data are not pused to FIFO and DRDY interrupt is set
|
||||
* @sa INV_IMU_FIFO_CONFIG_t
|
||||
*/
|
||||
int inv_imu_configure_fifo(struct inv_imu_device *s,
|
||||
INV_IMU_FIFO_CONFIG_t fifo_config);
|
||||
|
||||
/** @brief Get FIFO timestamp resolution
|
||||
* @return the timestamp resolution in us as a q24 or 0 in case of error
|
||||
*/
|
||||
uint32_t inv_imu_get_fifo_timestamp_resolution_us_q24(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Get register timestamp resolution
|
||||
* @return the timestamp resolution in us as a q24 or 0 in case of error
|
||||
*/
|
||||
uint32_t inv_imu_get_reg_timestamp_resolution_us_q24(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Enable Wake On Motion.
|
||||
* @param[in] wom_x_th threshold value for the Wake on Motion Interrupt for X-axis accelerometer.
|
||||
* @param[in] wom_y_th threshold value for the Wake on Motion Interrupt for Y-axis accelerometer.
|
||||
* @param[in] wom_z_th threshold value for the Wake on Motion Interrupt for Z-axis accelerometer.
|
||||
* @param[in] wom_int select which mode between AND/OR is used to generate interrupt.
|
||||
* @param[in] wom_dur select the number of overthreshold event to wait before generating interrupt.
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_configure_wom(struct inv_imu_device *s,
|
||||
const uint8_t wom_x_th,
|
||||
const uint8_t wom_y_th,
|
||||
const uint8_t wom_z_th,
|
||||
WOM_CONFIG_WOM_INT_MODE_t wom_int,
|
||||
WOM_CONFIG_WOM_INT_DUR_t wom_dur);
|
||||
|
||||
/** @brief Enable Wake On Motion.
|
||||
* note : WoM requests to have the accelerometer enabled to work.
|
||||
* As a consequence Fifo water-mark interrupt is disabled to only trigger WoM interrupts.
|
||||
* To have good performance, it's recommended to set accelerometer ODR (Output Data Rate) to 20ms
|
||||
* and the accelerometer in Low Power Mode.
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_enable_wom(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Disable Wake On Motion.
|
||||
* note : Fifo water-mark interrupt is re-enabled when WoM is disabled.
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_disable_wom(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Start DMP for APEX algorithms and selftest
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_start_dmp(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Reset DMP for APEX algorithms and selftest
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_reset_dmp(struct inv_imu_device *s,
|
||||
const APEX_CONFIG0_DMP_MEM_RESET_t sram_reset);
|
||||
|
||||
/** @breif Set the UI endianness and set the inv_device endianness field
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_set_endianness(struct inv_imu_device *s,
|
||||
INTF_CONFIG0_DATA_ENDIAN_t endianness);
|
||||
|
||||
/** @breif Read the UI endianness and set the inv_device endianness field
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_get_endianness(struct inv_imu_device *s);
|
||||
|
||||
//The device powers up in sleep mode.
|
||||
//any time change
|
||||
//Sleep mode, and Accelerometer low power mode with WUOSC do not support MREG1, MREG2 or MREG3 access.
|
||||
//need power on the RC oscillator using register field IDLE from register PWR_MGMT0.
|
||||
int inv_imu_enter_sleep(struct inv_imu_device *s);
|
||||
|
||||
//power on:
|
||||
//After powering the gyroscope off, a period of > 20ms should be allowed to elapse before it is powered back on.
|
||||
//Accelerometer Startup Time From sleep mode to valid data:10ms.
|
||||
//gpro need >45ms
|
||||
int inv_imu_exit_sleep(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Configure Fifo decimation
|
||||
* @param[in] requested decimation factor value from 2 to 256
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_configure_fifo_data_rate(struct inv_imu_device *s,
|
||||
FDR_CONFIG_FDR_SEL_t dec_factor);
|
||||
|
||||
/** @brief Return driver version x.y.z-suffix as a char array
|
||||
* @retval driver version a char array "x.y.z-suffix"
|
||||
*/
|
||||
const char *inv_imu_get_version(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _INV_IMU_DRIVER_H_ */
|
||||
|
||||
/** @} */
|
||||
|
||||
65
apps/common/device/imu_sensor/icm_42670p/inv_imu_extfunc.h
Normal file
65
apps/common/device/imu_sensor/icm_42670p/inv_imu_extfunc.h
Normal file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* ________________________________________________________________________________________________________
|
||||
* Copyright (c) 2017 InvenSense Inc. All rights reserved.
|
||||
*
|
||||
* This software, related documentation and any modifications thereto (collectively "Software") is subject
|
||||
* to InvenSense and its licensors' intellectual property rights under U.S. and international copyright
|
||||
* and other intellectual property rights laws.
|
||||
*
|
||||
* InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software
|
||||
* and any use, reproduction, disclosure or distribution of the Software without an express license agreement
|
||||
* from InvenSense is strictly prohibited.
|
||||
*
|
||||
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, THE SOFTWARE IS
|
||||
* PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
|
||||
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, IN NO EVENT SHALL
|
||||
* INVENSENSE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY
|
||||
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
||||
* OF THE SOFTWARE.
|
||||
* ________________________________________________________________________________________________________
|
||||
*/
|
||||
|
||||
/** @defgroup DriverExt IMU driver extern functions
|
||||
* @brief Extern functions for IMU devices
|
||||
* @ingroup Driver
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @file inv_imu_extfunc.h
|
||||
* Extern functions for IMU devices
|
||||
*/
|
||||
|
||||
#ifndef _INV_IMU_EXTFUNC_H_
|
||||
#define _INV_IMU_EXTFUNC_H_
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/** @brief Hook for low-level high res system sleep() function to be implemented by upper layer
|
||||
* ~100us resolution is sufficient
|
||||
* @param[in] us number of us the calling thread should sleep
|
||||
*/
|
||||
extern void inv_imu_sleep_us(uint32_t us);
|
||||
|
||||
/** @brief Hook for low-level high res system get_time() function to be implemented by upper layer
|
||||
* Value shall be on 64bit with a 1 us resolution
|
||||
* @return The current time in us
|
||||
*/
|
||||
extern uint64_t inv_imu_get_time_us(void);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _INV_IMU_EXTFUNC_H_ */
|
||||
|
||||
/** @} */
|
||||
|
||||
3392
apps/common/device/imu_sensor/icm_42670p/inv_imu_regmap.h
Normal file
3392
apps/common/device/imu_sensor/icm_42670p/inv_imu_regmap.h
Normal file
File diff suppressed because it is too large
Load Diff
275
apps/common/device/imu_sensor/icm_42670p/inv_imu_transport.c
Normal file
275
apps/common/device/imu_sensor/icm_42670p/inv_imu_transport.c
Normal file
@ -0,0 +1,275 @@
|
||||
/*
|
||||
* ________________________________________________________________________________________________________
|
||||
* Copyright (c) 2015-2015 InvenSense Inc. All rights reserved.
|
||||
*
|
||||
* This software, related documentation and any modifications thereto (collectively "Software") is subject
|
||||
* to InvenSense and its licensors' intellectual property rights under U.S. and international copyright
|
||||
* and other intellectual property rights laws.
|
||||
*
|
||||
* InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software
|
||||
* and any use, reproduction, disclosure or distribution of the Software without an express license agreement
|
||||
* from InvenSense is strictly prohibited.
|
||||
*
|
||||
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, THE SOFTWARE IS
|
||||
* PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
|
||||
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, IN NO EVENT SHALL
|
||||
* INVENSENSE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY
|
||||
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
||||
* OF THE SOFTWARE.
|
||||
* ________________________________________________________________________________________________________
|
||||
*/
|
||||
|
||||
#include "inv_imu_extfunc.h"
|
||||
#include "inv_imu_transport.h"
|
||||
#include "inv_imu_regmap.h"
|
||||
|
||||
#include "InvError.h"
|
||||
|
||||
|
||||
/* Function definition */
|
||||
static uint8_t *get_register_cache_addr(struct inv_imu_device *s, uint32_t reg);
|
||||
static int write_sreg(struct inv_imu_device *s, uint8_t reg, uint32_t len, const uint8_t *buf);
|
||||
static int read_sreg(struct inv_imu_device *s, uint8_t reg, uint32_t len, uint8_t *buf);
|
||||
static int write_mclk_reg(struct inv_imu_device *s, uint16_t regaddr, uint8_t wr_cnt, const uint8_t *buf);
|
||||
static int read_mclk_reg(struct inv_imu_device *s, uint16_t regaddr, uint8_t rd_cnt, uint8_t *buf);
|
||||
|
||||
|
||||
int inv_imu_init_transport(struct inv_imu_device *s)
|
||||
{
|
||||
int status = 0;
|
||||
struct inv_imu_transport *t = (struct inv_imu_transport *)s;
|
||||
|
||||
status |= read_sreg(s, (uint8_t)PWR_MGMT0, 1, &(t->register_cache.pwr_mgmt0_reg));
|
||||
status |= read_sreg(s, (uint8_t)GYRO_CONFIG0, 1, &(t->register_cache.gyro_config0_reg));
|
||||
status |= read_sreg(s, (uint8_t)ACCEL_CONFIG0, 1, &(t->register_cache.accel_config0_reg));
|
||||
|
||||
status |= read_mclk_reg(s, (TMST_CONFIG1_MREG1 & 0xFFFF), 1, &(t->register_cache.tmst_config1_reg));
|
||||
|
||||
t->need_mclk_cnt = 0;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int inv_imu_read_reg(struct inv_imu_device *s, uint32_t reg, uint32_t len, uint8_t *buf)
|
||||
{
|
||||
uint32_t i;
|
||||
int rc = 0;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
uint8_t *cache_addr = get_register_cache_addr(s, reg + i);
|
||||
|
||||
if (cache_addr) {
|
||||
buf[i] = *cache_addr;
|
||||
} else {
|
||||
if (!(reg & 0x10000)) {
|
||||
rc |= read_mclk_reg(s, ((reg + i) & 0xFFFF), 1, &buf[i]);
|
||||
} else {
|
||||
rc |= read_sreg(s, (uint8_t)reg + i, len - i, &buf[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int inv_imu_write_reg(struct inv_imu_device *s, uint32_t reg, uint32_t len, const uint8_t *buf)
|
||||
{
|
||||
uint32_t i;
|
||||
int rc = 0;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
uint8_t *cache_addr = get_register_cache_addr(s, reg + i);
|
||||
|
||||
if (cache_addr) {
|
||||
*cache_addr = buf[i];
|
||||
}
|
||||
|
||||
if (!(reg & 0x10000)) {
|
||||
rc |= write_mclk_reg(s, ((reg + i) & 0xFFFF), 1, &buf[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (reg & 0x10000) {
|
||||
rc |= write_sreg(s, (uint8_t)reg, len, buf);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int inv_imu_switch_on_mclk(struct inv_imu_device *s)
|
||||
{
|
||||
int status = 0;
|
||||
uint8_t data;
|
||||
struct inv_imu_transport *t = (struct inv_imu_transport *)s;
|
||||
|
||||
/* set IDLE bit only if it is not set yet */
|
||||
if (t->need_mclk_cnt == 0) {
|
||||
|
||||
status |= inv_imu_read_reg(s, PWR_MGMT0, 1, &data);
|
||||
data |= PWR_MGMT0_IDLE_MASK;
|
||||
status |= inv_imu_write_reg(s, PWR_MGMT0, 1, &data);
|
||||
|
||||
if (status) {
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Check if MCLK is ready */
|
||||
do {
|
||||
status = inv_imu_read_reg(s, MCLK_RDY, 1, &data);
|
||||
} while ((status != 0) || !(data & MCLK_RDY_MCLK_RDY_MASK));
|
||||
} else {
|
||||
|
||||
/* Make sure it is already on */
|
||||
status |= inv_imu_read_reg(s, PWR_MGMT0, 1, &data);
|
||||
if (0 == (data &= PWR_MGMT0_IDLE_MASK)) {
|
||||
status |= INV_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/* Increment the counter to keep track of number of MCLK requesters */
|
||||
t->need_mclk_cnt++;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int inv_imu_switch_off_mclk(struct inv_imu_device *s)
|
||||
{
|
||||
int status = 0;
|
||||
uint8_t data;
|
||||
struct inv_imu_transport *t = (struct inv_imu_transport *)s;
|
||||
|
||||
/* Reset the IDLE but only if there is one requester left */
|
||||
if (t->need_mclk_cnt == 1) {
|
||||
status |= inv_imu_read_reg(s, PWR_MGMT0, 1, &data);
|
||||
data &= ~PWR_MGMT0_IDLE_MASK;
|
||||
status |= inv_imu_write_reg(s, PWR_MGMT0, 1, &data);
|
||||
} else {
|
||||
/* Make sure it is still on */
|
||||
status |= inv_imu_read_reg(s, PWR_MGMT0, 1, &data);
|
||||
if (0 == (data &= PWR_MGMT0_IDLE_MASK)) {
|
||||
status |= INV_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/* Decrement the counter */
|
||||
t->need_mclk_cnt--;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/* Static function */
|
||||
|
||||
static uint8_t *get_register_cache_addr(struct inv_imu_device *s, uint32_t reg)
|
||||
{
|
||||
struct inv_imu_transport *t = (struct inv_imu_transport *)s;
|
||||
|
||||
switch (reg) {
|
||||
case PWR_MGMT0:
|
||||
return &(t->register_cache.pwr_mgmt0_reg);
|
||||
case GYRO_CONFIG0:
|
||||
return &(t->register_cache.gyro_config0_reg);
|
||||
case ACCEL_CONFIG0:
|
||||
return &(t->register_cache.accel_config0_reg);
|
||||
case TMST_CONFIG1_MREG1:
|
||||
return &(t->register_cache.tmst_config1_reg);
|
||||
default:
|
||||
return (uint8_t *)0; // Not found
|
||||
}
|
||||
}
|
||||
|
||||
static int read_sreg(struct inv_imu_device *s, uint8_t reg, uint32_t len, uint8_t *buf)
|
||||
{
|
||||
struct inv_imu_serif *serif = (struct inv_imu_serif *)s;
|
||||
|
||||
if (len > serif->max_read) {
|
||||
return INV_ERROR_SIZE;
|
||||
}
|
||||
|
||||
if (serif->read_reg(serif, reg, buf, len) != 0) {
|
||||
return INV_ERROR_TRANSPORT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int write_sreg(struct inv_imu_device *s, uint8_t reg, uint32_t len, const uint8_t *buf)
|
||||
{
|
||||
struct inv_imu_serif *serif = (struct inv_imu_serif *)s;
|
||||
|
||||
if (len > serif->max_write) {
|
||||
return INV_ERROR_SIZE;
|
||||
}
|
||||
|
||||
if (serif->write_reg(serif, reg, buf, len) != 0) {
|
||||
return INV_ERROR_TRANSPORT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int read_mclk_reg(struct inv_imu_device *s, uint16_t regaddr, uint8_t rd_cnt, uint8_t *buf)
|
||||
{
|
||||
uint8_t data;
|
||||
uint8_t blk_sel = (regaddr & 0xFF00) >> 8;
|
||||
int status = 0;
|
||||
|
||||
// Have IMU not in IDLE mode to access MCLK domain
|
||||
status |= inv_imu_switch_on_mclk(s);
|
||||
|
||||
// optimize by changing BLK_SEL only if not NULL
|
||||
if (blk_sel) {
|
||||
status |= write_sreg(s, (uint8_t)BLK_SEL_R & 0xff, 1, &blk_sel);
|
||||
}
|
||||
|
||||
data = (regaddr & 0x00FF);
|
||||
status |= write_sreg(s, (uint8_t)MADDR_R, 1, &data);
|
||||
inv_imu_sleep_us(10);
|
||||
status |= read_sreg(s, (uint8_t)M_R, rd_cnt, buf);
|
||||
inv_imu_sleep_us(10);
|
||||
|
||||
if (blk_sel) {
|
||||
data = 0;
|
||||
status |= write_sreg(s, (uint8_t)BLK_SEL_R, 1, &data);
|
||||
}
|
||||
|
||||
// switch OFF MCLK if needed
|
||||
status |= inv_imu_switch_off_mclk(s);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int write_mclk_reg(struct inv_imu_device *s, uint16_t regaddr, uint8_t wr_cnt, const uint8_t *buf)
|
||||
{
|
||||
uint8_t data;
|
||||
uint8_t blk_sel = (regaddr & 0xFF00) >> 8;
|
||||
int status = 0;
|
||||
|
||||
// Have IMU not in IDLE mode to access MCLK domain
|
||||
status |= inv_imu_switch_on_mclk(s);
|
||||
|
||||
// optimize by changing BLK_SEL only if not NULL
|
||||
if (blk_sel) {
|
||||
status |= write_sreg(s, (uint8_t)BLK_SEL_W, 1, &blk_sel);
|
||||
}
|
||||
|
||||
data = (regaddr & 0x00FF);
|
||||
status |= write_sreg(s, (uint8_t)MADDR_W, 1, &data);
|
||||
for (uint8_t i = 0; i < wr_cnt; i++) {
|
||||
status |= write_sreg(s, (uint8_t)M_W, 1, &buf[i]);
|
||||
inv_imu_sleep_us(10);
|
||||
}
|
||||
|
||||
if (blk_sel) {
|
||||
data = 0;
|
||||
status = write_sreg(s, (uint8_t)BLK_SEL_W, 1, &data);
|
||||
}
|
||||
|
||||
status |= inv_imu_switch_off_mclk(s);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
122
apps/common/device/imu_sensor/icm_42670p/inv_imu_transport.h
Normal file
122
apps/common/device/imu_sensor/icm_42670p/inv_imu_transport.h
Normal file
@ -0,0 +1,122 @@
|
||||
/*
|
||||
* ________________________________________________________________________________________________________
|
||||
* Copyright (c) 2015-2015 InvenSense Inc. All rights reserved.
|
||||
*
|
||||
* This software, related documentation and any modifications thereto (collectively "Software") is subject
|
||||
* to InvenSense and its licensors' intellectual property rights under U.S. and international copyright
|
||||
* and other intellectual property rights laws.
|
||||
*
|
||||
* InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software
|
||||
* and any use, reproduction, disclosure or distribution of the Software without an express license agreement
|
||||
* from InvenSense is strictly prohibited.
|
||||
*
|
||||
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, THE SOFTWARE IS
|
||||
* PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
|
||||
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, IN NO EVENT SHALL
|
||||
* INVENSENSE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY
|
||||
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
||||
* OF THE SOFTWARE.
|
||||
* ________________________________________________________________________________________________________
|
||||
*/
|
||||
|
||||
/** @defgroup Transport IMU transport
|
||||
* @brief Low-level IMU SCLK register access
|
||||
* @ingroup Driver
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @file inv_imu_transport.h
|
||||
* Low-level IMU SCLK register access
|
||||
*/
|
||||
|
||||
#ifndef _INV_IMU_TRANSPORT_H_
|
||||
#define _INV_IMU_TRANSPORT_H_
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* forward declaration */
|
||||
struct inv_imu_device;
|
||||
|
||||
|
||||
/** @brief enumeration of serial interfaces available on IMU */
|
||||
typedef enum {
|
||||
UI_I2C,
|
||||
UI_SPI4,
|
||||
UI_SPI3
|
||||
} SERIAL_IF_TYPE_t;
|
||||
|
||||
/** @brief basesensor serial interface
|
||||
*/
|
||||
struct inv_imu_serif {
|
||||
void *context;
|
||||
int (*read_reg)(struct inv_imu_serif *serif, uint8_t reg, uint8_t *buf, uint32_t len);
|
||||
int (*write_reg)(struct inv_imu_serif *serif, uint8_t reg, const uint8_t *buf, uint32_t len);
|
||||
int (*configure)(struct inv_imu_serif *serif);
|
||||
uint32_t max_read;
|
||||
uint32_t max_write;
|
||||
SERIAL_IF_TYPE_t serif_type;
|
||||
};
|
||||
|
||||
/** @brief transport interface
|
||||
*/
|
||||
struct inv_imu_transport {
|
||||
struct inv_imu_serif serif; /**< Warning : this field MUST be the first one of struct inv_imu_transport */
|
||||
|
||||
/** @brief Contains mirrored values of some IP registers */
|
||||
struct register_cache {
|
||||
uint8_t pwr_mgmt0_reg; /**< PWR_MGMT0, Bank: 0 */
|
||||
uint8_t gyro_config0_reg; /**< GYRO_CONFIG0, Bank: 0 */
|
||||
uint8_t accel_config0_reg; /**< ACCEL_CONFIG0, Bank: 0 */
|
||||
uint8_t tmst_config1_reg; /**< TMST_CONFIG1, Bank: MREG_TOP1 */
|
||||
} register_cache; /**< Store mostly used register values on SRAM */
|
||||
|
||||
uint8_t need_mclk_cnt; /**< internal counter to keep track of everyone that needs MCLK */
|
||||
|
||||
};
|
||||
|
||||
/** @brief Init cache variable.
|
||||
* @return 0 in case of success, -1 for any error
|
||||
*/
|
||||
int inv_imu_init_transport(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Reads data from a register on IMU.
|
||||
* @param[in] reg register address to be read
|
||||
* @param[in] len number of byte to be read
|
||||
* @param[out] buf output data from the register
|
||||
* @return 0 in case of success, -1 for any error
|
||||
*/
|
||||
int inv_imu_read_reg(struct inv_imu_device *s, uint32_t reg, uint32_t len, uint8_t *buf);
|
||||
|
||||
/** @brief Writes data to a register on IMU.
|
||||
* @param[in] reg register address to be written
|
||||
* @param[in] len number of byte to be written
|
||||
* @param[in] buf input data to write
|
||||
* @return 0 in case of success, -1 for any error
|
||||
*/
|
||||
int inv_imu_write_reg(struct inv_imu_device *s, uint32_t reg, uint32_t len, const uint8_t *buf);
|
||||
|
||||
/** @brief Enable MCLK so that MREG are clocked and system beyond SOI can be safely accessed
|
||||
* @return 0 in case of success, -1 for any error
|
||||
*/
|
||||
int inv_imu_switch_on_mclk(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Disable MCLK so that MREG are not clocked anymore, hence reducing power consumption
|
||||
* @return 0 in case of success, -1 for any error
|
||||
*/
|
||||
int inv_imu_switch_off_mclk(struct inv_imu_device *s);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _INV_IMU_TRANSPORT_H_ */
|
||||
|
||||
/** @} */
|
||||
|
||||
38
apps/common/device/imu_sensor/icm_42670p/inv_imu_version.h
Normal file
38
apps/common/device/imu_sensor/icm_42670p/inv_imu_version.h
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* ________________________________________________________________________________________________________
|
||||
* Copyright (c) 2019 InvenSense Inc. All rights reserved.
|
||||
*
|
||||
* This software, related documentation and any modifications thereto (collectively “Software”) is subject
|
||||
* to InvenSense and its licensors' intellectual property rights under U.S. and international copyright
|
||||
* and other intellectual property rights laws.
|
||||
*
|
||||
* InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software
|
||||
* and any use, reproduction, disclosure or distribution of the Software without an express license agreement
|
||||
* from InvenSense is strictly prohibited.
|
||||
*
|
||||
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, THE SOFTWARE IS
|
||||
* PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
|
||||
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, IN NO EVENT SHALL
|
||||
* INVENSENSE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY
|
||||
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
||||
* OF THE SOFTWARE.
|
||||
* ________________________________________________________________________________________________________
|
||||
*/
|
||||
|
||||
#ifndef _INV_IMU_VERSION_H_
|
||||
#define _INV_IMU_VERSION_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define INV_IMU_VERSION_STRING "2.0.4"
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _INV_IMU_VERSION_H_ */
|
||||
|
||||
238
apps/common/device/imu_sensor/imuSensor_manage.c
Normal file
238
apps/common/device/imu_sensor/imuSensor_manage.c
Normal file
@ -0,0 +1,238 @@
|
||||
#include "imuSensor_manage.h"
|
||||
/* #include "asm/iic_hw.h" */
|
||||
/* #include "asm/iic_soft.h" */
|
||||
|
||||
#if TCFG_IMUSENSOR_ENABLE
|
||||
#undef LOG_TAG_CONST
|
||||
#define LOG_TAG "[imu]"
|
||||
#define LOG_ERROR_ENABLE
|
||||
#define LOG_INFO_ENABLE
|
||||
#include "debug.h"
|
||||
|
||||
static struct imusensor_platform_data *platform_data;
|
||||
IMU_SENSOR_INTERFACE *imuSensor_hdl = NULL;
|
||||
u8 imu_sensor_cnt = 0;
|
||||
|
||||
#if 0/*{{{*/
|
||||
u8 imusensor_write_nbyte(u8 w_chip_id, u8 register_address, u8 *buf, u8 data_len)
|
||||
{
|
||||
u8 write_len = 0;
|
||||
u8 i;
|
||||
|
||||
iic_start(imuSensor_info->iic_hdl);
|
||||
if (0 == iic_tx_byte(imuSensor_info->iic_hdl, w_chip_id)) {
|
||||
write_len = 0;
|
||||
r_printf("\n imuSensor iic w err 0\n");
|
||||
goto __wend;
|
||||
}
|
||||
|
||||
delay(imuSensor_info->iic_delay);
|
||||
|
||||
if (0 == iic_tx_byte(imuSensor_info->iic_hdl, register_address)) {
|
||||
write_len = 0;
|
||||
r_printf("\n imuSensor iic w err 1\n");
|
||||
goto __wend;
|
||||
}
|
||||
|
||||
for (i = 0; i < data_len; i++) {
|
||||
delay(imuSensor_info->iic_delay);
|
||||
if (0 == iic_tx_byte(imuSensor_info->iic_hdl, buf[i])) {
|
||||
write_len = 0;
|
||||
r_printf("\n imuSensor iic w err 2\n");
|
||||
goto __wend;
|
||||
}
|
||||
write_len++;
|
||||
}
|
||||
|
||||
__wend:
|
||||
iic_stop(imuSensor_info->iic_hdl);
|
||||
return write_len;
|
||||
}
|
||||
|
||||
u8 imusensor_read_nbyte(u8 r_chip_id, u8 register_address, u8 *buf, u8 data_len)
|
||||
{
|
||||
u8 read_len = 0;
|
||||
|
||||
iic_start(imuSensor_info->iic_hdl);
|
||||
if (0 == iic_tx_byte(imuSensor_info->iic_hdl, r_chip_id - 1)) {
|
||||
r_printf("\n imuSensor iic r err 0\n");
|
||||
read_len = 0;
|
||||
goto __rend;
|
||||
}
|
||||
|
||||
delay(imuSensor_info->iic_delay);
|
||||
if (0 == iic_tx_byte(imuSensor_info->iic_hdl, register_address)) {
|
||||
r_printf("\n imuSensor iic r err 1\n");
|
||||
read_len = 0;
|
||||
goto __rend;
|
||||
}
|
||||
|
||||
iic_start(imuSensor_info->iic_hdl);
|
||||
if (0 == iic_tx_byte(imuSensor_info->iic_hdl, r_chip_id)) {
|
||||
r_printf("\n imuSensor iic r err 2\n");
|
||||
read_len = 0;
|
||||
goto __rend;
|
||||
}
|
||||
|
||||
delay(imuSensor_info->iic_delay);
|
||||
|
||||
for (; data_len > 1; data_len--) {
|
||||
*buf++ = iic_rx_byte(imuSensor_info->iic_hdl, 1);
|
||||
read_len ++;
|
||||
}
|
||||
|
||||
*buf = iic_rx_byte(imuSensor_info->iic_hdl, 0);
|
||||
read_len ++;
|
||||
|
||||
__rend:
|
||||
iic_stop(imuSensor_info->iic_hdl);
|
||||
delay(imuSensor_info->iic_delay);
|
||||
|
||||
return read_len;
|
||||
}
|
||||
#endif/*}}}*/
|
||||
|
||||
extern char *strchrnul(const char *__s, int __c)
|
||||
__THROW __attribute_pure__ __nonnull((1));
|
||||
int imu_sensor_io_ctl(u8 *sensor_name, enum OPERATION_SENSOR cmd, void *arg)
|
||||
{
|
||||
int retval = -1;
|
||||
list_for_each_imusensor(imuSensor_hdl) {
|
||||
/* log_info("%s?=%s", sensor_name, imuSensor_hdl->logo); */
|
||||
if ((sensor_name == NULL) && (cmd == IMU_GET_SENSOR_NAME)) {
|
||||
log_info("get name:%s", imuSensor_hdl->logo);
|
||||
retval = 1;
|
||||
continue;
|
||||
}
|
||||
if (!memcmp(imuSensor_hdl->logo, sensor_name, strlen(imuSensor_hdl->logo))) {
|
||||
/* if (!memcmp(imuSensor_hdl->logo, sensor_name, sizeof(imuSensor_hdl->logo))) { */
|
||||
if ((strchrnul(sensor_name, '\0') - (u32)sensor_name) != (strrchr(imuSensor_hdl->logo, '\0') - (u32)(imuSensor_hdl->logo))) {
|
||||
goto __imu_exit;
|
||||
}
|
||||
retval = imuSensor_hdl->imu_sensor_ctl(cmd, arg);
|
||||
return retval;//1:ok
|
||||
}
|
||||
}
|
||||
__imu_exit:
|
||||
if (retval < 0) {
|
||||
log_e(">>>sensor_name(%s) io_ctl fail: sensor_name err\n", sensor_name);
|
||||
}
|
||||
return retval;//1:ok
|
||||
}
|
||||
|
||||
int imu_sensor_init(void *_data, u16 _data_size)
|
||||
{
|
||||
int retval = -1;
|
||||
u8 data_len = _data_size / sizeof(struct imusensor_platform_data);
|
||||
if (data_len < 1) {
|
||||
log_error("_data_size:%d\n", _data_size);
|
||||
return retval;
|
||||
}
|
||||
platform_data = (const struct imusensor_platform_data *)_data;
|
||||
/* log_info("-----imusensor_dev_begin:0x%x,imusensor_dev_end:0x%x", imusensor_dev_begin, imusensor_dev_end); */
|
||||
for (u8 i = 0; i < data_len; i++) {
|
||||
retval = -1;
|
||||
list_for_each_imusensor(imuSensor_hdl) {
|
||||
/* log_info("%s?=%s", platform_data[i].imu_sensor_name, imuSensor_hdl->logo); */
|
||||
if (!memcmp(imuSensor_hdl->logo, platform_data[i].imu_sensor_name, sizeof(platform_data[i].imu_sensor_name))) {
|
||||
|
||||
retval = -1;
|
||||
if (imuSensor_hdl->imu_sensor_init(&platform_data[i]) == 0) {
|
||||
g_printf(">>>>imuSensor(%s)_Init SUCC\n", platform_data[i].imu_sensor_name);
|
||||
imu_sensor_cnt++;
|
||||
retval = 1;
|
||||
} else {
|
||||
g_printf(">>>>imuSensor(%s)_Init ERROR\n", platform_data[i].imu_sensor_name);
|
||||
retval = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (retval < 0) {
|
||||
log_e(">>>imuSensor(%s) init fail: logo err\n", platform_data[i].imu_sensor_name);
|
||||
}
|
||||
}
|
||||
|
||||
return retval;//1:ok
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**********************test***********************/
|
||||
#if 0
|
||||
u8 test_buf[36 * 20]; //(8+12+12+4)*60=
|
||||
void imu_test()
|
||||
{
|
||||
u8 name_test[20] = "sh3011";
|
||||
u8 arg_data;
|
||||
/* imu_sensor_init(); */
|
||||
imu_sensor_io_ctl(name_test, 0xff, NULL);
|
||||
imu_sensor_io_ctl(NULL, IMU_GET_SENSOR_NAME, name_test);
|
||||
memset(name_test, 0, 20);
|
||||
memcpy(name_test, "sh3001", 6);
|
||||
imu_sensor_io_ctl(name_test, 0xff, NULL);
|
||||
imu_sensor_io_ctl(name_test, IMU_SENSOR_SEARCH, &arg_data);
|
||||
memset(name_test, 0, 20);
|
||||
memcpy(name_test, "mpu9250", 7);
|
||||
imu_sensor_io_ctl(name_test, 0xff, NULL);
|
||||
imu_sensor_io_ctl(name_test, IMU_SENSOR_SEARCH, &arg_data);
|
||||
memset(name_test, 0, 20);
|
||||
memcpy(name_test, "mpu6887p", 8);
|
||||
imu_sensor_io_ctl(name_test, 0xff, NULL);
|
||||
imu_sensor_io_ctl(name_test, IMU_SENSOR_SEARCH, &arg_data);
|
||||
imu_sensor_io_ctl("mpu6887p1", IMU_SENSOR_SEARCH, &arg_data);
|
||||
memset(name_test, 0, 20);
|
||||
memcpy(name_test, "qmi8658", 7);
|
||||
imu_sensor_io_ctl(name_test, 0xff, NULL);
|
||||
imu_sensor_io_ctl(name_test, IMU_SENSOR_SEARCH, &arg_data);
|
||||
memset(name_test, 0, 20);
|
||||
memcpy(name_test, "lsm6dsl", 7);
|
||||
imu_sensor_io_ctl(name_test, IMU_SENSOR_SEARCH, &arg_data);
|
||||
|
||||
memcpy(name_test, "icm42670p", 9);
|
||||
imu_sensor_io_ctl(name_test, 0xff, NULL);
|
||||
imu_sensor_io_ctl(name_test, IMU_SENSOR_SEARCH, &arg_data);
|
||||
imu_axis_data_t raw_acc_xyz;
|
||||
imu_axis_data_t raw_gyro_xyz;
|
||||
imu_sensor_data_t raw_sensor_datas;
|
||||
memset((u8 *)&raw_acc_xyz, 0, sizeof(imu_axis_data_t));
|
||||
memset((u8 *)&raw_gyro_xyz, 0, sizeof(imu_axis_data_t));
|
||||
memset((u8 *)&raw_sensor_datas, 0, sizeof(imu_sensor_data_t));
|
||||
uint64_t timestamp;
|
||||
float accel_g[3];
|
||||
float gyro_dps[3];
|
||||
float temp_degc;
|
||||
int pack_len = 0;
|
||||
while (1) {
|
||||
pack_len = imu_sensor_io_ctl(name_test, IMU_GET_SENSOR_READ_FIFO, test_buf);
|
||||
if (pack_len > 0) {
|
||||
memcpy((u8 *)×tamp, test_buf, 8);
|
||||
memcpy((u8 *)accel_g, test_buf + 8, 12);
|
||||
memcpy((u8 *)gyro_dps, test_buf + 20, 12);
|
||||
memcpy((u8 *)&temp_degc, test_buf + 32, 4);
|
||||
log_info("pack_len:%d first pack:%u: accel_g*10:%d, %d, %d, temp_degc*10:%d, gyro_dps*10:%d, %d, %d", pack_len,
|
||||
(uint32_t)timestamp,
|
||||
(s32)(accel_g[0] * 10), (s32)(accel_g[1] * 10), (s32)(accel_g[2] * 10),
|
||||
(s32)(temp_degc * 10),
|
||||
(s32)(gyro_dps[0] * 10), (s32)(gyro_dps[1] * 10), (s32)(gyro_dps[2] * 10));
|
||||
}
|
||||
|
||||
/* imu_sensor_io_ctl(name_test, IMU_SENSOR_READ_DATA, &raw_sensor_datas); */
|
||||
/* log_info("qmi8658 raw:acc_x:%d acc_y:%d acc_z:%d gyro_x:%d gyro_y:%d gyro_z:%d", raw_sensor_datas.acc.x, raw_sensor_datas.acc.y, raw_sensor_datas.acc.z, raw_sensor_datas.gyro.x, raw_sensor_datas.gyro.y, raw_sensor_datas.gyro.z); */
|
||||
/* log_info("qmi8658 temp:%d.%d\n", (u16)raw_sensor_datas.temp_data, (u16)(((u16)(raw_sensor_datas.temp_data * 100)) % 100)); */
|
||||
/* mdelay(10); */
|
||||
/* imu_sensor_io_ctl(name_test, IMU_GET_ACCEL_DATA, &raw_acc_xyz); */
|
||||
/* log_info("qmi8658 acc: %d %d %d\n", raw_acc_xyz.x, raw_acc_xyz.y, raw_acc_xyz.z); */
|
||||
/* mdelay(10); */
|
||||
/* imu_sensor_io_ctl(name_test, IMU_GET_GYRO_DATA, &raw_gyro_xyz); */
|
||||
/* log_info("qmi8658 gyro: %d %d %d\n", raw_gyro_xyz.x, raw_gyro_xyz.y, raw_gyro_xyz.z); */
|
||||
|
||||
mdelay(50);
|
||||
wdt_clear();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user