[LC] 398. Random Pick Index

本文探讨了在LeetCode随机取数问题中,如何利用蓄水池算法实现O(1)额外空间复杂度的目标。通过遍历数组并采用特定概率替换策略,确保每个元素被选取的概率相同,从而高效地选出目标值。

https://leetcode.com/problems/random-pick-index/

Well.. 这一题,直白的方法太多了。譬如直接扣一个Map<Integer, List<Integer>>的cache,然后每次就先从map里面找到那个index list,然后用Random.nextInt选出来就好。这个方法构造函数是O(n)的,然后pick是O(1)的(假设random是O(1))的话。

或者pick的时候先遍历一遍nums,然后构造一个index list,在nextInt从index里面取出来。这个方法构造函数是O(1),pick是O(n)复杂度和O(n)空间复杂度。

但题目要求不能用too much extra space,所以,要不,咱就别用了。=。=....下面介绍的是一种构造函数是O(1),pick是O(n)时间O(1)空间的做法。这个做法其实之前也遇到过一些题目,不过忘了,请google或者百度蓄水池算法。。。

譬如这一个链接:https://www.cnblogs.com/snowInPluto/p/5996269.html

当然我们的蓄水池跟上面的链接不太一样,譬如说:一个数组arr有n个数,我们要随机取其中一个

那么我们可以遍历整个数组arr,第一个数字我们用100%的概率取得,第二个数字1 / 2概率替换当前的结果,第三个数字 1 / 3的概率替换当前的结果,第四个数字1 / 4的概率替换如此类推,到第n个数字用1 / n的概率替换。这样,我们就可以获得一个跟arr[random.nextInt(arr.length)]等价的效果,也就是随机取一个,并且每个数字被取到的概率是一样的。nice不nice。。。=。=

好吧,如果说一个input的数组是定长的,这样做是很蠢的。但是如果我们要从一个数据流里面,或者说不知道多长的数据里,取一个随机数字并且每一个数字被取到的概率是相等的话,这种做法就很有用了。这也就是O(1) extra space的方法解决本题的关键。在pick给定一个target的情况下,我们遍历一次数组,然后遇到target相等的数字就用到上文描述的蓄水池算法,那么我们最后就能得到我们需要的结果。那么如何做到“用 1 / n的概率替换当前的结果“这个事情呢?其实也很简单,就做一个random.nextInt(n) == 0的if判断即可,nextInt hit到任何一个数字的概率都是 1 / n,所以得到0的概率也是一样的。根据上述描述,得到代码如下:

class Solution {
    int[] data;
    
    public Solution(int[] nums) {
        this.data = nums;
    }
    
    public int pick(int target) {
        int counter = 0;
        int candidate = 0;
        Random r = new Random();
        for (int i = 0; i < this.data.length; i++) {
            if (this.data[i] == target) {
                counter++;
                if (r.nextInt(counter) == 0) {
                    candidate = i;
                }
            }
        }
        
        return candidate;
    }
}

 

import os, re, glob, math, random, argparse, warnings from pathlib import Path import numpy as np import scipy.io as sio import scipy.signal as sig from scipy.stats import kurtosis import yaml import matplotlib.pyplot as plt from sklearn.manifold import TSNE from collections import defaultdict warnings.filterwarnings("ignore") # ========== 基础工具 ========== def load_cfg(p): with open(p, "r", encoding="utf-8") as f: return yaml.safe_load(f) def ensure_1d(x): if x is None: return None x = np.asarray(x) if x.ndim == 1: return x.astype(np.float64) return x.reshape(-1).astype(np.float64) def detrend(x): return sig.detrend(x, type="linear") def bandpass(x, fs, f1, f2, order=4): f2 = min(f2, 0.45*fs) if f1 >= f2: f1, f2 = max(5.0, min(f1, 0.45*fs-10)), max(50.0, min(f2, 0.45*fs-5)) sos = sig.butter(order, [f1, f2], btype="bandpass", fs=fs, output="sos") return sig.sosfiltfilt(sos, x) def envelope(x): return np.abs(sig.hilbert(x)) def zscore(x, eps=1e-8): std = x.std() if not np.isfinite(std) or std < eps: return np.zeros_like(x) return (x - x.mean()) / (std + eps) def resample_to_uniform(x, fs_src, fs_tgt): x = np.asarray(x, dtype=np.float64) if x.size == 0 or fs_src <= 0 or fs_tgt <= 0 or abs(fs_src - fs_tgt) < 1e-9: return x n_out = max(1, int(round(len(x) * float(fs_tgt) / float(fs_src)))) t_src = np.linspace(0.0, (len(x)-1)/fs_src, num=len(x), endpoint=True) t_new = np.linspace(0.0, (len(x)-1)/fs_src, num=n_out, endpoint=True) return np.interp(t_new, t_src, x).astype(np.float64) def windowing(x, fs, win_sec=1.0, overlap=0.5, drop_edges_sec=0.0): x = x[int(drop_edges_sec*fs):] step = int(win_sec*fs*(1-overlap)) L = int(win_sec*fs) out = [] for s in range(0, max(1, len(x)-L+1), step if step>0 else L): seg = x[s:s+L] if len(seg)==L: out.append(seg) if not out and len(x)>0: out = [np.pad(x, (0, L-len(x)))[:L]] return out def spectral_kurtosis_band(x, fs, nfft=2048, hop=None, fmin=50, fmax=None, topk=1, bw_frac=0.15): x = np.asarray(x, dtype=np.float64) if hop is None: hop = nfft // 4 if fmax is None: fmax = fs*0.45 if len(x) < nfft: return [], None, None win = np.hanning(nfft) specs = [] for i in range(0, len(x)-nfft+1, hop): seg = x[i:i+nfft] * win X = np.fft.rfft(seg) P = np.abs(X)**2 specs.append(P) if len(specs) == 0: return [], None, None S = np.stack(specs, 0) freqs = np.fft.rfftfreq(nfft, 1.0/fs) m = (freqs >= fmin) & (freqs <= fmax) S = S[:, m]; freqs = freqs[m] if S.shape[1] < 10: return [], None, None mu1 = S.mean(axis=0) var = ((S - mu1)**2).mean(axis=0) + 1e-12 mu4 = ((S - mu1)**4).mean(axis=0) sk = mu4 / (var**2) - 3.0 idx = np.argsort(sk)[::-1][:topk] bands = [] for i in idx: fc = freqs[i] bw = max(20.0, fc * bw_frac) f1 = max(freqs[0], fc - bw/2.0) f2 = min(freqs[-1], fc + bw/2.0) if f2 > f1 + 5.0: bands.append((float(f1), float(f2))) return bands, freqs, sk def order_resample(x, fs, rpm, spr=200): if rpm is None or rpm <= 0: return x, fs fr = rpm / 60.0 T = len(x) / fs n_rev = fr * T if n_rev < 1e-3: return x, fs N = int(max(4*spr, n_rev * spr)) t = np.arange(len(x)) / fs theta = 2*np.pi*fr*t theta_target = np.linspace(theta[0], theta[-1], N) x_res = np.interp(theta_target, theta, x).astype(np.float64) fs_equiv = spr * fr return x_res, fs_equiv def parse_rpm_from_name(fn): m = re.search(r"\((\d+)\s*rpm\)", fn.replace("RPM","rpm")) if m: return float(m.group(1)) return None def read_mat_any(path): mat = sio.loadmat(path, squeeze_me=True, struct_as_record=False) keys_map = {k.lower(): k for k in mat.keys()} def pick_any(*cands): for c in cands: lc = c.lower() if lc in keys_map: return mat[keys_map[lc]] return None de = pick_any('DE','DE_value','X_DE','DE_time','x_de','x_de_time') fe = pick_any('FE','FE_value','X_FE','FE_time','x_fe','x_fe_time') ba = pick_any('BA','BA_value','X_BA','BA_time','x_ba','x_ba_time') time = pick_any('time','t','time_series','DE_time','FE_time','BA_time','X_DE_time','X_FE_time','X_BA_time') rpm = pick_any('rpm','x118rpm','speed','rot_rpm') # 兜底:挑最长 ndarray 为 DE if all(v is None for v in [de,fe,ba]): cands = [v.reshape(-1) for v in mat.values() if isinstance(v, np.ndarray) and v.size>100] if cands: de = max(cands, key=lambda a: a.size) return {"DE":ensure_1d(de), "FE":ensure_1d(fe), "BA":ensure_1d(ba), "time":ensure_1d(time), "RPM":rpm} def bearing_freqs(rpm, n, d, D, theta_deg=0.0): fr = float(rpm) / 60.0 c = (d / D) * math.cos(math.radians(theta_deg)) bpfo = 0.5 * n * fr * (1 - c) bpfi = 0.5 * n * fr * (1 + c) bsf = (D/(2*d)) * fr * (1 - c**2) ftf = 0.5 * fr * (1 - c) return fr, bpfo, bpfi, bsf, ftf def is_under_dir(child_path, parent_dir): try: child = Path(child_path).resolve() parent = Path(parent_dir).resolve() return parent in child.parents or child == parent except Exception: return False # ========== 标签推断 ========== def infer_label_from_path(p): p_norm = p.replace("\\","/").lower() if "/b/" in p_norm or os.sep+"b"+os.sep in p_norm: return "B" if "/ir/" in p_norm or os.sep+"ir"+os.sep in p_norm: return "IR" if "/or/" in p_norm or os.sep+"or"+os.sep in p_norm: return "OR" if "normal" in p_norm or "n_" in os.path.basename(p_norm): return "N" if "normal_data" in p_norm: return "N" return "UNK" # ========== 预处理主流程 ========== def choose_rpm(rec, fpath, cfg, rpm_pref=None): # 1) mat 变量 rr = rec.get("RPM") if rr is not None and np.isscalar(rr): try: val = float(rr) if val > 0: return val except: pass # 2) 文件名 val = parse_rpm_from_name(Path(fpath).name) if val is not None and val > 0: return val # 3) 外部优先提示(目标域 rpm_approx 等) if rpm_pref is not None and rpm_pref > 0: return float(rpm_pref) # 4) 源域候选 cand = cfg.get("conditions",{}).get("rpm_source_candidates", [1797,1772,1750,1730]) return float(cand[0]) if len(cand)>0 else None def preprocess_one_file(fpath, cfg, out_dir, fs_out=32000, use_order=True, rpm_pref=None, verbose=False): rec = read_mat_any(fpath) # 选通道(优先 DE,其次 FE,再 BA) x = rec["DE"]; used_ch = "DE" if x is None: x = rec["FE"]; used_ch = "FE" if x is None: x = rec["BA"]; used_ch = "BA" if x is None or x.size < 10: return None # 源采样率估计:time -> fs 或文件名猜测(48kHz/12kHz) fs_src = None if rec["time"] is not None and len(rec["time"])>1: dt = float(np.median(np.diff(rec["time"]))) if dt > 0: fs_src = 1.0/dt if fs_src is None: fs_src = 48000.0 if "48khz" in fpath.lower() else 12000.0 # 统一重采样到 fs_out x = resample_to_uniform(x, fs_src, fs_out) fs_eff = fs_out # 去趋势 if cfg["preprocess_default"].get("detrend", True): x = detrend(x) # 阶次分析(常速/近似常速),并回采样到 fs_out rpm_val = choose_rpm(rec, fpath, cfg, rpm_pref=rpm_pref) if use_order and (rpm_val is not None) and (rpm_val>0): x_ord, fs_ord = order_resample(x, fs_eff, rpm_val, spr=int(cfg["preprocess_default"].get("order_spr",200))) x = resample_to_uniform(x_ord, fs_ord, fs_out) # 回到统一 fs fs_eff = fs_out # 谱峭度 -> 自适应带通 pp = cfg["preprocess_default"] use_sk = pp.get("use_spectral_kurtosis", True) if use_sk: bands, freqs, sk = spectral_kurtosis_band( x, fs_eff, nfft=pp.get("sk_nfft", 2048), fmin=pp.get("sk_fmin", 50), fmax=pp.get("sk_fmax", int(0.45*fs_eff)), topk=pp.get("sk_topk", 1), bw_frac=pp.get("sk_bw_frac", 0.15) ) if len(bands)>0: f1, f2 = bands[0] else: f1, f2 = pp.get("bandpass_hz",[500,10000]) else: f1, f2 = pp.get("bandpass_hz",[500,10000]) x_bp = bandpass(x, fs_eff, f1, f2) x_env = envelope(x_bp) x_norm = zscore(x_env) if pp.get("normalize","zscore")=="zscore" else x_env # 切片 seg = pp.get("segment", {"win_sec":1.0,"overlap":0.5,"drop_edges_sec":0.0}) wins = windowing(x_norm, fs_eff, seg.get("win_sec",1.0), seg.get("overlap",0.5), seg.get("drop_edges_sec",0.0)) if not wins: return None # 保存 .npy(每个窗口一个文件),生成索引 os.makedirs(out_dir, exist_ok=True) label = infer_label_from_path(fpath) # "B"/"IR"/"OR"/"N"/"UNK" base = Path(fpath).stem rows = [] for i,w in enumerate(wins): outp = os.path.join(out_dir, f"{base}__{i:04d}.npy") np.save(outp, w.astype(np.float32)) rows.append((outp, label, used_ch, f1, f2, rpm_val, fs_eff)) # 返回可视化需要的中间结果 return { "rows": rows, "raw": x, "bp": x_bp, "env": x_env, "norm": x_norm, "fs": fs_eff, "band": (f1,f2), "sk": (freqs, sk) if use_sk else (None, None), "label": label, "used_ch": used_ch } # ========== 可视化 ========== def plot_one_sample(figdir, recinfo, cfg, title_hint=""): os.makedirs(figdir, exist_ok=True) x, x_bp, x_env, fs = recinfo["raw"], recinfo["bp"], recinfo["env"], recinfo["fs"] label, band = recinfo["label"], recinfo["band"] freqs, sk = recinfo["sk"] # 1) 原始 vs 预处理后(时域) T = np.arange(len(x))/fs plt.figure(figsize=(10,3)) plt.plot(T, x, lw=0.6) plt.title(f"Raw waveform ({title_hint})") plt.xlabel("Time (s)"); plt.ylabel("Amplitude"); plt.tight_layout() plt.savefig(os.path.join(figdir, f"{title_hint}_raw.png")); plt.close() T2 = np.arange(len(x_bp))/fs plt.figure(figsize=(10,3)) plt.plot(T2, x_bp, lw=0.6) plt.title(f"Bandpassed waveform {band} Hz ({title_hint})") plt.xlabel("Time (s)"); plt.ylabel("Amplitude"); plt.tight_layout() plt.savefig(os.path.join(figdir, f"{title_hint}_bandpassed.png")); plt.close() plt.figure(figsize=(10,3)) plt.plot(T2, x_env, lw=0.6) plt.title(f"Envelope (Hilbert) ({title_hint})") plt.xlabel("Time (s)"); plt.ylabel("Amplitude"); plt.tight_layout() plt.savefig(os.path.join(figdir, f"{title_hint}_envelope.png")); plt.close() # 2) PSD f, Pxx = sig.welch(x_bp, fs=fs, nperseg=4096) plt.figure(figsize=(6,4)) plt.semilogy(f, Pxx + 1e-12) plt.title(f"PSD (bandpassed) ({title_hint})"); plt.xlabel("Hz"); plt.ylabel("PSD") plt.tight_layout(); plt.savefig(os.path.join(figdir, f"{title_hint}_psd.png")); plt.close() # 3) 包络谱 N = 1<<int(np.ceil(np.log2(len(x_env)))) Ef = np.fft.rfftfreq(N, 1.0/fs) Es = np.abs(np.fft.rfft(x_env, N)) plt.figure(figsize=(8,4)) plt.plot(Ef, Es, lw=0.7) plt.xlim(0, min(5000, fs*0.45)) plt.title(f"Envelope spectrum ({title_hint})"); plt.xlabel("Hz"); plt.ylabel("|E(f)|") # 叠加轴承故障特征频率(用 DE 几何) geom = cfg["bearings"]["DE"] rpm_approx = recinfo["rows"][0][5] or cfg["conditions"]["rpm_source_candidates"][0] _, bpfo, bpfi, bsf, ftf = bearing_freqs(rpm_approx, geom["n"], geom["d_in"], geom["D_in"], geom["theta_deg"]) for name,base in [("BPFI",bpfi),("BPFO",bpfo),("BSF",bsf),("FTF",ftf)]: for k in [1,2]: f0 = k*base if f0 < fs*0.45: plt.axvline(f0, ls="--", lw=0.7, color="r") plt.text(f0, max(Es)*0.05, f"{name}{k}", rotation=90, va="bottom", ha="right", fontsize=8) plt.tight_layout(); plt.savefig(os.path.join(figdir, f"{title_hint}_envelope_spectrum.png")); plt.close() # 4) 谱峭度(若开启) if freqs is not None and sk is not None: plt.figure(figsize=(8,3)) plt.plot(freqs, sk, lw=0.8) plt.title(f"Spectral kurtosis ({title_hint})") plt.xlabel("Hz"); plt.ylabel("SK") if band: plt.axvspan(band[0], band[1], color="orange", alpha=0.25, label=f"Band {band[0]:.0f}-{band[1]:.0f} Hz") plt.legend() plt.tight_layout(); plt.savefig(os.path.join(figdir, f"{title_hint}_spectral_kurtosis.png")); plt.close() def tsne_overview(emb_list, lab_list, out_png): if len(emb_list)==0: return X = np.vstack(emb_list) L = np.array(lab_list) tsne = TSNE(n_components=2, perplexity=30, learning_rate="auto", init="pca") Z = tsne.fit_transform(X) plt.figure(figsize=(6,5)) for cls, col in zip(["OR","IR","B","N","UNK"], ["tab:blue","tab:orange","tab:green","tab:red","tab:gray"]): m = (L==cls) if m.sum()>0: plt.scatter(Z[m,0], Z[m,1], s=10, alpha=0.7, label=cls, c=col) plt.legend(); plt.title("t-SNE on log-magnitude spectrum features") plt.tight_layout(); plt.savefig(out_png); plt.close() # ========== 文件收集(source / target / all)========== def collect_source_files(cfg): root = cfg["paths"]["source_dir"] files = [] layout = cfg["source_domain"]["folder_layout"] for block in layout: bpath = os.path.join(root, block["path"]) if "classes" in block: for c in block["classes"]: files += glob.glob(os.path.join(bpath, c, "**", "*.mat"), recursive=True) if "files" in block: files += [os.path.join(bpath, f) for f in block["files"]] return sorted(files) def collect_target_files(cfg): root = cfg["paths"]["target_dir"] pat = cfg.get("target_domain", {}).get("files_pattern", "[A-P].mat") files = glob.glob(os.path.join(root, pat)) if not files: files = glob.glob(os.path.join(root, "*.mat")) return sorted(files) def collect_all_files(cfg): # 递归 root_dir 下所有 .mat(包含源域 + 目标域) root = cfg["paths"]["root_dir"] return sorted(glob.glob(os.path.join(root, "**", "*.mat"), recursive=True)) # ========== 主流程 ========== def main(): ap = argparse.ArgumentParser() ap.add_argument("--cfg", type=str, required=True) ap.add_argument("--out", type=str, default="./preprocessed") ap.add_argument("--max_per_class", type=int, default=999999) ap.add_argument("--fs_out", type=float, default=32000) ap.add_argument("--seed", type=int, default=0) ap.add_argument("--scope", type=str, choices=["source","target","all"], default="source", help="选择处理范围:source=仅源域;target=仅目标域;all=根目录下所有 .mat") args = ap.parse_args() random.seed(args.seed); np.random.seed(args.seed) cfg = load_cfg(args.cfg) fs_out = int(cfg["target_domain"]["fs_hz"]) if args.fs_out is None else int(args.fs_out) # 根据 scope 选择文件 if args.scope == "source": mat_files = collect_source_files(cfg) elif args.scope == "target": mat_files = collect_target_files(cfg) else: mat_files = collect_all_files(cfg) print(f"[INFO] found mat files: {len(mat_files)} (scope={args.scope})") os.makedirs(args.out, exist_ok=True) index_rows = ["file,window,label,channel,f1,f2,rpm,fs"] by_label_counter = defaultdict(int) tsne_feats, tsne_labels = [], [] per_class_limit = args.max_per_class random.shuffle(mat_files) viz_keep = defaultdict(list) target_dir = cfg["paths"]["target_dir"] target_rpm_approx = cfg.get("target_domain", {}).get("rpm_approx", None) for fp in mat_files: lab = infer_label_from_path(fp) if lab not in ["OR","IR","B","N","UNK"]: lab = "UNK" if by_label_counter[lab] >= per_class_limit: continue # 目标域优先使用 rpm_approx;否则走通用选择 rpm_pref = None if args.scope in ("target", "all"): if is_under_dir(fp, target_dir) and target_rpm_approx is not None: try: rpm_pref = float(target_rpm_approx) except: rpm_pref = None info = preprocess_one_file( fp, cfg, out_dir=args.out, fs_out=fs_out, use_order=cfg["preprocess_default"].get("use_order_tracking", True), rpm_pref=rpm_pref ) if info is None: continue for (wpath, label, ch, f1, f2, rpm, fs) in info["rows"]: index_rows.append(f"{wpath},{label},{ch},{f1:.2f},{f2:.2f},{rpm},{fs}") by_label_counter[lab] += 1 # 取少量窗口做 t-SNE 的简易频谱特征 for r in info["rows"][:3]: w = np.load(r[0]) N = 1<<int(np.ceil(np.log2(len(w)))) Wf = np.fft.rfft(w, N) feat = np.log1p(np.abs(Wf))[:2048] tsne_feats.append(feat.astype(np.float32)) tsne_labels.append(lab) if len(viz_keep[lab]) < 2: viz_keep[lab].append((fp, info)) with open(os.path.join(args.out, "index.csv"), "w", encoding="utf-8") as f: f.write("\n".join(index_rows)) print(f"[INFO] saved index.csv with {len(index_rows)-1} rows") figdir = os.path.join(args.out, "figs") for lab, lst in viz_keep.items(): for _, (fp, info) in enumerate(lst): title = f"{lab}_{Path(fp).stem}" plot_one_sample(figdir, info, cfg, title_hint=title) if len(tsne_feats) > 10: tsne_overview(tsne_feats, tsne_labels, os.path.join(args.out, "tsne_overview.png")) print("[INFO] saved tsne_overview.png") print("[COUNT] per class (processed files):", dict(by_label_counter)) print(f"[DONE] preprocessed windows saved to: {args.out}") if __name__ == "__main__": main() 这段python代码有错误:usage: preprocess_and_viz.py [-h] --cfg CFG [--out OUT] [--max_per_class MAX_PER_CLASS] [--fs_out FS_OUT] [--seed SEED] [--scope {source,target,all}] preprocess_and_viz.py: error: the following arguments are required: --cfg 怎么修改
09-25
#include <stdint.h> #include <stddef.h> #include <string.h> #include <assert.h> #include <stdio.h> #include "btdm_host.h" #include "btdm_utils.h" #include "pan_api.h" #include "fdb_app.h" #include "app_config.h" #include "app_bt.h" #include "user_bt.h" #include "ethernetif.h" #include "FreeRTOS.h" #ifndef LOG_ENABLE #define LOG_ENABLE #endif #include "co_log.h" #ifdef LOG_LOCAL_LEVEL #undef LOG_LOCAL_LEVEL #endif #define LOG_LOCAL_LEVEL LOG_LEVEL_INFO #define max(a, b) ((a) > (b) ? (a) : (b)) #define min(a, b) ((a) > (b) ? (b) : (a)) const BtAccessModeInfo access_mode_nc = { .inqInterval = 0x800, .inqWindow = 0x12, .pageInterval = 0x800, .pageWindow = 0x12, }; static BtHandler securityHandler; static BtHandler globalHandler; static BtSecurityParms secParms; static char hf_codec[2]; uint8_t default_name[] = "FR30xx_0000"; //HfChannel hf_channel[NUM_BT_DEVICES]; //HfgChannel hfg_channel[NUM_BT_DEVICES]; //A2dpStream Stream[NUM_STREAMS]; //AvrcpChannel rcpCtChannel[NUM_BT_DEVICES]; //AvrcpChannel rcpTgChannel[NUM_BT_DEVICES]; HfChannel *hf_channel; HfgChannel *hfg_channel; A2dpStream *Stream; AvrcpChannel *rcpCtChannel; AvrcpChannel *rcpTgChannel; //BtPacket *scoPacket; uint8_t SbcSnkElements[]={ A2DP_SBC_CODEC_INF_ELEMENT( /* 48000 and 44100 are required for SNK */ A2DP_SBC_CODEC_FREQ_48000 | A2DP_SBC_CODEC_FREQ_44100 | A2DP_SBC_CODEC_FREQ_32000 | A2DP_SBC_CODEC_FREQ_16000, /* All modes required for SNK */ A2DP_SBC_CODEC_CHNL_MODE_MONO | A2DP_SBC_CODEC_CHNL_MODE_DUAL | A2DP_SBC_CODEC_CHNL_MODE_STEREO | A2DP_SBC_CODEC_CHNL_MODE_JOINT, /* One block size must be supported */ A2DP_SBC_CODEC_BLOCKS_16 | A2DP_SBC_CODEC_BLOCKS_12 | A2DP_SBC_CODEC_BLOCKS_8 | A2DP_SBC_CODEC_BLOCKS_4, /* Both 8 and 4 must be supported */ A2DP_SBC_CODEC_SUBBANDS_8 | A2DP_SBC_CODEC_SUBBANDS_4, /* Both allocation methods must be supported in SNK */ A2DP_SBC_CODEC_ALLOCATION_LOUDNESS | A2DP_SBC_CODEC_ALLOCATION_SNR, /* Minium bitpool */ 2, /* Maximum bitpool */ 53) }; uint8_t AacSnkElements[] = { A2DP_AAC_CODEC_MPEG2_LC | A2DP_AAC_CODEC_MPEG4_LC, A2DP_AAC_CODEC_FREQ_44100, A2DP_AAC_CODEC_FREQ_48000 | A2DP_AAC_CODEC_CHNL_MONO | A2DP_AAC_CODEC_CHNL_STEREO, A2DP_AAC_CODEC_VBR, 0x00, 0x00 }; /* Source SBC Elements */ static uint8_t SbcSrcElements[] = { A2DP_SBC_CODEC_INF_ELEMENT(/* 48000 or 44100 is required for SRC */ /*A2DP_SBC_CODEC_FREQ_48000 | */ A2DP_SBC_CODEC_FREQ_44100 /*| A2DP_SBC_CODEC_FREQ_32000 | A2DP_SBC_CODEC_FREQ_16000*/, /* MONO and one other required for SRC */ A2DP_SBC_CODEC_CHNL_MODE_MONO | A2DP_SBC_CODEC_CHNL_MODE_DUAL | A2DP_SBC_CODEC_CHNL_MODE_STEREO | A2DP_SBC_CODEC_CHNL_MODE_JOINT, /* One block size must be supported */ A2DP_SBC_CODEC_BLOCKS_16 | A2DP_SBC_CODEC_BLOCKS_12 | A2DP_SBC_CODEC_BLOCKS_8 | A2DP_SBC_CODEC_BLOCKS_4, /* SRC must support 8 subbands */ A2DP_SBC_CODEC_SUBBANDS_8 | A2DP_SBC_CODEC_SUBBANDS_4, /* SRC must support LOUDNESS */ A2DP_SBC_CODEC_ALLOCATION_LOUDNESS | A2DP_SBC_CODEC_ALLOCATION_SNR, /* Minium bitpool */ 2, /* Maximum bitpool */ 53) }; AvdtpCodec sbcSnkCodec1; //local codec information AvdtpCodec aacSnkCodec1; AvdtpCodec sbcSnkCodec2; //local codec information AvdtpCodec aacSnkCodec2; AvdtpCodec sbcSrcCodec1; AvdtpCodec sbcSrcCodec2; static AvdtpCodec cfgCodec; static uint8_t cfgElements[4]; BtRemoteDevice *last_rem_dev = NULL; extern void CMGR_SetAudioVoiceSettings(BtScoAudioSettings settings); MeCommandToken *name_token; static void name_result_handler(const BtEvent *event) { printf("name result: %d,%d\r\n",event->eType,event->errCode); if((event->eType != BTEVENT_NAME_RESULT) || (event->p.meToken != name_token)){ return; } if(event->errCode == 0){ printf("$$$$$addr:%x,%x,name:%d,%s\r\n",event->p.meToken->p.name.bdAddr.A[0],event->p.meToken->p.name.bdAddr.A[1],event->p.meToken->p.name.io.out.len,event->p.meToken->p.name.io.out.name); } if(name_token){ btdm_free(name_token); name_token = 0; } } void bt_name_query(BD_ADDR *addr, BtPageScanInfo *psi) { BtStatus status; ///doing name request if(name_token){ return; } name_token = (MeCommandToken *)btdm_malloc(sizeof(MeCommandToken)); memcpy(&name_token->p.name.bdAddr,addr,6); memcpy(&name_token->p.name.io.in.psi,psi,sizeof(BtPageScanInfo)); //memset(&name_token.p.name.io.in.psi,0,sizeof(BtPageScanInfo)); name_token->callback = name_result_handler; status = ME_GetRemoteDeviceName(name_token); if(status != BT_STATUS_PENDING){ btdm_free(name_token); name_token = 0; } printf("bt_name_query: %x,%x\r\n",addr->A[0],addr->A[1]); } uint8_t bt_get_free_hf_channel(void) { uint8_t index = 0; for(index = 0; index < NUM_BT_DEVICES; index++){ if(hf_channel[index].state == HF_STATE_CLOSED){ break; } } return index; } uint8_t bt_get_free_hfg_channel(void) { uint8_t index = 0; for(index = 0; index < NUM_BT_DEVICES; index++){ if(hfg_channel[index].state == HFG_STATE_CLOSED){ break; } } return index; } uint8_t bt_get_free_a2dp_sink_stream(void) { uint8_t index = 0; for(index = 0; index < NUM_BT_DEVICES; index++){ //if(Is_a2dp_stream_registered(&Stream[index]) && (Stream[index].device->state == A2DP_DEV_STATE_DISCONNECTED)){ if(Is_a2dp_stream_registered(&Stream[index]) && (Stream[index].device == NULL)){ break; } } return index; } uint8_t bt_get_free_a2dp_source_stream(void) { uint8_t index = 0; for(index = 2; index < NUM_STREAMS; index++){ //if(Is_a2dp_stream_registered(&Stream[index]) && (Stream[index].device->state == A2DP_DEV_STATE_DISCONNECTED)){ if(Is_a2dp_stream_registered(&Stream[index]) && (Stream[index].device == NULL)){ break; } } return index; } uint8_t bt_get_free_avrcp_channel(void) { uint8_t index = 0; for(index = 0; index < NUM_BT_DEVICES; index++){ if(rcpCtChannel[index].chnl.conn.state == 0){ break; } } return index; } void bt_avrcp_register_notification(AvrcpChannel *chnl, uint16_t event_mask) { AvrcpAdvancedPdu *avrcp_cmd; BtStatus status; printf("avrcp register event:%x\r\n",event_mask); if(event_mask & AVRCP_ENABLE_PLAY_STATUS_CHANGED){ ///注册播放状态改变事件,当TG播放状态改变时,产生AVRCP_EVENT_ADV_NOTIFY事件 avrcp_cmd = (AvrcpAdvancedPdu *)btdm_malloc(sizeof(AvrcpAdvancedPdu)); avrcp_cmd->parms = (uint8_t *)btdm_malloc(64); status = AVRCP_CtRegisterNotification(chnl, avrcp_cmd, AVRCP_EID_MEDIA_STATUS_CHANGED, 0); if (status != BT_STATUS_PENDING) { btdm_free(avrcp_cmd->parms); btdm_free(avrcp_cmd); } } if(event_mask & AVRCP_ENABLE_TRACK_CHANGED){ ///注册歌曲改变事件,当TG播放状态改变时,产生AVRCP_EVENT_ADV_NOTIFY事件 avrcp_cmd = (AvrcpAdvancedPdu *)btdm_malloc(sizeof(AvrcpAdvancedPdu)); avrcp_cmd->parms = (uint8_t *)btdm_malloc(64); status = AVRCP_CtRegisterNotification(chnl, avrcp_cmd, AVRCP_EID_TRACK_CHANGED, 0); if (status != BT_STATUS_PENDING) { btdm_free(avrcp_cmd->parms); btdm_free(avrcp_cmd); } } if(event_mask & AVRCP_ENABLE_VOLUME_CHANGED){ ///注册歌曲改变事件,当TG播放状态改变时,产生AVRCP_EVENT_ADV_NOTIFY事件 avrcp_cmd = (AvrcpAdvancedPdu *)btdm_malloc(sizeof(AvrcpAdvancedPdu)); avrcp_cmd->parms = (uint8_t *)btdm_malloc(64); status = AVRCP_CtRegisterNotification(chnl, avrcp_cmd, AVRCP_EID_VOLUME_CHANGED, 0); if (status != BT_STATUS_PENDING) { btdm_free(avrcp_cmd->parms); btdm_free(avrcp_cmd); } } } /// 0--- not supported type, 1---cvsd, 2---msbc, 3---cvsd&msbc static uint8_t bt_parse_hf_codec_type(uint8_t *data) { uint8_t ret = 0; uint8_t index,len; len = strlen((void *)data); for(uint8_t i = 0; i < len; i++) { if((data[i] > '9') || (data[i] < '1')){ continue; } if(ret == 0){ if(data[i] == '1'){ ret = 1; } else if(data[i] == '2'){ ret = 2; } else{ ret = 0; break; } } else if(ret == 1){ if(data[i] == '2'){ ret = 3; } else{ ret = 0; break; } } else if(ret == 2){ if(data[i] == '1'){ ret = 3; } else{ ret = 0; break; } } } return ret; } static void security_event_handler(const BtEvent *event) { //BtDeviceContext *bdc; switch(event->eType) { case BTEVENT_PIN_REQ: SEC_SetPin(event->p.remDev, (const uint8_t *)"0000", 4, BPT_SAVE_TRUSTED); break; case BTEVENT_AUTHORIZATION_REQ: SEC_Authorize(event->p.remDev, TRUE, TRUE); break; //case BTEVENT_PAIRING_COMPLETE: // bdc = DS_FindDevice(&event->p.pairingInfo.remDev->bdAddr); // break; default: //co_printf("SecurityEventHandler: event--0x%02x is not implemented.\r\n", event->eType); break; } } static void me_callback(const BtEvent *event) { LOG_INFO(NULL, "me_callback :%d,%d\r\n",event->eType,event->errCode); switch (event->eType) { case BTEVENT_HCI_INITIALIZED: break; case BTEVENT_INQUIRY_CANCELED: //printf("inquiry canceled\r\n"); bt_update_conn_status(BT_INFO_INQ_CANCEL, NULL, NULL); break; case BTEVENT_INQUIRY_RESULT: // { // uint8_t name[MAX_NAME_SIZE]; // uint8_t len; // printf("inq result: %x\r\n",event->p.inqResult.classOfDevice); // printf("addr:0x%02x%02x%02x%02x%02x%02x\r\n",event->p.inqResult.bdAddr.A[0],event->p.inqResult.bdAddr.A[1],event->p.inqResult.bdAddr.A[2], // event->p.inqResult.bdAddr.A[3],event->p.inqResult.bdAddr.A[4],event->p.inqResult.bdAddr.A[5]); // printf("rssi:%d,name: ",event->p.inqResult.rssi); // bt_parse_inq_result((uint8_t *)event->p.inqResult.extInqResp,name,&len); // for(uint8_t i = 0; i < len; i++) // { // printf("%c",name[i]); // } // printf("\r\n"); // } bt_update_conn_status(BT_INFO_INQ_RESULT, NULL, &event->p.inqResult); break; case BTEVENT_INQUIRY_COMPLETE: bt_update_conn_status(BT_INFO_INQ_COMP, NULL, NULL); //ME_Inquiry(BT_IAC_GIAC, 5, 5); break; case BTEVENT_LINK_CONNECT_REQ: ME_AcceptIncomingLink(event->p.remDev, BCR_SLAVE); break; case BTEVENT_LINK_CONNECT_IND: // if(user_bt_env.bt_connect_cb){ // user_bt_env.bt_connect_cb(BTEVENT_LINK_CONNECT_IND, &event->p.remDev->bdAddr, event->errCode); // } last_rem_dev = event->p.remDev; bt_connect_act_cmp(BT_EVENT_CON_IND, event->errCode, event->p.remDev); break; case BTEVENT_LINK_CONNECT_CNF: // if(user_bt_env.bt_connect_cb){ // user_bt_env.bt_connect_cb(BTEVENT_LINK_CONNECT_CNF, &event->p.remDev->bdAddr, event->errCode); // } last_rem_dev = event->p.remDev; bt_connect_act_cmp(BT_EVENT_CON_CNF, event->errCode, event->p.remDev); break; case BTEVENT_LINK_DISCONNECT: // if(user_bt_env.bt_disconnect_cb){ // user_bt_env.bt_disconnect_cb(&event->p.bdAddr, event->errCode); // } bt_connect_act_cmp(BT_EVENT_DISCONNECT, event->errCode, event->p.remDev); break; case BTEVENT_ACCESSIBLE_CHANGE: printf("access state = %d\r\n",event->p.aMode); // if(user_bt_env.bt_access_change_cb){ // user_bt_env.bt_access_change_cb(event->p.aMode); // } bt_connect_act_cmp(BT_EVENT_ACC_CHG, event->p.aMode, NULL); break; case BTEVENT_MODE_CHANGE: if(event->p.modeChange.curMode == 0){ printf("Active Mode.\r\n"); }else{ printf("Sniff Mode.\r\n"); } break; case BTEVENT_ROLE_CHANGE: printf("role = %d\r\n",event->p.roleChange.newRole); break; case BTEVENT_HCI_COMMAND_SENT: break; default: break; } } static void hf_callback(HfChannel *Chan, HfCallbackParms *Info) { // static bool scoPacketSent = true; if ((Info->event != HF_EVENT_AUDIO_DATA) && (Info->event != HF_EVENT_AUDIO_DATA_SENT)) { printf("hf_callback: event = %d.\r\n", Info->event); } switch(Info->event){ case HF_EVENT_GATEWAY_FEATURES: //printf("gw feature: %x\r\n",Info->p.features); if((Info->p.features & HFG_FEATURE_CODEC_NEGOTIATON) && (HF_GetSupportedFeature() & HF_FEATURE_CODEC_NEGOTIATION_CFG)){ CMGR_SetAudioVoiceSettings(0x63); }else{ CMGR_SetAudioVoiceSettings(0x60); } break; case HF_EVENT_SERVICE_CONNECT_REQ: bt_update_conn_status(BT_PROFILE_HF_CONN_REQ, Chan, Info); break; case HF_EVENT_SERVICE_CONNECTED: LOG_INFO(NULL,"hf connected\r\n"); //A2DP_OpenStream(&Stream[0], &Info->p.remDev->bdAddr); bt_update_conn_status(BT_PROFILE_HF_CONN, Chan, Info); break; case HF_EVENT_SERVICE_DISCONNECTED: LOG_INFO(NULL,"hf disconnected %d\r\n",Info->errCode); bt_update_conn_status(BT_PROFILE_HF_DISCONN, Chan, Info); break; case HF_EVENT_CALL_IND: bt_update_conn_status(BT_PROFILE_HF_CALL, Chan, Info); break; case HF_EVENT_CALLSETUP_IND: bt_update_conn_status(BT_PROFILE_HF_CALLSETUP, Chan, Info); break; case HF_EVENT_CALLHELD_IND: break; case HF_EVENT_RING_IND: bt_update_conn_status(BT_PROFILE_HF_RING, Chan, Info); break; case HF_EVENT_CALLER_ID_NOTIFY: break; case HF_EVENT_SPEAKER_VOLUME: bt_update_conn_status(BT_PROFILE_HF_SPK_VOL, Chan, Info); break; case HF_EVENT_CURRENT_CALL_STATE: bt_update_conn_status(BT_PROFILE_HF_CURRENT_CALL, Chan, Info); break; case HF_EVENT_AT_RESULT_DATA: bt_update_conn_status(BT_PROFILE_HF_AT_RESULT, Chan, Info); break; case HF_EVENT_AUDIO_CONNECTED: bt_update_conn_status(BT_PROFILE_HF_AUDIO_CONN, Chan, Info); break; case HF_EVENT_AUDIO_DISCONNECTED: bt_update_conn_status(BT_PROFILE_HF_AUDIO_DISCONN, Chan, Info); break; case HF_EVENT_AUDIO_DATA: bt_update_conn_status(BT_PROFILE_HF_AUDIO_DATA, Chan, Info); break; case HF_EVENT_AUDIO_DATA_SENT: // scoPacketSent = true; btdm_free(Info->p.audioPacket->data); btdm_free(Info->p.audioPacket); break; #if HF_CODEC_NEG == XA_ENABLED case HF_EVENT_CODEC_NEGOTIATION: { HfCommand *cmd; if(Info->p.codecID == 1){ //cvsd CMGR_SetAudioVoiceSettings(0x60); }else if(Info->p.codecID == 2){ //msbc CMGR_SetAudioVoiceSettings(0x63); } BtStatus ret = BT_STATUS_NO_RESOURCES; cmd = (HfCommand *)btdm_malloc(sizeof(HfCommand)); if(cmd != NULL){ hf_codec[0] = Info->p.codecID + '0'; hf_codec[1] = 0; ret = HF_CodecConnectionSetup((HfChannel *)Chan, hf_codec, cmd); } if(ret != BT_STATUS_PENDING){ btdm_free((void *)cmd); } } break; #endif case HF_EVENT_COMMAND_COMPLETE: btdm_free((uint8_t *)Info->p.command); break; default: break; } } static void hfg_callback(HfgChannel *Chan, HfgCallbackParms *Info) { BtStatus status; HfgResponse *rsp; uint8_t codec_type; if ((Info->hfgEvent != HFG_EVENT_AUDIO_DATA) && (Info->hfgEvent != HFG_EVENT_AUDIO_DATA_SENT)) { LOG_INFO(NULL, "hfg_callback :%d\r\n",Info->hfgEvent); } switch (Info->hfgEvent) { case HFG_EVENT_HANDSFREE_FEATURES: printf("remote hf feature: %x\r\n",Info->p.features); // if(Info->p.features & HF_FEATURE_CODEC_NEGOTIATION){ // CMGR_SetAudioVoiceSettings(0x63); // }else{ // CMGR_SetAudioVoiceSettings(0x60); // } break; case HFG_EVENT_SERVICE_CONNECT_REQ: bt_update_conn_status(BT_PROFILE_HFG_CONN_REQ, Chan, Info); break; case HFG_EVENT_SERVICE_CONNECTED: bt_update_conn_status(BT_PROFILE_HFG_CONN, Chan, Info); break; case HFG_EVENT_SERVICE_DISCONNECTED: bt_update_conn_status(BT_PROFILE_HFG_DISCONN, Chan, Info); break; case HFG_EVENT_AUDIO_CONNECTED: { HfgResponse *rsp; rsp = (HfgResponse *)btdm_malloc(sizeof(HfgResponse)); HFG_SetIndicatorValue(Chan, HFG_IND_CALL, TRUE, rsp); bt_update_conn_status(BT_PROFILE_HFG_AUDIO_CONN, Chan, Info); } break; case HFG_EVENT_AUDIO_DISCONNECTED: { HfgResponse *rsp; rsp = (HfgResponse *)btdm_malloc(sizeof(HfgResponse)); HFG_SetIndicatorValue(Chan, HFG_IND_CALL, FALSE, rsp); bt_update_conn_status(BT_PROFILE_HFG_AUDIO_DISCONN, Chan, Info); } break; case HFG_EVENT_AT_COMMAND_DATA: for(uint8_t i = 0; i < Info->p.data->dataLen; i++) printf("%c",Info->p.data->rawData[i]); printf("\r\n"); rsp = (HfgResponse *)btdm_malloc(sizeof(HfgResponse)); status = HFG_SendOK(Chan,rsp); if(status != BT_STATUS_PENDING){ btdm_free((void *)rsp); } // if(memcmp(Info->p.data->rawData,"AT+IPHONEACCEV=1,1,9",sizeof("AT+IPHONEACCEV=1,1,9")) == 0) // { // status = BT_STATUS_NO_RESOURCES; // rsp = (HfgResponse *)btdm_malloc(sizeof(HfgResponse)); // if(rsp != NULL){ // status = HFG_CreateCodecConnection(&hfg_channel[0], 1, rsp); // } // if(status != BT_STATUS_PENDING){ // btdm_free((void *)rsp); // } // printf("status = %d\r\n",status); // } break; case HFG_EVENT_SUPPORTED_CODEC: codec_type = bt_parse_hf_codec_type(Info->p.ptr); if(codec_type >= 2){ CMGR_SetAudioVoiceSettings(0x63); }else{ CMGR_SetAudioVoiceSettings(0x60); } break; case HFG_EVENT_AUDIO_DATA: { // if(Info->p.audioData->len == 120){ // fputc('M',NULL); // }else if(Info->p.audioData->len == 60){ // fputc('m',NULL); // } // printf("audio data: "); // for(uint8_t i = 0; i < Info->p.audioData->len; i++) // { // printf("%02x ",Info->p.audioData->data[i]); //} // printf("\r\n"); bt_update_conn_status(BT_PROFILE_HFG_AUDIO_DATA, Chan, Info); } break; case HFG_EVENT_AUDIO_DATA_SENT: //fputc('s',NULL); btdm_free((void *)Info->p.audioPacket->data); btdm_free((void *)Info->p.audioPacket); break; case HFG_EVENT_CODEC_CONNECTION_RSP: codec_type = bt_parse_hf_codec_type(Info->p.ptr); printf("hfg codec connection rsp: %s,type = %d\r\n",Info->p.ptr,codec_type); if(codec_type >= 2){ CMGR_SetAudioVoiceSettings(0x63); }else{ CMGR_SetAudioVoiceSettings(0x60); } HFG_CreateAudioLink(&hfg_channel[0],HFG_AR_LOCAL_USER_ACTION); break; case HFG_EVENT_RESPONSE_COMPLETE: btdm_free((void *)Info->p.response); break; } } static void a2dp_callback(A2dpStream *cbStream, const A2dpCallbackParms *Parms) { AvdtpCodec *codec; uint8_t *elements; uint8_t *reqElements; uint8_t error = A2DP_ERR_NO_ERROR; if((Parms->event != A2DP_EVENT_STREAM_DATA_IND ) && (Parms->event != A2DP_EVENT_STREAM_SBC_PACKET_SENT)) { LOG_INFO(NULL, "a2dp callback event=%d,%x,%x\r\n", Parms->event,Parms->error,Parms->discReason); } switch(Parms->event) { case A2DP_EVENT_STREAM_OPEN_IND: bt_update_conn_status(BT_PROFILE_A2DP_OPEN_IND, cbStream, Parms); if (AVDTP_CODEC_TYPE_SBC == Parms->p.configReq->codec.codecType) { codec = A2DP_GetRegisteredCodec(cbStream); elements = codec->elements; reqElements = Parms->p.configReq->codec.elements; printf("a2dp local codec: %x,%x,%x,%x\r\n",elements[0],elements[1],elements[2],elements[3]); printf("a2dp remote codec: %x,%x,%x,%x\r\n",reqElements[0],reqElements[1],reqElements[2],reqElements[3]); /* Check requested elements with registered elements */ if (!(reqElements[0] & (elements[0] & 0xF0))) { error = A2DP_ERR_NOT_SUPPORTED_SAMP_FREQ; } else if (!(reqElements[0] & (elements[0] & 0x0F))) { error = A2DP_ERR_NOT_SUPPORTED_CHANNEL_MODE; } else if (!(reqElements[1] & (elements[1] & 0x0C))) { error = A2DP_ERR_NOT_SUPPORTED_SUBBANDS; } else if (!(reqElements[1] & (elements[1] & 0x03))) { error = A2DP_ERR_NOT_SUPPORTED_ALLOC_METHOD; } else if (reqElements[2] < elements[2]) { error = A2DP_ERR_NOT_SUPPORTED_MIN_BITPOOL_VALUE; } else if (reqElements[3] > elements[3]) { error = A2DP_ERR_NOT_SUPPORTED_MAX_BITPOOL_VALUE; } // if(error == A2DP_ERR_NO_ERROR){ // // sbcinfo.bitPool = reqElements[3]; // // if(reqElements[0]&0x20){ // sbcinfo.sampleFreq = 2;//44100 // } // else{ // sbcinfo.sampleFreq = 3;//48000 // } // // if(reqElements[1]&0x01){ // sbcinfo.allocMethod = 0;//loudness // } // else{ // sbcinfo.allocMethod = 1;//snr // } // } // codec->freq = (reqElements[0] & 0xF0) >> 5; A2DP_OpenStreamRspWithSinkDelay(cbStream, error, AVDTP_SRV_CAT_MEDIA_CODEC, 0); } else if(AVDTP_CODEC_TYPE_MPEG2_4_AAC== Parms->p.configReq->codec.codecType) { codec = A2DP_GetRegisteredCodec(cbStream); elements = codec->elements; reqElements = Parms->p.configReq->codec.elements; // if(reqElements[1] & 0x01) { // codec->freq = 1; // } // else if(reqElements[2] & 0x80) { // codec->freq = 0; // } A2DP_OpenStreamRspWithSinkDelay(cbStream, error, AVDTP_SRV_CAT_MEDIA_CODEC, 0); } else { /* Refuse to accept incoming con to MP3 stream for now */ A2DP_OpenStreamRspWithSinkDelay(cbStream, AVRCP_ERR_UNKNOWN_ERROR, AVDTP_SRV_CAT_MEDIA_CODEC, 0); } break; case A2DP_EVENT_CODEC_INFO: printf("codec info: %x,%x,%x,%x\r\n",Parms->p.codec->elements[0],Parms->p.codec->elements[1],Parms->p.codec->elements[2],Parms->p.codec->elements[3]); /* Found a matching codec */ codec = A2DP_GetRegisteredCodec(cbStream); elements = codec->elements; /* Save the remote codec information. Selection * of capabilities will be made from the UI. */ cfgCodec.codecType = Parms->p.codec->codecType; cfgCodec.elemLen = Parms->p.codec->elemLen; cfgCodec.elements = cfgElements; if (cfgCodec.codecType == AVDTP_CODEC_TYPE_SBC) { /* Only the matching codec information * elements can be selected. */ cfgCodec.elements[0] = (uint8_t)(Parms->p.codec->elements[0] & elements[0]); cfgCodec.elements[1] = (uint8_t)(Parms->p.codec->elements[1] & elements[1]); cfgCodec.elements[2] = (uint8_t)(max(Parms->p.codec->elements[2], elements[2])); cfgCodec.elements[3] = (uint8_t)(min(Parms->p.codec->elements[3], elements[3])); } break; case A2DP_EVENT_GET_CONFIG_IND: LOG_INFO(NULL, "codec type=%d,%x,%x,%x,%x\r\n",cfgCodec.codecType,cfgCodec.elements[0],cfgCodec.elements[1],cfgCodec.elements[2],cfgCodec.elements[3]); /* Make sure something valid is configured for each field */ if (cfgCodec.codecType == AVDTP_CODEC_TYPE_SBC) { if ( (cfgCodec.elements[0] & 0xF0) && (cfgCodec.elements[0] & 0x0F) && (cfgCodec.elements[1] & 0xF0) && (cfgCodec.elements[1] & 0x0C) && (cfgCodec.elements[1] & 0x03)) { /* Pick the sampling rate supported */ if (cfgCodec.elements[0] & 0x80) { cfgCodec.elements[0] &= 0x8F; } else if (cfgCodec.elements[0] & 0x40) { cfgCodec.elements[0] &= 0x4F; } else if (cfgCodec.elements[0] & 0x20) { cfgCodec.elements[0] &= 0x2F; } else if (cfgCodec.elements[0] & 0x10) { cfgCodec.elements[0] &= 0x1F; } /* Pick the channel mode */ if (cfgCodec.elements[0] & 0x01) { cfgCodec.elements[0] &= 0xF1; } else if (cfgCodec.elements[0] & 0x02) { cfgCodec.elements[0] &= 0xF2; } else if (cfgCodec.elements[0] & 0x04) { cfgCodec.elements[0] &= 0xF4; } else if (cfgCodec.elements[0] & 0x08) { cfgCodec.elements[0] &= 0xF8; } /* Pick the block length */ // if (cfgCodec.elements[1] & 0x80) { // cfgCodec.elements[1] &= 0x8F; // } else if (cfgCodec.elements[1] & 0x40) { // cfgCodec.elements[1] &= 0x4F; // } else if (cfgCodec.elements[1] & 0x20) { // cfgCodec.elements[1] &= 0x2F; // } else if (cfgCodec.elements[1] & 0x10) { // cfgCodec.elements[1] &= 0x1F; // } cfgCodec.elements[1] &= 0x1F; /* Pick the number of subbands */ if (cfgCodec.elements[1] & 0x04) { cfgCodec.elements[1] &= 0xF7; } else if (cfgCodec.elements[1] & 0x08) { cfgCodec.elements[1] &= 0xFB; } /* Pick the allocation method */ if (cfgCodec.elements[1] & 0x01) { cfgCodec.elements[1] &= 0xFD; } else if (cfgCodec.elements[1] & 0x02) { cfgCodec.elements[1] &= 0xFE; } /* Select Min/Max Bitpools */ cfgCodec.elements[2] = cfgCodec.elements[2]; cfgCodec.elements[3] = cfgCodec.elements[3]; // /* copy codec info to local*/ // sbcinfo.bitPool = cfgCodec.elements[3]; // // if(cfgCodec.elements[0]&0x20){ // sbcinfo.sampleFreq = 2;//44100 // } // else{ // sbcinfo.sampleFreq = 3;//48000 // } // // if(cfgCodec.elements[1]&0x01){ // sbcinfo.allocMethod = 0;//loudness // } // else{ // sbcinfo.allocMethod = 1;//snr // } A2DP_SetStreamConfigWithSinkDelay(cbStream, &cfgCodec, 0, 0); } else{ A2DP_CloseStream(cbStream); } } break; case A2DP_EVENT_STREAM_OPEN: LOG_INFO(NULL,"a2dp connected\r\n"); bt_update_conn_status(BT_PROFILE_A2DP_CONN, cbStream, Parms); break; case A2DP_EVENT_STREAM_START_IND: A2DP_StartStreamRsp(cbStream, A2DP_ERR_NO_ERROR); break; case A2DP_EVENT_STREAM_STARTED: bt_update_conn_status(BT_PROFILE_A2DP_PLAYING, cbStream, Parms); break; case A2DP_EVENT_STREAM_SUSPENDED: bt_update_conn_status(BT_PROFILE_A2DP_SUSPEND, cbStream, Parms); break; case A2DP_EVENT_STREAM_CLOSED: bt_update_conn_status(BT_PROFILE_A2DP_DISCONN, cbStream, Parms); break; case A2DP_EVENT_STREAM_DATA_IND: bt_update_conn_status(BT_PROFILE_A2DP_STREAM_DATA, cbStream, Parms); break; case A2DP_EVENT_STREAM_SBC_PACKET_SENT: bt_update_conn_status(BT_PROFILE_A2DP_SBC_PKT_SENT, cbStream, Parms); break; default: break; } } static void avrcp_callback(AvrcpChannel *chnl, const AvrcpCallbackParms *Parms) { AvrcpAdvancedPdu *avrcp_cmd; BtStatus status; LOG_INFO(NULL, "avrcp callback event=%d, status=%d, chnl=%x\r\n",Parms->event, Parms->status, chnl); switch (Parms->event) { case AVRCP_EVENT_CONNECT_IND: AVRCP_ConnectRsp(chnl,TRUE); break; case AVRCP_EVENT_CONNECT: { avrcp_cmd = btdm_malloc(sizeof(AvrcpAdvancedPdu)); avrcp_cmd->parms = (uint8_t *)btdm_malloc(64); status = AVRCP_CtGetCapabilities((AvrcpChannel *)chnl, avrcp_cmd, AVRCP_CAPABILITY_EVENTS_SUPPORTED); if (status != BT_STATUS_PENDING) { btdm_free(avrcp_cmd->parms); btdm_free(avrcp_cmd); } AVRCP_TgSetEventMask(chnl,AVRCP_ENABLE_VOLUME_CHANGED); } LOG_INFO(NULL, "avrcp connected\r\n"); bt_update_conn_status(BT_PROFILE_AVRCP_CONN, chnl, Parms); break; case AVRCP_EVENT_DISCONNECT: LOG_INFO(NULL, "avrcp disconnected\r\n"); bt_update_conn_status(BT_PROFILE_AVRCP_DISCONN, chnl, Parms); break; case AVRCP_EVENT_ADV_INFO: if(Parms->advOp == AVRCP_OP_SET_ABSOLUTE_VOLUME) { //LOG_INFO("SET_ABSOLUTE_VOLUME is %d.\r\n", event->param.adv.info.volume); printf("+VOL:%02x\r\n",Parms->p.adv.info.volume); } break; case AVRCP_EVENT_ADV_RESPONSE: ///本地查询TG支持事件,返回消�? /**/ if((Parms->advOp == AVRCP_OP_GET_CAPABILITIES) &&(Parms->p.adv.rsp.capability.type == AVRCP_CAPABILITY_EVENTS_SUPPORTED)){ //printf("cap eventmaskk = %x\r\n",event->param.adv.rsp.capability.info.eventMask); uint16_t event_mask = Parms->p.adv.rsp.capability.info.eventMask; bt_update_conn_status(BT_PROFILE_AVRCP_EVENT_SUPPORT, chnl, &event_mask); } ///本地注册事件,返回的当前状�? if(Parms->advOp == AVRCP_OP_REGISTER_NOTIFY) { ///播放状态改变通知的当前状�? if(Parms->p.adv.notify.event == AVRCP_EID_MEDIA_STATUS_CHANGED) { } else if(Parms->p.adv.notify.event == AVRCP_EID_TRACK_CHANGED){ //user_bt_get_media_info(); } } if(Parms->advOp == AVRCP_OP_GET_MEDIA_INFO){ uint16_t len0 = Parms->p.adv.rsp.element.txt[0].length; uint16_t len1 = Parms->p.adv.rsp.element.txt[1].length; printf("media info: %d,%s,%d\r\n",len0,Parms->p.adv.rsp.element.txt[0].string,len1); } if(Parms->advOp == AVRCP_OP_GET_PLAY_STATUS){ printf("media length:%d,pos:%d,status:%d\r\n",Parms->p.adv.rsp.playStatus.length,Parms->p.adv.rsp.playStatus.position,Parms->p.adv.rsp.playStatus.mediaStatus); } break; case AVRCP_EVENT_PANEL_CNF: if(Parms->p.panelCnf.press == TRUE){ switch(Parms->p.panelCnf.operation) { case AVRCP_POP_PAUSE: AVRCP_SetPanelKey(chnl, AVRCP_POP_PAUSE, FALSE); break; case AVRCP_POP_PLAY: AVRCP_SetPanelKey(chnl, AVRCP_POP_PLAY, FALSE); break; case AVRCP_POP_FORWARD: AVRCP_SetPanelKey(chnl, AVRCP_POP_FORWARD, FALSE); break; case AVRCP_POP_BACKWARD: AVRCP_SetPanelKey(chnl, AVRCP_POP_BACKWARD, FALSE); break; case AVRCP_POP_STOP: AVRCP_SetPanelKey(chnl, AVRCP_POP_STOP, FALSE); break; } } break; case AVRCP_EVENT_ADV_NOTIFY: { const AvrcpAdvNotifyParms *avrcp_ntf = &Parms->p.adv.notify; if(Parms->errorCode == AVRCP_ERR_NO_ERROR) { switch(avrcp_ntf->event) { case AVRCP_EID_TRACK_CHANGED: { avrcp_cmd = (AvrcpAdvancedPdu *)btdm_malloc(sizeof(AvrcpAdvancedPdu)); avrcp_cmd->parms = (uint8_t *)btdm_malloc(64); status = AVRCP_CtRegisterNotification(chnl, avrcp_cmd, AVRCP_EID_TRACK_CHANGED, 0); if (status != BT_STATUS_PENDING) { btdm_free(avrcp_cmd->parms); btdm_free(avrcp_cmd); } } break; case AVRCP_EID_MEDIA_STATUS_CHANGED: { ///重新注册播放状态改变通知消息 uint8_t media_status = Parms->p.adv.notify.p.mediaStatus; bt_update_conn_status(BT_PROFILE_AVRCP_MEDIA_STATUS, chnl, &media_status); avrcp_cmd = (AvrcpAdvancedPdu *)btdm_malloc(sizeof(AvrcpAdvancedPdu)); avrcp_cmd->parms = (uint8_t *)btdm_malloc(64); status = AVRCP_CtRegisterNotification(chnl, avrcp_cmd, AVRCP_EID_MEDIA_STATUS_CHANGED, 0); if (status != BT_STATUS_PENDING) { btdm_free(avrcp_cmd->parms); btdm_free(avrcp_cmd); } } break; } } } break; case AVRCP_EVENT_ADV_TX_DONE: btdm_free(Parms->p.adv.txPdu->parms); btdm_free(Parms->p.adv.txPdu); break; default: break; } } static void pbap_callback(PbapClientCallbackParms *Parms) { printf("pbap callback event = %d\r\n",Parms->event); switch (Parms->event) { case PBAP_EVENT_PARAMS_RX: { if ((Parms->oper == PBAPOP_PULL_PHONEBOOK) || (Parms->oper == PBAPOP_PULL_VCARD_LISTING)) { printf("miss calls: %d,pb size=%d\r\n",Parms->u.paramsRx.newMissedCalls,Parms->u.paramsRx.phonebookSize); } } break; case PBAP_EVENT_DATA_IND: bt_update_conn_status(BT_PROFILE_PBAP_DATA_IND, NULL, Parms); break; case PBAP_EVENT_TP_CONNECTED: bt_update_conn_status(BT_PROFILE_PBAP_CONN, NULL, Parms); break; case PBAP_EVENT_TP_DISCONNECTED: bt_update_conn_status(BT_PROFILE_PBAP_DISCONN, NULL, Parms); break; case PBAP_EVENT_CONTINUE: /* Always call continue to keep the commands flowing */ PBAP_ClientContinue(Parms->client); break; case PBAP_EVENT_ABORTED: /* The requested operation was aborted. */ break; case PBAP_EVENT_COMPLETE: bt_update_conn_status(BT_PROFILE_PBAP_COMP, NULL, Parms); break; default: break; } } #if BTDM_STACK_ENABLE_PAN static void HandleFilters(PanUser *pan, uint16_t *range, uint16_t numRanges) { BtStatus status; uint8_t i; PanControlRespPkt *controlRespPkt; LOG_INFO(NULL, "Pan: Rx'd BNEP_CONTROL:NET_TYPE_SET %d Filter ranges\r\n", numRanges); for (i = 0; i < numRanges*2; i+=2) { LOG_INFO(NULL, " ==>Range start: %#.4x\r\n", BEtoHost16((uint8_t *)&range[i])); LOG_INFO(NULL, " ==>Range end: %#.4x\r\n", BEtoHost16((uint8_t *)&range[i+1])); } controlRespPkt = pvPortMalloc(sizeof(PanControlRespPkt)); if (controlRespPkt == 0) { LOG_INFO(NULL, "PanApp: No Resources\r\n"); return; } /* Set the response message */ StoreBE16(controlRespPkt->message, BNEP_FR_OPERATION_SUCCESS); /* Send the Control Response packet */ status = PAN_ControlResponse(pan, BNEP_FILTER_NET_TYPE_RESPONSE_MSG, controlRespPkt); LOG_INFO(NULL, "PanApp: PAN_ControlResponse() Returned 0x%04x\r\n", status); if (status != BT_STATUS_PENDING) { vPortFree(controlRespPkt); } } static void HandleAddrs(PanUser *pan, BNEP_ADDR *addr, uint16_t numRanges) { BtStatus status; uint8_t i; PanControlRespPkt *controlRespPkt; uint8_t buffer[40]; LOG_INFO(NULL, "Pan: Rx'd BNEP_CONTROL:MULTI_ADDR_SET %d Address ranges\r\n", numRanges); for (i = 0; i < numRanges*2; i+=2) { bnep_addr_ntoa((BNEP_ADDR *)(&addr[i]), (char *)buffer); LOG_INFO(NULL, " ==>Address start: %s\r\n", buffer); bnep_addr_ntoa((BNEP_ADDR *)(&addr[i+1]), (char *)buffer); LOG_INFO(NULL, " ==>Address end: %s\r\n", buffer); } controlRespPkt = pvPortMalloc(sizeof(PanControlRespPkt)); if (controlRespPkt == 0) { LOG_INFO(NULL, "PanApp: No Resources\r\n"); return; } /* Set the response message */ StoreBE16(controlRespPkt->message, BNEP_FR_OPERATION_SUCCESS); /* Send the Control Response packet */ status = PAN_ControlResponse(pan, BNEP_FILTER_MULTI_ADDR_RESPONSE_MSG, controlRespPkt); LOG_INFO(NULL, "PanApp: PAN_ControlResponse() Returned 0x%04x\r\n", status); if (status != BT_STATUS_PENDING) { vPortFree(controlRespPkt); } } /* --------------------------------------------------------------------------- * PAN PANU Packet handler * --------------------------------------------------------------------------- */ static void HandlePanuPacket(PanCallbackParms *Info) { bool DisplayUnknownPackets = true; uint16_t bodyLen, ipLen, ipTotLen; BtStatus status; ArpHeader *arpHdrIn; IpHeader *ipHdr; UdpHeader *udpHdr; DhcpHeader *dhcpHdr; IcmpHeader *icmpHdr; PanPacket *panPkt = 0; BNEP_ADDR *macAddr = 0; uint8_t buff[1024]; uint32_t myIpAddr, dstIP; PanPacketType panPktType; switch (Info->type) { case PANPKT_ARP_REQUEST: LOG_INFO(NULL, "Received ARP Request\r\n"); arpHdrIn = (ArpHeader *)(Info->pkt + ETHER_HDR_SIZE); /* The reply is already set up. Just forward it. */ PAN_ForwardPkt(Info->pan, Info->pkt, Info->rxPktLen); break; case PANPKT_ARP_REPLY: LOG_INFO(NULL, "Received ARP Reply\r\n"); arpHdrIn = (ArpHeader *)Info->pkt; myIpAddr = PAN_GetLocalIpAddr_v2(); if (myIpAddr == BEtoHost32((uint8_t *)&arpHdrIn->dstIP) && PAN_GetRemoteIpAddr_v2(Info->pan) == BEtoHost32((uint8_t *)&arpHdrIn->srcIP)) { /* This is a response to my arp request */ PAN_SetRemoteMacAddr(Info->pan, arpHdrIn->srcMac); LOG_INFO(NULL, "Destination MAC address = %02x:%02x:%02x:%02x:%02x:%02x\r\n", arpHdrIn->srcMac[0], arpHdrIn->srcMac[1], arpHdrIn->srcMac[2], arpHdrIn->srcMac[3], arpHdrIn->srcMac[4], arpHdrIn->srcMac[5]); } break; case PANPKT_IP: if (DisplayUnknownPackets == true) { LOG_INFO(NULL, "Received IPv4 Packet\r\n"); // SOCKADDR_IN from; // ipHdr = (IpHeader *)Info->pkt; // memset((uint8_t*)&from, 0, sizeof(from)); // from.sin_addr.S_un.S_addr = ipHdr->srcIP; // from.sin_family = AF_INET; // from.sin_port = 0; // LOG_INFO(NULL, "Remote IP address: %s, protocol: %d, Length: %d\r\n", // inet_ntoa(from.sin_addr), ipHdr->proto, ipHdr->totalLen); } break; case PANPKT_TCP: if (DisplayUnknownPackets == true) { LOG_INFO(NULL, "Received TCP Packet\r\n"); ipHdr = (IpHeader *)Info->pkt; } break; case PANPKT_UDP: if (DisplayUnknownPackets == true) { LOG_INFO(NULL, "Received UDP Packet\r\n"); ipHdr = (IpHeader *)Info->pkt; udpHdr = (UdpHeader *)((uint8_t *)ipHdr + sizeof(IpHeader)); } break; case PANPKT_DHCP_REQUEST: LOG_INFO(NULL, "Received DHCP Request Packet\r\n"); LOG_INFO(NULL, " Not valid for a PANU!\r\n"); break; case PANPKT_DHCP_REPLY: /* This is for me */ { LOG_INFO(NULL, "Received my DHCP Reply Packet\r\n"); // SOCKADDR_IN sAddr = {AF_INET, 0, 0, 0}; // dhcpHdr = (DhcpHeader *)(Info->pkt + sizeof(IpHeader) + sizeof(UdpHeader)); // if (dhcpHdr->options[2] == DHCPOFFER) { // sAddr.sin_addr.S_un.S_addr = dhcpHdr->yiaddr; // LOG_INFO(NULL, "DHCP server offered IP address %s\r\n", inet_ntoa(sAddr.sin_addr)); // /* Set the device addresses used to make the DHCPREQUEST packet */ // PAN_SetLocalIpAddr_v2(BEtoHost32((uint8_t *)&dhcpHdr->yiaddr)); // PAN_SetDhcpAddr_v2(BEtoHost32((uint8_t *)&dhcpHdr->siaddr)); // bodyLen = MakeDhcpPacket(INADDR_BROADCAST, &panPkt, BOOTP_CLIENT, DHCPREQUEST); // status = PAN_SendPkt(Info->pan, panPkt, PANPKT_DHCP_REQUEST, bodyLen); // LOG_INFO(NULL, "PanApp: PAN_SendPkt() Returned 0x%04x\r\n", status); // } // else if (dhcpHdr->options[2] == DHCPACK) { // sAddr.sin_addr.S_un.S_addr = dhcpHdr->yiaddr; // LOG_INFO(NULL, "DHCP server ACK'd IP address %s\r\n", inet_ntoa(sAddr.sin_addr)); // } } break; case PANPKT_ETHER_PKT: PAN_ForwardPkt(Info->pan, Info->pkt, Info->rxPktLen); break; default: LOG_INFO(NULL, "PanApp: Rx'd unrecognized packet type %d\r\n", Info->type); break; } } void pan_callback(PanCallbackParms *Params) { BtStatus status; PanPacket *panPkt = 0; ArpHeader *arpHdr; uint16_t bodyLen; PanSetupConnPkt *setupPkt; PanControlRespPkt *setupRespPkt; uint16_t numRanges; PanPacketType panPktType; switch (Params->event) { case PANEVENT_OPEN: LOG_INFO(NULL, "PanApp: Received PANEVENT_OPEN event\r\n"); #if 1 BD_ADDR addr; BNEP_ADDR addr_local, addr_remote; ME_ReadLocalBdAddr(&addr); memcpy(&addr_local.addr[0], &addr.A[0], BNEP_ADDR_SIZE); addr_remote = Params->pan->bnepPanu.bnepAddr; /* notify LWIP data link layer is established */ bnep_lwip_netif_up(Params->pan, &addr_local, &addr_remote); #else /* ARP to verify my Link Local address */ panPktType = PANPKT_ARP_REQUEST; bodyLen = sizeof(ArpHeader); panPkt = pvPortMalloc(sizeof(PanPacket) + bodyLen); arpHdr = (ArpHeader *)panPkt->body; /* Set the target address to my initial Link Local address */ PAN_MakeArpHdr(arpHdr, PAN_GetLocalIpAddr_v2()); status = PAN_SendPkt(Params->pan, panPkt, panPktType, bodyLen); if (status != BT_STATUS_PENDING) { LOG_INFO(NULL, "PanApp: Send failed\r\n"); vPortFree(panPkt); return; } LOG_INFO(NULL, "PanApp: Sent ARP to validate Link Local Address\r\n"); #endif break; case PANEVENT_SETUP_CONNECTION: LOG_INFO(NULL, "PanApp: Received PANEVENT_SETUP_CONNECTION event\r\n"); /* Complete the open with a Setup Connection Request */ setupPkt = pvPortMalloc(sizeof(PanSetupConnPkt)); if (setupPkt == 0) { LOG_INFO(NULL, "PanApp: No Resources"); return; } status = PAN_SetupConnection(Params->pan, setupPkt); LOG_INFO(NULL, "PanApp: PAN_SetupConnection() Returned 0x%04x\r\n", status); if (status != BT_STATUS_PENDING) { vPortFree(setupPkt); } break; case PANEVENT_SETUP_CONN_REQ: LOG_INFO(NULL, "PanApp: Received PANEVENT_SETUP_CONN_REQ event\r\n"); /* Complete the open with a Setup Connection Response */ setupRespPkt = pvPortMalloc(sizeof(PanControlRespPkt)); if (setupRespPkt == 0) { LOG_INFO(NULL, "PanApp: No Resources\r\n"); return; } /* The setup connection message has already been validated. The * status parameter contains the validation results of type * BnepSetupResponseMsg. Just copy the status into my response * and send it back. */ StoreBE16(setupRespPkt->message, Params->status); status = PAN_ControlResponse(Params->pan, BNEP_SETUP_CONNECTION_RESPONSE_MSG, setupRespPkt); LOG_INFO(NULL, "PanApp: PAN_ControlResponse() Returned 0x%04x\r\n", status); if (status != BT_STATUS_PENDING) { btdm_free(setupRespPkt); } break; case PANEVENT_CONTROL_IND: switch (Params->pkt[1]) { case BNEP_FILTER_NET_TYPE_SET_MSG: numRanges = Params->rxPktLen - BNEP_CONTROL_HDR_SIZE; numRanges /= ETHER_RANGE_SIZE; HandleFilters(Params->pan, (uint16_t *)(Params->pkt + 2), numRanges); break; case BNEP_FILTER_NET_TYPE_RESPONSE_MSG: LOG_INFO(NULL, "PanApp: Received FILTER_NET_TYPE_RESPONSE event\r\n"); break; case BNEP_FILTER_MULTI_ADDR_SET_MSG: numRanges = Params->rxPktLen - BNEP_CONTROL_HDR_SIZE; numRanges /= BNEP_ADDR_SIZE * 2; HandleAddrs(Params->pan, (BNEP_ADDR *)(Params->pkt + 2), numRanges); break; case BNEP_FILTER_MULTI_ADDR_RESPONSE_MSG: LOG_INFO(NULL, "PanApp: Received MULTI_ADDR_RESPONSE event\r\n"); break; default: break; } break; case PANEVENT_CLOSED: LOG_INFO(NULL, "PanApp: Received PANEVENT_CLOSED event\r\n"); bnep_lwip_netif_down(); break; case PANEVENT_DATA_IND: LOG_INFO(NULL, "PanApp: Received PANEVENT_DATA_IND event\r\n"); HandlePanuPacket(Params); break; case PANEVENT_DATA_HANDLED: LOG_INFO(NULL, "PanApp: Received PANEVENT_DATA_HANDLED event\r\n"); vPortFree(Params->pkt); break; case PANEVENT_SDP_FAILED: LOG_INFO(NULL, "PanApp: Received PANEVENT_SDP_FAILED event\r\n"); break; default: LOG_INFO(NULL, "PanApp: Received Unknown Event %d with status 0x%04x\r\n", Params->event, Params->status); break; } } #endif //void a2dp_device_callback(void *Device, const void *Parms) //{ // switch(*(volatile uint8_t *)Parms){ // case 1/*AVDEV_EVENT_AVDTP_CONNECT_IND*/: // AVDEV_SignalConnectRsp(Device, TRUE, a2dp_device_callback); // break; // default: // break; // } //} void app_btdm_struct_size_dump(void) { printf("BTDM STRUCT SIZE: defined in stack.\r\n"); extern void btdm_struct_size_dump(void); btdm_struct_size_dump(); printf("BTDM STRUCT SIZE: defined in api.\r\n"); printf("BtEvent is %d\r\n", sizeof(BtEvent)); printf("BtRemoteDevice is %d\r\n", sizeof(BtRemoteDevice)); printf("RfDeferEvent is %d\r\n", sizeof(RfDeferEvent)); printf("RfChannel is %d\r\n", sizeof(RfChannel)); printf("HfChannel is %d\r\n", sizeof(HfChannel)); printf("HfCommand is %d\r\n", sizeof(HfCommand)); printf("HfCallbackParms is %d\r\n", sizeof(HfCallbackParms)); printf("HfgChannel is %d\r\n", sizeof(HfgChannel)); printf("HfgCallbackParms is %d\r\n", sizeof(HfgCallbackParms)); printf("A2dpStream is %d\r\n", sizeof(A2dpStream)); printf("A2dpCallbackParms is %d\r\n", sizeof(A2dpCallbackParms)); printf("AvdtpStream is %d\r\n", sizeof(AvdtpStream)); printf("AvdtpConn is %d\r\n", sizeof(AvdtpConn)); printf("AvdtpCallbackParms is %d\r\n", sizeof(AvdtpCallbackParms)); printf("AvctpCallbackParms is %d\r\n", sizeof(AvctpCallbackParms)); printf("AvctpChannel is %d\r\n", sizeof(AvctpChannel)); printf("AvctpCmdFrame is %d\r\n", sizeof(AvctpCmdFrame)); printf("AvctpRspFrame is %d\r\n", sizeof(AvctpRspFrame)); printf("AvrcpChannel is %d\r\n", sizeof(AvrcpChannel)); printf("AvrcpCallbackParms is %d\r\n", sizeof(AvrcpCallbackParms)); printf("AvrcpAdvancedPdu is %d\r\n", sizeof(AvrcpAdvancedPdu)); printf("AvrcpPlayerSetting is %d\r\n", sizeof(AvrcpPlayerSetting)); printf("AvrcpPlayerStrings is %d\r\n", sizeof(AvrcpPlayerStrings)); printf("AvrcpEqString is %d\r\n", sizeof(AvrcpEqString)); printf("AvrcpRepeatString is %d\r\n", sizeof(AvrcpRepeatString)); printf("AvrcpShuffleString is %d\r\n", sizeof(AvrcpShuffleString)); printf("AvrcpScanString is %d\r\n", sizeof(AvrcpScanString)); printf("AvrcpExtString is %d\r\n", sizeof(AvrcpExtString)); printf("AvrcpCharSets is %d\r\n", sizeof(AvrcpCharSets)); printf("AvrcpMediaInfo is %d\r\n", sizeof(AvrcpMediaInfo)); printf("AvrcpMediaPlayStatus is %d\r\n", sizeof(AvrcpMediaPlayStatus)); printf("AvrcpTrackStruct is %d\r\n", sizeof(AvrcpTrackStruct)); } void app_bt_send_sco_data(void *channel, uint8_t seq, uint8_t *data, uint16_t length) { BtPacket *sco_packet; HfChannel *Chan = channel; uint16_t data_length; uint8_t sub_seq = 0; uint8_t index; BtStatus status = BT_STATUS_SUCCESS; sco_packet = btdm_malloc(sizeof(BtPacket)); if (sco_packet) { memset((void *)sco_packet, 0, sizeof(BtPacket)); if (length == 57) { data_length = 60; sco_packet->data = btdm_malloc(data_length); sco_packet->data[0] = 0x01; if (seq & 0x01) { sub_seq = 0x30; } if (seq & 0x02) { sub_seq |= 0xc0; } sco_packet->data[1] = 0x08 | sub_seq; memcpy(&sco_packet->data[2], data, length); sco_packet->data[59] = 0x00; sco_packet->dataLen = data_length; } else { sco_packet->data = btdm_malloc(length); memcpy(sco_packet->data, data, length); sco_packet->dataLen = length; } for(index = 0; index < NUM_BT_DEVICES; index++) { if((uint32_t)&hfg_channel[index] == (uint32_t)channel){ status = HFG_SendAudioData((HfgChannel *)Chan, sco_packet); break; } else if((uint32_t)&hf_channel[index] == (uint32_t)channel){ status = HF_SendAudioData((HfChannel *)Chan, sco_packet); break; } } if((index == NUM_BT_DEVICES) || (status != BT_STATUS_PENDING)){ btdm_free(sco_packet->data); btdm_free(sco_packet); } } } void app_bt_init(void) { // app_btdm_struct_size_dump(); #define EIR_DATA_SIZE 50 uint8_t eir_data[EIR_DATA_SIZE]; uint8_t index = 0; uint8_t rand_num[4]; uint8_t hex_2_char[] = {'0', '1', '2','3', '4', '5','6', '7', '8','9', 'a', 'b','c', 'd', 'e', 'f'}; #if BTDM_STACK_ENABLE_HF hf_channel = btdm_malloc(sizeof(HfChannel) * NUM_BT_DEVICES); #endif #if BTDM_STACK_ENABLE_AG hfg_channel = btdm_malloc(sizeof(HfgChannel) * NUM_BT_DEVICES); #endif Stream = btdm_malloc(sizeof(A2dpStream) * NUM_STREAMS); #if BTDM_STACK_ENABLE_AVRCP rcpCtChannel = btdm_malloc(sizeof(AvrcpChannel) * NUM_BT_DEVICES); rcpTgChannel = btdm_malloc(sizeof(AvrcpChannel) * NUM_BT_DEVICES); #endif // scoPacket = btdm_malloc(sizeof(BtPacket)); // memset((void *)scoPacket, 0, sizeof(BtPacket)); // scoPacket->data = btdm_malloc(120); ME_InitHandler(&securityHandler); securityHandler.callback = security_event_handler; SEC_RegisterPairingHandler(&securityHandler); SEC_RegisterAuthorizeHandler(&securityHandler); /* Set our promiscuous link policies */ ME_SetDefaultLinkPolicy(((BLP_MASTER_SLAVE_SWITCH|BLP_SNIFF_MODE)&(~BLP_MASK)), ((BLP_MASTER_SLAVE_SWITCH|BLP_SNIFF_MODE)&(~BLP_MASK))); #if BT_ADDR_RANDOM_ENABLE if(flashdb_get(FDB_KEY_USER_RANDOM_SEED, (void *)&rand_num[0], 4) != 0){ default_name[7] = hex_2_char[(rand_num[1]&0xf0) >> 4]; default_name[8] = hex_2_char[(rand_num[1]&0x0f)]; default_name[9] = hex_2_char[(rand_num[0]&0xf0) >> 4]; default_name[10] = hex_2_char[(rand_num[0]&0x0f)]; } #endif ME_SetLocalDeviceName((const uint8_t *)default_name, sizeof(default_name)); memset(&eir_data[0],0,EIR_DATA_SIZE); eir_data[index++] = sizeof(default_name) + 1; eir_data[index++] = 0x09; memcpy(&(eir_data[index]),default_name,sizeof(default_name)); ME_SetExtInquiryRsp(0x01,eir_data,sizeof(default_name)+1); SEC_SetBondingMode(GENERAL_BONDING); SEC_SetIoCapabilities(IO_NO_IO); ME_InitHandler(&(globalHandler)); globalHandler.callback = me_callback; ME_RegisterGlobalHandler(&globalHandler); // ME_SetEventMask(&globalHandler, (BEM_ACCESSIBLE_CHANGE | // BEM_LINK_CONNECT_CNF | // BEM_LINK_CONNECT_IND | // BEM_LINK_DISCONNECT | // BEM_ROLE_CHANGE | // BEM_MODE_CHANGE | // BEM_INQUIRY_COMPLETE | // BEM_INQUIRY_RESULT | // BEM_INQUIRY_CANCELED)); ME_SetEventMask(&globalHandler, BEM_ALL_EVENTS); ME_RegisterAcceptHandler(&globalHandler); secParms.level = (BSL_SECURITY_L2_IN | BSL_SECURITY_L2_OUT);//HF_SECURITY_SETTINGS; secParms.pinLen = 4; #if BTDM_STACK_ENABLE_HF HF_SetSupportedFeature(HF_SDK_FEATURES); for (uint8_t i=0; i<NUM_BT_DEVICES; i++) { HF_RegisterSec(&hf_channel[i], hf_callback, &secParms); } #endif ME_SetClassOfDevice( COD_AUDIO | COD_MAJOR_AUDIO | COD_MINOR_AUDIO_HANDSFREE); #if BTDM_STACK_ENABLE_AG HFG_SetSupportedFeature(HFG_SDK_FEATURES); for (uint8_t i=0; i<NUM_BT_DEVICES; i++) { HFG_RegisterSec(&hfg_channel[i], hfg_callback, &secParms); } #endif #if BTDM_STACK_ENABLE_A2DP_SNK /* Register SBC stream sink */ sbcSnkCodec1.codecType = AVDTP_CODEC_TYPE_SBC; sbcSnkCodec1.elemLen = sizeof(SbcSnkElements); sbcSnkCodec1.elements = SbcSnkElements; #if BTDM_STACK_ENABLE_AAC aacSnkCodec1.codecType = AVDTP_CODEC_TYPE_MPEG2_4_AAC; aacSnkCodec1.elemLen = sizeof(AacSnkElements); aacSnkCodec1.elements = AacSnkElements; #else sbcSnkCodec2.codecType = AVDTP_CODEC_TYPE_SBC; sbcSnkCodec2.elemLen = sizeof(SbcSnkElements); sbcSnkCodec2.elements = SbcSnkElements; #endif Stream[0].type = A2DP_STREAM_TYPE_SINK; Stream[1].type = A2DP_STREAM_TYPE_SINK; A2DP_Register(&Stream[0], &sbcSnkCodec1, a2dp_callback); #if BTDM_STACK_ENABLE_AAC A2DP_Register(&Stream[1], &aacSnkCodec1, a2dp_callback); #else A2DP_Register(&Stream[1], &sbcSnkCodec2, a2dp_callback); #endif #endif #if BTDM_STACK_ENABLE_PAN PanService pan_service; pan_service.type = 0x1115; // PANU pan_service.callback = pan_callback; PAN_Register(&pan_service); bnep_lwip_init(); #endif #if BTDM_STACK_ENABLE_A2DP_SRC /* Register SBC stream src */ sbcSrcCodec1.codecType = AVDTP_CODEC_TYPE_SBC; sbcSrcCodec1.elemLen = sizeof(SbcSrcElements); sbcSrcCodec1.elements = SbcSrcElements; Stream[2].type = A2DP_STREAM_TYPE_SOURCE; Stream[3].type = A2DP_STREAM_TYPE_SOURCE; A2DP_Register(&Stream[2], &sbcSrcCodec1, a2dp_callback); A2DP_Register(&Stream[3], &sbcSrcCodec1, a2dp_callback); #endif // AVDEV_ListenSignalLink(a2dp_device_callback); #if BTDM_STACK_ENABLE_AVRCP || BTDM_STACK_ENABLE_A2DP_SNK || BTDM_STACK_ENABLE_A2DP_SRC for (uint8_t i=0; i<NUM_BT_DEVICES; i++) { AVRCP_RegisterSec(&rcpCtChannel[i], avrcp_callback, AVRCP_CT|AVRCP_TG, &secParms); #if AVRCP_ADVANCED_TARGET == XA_ENABLED AVRCP_TgSetEventMask(&rcpCtChannel[i], AVRCP_ENABLE_VOLUME_CHANGED); #endif //AVRCP_RegisterSec(&rcpTgChannel[i], avrcp_callback, AVRCP_TG, &secParms); } #endif ME_SetAccessibleModeC(BAM_NOT_ACCESSIBLE, &access_mode_nc); ME_SetAccessibleModeNC(BAM_GENERAL_ACCESSIBLE, &access_mode_nc); } 打印完[INFO] me_callback :105,151就卡死了为什么 c语言
09-03
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值