init
This commit is contained in:
parent
725089a6b7
commit
03d6312e22
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,11 @@
|
|||
[package]
|
||||
name = "cue"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
iced = { version = "0.13", features = ["canvas", "tokio"] }
|
||||
btleplug = "0.11"
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
futures = "0.3"
|
||||
uuid = "1"
|
||||
|
|
@ -0,0 +1,234 @@
|
|||
use futures::SinkExt;
|
||||
use iced::widget::{button, column, container, pick_list, row, scrollable, text, text_input};
|
||||
use iced::{Element, Length, Subscription, Task, Theme};
|
||||
use std::time::Duration;
|
||||
use tokio::sync::mpsc;
|
||||
|
||||
use crate::ble::BleEvent;
|
||||
use crate::protocol::{self, EisMessage, EisPoint, Rcal, Rtia};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Message {
|
||||
BleReady(mpsc::UnboundedSender<Vec<u8>>),
|
||||
BleStatus(String),
|
||||
BleData(EisMessage),
|
||||
FreqStartChanged(String),
|
||||
FreqStopChanged(String),
|
||||
PpdChanged(String),
|
||||
RtiaSelected(Rtia),
|
||||
RcalSelected(Rcal),
|
||||
ApplySettings,
|
||||
StartSweep,
|
||||
}
|
||||
|
||||
pub struct App {
|
||||
status: String,
|
||||
points: Vec<EisPoint>,
|
||||
sweep_total: u16,
|
||||
|
||||
freq_start: String,
|
||||
freq_stop: String,
|
||||
ppd: String,
|
||||
rtia: Rtia,
|
||||
rcal: Rcal,
|
||||
|
||||
cmd_tx: Option<mpsc::UnboundedSender<Vec<u8>>>,
|
||||
}
|
||||
|
||||
impl App {
|
||||
pub fn new() -> (Self, Task<Message>) {
|
||||
(Self {
|
||||
status: "Starting...".into(),
|
||||
points: Vec::new(),
|
||||
sweep_total: 0,
|
||||
freq_start: "1000".into(),
|
||||
freq_stop: "200000".into(),
|
||||
ppd: "10".into(),
|
||||
rtia: Rtia::R5K,
|
||||
rcal: Rcal::R3K,
|
||||
cmd_tx: None,
|
||||
}, Task::none())
|
||||
}
|
||||
|
||||
pub fn title(&self) -> String {
|
||||
"Cue".into()
|
||||
}
|
||||
|
||||
pub fn theme(&self) -> Theme {
|
||||
Theme::Dark
|
||||
}
|
||||
|
||||
fn send_cmd(&self, sysex: &[u8]) {
|
||||
if let Some(tx) = &self.cmd_tx {
|
||||
let _ = tx.send(protocol::wrap_ble_midi(sysex));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update(&mut self, message: Message) -> Task<Message> {
|
||||
match message {
|
||||
Message::BleReady(tx) => {
|
||||
self.cmd_tx = Some(tx);
|
||||
self.send_cmd(&protocol::build_sysex_get_config());
|
||||
}
|
||||
Message::BleStatus(s) => self.status = s,
|
||||
Message::BleData(msg) => match msg {
|
||||
EisMessage::SweepStart { num_points, freq_start, freq_stop } => {
|
||||
self.points.clear();
|
||||
self.sweep_total = num_points;
|
||||
self.status = format!(
|
||||
"Sweep: {} pts, {:.0}--{:.0} Hz",
|
||||
num_points, freq_start, freq_stop
|
||||
);
|
||||
}
|
||||
EisMessage::DataPoint { point, .. } => {
|
||||
self.points.push(point);
|
||||
self.status = format!(
|
||||
"Receiving: {}/{}",
|
||||
self.points.len(), self.sweep_total
|
||||
);
|
||||
}
|
||||
EisMessage::SweepEnd => {
|
||||
self.status = format!(
|
||||
"Sweep complete: {} points", self.points.len()
|
||||
);
|
||||
}
|
||||
EisMessage::Config(cfg) => {
|
||||
self.freq_start = format!("{:.0}", cfg.freq_start);
|
||||
self.freq_stop = format!("{:.0}", cfg.freq_stop);
|
||||
self.ppd = format!("{}", cfg.ppd);
|
||||
self.rtia = cfg.rtia;
|
||||
self.rcal = cfg.rcal;
|
||||
self.status = "Config received".into();
|
||||
}
|
||||
},
|
||||
Message::FreqStartChanged(s) => self.freq_start = s,
|
||||
Message::FreqStopChanged(s) => self.freq_stop = s,
|
||||
Message::PpdChanged(s) => self.ppd = s,
|
||||
Message::RtiaSelected(r) => self.rtia = r,
|
||||
Message::RcalSelected(r) => self.rcal = r,
|
||||
Message::ApplySettings => {
|
||||
let fs = self.freq_start.parse::<f32>().unwrap_or(1000.0);
|
||||
let fe = self.freq_stop.parse::<f32>().unwrap_or(200000.0);
|
||||
let ppd = self.ppd.parse::<u16>().unwrap_or(10);
|
||||
self.send_cmd(&protocol::build_sysex_set_sweep(fs, fe, ppd));
|
||||
self.send_cmd(&protocol::build_sysex_set_rtia(self.rtia));
|
||||
self.send_cmd(&protocol::build_sysex_set_rcal(self.rcal));
|
||||
self.send_cmd(&protocol::build_sysex_get_config());
|
||||
}
|
||||
Message::StartSweep => {
|
||||
self.send_cmd(&protocol::build_sysex_start_sweep());
|
||||
}
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
|
||||
pub fn subscription(&self) -> Subscription<Message> {
|
||||
Subscription::run_with_id(
|
||||
"ble",
|
||||
iced::stream::channel(100, |mut output| async move {
|
||||
loop {
|
||||
let (ble_tx, mut ble_rx) =
|
||||
mpsc::unbounded_channel::<BleEvent>();
|
||||
let (cmd_tx, cmd_rx) =
|
||||
mpsc::unbounded_channel::<Vec<u8>>();
|
||||
|
||||
let _ = output.send(Message::BleReady(cmd_tx)).await;
|
||||
|
||||
let tx = ble_tx.clone();
|
||||
tokio::spawn(async move {
|
||||
if let Err(e) = crate::ble::connect_and_run(tx, cmd_rx).await {
|
||||
eprintln!("BLE: {e}");
|
||||
}
|
||||
});
|
||||
|
||||
while let Some(ev) = ble_rx.recv().await {
|
||||
let msg = match ev {
|
||||
BleEvent::Status(s) => Message::BleStatus(s),
|
||||
BleEvent::Data(m) => Message::BleData(m),
|
||||
};
|
||||
let _ = output.send(msg).await;
|
||||
}
|
||||
|
||||
let _ = output
|
||||
.send(Message::BleStatus("Reconnecting...".into()))
|
||||
.await;
|
||||
tokio::time::sleep(Duration::from_secs(2)).await;
|
||||
}
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn view(&self) -> Element<'_, Message> {
|
||||
let status = text(&self.status).size(16);
|
||||
|
||||
let controls = row![
|
||||
column![
|
||||
text("Start Hz").size(12),
|
||||
text_input("1000", &self.freq_start)
|
||||
.on_input(Message::FreqStartChanged)
|
||||
.width(100),
|
||||
]
|
||||
.spacing(2),
|
||||
column![
|
||||
text("Stop Hz").size(12),
|
||||
text_input("200000", &self.freq_stop)
|
||||
.on_input(Message::FreqStopChanged)
|
||||
.width(100),
|
||||
]
|
||||
.spacing(2),
|
||||
column![
|
||||
text("PPD").size(12),
|
||||
text_input("10", &self.ppd)
|
||||
.on_input(Message::PpdChanged)
|
||||
.width(60),
|
||||
]
|
||||
.spacing(2),
|
||||
column![
|
||||
text("RTIA").size(12),
|
||||
pick_list(Rtia::ALL, Some(self.rtia), Message::RtiaSelected),
|
||||
]
|
||||
.spacing(2),
|
||||
column![
|
||||
text("RCAL").size(12),
|
||||
pick_list(Rcal::ALL, Some(self.rcal), Message::RcalSelected),
|
||||
]
|
||||
.spacing(2),
|
||||
button("Apply").on_press(Message::ApplySettings),
|
||||
button("Sweep").on_press(Message::StartSweep),
|
||||
]
|
||||
.spacing(10)
|
||||
.align_y(iced::Alignment::End);
|
||||
|
||||
let header = row![
|
||||
text("Freq (Hz)").width(100),
|
||||
text("|Z| (Ohm)").width(100),
|
||||
text("Phase (deg)").width(100),
|
||||
text("Re (Ohm)").width(100),
|
||||
text("Im (Ohm)").width(100),
|
||||
]
|
||||
.spacing(10);
|
||||
|
||||
let mut data_rows = column![header].spacing(4);
|
||||
for pt in &self.points {
|
||||
data_rows = data_rows.push(
|
||||
row![
|
||||
text(format!("{:.1}", pt.freq_hz)).width(100),
|
||||
text(format!("{:.2}", pt.mag_ohms)).width(100),
|
||||
text(format!("{:.2}", pt.phase_deg)).width(100),
|
||||
text(format!("{:.2}", pt.z_real)).width(100),
|
||||
text(format!("{:.2}", pt.z_imag)).width(100),
|
||||
]
|
||||
.spacing(10),
|
||||
);
|
||||
}
|
||||
|
||||
let content = column![status, controls, scrollable(data_rows)]
|
||||
.spacing(20)
|
||||
.padding(20);
|
||||
|
||||
container(content)
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
use btleplug::api::{Central, Manager as _, Peripheral as _, ScanFilter, WriteType};
|
||||
use btleplug::platform::{Adapter, Manager, Peripheral};
|
||||
use futures::StreamExt;
|
||||
use std::time::Duration;
|
||||
use tokio::sync::mpsc;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::protocol::{self, EisMessage};
|
||||
|
||||
const MIDI_CHR_UUID: Uuid = Uuid::from_u128(0x7772E5DB_3868_4112_A1A9_F2669D106BF3);
|
||||
const DEVICE_NAME: &str = "EIS4";
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum BleEvent {
|
||||
Status(String),
|
||||
Data(EisMessage),
|
||||
}
|
||||
|
||||
pub async fn connect_and_run(
|
||||
tx: mpsc::UnboundedSender<BleEvent>,
|
||||
mut cmd_rx: mpsc::UnboundedReceiver<Vec<u8>>,
|
||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
let _ = tx.send(BleEvent::Status("Scanning...".into()));
|
||||
|
||||
let manager = Manager::new().await?;
|
||||
let adapter = manager.adapters().await?.into_iter().next()
|
||||
.ok_or("no BLE adapter")?;
|
||||
|
||||
adapter.start_scan(ScanFilter::default()).await?;
|
||||
tokio::time::sleep(Duration::from_secs(3)).await;
|
||||
|
||||
let device = find_device(&adapter).await?;
|
||||
let _ = tx.send(BleEvent::Status("Connecting...".into()));
|
||||
|
||||
device.connect().await?;
|
||||
device.discover_services().await?;
|
||||
|
||||
let chars = device.characteristics();
|
||||
let midi_chr = chars.iter()
|
||||
.find(|c| c.uuid == MIDI_CHR_UUID)
|
||||
.ok_or("MIDI characteristic not found")?
|
||||
.clone();
|
||||
|
||||
device.subscribe(&midi_chr).await?;
|
||||
let _ = tx.send(BleEvent::Status("Connected".into()));
|
||||
|
||||
let mut notifs = device.notifications().await?;
|
||||
|
||||
loop {
|
||||
tokio::select! {
|
||||
Some(notif) = notifs.next() => {
|
||||
if notif.uuid == MIDI_CHR_UUID {
|
||||
if let Some(sysex) = protocol::extract_sysex_from_ble_midi(¬if.value) {
|
||||
if let Some(msg) = protocol::parse_sysex(&sysex) {
|
||||
let _ = tx.send(BleEvent::Data(msg));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(pkt) = cmd_rx.recv() => {
|
||||
device.write(&midi_chr, &pkt, WriteType::WithoutResponse).await.ok();
|
||||
}
|
||||
else => break,
|
||||
}
|
||||
}
|
||||
|
||||
let _ = tx.send(BleEvent::Status("Disconnected".into()));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn find_device(adapter: &Adapter) -> Result<Peripheral, Box<dyn std::error::Error + Send + Sync>> {
|
||||
let peripherals = adapter.peripherals().await?;
|
||||
for p in peripherals {
|
||||
if let Some(props) = p.properties().await? {
|
||||
if props.local_name.as_deref() == Some(DEVICE_NAME) {
|
||||
return Ok(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(format!("{} not found", DEVICE_NAME).into())
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
mod app;
|
||||
mod ble;
|
||||
mod protocol;
|
||||
|
||||
fn main() -> iced::Result {
|
||||
iced::application(app::App::title, app::App::update, app::App::view)
|
||||
.theme(app::App::theme)
|
||||
.subscription(app::App::subscription)
|
||||
.run_with(app::App::new)
|
||||
}
|
||||
|
|
@ -0,0 +1,204 @@
|
|||
/// EIS4 SysEx Protocol — manufacturer ID 0x7D (non-commercial)
|
||||
|
||||
pub const SYSEX_MFR: u8 = 0x7D;
|
||||
|
||||
/* ESP32 → Cue */
|
||||
pub const RSP_SWEEP_START: u8 = 0x01;
|
||||
pub const RSP_DATA_POINT: u8 = 0x02;
|
||||
pub const RSP_SWEEP_END: u8 = 0x03;
|
||||
pub const RSP_CONFIG: u8 = 0x04;
|
||||
|
||||
/* Cue → ESP32 */
|
||||
pub const CMD_SET_SWEEP: u8 = 0x10;
|
||||
pub const CMD_SET_RTIA: u8 = 0x11;
|
||||
pub const CMD_SET_RCAL: u8 = 0x12;
|
||||
pub const CMD_START_SWEEP: u8 = 0x13;
|
||||
pub const CMD_GET_CONFIG: u8 = 0x14;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Rtia {
|
||||
R200, R1K, R5K, R10K, R20K, R40K, R80K, R160K, ExtDe0,
|
||||
}
|
||||
|
||||
impl Rtia {
|
||||
pub fn from_byte(b: u8) -> Option<Self> {
|
||||
Some(match b {
|
||||
0 => Self::R200, 1 => Self::R1K, 2 => Self::R5K, 3 => Self::R10K,
|
||||
4 => Self::R20K, 5 => Self::R40K, 6 => Self::R80K, 7 => Self::R160K,
|
||||
8 => Self::ExtDe0,
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
pub fn as_byte(self) -> u8 { self as u8 }
|
||||
pub fn label(self) -> &'static str {
|
||||
match self {
|
||||
Self::R200 => "200Ω", Self::R1K => "1kΩ", Self::R5K => "5kΩ",
|
||||
Self::R10K => "10kΩ", Self::R20K => "20kΩ", Self::R40K => "40kΩ",
|
||||
Self::R80K => "80kΩ", Self::R160K => "160kΩ", Self::ExtDe0 => "Ext 3kΩ (DE0)",
|
||||
}
|
||||
}
|
||||
pub const ALL: &[Self] = &[
|
||||
Self::R200, Self::R1K, Self::R5K, Self::R10K,
|
||||
Self::R20K, Self::R40K, Self::R80K, Self::R160K, Self::ExtDe0,
|
||||
];
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Rtia {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str(self.label())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Rcal {
|
||||
R200, R3K,
|
||||
}
|
||||
|
||||
impl Rcal {
|
||||
pub fn from_byte(b: u8) -> Option<Self> {
|
||||
Some(match b { 0 => Self::R200, 1 => Self::R3K, _ => return None })
|
||||
}
|
||||
pub fn as_byte(self) -> u8 { self as u8 }
|
||||
pub fn label(self) -> &'static str {
|
||||
match self { Self::R200 => "200Ω (RCAL0↔RCAL1)", Self::R3K => "3kΩ (RCAL0↔AIN0)" }
|
||||
}
|
||||
pub const ALL: &[Self] = &[Self::R200, Self::R3K];
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Rcal {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str(self.label())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct EisPoint {
|
||||
pub freq_hz: f32,
|
||||
pub mag_ohms: f32,
|
||||
pub phase_deg: f32,
|
||||
pub z_real: f32,
|
||||
pub z_imag: f32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct EisConfig {
|
||||
pub freq_start: f32,
|
||||
pub freq_stop: f32,
|
||||
pub ppd: u16,
|
||||
pub rtia: Rtia,
|
||||
pub rcal: Rcal,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum EisMessage {
|
||||
SweepStart { num_points: u16, freq_start: f32, freq_stop: f32 },
|
||||
DataPoint { index: u16, point: EisPoint },
|
||||
SweepEnd,
|
||||
Config(EisConfig),
|
||||
}
|
||||
|
||||
fn decode_u16(data: &[u8]) -> u16 {
|
||||
let b0 = data[1] | ((data[0] & 1) << 7);
|
||||
let b1 = data[2] | ((data[0] & 2) << 6);
|
||||
u16::from_le_bytes([b0, b1])
|
||||
}
|
||||
|
||||
fn decode_float(data: &[u8]) -> f32 {
|
||||
let m = data[0];
|
||||
let b0 = data[1] | ((m & 1) << 7);
|
||||
let b1 = data[2] | ((m & 2) << 6);
|
||||
let b2 = data[3] | ((m & 4) << 5);
|
||||
let b3 = data[4] | ((m & 8) << 4);
|
||||
f32::from_le_bytes([b0, b1, b2, b3])
|
||||
}
|
||||
|
||||
fn encode_float(val: f32) -> [u8; 5] {
|
||||
let p = val.to_le_bytes();
|
||||
[
|
||||
((p[0] >> 7) & 1) | ((p[1] >> 6) & 2) | ((p[2] >> 5) & 4) | ((p[3] >> 4) & 8),
|
||||
p[0] & 0x7F, p[1] & 0x7F, p[2] & 0x7F, p[3] & 0x7F,
|
||||
]
|
||||
}
|
||||
|
||||
fn encode_u16(val: u16) -> [u8; 3] {
|
||||
let p = val.to_le_bytes();
|
||||
[((p[0] >> 7) & 1) | ((p[1] >> 6) & 2), p[0] & 0x7F, p[1] & 0x7F]
|
||||
}
|
||||
|
||||
pub fn parse_sysex(data: &[u8]) -> Option<EisMessage> {
|
||||
if data.len() < 2 || data[0] != SYSEX_MFR { return None; }
|
||||
match data[1] {
|
||||
RSP_SWEEP_START if data.len() >= 15 => {
|
||||
let p = &data[2..];
|
||||
Some(EisMessage::SweepStart {
|
||||
num_points: decode_u16(&p[0..3]),
|
||||
freq_start: decode_float(&p[3..8]),
|
||||
freq_stop: decode_float(&p[8..13]),
|
||||
})
|
||||
}
|
||||
RSP_DATA_POINT if data.len() >= 30 => {
|
||||
let p = &data[2..];
|
||||
Some(EisMessage::DataPoint {
|
||||
index: decode_u16(&p[0..3]),
|
||||
point: EisPoint {
|
||||
freq_hz: decode_float(&p[3..8]),
|
||||
mag_ohms: decode_float(&p[8..13]),
|
||||
phase_deg: decode_float(&p[13..18]),
|
||||
z_real: decode_float(&p[18..23]),
|
||||
z_imag: decode_float(&p[23..28]),
|
||||
},
|
||||
})
|
||||
}
|
||||
RSP_SWEEP_END => Some(EisMessage::SweepEnd),
|
||||
RSP_CONFIG if data.len() >= 17 => {
|
||||
let p = &data[2..];
|
||||
Some(EisMessage::Config(EisConfig {
|
||||
freq_start: decode_float(&p[0..5]),
|
||||
freq_stop: decode_float(&p[5..10]),
|
||||
ppd: decode_u16(&p[10..13]),
|
||||
rtia: Rtia::from_byte(p[13]).unwrap_or(Rtia::R5K),
|
||||
rcal: Rcal::from_byte(p[14]).unwrap_or(Rcal::R3K),
|
||||
}))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build_sysex_set_sweep(freq_start: f32, freq_stop: f32, ppd: u16) -> Vec<u8> {
|
||||
let mut sx = vec![0xF0, SYSEX_MFR, CMD_SET_SWEEP];
|
||||
sx.extend_from_slice(&encode_float(freq_start));
|
||||
sx.extend_from_slice(&encode_float(freq_stop));
|
||||
sx.extend_from_slice(&encode_u16(ppd));
|
||||
sx.push(0xF7);
|
||||
sx
|
||||
}
|
||||
|
||||
pub fn build_sysex_set_rtia(rtia: Rtia) -> Vec<u8> {
|
||||
vec![0xF0, SYSEX_MFR, CMD_SET_RTIA, rtia.as_byte(), 0xF7]
|
||||
}
|
||||
|
||||
pub fn build_sysex_set_rcal(rcal: Rcal) -> Vec<u8> {
|
||||
vec![0xF0, SYSEX_MFR, CMD_SET_RCAL, rcal.as_byte(), 0xF7]
|
||||
}
|
||||
|
||||
pub fn build_sysex_start_sweep() -> Vec<u8> {
|
||||
vec![0xF0, SYSEX_MFR, CMD_START_SWEEP, 0xF7]
|
||||
}
|
||||
|
||||
pub fn build_sysex_get_config() -> Vec<u8> {
|
||||
vec![0xF0, SYSEX_MFR, CMD_GET_CONFIG, 0xF7]
|
||||
}
|
||||
|
||||
pub fn wrap_ble_midi(sysex: &[u8]) -> Vec<u8> {
|
||||
let mut pkt = vec![0x80, 0x80];
|
||||
pkt.extend_from_slice(sysex);
|
||||
pkt
|
||||
}
|
||||
|
||||
pub fn extract_sysex_from_ble_midi(packet: &[u8]) -> Option<Vec<u8>> {
|
||||
if packet.len() < 4 { return None; }
|
||||
let midi = &packet[2..];
|
||||
if midi.first() != Some(&0xF0) { return None; }
|
||||
let end = midi.iter().position(|&b| b == 0xF7)?;
|
||||
Some(midi[1..end].to_vec())
|
||||
}
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
idf_component_register(SRCS "eis4.c"
|
||||
idf_component_register(SRCS "eis4.c" "eis.c" "ble.c"
|
||||
INCLUDE_DIRS "."
|
||||
REQUIRES ad5941 ad5941_port)
|
||||
REQUIRES ad5941 ad5941_port bt nvs_flash)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,592 @@
|
|||
#include "ble.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "nimble/nimble_port.h"
|
||||
#include "nimble/nimble_port_freertos.h"
|
||||
#include "host/ble_hs.h"
|
||||
#include "host/ble_gap.h"
|
||||
#include "host/util/util.h"
|
||||
#include "host/ble_store.h"
|
||||
#include "services/gap/ble_svc_gap.h"
|
||||
#include "services/gatt/ble_svc_gatt.h"
|
||||
|
||||
void ble_store_config_init(void);
|
||||
|
||||
#define DEVICE_NAME "EIS4"
|
||||
#define CONNECTED_BIT BIT0
|
||||
#define CMD_QUEUE_LEN 4
|
||||
|
||||
/* BLE MIDI Service 03B80E5A-EDE8-4B33-A751-6CE34EC4C700 */
|
||||
static const ble_uuid128_t midi_svc_uuid = BLE_UUID128_INIT(
|
||||
0x00, 0xc7, 0xc4, 0x4e, 0xe3, 0x6c, 0x51, 0xa7,
|
||||
0x33, 0x4b, 0xe8, 0xed, 0x5a, 0x0e, 0xb8, 0x03);
|
||||
|
||||
/* BLE MIDI Characteristic 7772E5DB-3868-4112-A1A9-F2669D106BF3 */
|
||||
static const ble_uuid128_t midi_chr_uuid = BLE_UUID128_INIT(
|
||||
0xf3, 0x6b, 0x10, 0x9d, 0x66, 0xf2, 0xa9, 0xa1,
|
||||
0x12, 0x41, 0x68, 0x38, 0xdb, 0xe5, 0x72, 0x77);
|
||||
|
||||
static EventGroupHandle_t ble_events;
|
||||
static QueueHandle_t cmd_queue;
|
||||
static uint16_t conn_hdl = BLE_HS_CONN_HANDLE_NONE;
|
||||
static uint16_t midi_val_hdl;
|
||||
static uint16_t hid_input_val_hdl;
|
||||
static bool midi_notify_en;
|
||||
static bool hid_notify_en;
|
||||
|
||||
/* ---- HID keyboard report map ---- */
|
||||
|
||||
static const uint8_t hid_report_map[] = {
|
||||
0x05, 0x01, /* Usage Page (Generic Desktop) */
|
||||
0x09, 0x06, /* Usage (Keyboard) */
|
||||
0xA1, 0x01, /* Collection (Application) */
|
||||
0x85, 0x01, /* Report ID (1) */
|
||||
0x05, 0x07, /* Usage Page (Keyboard) */
|
||||
0x19, 0xE0, 0x29, 0xE7, /* Usage Min/Max (modifiers) */
|
||||
0x15, 0x00, 0x25, 0x01, /* Logical Min/Max */
|
||||
0x75, 0x01, 0x95, 0x08, /* 8x1-bit modifier keys */
|
||||
0x81, 0x02, /* Input (Variable) */
|
||||
0x95, 0x01, 0x75, 0x08, /* 1x8-bit reserved */
|
||||
0x81, 0x01, /* Input (Constant) */
|
||||
0x05, 0x08, /* Usage Page (LEDs) */
|
||||
0x19, 0x01, 0x29, 0x05, /* 5 LEDs */
|
||||
0x95, 0x05, 0x75, 0x01,
|
||||
0x91, 0x02, /* Output (Variable) */
|
||||
0x95, 0x01, 0x75, 0x03,
|
||||
0x91, 0x01, /* Output pad to byte */
|
||||
0x05, 0x07, /* Usage Page (Keyboard) */
|
||||
0x19, 0x00, 0x29, 0xFF, /* Key codes 0-255 */
|
||||
0x15, 0x00, 0x26, 0xFF, 0x00, /* Logical Min/Max (0-255) */
|
||||
0x95, 0x06, 0x75, 0x08, /* 6x8-bit key array */
|
||||
0x81, 0x00, /* Input (Array) */
|
||||
0xC0, /* End Collection */
|
||||
};
|
||||
|
||||
/* bcdHID=1.11, bCountryCode=0, Flags=NormallyConnectable */
|
||||
static const uint8_t hid_info[] = { 0x11, 0x01, 0x00, 0x02 };
|
||||
|
||||
/* PnP ID: src=USB-IF(2), VID=0x1209(pid.codes), PID=0x0001, ver=0x0100 */
|
||||
static const uint8_t pnp_id[] = { 0x02, 0x09, 0x12, 0x01, 0x00, 0x00, 0x01 };
|
||||
|
||||
/* ---- 7-bit MIDI encoding ---- */
|
||||
|
||||
static void encode_float(float val, uint8_t *out)
|
||||
{
|
||||
uint8_t *p = (uint8_t *)&val;
|
||||
out[0] = ((p[0] >> 7) & 1) | ((p[1] >> 6) & 2) |
|
||||
((p[2] >> 5) & 4) | ((p[3] >> 4) & 8);
|
||||
out[1] = p[0] & 0x7F;
|
||||
out[2] = p[1] & 0x7F;
|
||||
out[3] = p[2] & 0x7F;
|
||||
out[4] = p[3] & 0x7F;
|
||||
}
|
||||
|
||||
static void encode_u16(uint16_t val, uint8_t *out)
|
||||
{
|
||||
uint8_t *p = (uint8_t *)&val;
|
||||
out[0] = ((p[0] >> 7) & 1) | ((p[1] >> 6) & 2);
|
||||
out[1] = p[0] & 0x7F;
|
||||
out[2] = p[1] & 0x7F;
|
||||
}
|
||||
|
||||
static float decode_float(const uint8_t *d)
|
||||
{
|
||||
uint8_t b[4];
|
||||
b[0] = d[1] | ((d[0] & 1) << 7);
|
||||
b[1] = d[2] | ((d[0] & 2) << 6);
|
||||
b[2] = d[3] | ((d[0] & 4) << 5);
|
||||
b[3] = d[4] | ((d[0] & 8) << 4);
|
||||
float v;
|
||||
memcpy(&v, b, 4);
|
||||
return v;
|
||||
}
|
||||
|
||||
static uint16_t decode_u16(const uint8_t *d)
|
||||
{
|
||||
uint8_t b[2];
|
||||
b[0] = d[1] | ((d[0] & 1) << 7);
|
||||
b[1] = d[2] | ((d[0] & 2) << 6);
|
||||
uint16_t v;
|
||||
memcpy(&v, b, 2);
|
||||
return v;
|
||||
}
|
||||
|
||||
/* ---- command parsing from incoming SysEx ---- */
|
||||
|
||||
static void parse_command(const uint8_t *data, uint16_t len)
|
||||
{
|
||||
if (len < 5) return;
|
||||
const uint8_t *midi = data + 2;
|
||||
uint16_t mlen = len - 2;
|
||||
if (midi[0] != 0xF0 || midi[1] != 0x7D) return;
|
||||
|
||||
BleCommand cmd;
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.type = midi[2];
|
||||
|
||||
switch (cmd.type) {
|
||||
case CMD_SET_SWEEP:
|
||||
if (mlen < 16) return;
|
||||
cmd.sweep.freq_start = decode_float(&midi[3]);
|
||||
cmd.sweep.freq_stop = decode_float(&midi[8]);
|
||||
cmd.sweep.ppd = decode_u16(&midi[13]);
|
||||
break;
|
||||
case CMD_SET_RTIA:
|
||||
if (mlen < 5) return;
|
||||
cmd.rtia = midi[3];
|
||||
break;
|
||||
case CMD_SET_RCAL:
|
||||
if (mlen < 5) return;
|
||||
cmd.rcal = midi[3];
|
||||
break;
|
||||
case CMD_START_SWEEP:
|
||||
case CMD_GET_CONFIG:
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
xQueueSend(cmd_queue, &cmd, 0);
|
||||
}
|
||||
|
||||
/* ---- GATT access callbacks ---- */
|
||||
|
||||
static int midi_access_cb(uint16_t ch, uint16_t ah,
|
||||
struct ble_gatt_access_ctxt *ctxt, void *arg)
|
||||
{
|
||||
(void)ch; (void)ah; (void)arg;
|
||||
if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
|
||||
uint16_t len = OS_MBUF_PKTLEN(ctxt->om);
|
||||
uint8_t buf[64];
|
||||
if (len > sizeof(buf)) len = sizeof(buf);
|
||||
os_mbuf_copydata(ctxt->om, 0, len, buf);
|
||||
parse_command(buf, len);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hid_report_map_cb(uint16_t ch, uint16_t ah,
|
||||
struct ble_gatt_access_ctxt *ctxt, void *arg)
|
||||
{
|
||||
(void)ch; (void)ah; (void)arg;
|
||||
if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR)
|
||||
os_mbuf_append(ctxt->om, hid_report_map, sizeof(hid_report_map));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hid_info_cb(uint16_t ch, uint16_t ah,
|
||||
struct ble_gatt_access_ctxt *ctxt, void *arg)
|
||||
{
|
||||
(void)ch; (void)ah; (void)arg;
|
||||
if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR)
|
||||
os_mbuf_append(ctxt->om, hid_info, sizeof(hid_info));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hid_input_report_cb(uint16_t ch, uint16_t ah,
|
||||
struct ble_gatt_access_ctxt *ctxt, void *arg)
|
||||
{
|
||||
(void)ch; (void)ah; (void)arg;
|
||||
if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) {
|
||||
static const uint8_t empty[8] = {0};
|
||||
os_mbuf_append(ctxt->om, empty, sizeof(empty));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hid_output_report_cb(uint16_t ch, uint16_t ah,
|
||||
struct ble_gatt_access_ctxt *ctxt, void *arg)
|
||||
{
|
||||
(void)ch; (void)ah; (void)arg;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hid_input_ref_cb(uint16_t ch, uint16_t ah,
|
||||
struct ble_gatt_access_ctxt *ctxt, void *arg)
|
||||
{
|
||||
(void)ch; (void)ah; (void)arg;
|
||||
if (ctxt->op == BLE_GATT_ACCESS_OP_READ_DSC) {
|
||||
static const uint8_t ref[] = { 0x01, 0x01 }; /* Report ID 1, Input */
|
||||
os_mbuf_append(ctxt->om, ref, sizeof(ref));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hid_output_ref_cb(uint16_t ch, uint16_t ah,
|
||||
struct ble_gatt_access_ctxt *ctxt, void *arg)
|
||||
{
|
||||
(void)ch; (void)ah; (void)arg;
|
||||
if (ctxt->op == BLE_GATT_ACCESS_OP_READ_DSC) {
|
||||
static const uint8_t ref[] = { 0x01, 0x02 }; /* Report ID 1, Output */
|
||||
os_mbuf_append(ctxt->om, ref, sizeof(ref));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hid_boot_input_cb(uint16_t ch, uint16_t ah,
|
||||
struct ble_gatt_access_ctxt *ctxt, void *arg)
|
||||
{
|
||||
(void)ch; (void)ah; (void)arg;
|
||||
if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) {
|
||||
static const uint8_t empty[8] = {0};
|
||||
os_mbuf_append(ctxt->om, empty, sizeof(empty));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hid_boot_output_cb(uint16_t ch, uint16_t ah,
|
||||
struct ble_gatt_access_ctxt *ctxt, void *arg)
|
||||
{
|
||||
(void)ch; (void)ah; (void)arg;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hid_ctrl_cb(uint16_t ch, uint16_t ah,
|
||||
struct ble_gatt_access_ctxt *ctxt, void *arg)
|
||||
{
|
||||
(void)ch; (void)ah; (void)arg;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hid_proto_cb(uint16_t ch, uint16_t ah,
|
||||
struct ble_gatt_access_ctxt *ctxt, void *arg)
|
||||
{
|
||||
(void)ch; (void)ah; (void)arg;
|
||||
if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) {
|
||||
uint8_t mode = 1; /* Report Protocol */
|
||||
os_mbuf_append(ctxt->om, &mode, 1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bas_level_cb(uint16_t ch, uint16_t ah,
|
||||
struct ble_gatt_access_ctxt *ctxt, void *arg)
|
||||
{
|
||||
(void)ch; (void)ah; (void)arg;
|
||||
if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) {
|
||||
uint8_t level = 100;
|
||||
os_mbuf_append(ctxt->om, &level, 1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dis_pnp_cb(uint16_t ch, uint16_t ah,
|
||||
struct ble_gatt_access_ctxt *ctxt, void *arg)
|
||||
{
|
||||
(void)ch; (void)ah; (void)arg;
|
||||
if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR)
|
||||
os_mbuf_append(ctxt->om, pnp_id, sizeof(pnp_id));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ---- GATT service table ---- */
|
||||
|
||||
static const struct ble_gatt_svc_def gatt_svcs[] = {
|
||||
/* Device Information Service */
|
||||
{
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
.uuid = BLE_UUID16_DECLARE(0x180A),
|
||||
.characteristics = (struct ble_gatt_chr_def[]) {
|
||||
{ .uuid = BLE_UUID16_DECLARE(0x2A50), .access_cb = dis_pnp_cb,
|
||||
.flags = BLE_GATT_CHR_F_READ },
|
||||
{ 0 },
|
||||
},
|
||||
},
|
||||
/* Battery Service */
|
||||
{
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
.uuid = BLE_UUID16_DECLARE(0x180F),
|
||||
.characteristics = (struct ble_gatt_chr_def[]) {
|
||||
{ .uuid = BLE_UUID16_DECLARE(0x2A19), .access_cb = bas_level_cb,
|
||||
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY },
|
||||
{ 0 },
|
||||
},
|
||||
},
|
||||
/* HID Service */
|
||||
{
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
.uuid = BLE_UUID16_DECLARE(0x1812),
|
||||
.characteristics = (struct ble_gatt_chr_def[]) {
|
||||
{ .uuid = BLE_UUID16_DECLARE(0x2A4B), .access_cb = hid_report_map_cb,
|
||||
.flags = BLE_GATT_CHR_F_READ },
|
||||
{ .uuid = BLE_UUID16_DECLARE(0x2A4A), .access_cb = hid_info_cb,
|
||||
.flags = BLE_GATT_CHR_F_READ },
|
||||
/* Input Report */
|
||||
{ .uuid = BLE_UUID16_DECLARE(0x2A4D), .access_cb = hid_input_report_cb,
|
||||
.val_handle = &hid_input_val_hdl,
|
||||
.descriptors = (struct ble_gatt_dsc_def[]) {
|
||||
{ .uuid = BLE_UUID16_DECLARE(0x2908), .att_flags = BLE_ATT_F_READ,
|
||||
.access_cb = hid_input_ref_cb },
|
||||
{ 0 },
|
||||
},
|
||||
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC },
|
||||
/* Output Report (LEDs) */
|
||||
{ .uuid = BLE_UUID16_DECLARE(0x2A4D), .access_cb = hid_output_report_cb,
|
||||
.descriptors = (struct ble_gatt_dsc_def[]) {
|
||||
{ .uuid = BLE_UUID16_DECLARE(0x2908), .att_flags = BLE_ATT_F_READ,
|
||||
.access_cb = hid_output_ref_cb },
|
||||
{ 0 },
|
||||
},
|
||||
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE |
|
||||
BLE_GATT_CHR_F_WRITE_NO_RSP | BLE_GATT_CHR_F_READ_ENC |
|
||||
BLE_GATT_CHR_F_WRITE_ENC },
|
||||
/* Boot Keyboard Input Report */
|
||||
{ .uuid = BLE_UUID16_DECLARE(0x2A22), .access_cb = hid_boot_input_cb,
|
||||
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC },
|
||||
/* Boot Keyboard Output Report */
|
||||
{ .uuid = BLE_UUID16_DECLARE(0x2A32), .access_cb = hid_boot_output_cb,
|
||||
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE |
|
||||
BLE_GATT_CHR_F_WRITE_NO_RSP | BLE_GATT_CHR_F_READ_ENC },
|
||||
{ .uuid = BLE_UUID16_DECLARE(0x2A4C), .access_cb = hid_ctrl_cb,
|
||||
.flags = BLE_GATT_CHR_F_WRITE_NO_RSP },
|
||||
{ .uuid = BLE_UUID16_DECLARE(0x2A4E), .access_cb = hid_proto_cb,
|
||||
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE_NO_RSP },
|
||||
{ 0 },
|
||||
},
|
||||
},
|
||||
/* MIDI Service */
|
||||
{
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
.uuid = &midi_svc_uuid.u,
|
||||
.characteristics = (struct ble_gatt_chr_def[]) {
|
||||
{ .uuid = &midi_chr_uuid.u, .access_cb = midi_access_cb,
|
||||
.val_handle = &midi_val_hdl,
|
||||
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE_NO_RSP | BLE_GATT_CHR_F_NOTIFY },
|
||||
{ 0 },
|
||||
},
|
||||
},
|
||||
{ 0 },
|
||||
};
|
||||
|
||||
/* ---- send empty keyboard report ---- */
|
||||
|
||||
static void send_empty_hid_report(void)
|
||||
{
|
||||
if (conn_hdl == BLE_HS_CONN_HANDLE_NONE || !hid_notify_en)
|
||||
return;
|
||||
static const uint8_t empty[8] = {0};
|
||||
struct os_mbuf *om = ble_hs_mbuf_from_flat(empty, sizeof(empty));
|
||||
if (om)
|
||||
ble_gatts_notify_custom(conn_hdl, hid_input_val_hdl, om);
|
||||
}
|
||||
|
||||
/* ---- GAP / advertising ---- */
|
||||
|
||||
static void start_adv(void);
|
||||
|
||||
static int gap_event_cb(struct ble_gap_event *event, void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
switch (event->type) {
|
||||
case BLE_GAP_EVENT_CONNECT:
|
||||
if (event->connect.status == 0) {
|
||||
conn_hdl = event->connect.conn_handle;
|
||||
xEventGroupSetBits(ble_events, CONNECTED_BIT);
|
||||
ble_att_set_preferred_mtu(128);
|
||||
ble_gattc_exchange_mtu(conn_hdl, NULL, NULL);
|
||||
ble_gap_security_initiate(conn_hdl);
|
||||
printf("BLE: connected\n");
|
||||
} else {
|
||||
start_adv();
|
||||
}
|
||||
break;
|
||||
case BLE_GAP_EVENT_DISCONNECT:
|
||||
conn_hdl = BLE_HS_CONN_HANDLE_NONE;
|
||||
midi_notify_en = false;
|
||||
hid_notify_en = false;
|
||||
xEventGroupClearBits(ble_events, CONNECTED_BIT);
|
||||
printf("BLE: disconnected\n");
|
||||
start_adv();
|
||||
break;
|
||||
case BLE_GAP_EVENT_SUBSCRIBE:
|
||||
if (event->subscribe.attr_handle == midi_val_hdl)
|
||||
midi_notify_en = event->subscribe.cur_notify;
|
||||
if (event->subscribe.attr_handle == hid_input_val_hdl) {
|
||||
hid_notify_en = event->subscribe.cur_notify;
|
||||
if (hid_notify_en)
|
||||
send_empty_hid_report();
|
||||
}
|
||||
break;
|
||||
case BLE_GAP_EVENT_REPEAT_PAIRING: {
|
||||
struct ble_gap_conn_desc desc;
|
||||
ble_gap_conn_find(event->repeat_pairing.conn_handle, &desc);
|
||||
ble_store_util_delete_peer(&desc.peer_id_addr);
|
||||
return BLE_GAP_REPEAT_PAIRING_RETRY;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void start_adv(void)
|
||||
{
|
||||
struct ble_hs_adv_fields fields = {0};
|
||||
fields.flags = BLE_HS_ADV_F_DISC_GEN | BLE_HS_ADV_F_BREDR_UNSUP;
|
||||
fields.name = (uint8_t *)DEVICE_NAME;
|
||||
fields.name_len = strlen(DEVICE_NAME);
|
||||
fields.name_is_complete = 1;
|
||||
fields.appearance = 0x03C1; /* Keyboard */
|
||||
fields.appearance_is_present = 1;
|
||||
ble_uuid16_t adv_uuids[] = {
|
||||
BLE_UUID16_INIT(0x1812), /* HID */
|
||||
BLE_UUID16_INIT(0x180F), /* Battery */
|
||||
};
|
||||
fields.uuids16 = adv_uuids;
|
||||
fields.num_uuids16 = 2;
|
||||
fields.uuids16_is_complete = 0;
|
||||
ble_gap_adv_set_fields(&fields);
|
||||
|
||||
struct ble_hs_adv_fields rsp = {0};
|
||||
rsp.uuids128 = (ble_uuid128_t *)&midi_svc_uuid;
|
||||
rsp.num_uuids128 = 1;
|
||||
rsp.uuids128_is_complete = 1;
|
||||
ble_gap_adv_rsp_set_fields(&rsp);
|
||||
|
||||
struct ble_gap_adv_params params = {0};
|
||||
params.conn_mode = BLE_GAP_CONN_MODE_UND;
|
||||
params.disc_mode = BLE_GAP_DISC_MODE_GEN;
|
||||
ble_gap_adv_start(BLE_OWN_ADDR_PUBLIC, NULL, BLE_HS_FOREVER,
|
||||
¶ms, gap_event_cb, NULL);
|
||||
}
|
||||
|
||||
static void on_sync(void)
|
||||
{
|
||||
uint8_t addr_type;
|
||||
ble_hs_id_infer_auto(0, &addr_type);
|
||||
start_adv();
|
||||
printf("BLE: advertising as \"%s\"\n", DEVICE_NAME);
|
||||
}
|
||||
|
||||
static void on_reset(int reason) { (void)reason; }
|
||||
|
||||
static void host_task(void *param)
|
||||
{
|
||||
(void)param;
|
||||
nimble_port_run();
|
||||
nimble_port_freertos_deinit();
|
||||
}
|
||||
|
||||
/* ---- SysEx send ---- */
|
||||
|
||||
static int send_sysex(const uint8_t *sysex, uint16_t len)
|
||||
{
|
||||
if (conn_hdl == BLE_HS_CONN_HANDLE_NONE || !midi_notify_en)
|
||||
return -1;
|
||||
|
||||
uint16_t pkt_len = 2 + len;
|
||||
uint8_t pkt[80];
|
||||
if (pkt_len > sizeof(pkt))
|
||||
return -1;
|
||||
|
||||
pkt[0] = 0x80;
|
||||
pkt[1] = 0x80;
|
||||
memcpy(&pkt[2], sysex, len);
|
||||
|
||||
struct os_mbuf *om = ble_hs_mbuf_from_flat(pkt, pkt_len);
|
||||
if (!om) return -1;
|
||||
|
||||
return ble_gatts_notify_custom(conn_hdl, midi_val_hdl, om);
|
||||
}
|
||||
|
||||
/* ---- public API ---- */
|
||||
|
||||
int ble_init(void)
|
||||
{
|
||||
ble_events = xEventGroupCreate();
|
||||
cmd_queue = xQueueCreate(CMD_QUEUE_LEN, sizeof(BleCommand));
|
||||
|
||||
int rc = nimble_port_init();
|
||||
if (rc != ESP_OK) return rc;
|
||||
|
||||
ble_hs_cfg.sync_cb = on_sync;
|
||||
ble_hs_cfg.reset_cb = on_reset;
|
||||
ble_hs_cfg.sm_bonding = 1;
|
||||
ble_hs_cfg.sm_mitm = 0;
|
||||
ble_hs_cfg.sm_sc = 1;
|
||||
ble_hs_cfg.sm_io_cap = BLE_SM_IO_CAP_NO_IO;
|
||||
ble_hs_cfg.sm_our_key_dist = BLE_SM_PAIR_KEY_DIST_ENC | BLE_SM_PAIR_KEY_DIST_ID;
|
||||
ble_hs_cfg.sm_their_key_dist = BLE_SM_PAIR_KEY_DIST_ENC | BLE_SM_PAIR_KEY_DIST_ID;
|
||||
|
||||
ble_svc_gap_init();
|
||||
ble_svc_gatt_init();
|
||||
ble_svc_gap_device_name_set(DEVICE_NAME);
|
||||
ble_svc_gap_device_appearance_set(0x03C1);
|
||||
|
||||
rc = ble_gatts_count_cfg(gatt_svcs);
|
||||
if (rc) return rc;
|
||||
rc = ble_gatts_add_svcs(gatt_svcs);
|
||||
if (rc) return rc;
|
||||
|
||||
ble_store_config_init();
|
||||
nimble_port_freertos_init(host_task);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ble_is_connected(void)
|
||||
{
|
||||
return conn_hdl != BLE_HS_CONN_HANDLE_NONE;
|
||||
}
|
||||
|
||||
void ble_wait_for_connection(void)
|
||||
{
|
||||
xEventGroupWaitBits(ble_events, CONNECTED_BIT, pdFALSE, pdTRUE, portMAX_DELAY);
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
}
|
||||
|
||||
int ble_recv_command(BleCommand *cmd, uint32_t timeout_ms)
|
||||
{
|
||||
TickType_t ticks = (timeout_ms == UINT32_MAX) ? portMAX_DELAY : pdMS_TO_TICKS(timeout_ms);
|
||||
return xQueueReceive(cmd_queue, cmd, ticks) == pdTRUE ? 0 : -1;
|
||||
}
|
||||
|
||||
int ble_send_sweep_start(uint32_t num_points, float freq_start, float freq_stop)
|
||||
{
|
||||
uint8_t sx[20];
|
||||
uint16_t p = 0;
|
||||
sx[p++] = 0xF0; sx[p++] = 0x7D; sx[p++] = RSP_SWEEP_START;
|
||||
encode_u16((uint16_t)num_points, &sx[p]); p += 3;
|
||||
encode_float(freq_start, &sx[p]); p += 5;
|
||||
encode_float(freq_stop, &sx[p]); p += 5;
|
||||
sx[p++] = 0xF7;
|
||||
return send_sysex(sx, p);
|
||||
}
|
||||
|
||||
int ble_send_eis_point(uint16_t index, const EISPoint *pt)
|
||||
{
|
||||
uint8_t sx[36];
|
||||
uint16_t p = 0;
|
||||
sx[p++] = 0xF0; sx[p++] = 0x7D; sx[p++] = RSP_DATA_POINT;
|
||||
encode_u16(index, &sx[p]); p += 3;
|
||||
encode_float(pt->freq_hz, &sx[p]); p += 5;
|
||||
encode_float(pt->mag_ohms, &sx[p]); p += 5;
|
||||
encode_float(pt->phase_deg, &sx[p]); p += 5;
|
||||
encode_float(pt->z_real, &sx[p]); p += 5;
|
||||
encode_float(pt->z_imag, &sx[p]); p += 5;
|
||||
sx[p++] = 0xF7;
|
||||
return send_sysex(sx, p);
|
||||
}
|
||||
|
||||
int ble_send_sweep_end(void)
|
||||
{
|
||||
uint8_t sx[] = { 0xF0, 0x7D, RSP_SWEEP_END, 0xF7 };
|
||||
return send_sysex(sx, sizeof(sx));
|
||||
}
|
||||
|
||||
int ble_send_config(const EISConfig *cfg)
|
||||
{
|
||||
uint8_t sx[32];
|
||||
uint16_t p = 0;
|
||||
sx[p++] = 0xF0; sx[p++] = 0x7D; sx[p++] = RSP_CONFIG;
|
||||
encode_float(cfg->freq_start_hz, &sx[p]); p += 5;
|
||||
encode_float(cfg->freq_stop_hz, &sx[p]); p += 5;
|
||||
encode_u16(cfg->points_per_decade, &sx[p]); p += 3;
|
||||
sx[p++] = (uint8_t)cfg->rtia;
|
||||
sx[p++] = (uint8_t)cfg->rcal;
|
||||
sx[p++] = 0xF7;
|
||||
return send_sysex(sx, p);
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
#ifndef BLE_H
|
||||
#define BLE_H
|
||||
|
||||
#include "eis.h"
|
||||
|
||||
/* Commands: Cue → ESP32 (0x1x) */
|
||||
#define CMD_SET_SWEEP 0x10
|
||||
#define CMD_SET_RTIA 0x11
|
||||
#define CMD_SET_RCAL 0x12
|
||||
#define CMD_START_SWEEP 0x13
|
||||
#define CMD_GET_CONFIG 0x14
|
||||
|
||||
/* Responses: ESP32 → Cue (0x0x) */
|
||||
#define RSP_SWEEP_START 0x01
|
||||
#define RSP_DATA_POINT 0x02
|
||||
#define RSP_SWEEP_END 0x03
|
||||
#define RSP_CONFIG 0x04
|
||||
|
||||
typedef struct {
|
||||
uint8_t type;
|
||||
union {
|
||||
struct { float freq_start, freq_stop; uint16_t ppd; } sweep;
|
||||
uint8_t rtia;
|
||||
uint8_t rcal;
|
||||
};
|
||||
} BleCommand;
|
||||
|
||||
int ble_init(void);
|
||||
int ble_is_connected(void);
|
||||
void ble_wait_for_connection(void);
|
||||
|
||||
/* blocking receive from command queue */
|
||||
int ble_recv_command(BleCommand *cmd, uint32_t timeout_ms);
|
||||
|
||||
/* outbound data */
|
||||
int ble_send_sweep_start(uint32_t num_points, float freq_start, float freq_stop);
|
||||
int ble_send_eis_point(uint16_t index, const EISPoint *pt);
|
||||
int ble_send_sweep_end(void);
|
||||
int ble_send_config(const EISConfig *cfg);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,361 @@
|
|||
#include "eis.h"
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
/* resolved hardware state */
|
||||
static struct {
|
||||
EISConfig cfg;
|
||||
float sys_clk;
|
||||
float rcal_ohms;
|
||||
uint32_t rcal_sw_d, rcal_sw_p, rcal_sw_n, rcal_sw_t;
|
||||
uint32_t rtia_reg;
|
||||
uint32_t dertia_reg;
|
||||
} ctx;
|
||||
|
||||
static const uint32_t rtia_map[] = {
|
||||
[RTIA_200] = HSTIARTIA_200,
|
||||
[RTIA_1K] = HSTIARTIA_1K,
|
||||
[RTIA_5K] = HSTIARTIA_5K,
|
||||
[RTIA_10K] = HSTIARTIA_10K,
|
||||
[RTIA_20K] = HSTIARTIA_20K,
|
||||
[RTIA_40K] = HSTIARTIA_40K,
|
||||
[RTIA_80K] = HSTIARTIA_80K,
|
||||
[RTIA_160K] = HSTIARTIA_160K,
|
||||
[RTIA_EXT_DE0] = HSTIARTIA_OPEN,
|
||||
};
|
||||
|
||||
static void resolve_config(void)
|
||||
{
|
||||
/* RTIA */
|
||||
ctx.rtia_reg = rtia_map[ctx.cfg.rtia];
|
||||
ctx.dertia_reg = (ctx.cfg.rtia == RTIA_EXT_DE0) ? HSTIADERTIA_TODE : HSTIADERTIA_OPEN;
|
||||
|
||||
/* RCAL */
|
||||
switch (ctx.cfg.rcal) {
|
||||
case RCAL_200R:
|
||||
ctx.rcal_ohms = 200.0f;
|
||||
ctx.rcal_sw_d = SWD_RCAL0;
|
||||
ctx.rcal_sw_p = SWP_RCAL0;
|
||||
ctx.rcal_sw_n = SWN_RCAL1;
|
||||
ctx.rcal_sw_t = SWT_RCAL1 | SWT_TRTIA;
|
||||
break;
|
||||
default: /* RCAL_3K */
|
||||
ctx.rcal_ohms = 3000.0f;
|
||||
ctx.rcal_sw_d = SWD_RCAL0;
|
||||
ctx.rcal_sw_p = SWP_RCAL0;
|
||||
ctx.rcal_sw_n = SWN_AIN0;
|
||||
ctx.rcal_sw_t = SWT_AIN0 | SWT_TRTIA;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void apply_hsloop(void)
|
||||
{
|
||||
HSLoopCfg_Type hs;
|
||||
AD5940_StructInit(&hs, sizeof(hs));
|
||||
hs.HsDacCfg.ExcitBufGain = EXCITBUFGAIN_2;
|
||||
hs.HsDacCfg.HsDacGain = HSDACGAIN_0P2;
|
||||
hs.HsDacCfg.HsDacUpdateRate = 7;
|
||||
hs.HsTiaCfg.HstiaBias = HSTIABIAS_1P1;
|
||||
hs.HsTiaCfg.HstiaRtiaSel = ctx.rtia_reg;
|
||||
hs.HsTiaCfg.HstiaCtia = 16;
|
||||
hs.HsTiaCfg.HstiaDeRtia = ctx.dertia_reg;
|
||||
hs.HsTiaCfg.HstiaDeRload = HSTIADERLOAD_OPEN;
|
||||
hs.HsTiaCfg.HstiaDe1Rtia = HSTIADERTIA_OPEN;
|
||||
hs.HsTiaCfg.HstiaDe1Rload = HSTIADERLOAD_OPEN;
|
||||
hs.HsTiaCfg.DiodeClose = bFALSE;
|
||||
hs.WgCfg.WgType = WGTYPE_SIN;
|
||||
hs.WgCfg.GainCalEn = bTRUE;
|
||||
hs.WgCfg.OffsetCalEn = bTRUE;
|
||||
hs.WgCfg.SinCfg.SinAmplitudeWord = ctx.cfg.excit_amp;
|
||||
hs.WgCfg.SinCfg.SinFreqWord = 0;
|
||||
hs.WgCfg.SinCfg.SinOffsetWord = 0;
|
||||
hs.WgCfg.SinCfg.SinPhaseWord = 0;
|
||||
hs.SWMatCfg.Dswitch = ctx.rcal_sw_d;
|
||||
hs.SWMatCfg.Pswitch = ctx.rcal_sw_p;
|
||||
hs.SWMatCfg.Nswitch = ctx.rcal_sw_n;
|
||||
hs.SWMatCfg.Tswitch = ctx.rcal_sw_t;
|
||||
AD5940_HSLoopCfgS(&hs);
|
||||
|
||||
if (ctx.cfg.rtia == RTIA_EXT_DE0)
|
||||
AD5940_WriteReg(REG_AFE_DE0RESCON, 0x97);
|
||||
}
|
||||
|
||||
/* ---------- public ---------- */
|
||||
|
||||
void eis_default_config(EISConfig *cfg)
|
||||
{
|
||||
memset(cfg, 0, sizeof(*cfg));
|
||||
cfg->freq_start_hz = 1000.0f;
|
||||
cfg->freq_stop_hz = 200000.0f;
|
||||
cfg->points_per_decade = 10;
|
||||
cfg->rtia = RTIA_5K;
|
||||
cfg->rcal = RCAL_3K;
|
||||
cfg->pga = ADCPGA_1P5;
|
||||
cfg->excit_amp = 500;
|
||||
}
|
||||
|
||||
uint32_t eis_calc_num_points(const EISConfig *cfg)
|
||||
{
|
||||
if (cfg->freq_stop_hz <= cfg->freq_start_hz || cfg->points_per_decade == 0)
|
||||
return 1;
|
||||
float decades = log10f(cfg->freq_stop_hz / cfg->freq_start_hz);
|
||||
uint32_t n = (uint32_t)(decades * cfg->points_per_decade + 0.5f) + 1;
|
||||
if (n > EIS_MAX_POINTS) n = EIS_MAX_POINTS;
|
||||
if (n < 2) n = 2;
|
||||
return n;
|
||||
}
|
||||
|
||||
void eis_init(const EISConfig *cfg)
|
||||
{
|
||||
memcpy(&ctx.cfg, cfg, sizeof(EISConfig));
|
||||
ctx.sys_clk = 16000000.0f;
|
||||
resolve_config();
|
||||
|
||||
CLKCfg_Type clk;
|
||||
memset(&clk, 0, sizeof(clk));
|
||||
clk.HFOSCEn = bTRUE;
|
||||
clk.HfOSC32MHzMode = bFALSE;
|
||||
clk.SysClkSrc = SYSCLKSRC_HFOSC;
|
||||
clk.ADCCLkSrc = ADCCLKSRC_HFOSC;
|
||||
clk.SysClkDiv = SYSCLKDIV_1;
|
||||
clk.ADCClkDiv = ADCCLKDIV_1;
|
||||
clk.LFOSCEn = bTRUE;
|
||||
clk.HFXTALEn = bFALSE;
|
||||
AD5940_CLKCfg(&clk);
|
||||
|
||||
AFERefCfg_Type ref;
|
||||
AD5940_StructInit(&ref, sizeof(ref));
|
||||
ref.HpBandgapEn = bTRUE;
|
||||
ref.Hp1V1BuffEn = bTRUE;
|
||||
ref.Hp1V8BuffEn = bTRUE;
|
||||
ref.HSDACRefEn = bTRUE;
|
||||
ref.LpBandgapEn = bFALSE;
|
||||
ref.LpRefBufEn = bFALSE;
|
||||
AD5940_REFCfgS(&ref);
|
||||
|
||||
AD5940_AFEPwrBW(AFEPWR_LP, AFEBW_250KHZ);
|
||||
|
||||
AD5940_INTCCfg(AFEINTC_0, AFEINTSRC_DFTRDY, bTRUE);
|
||||
AD5940_INTCCfg(AFEINTC_1, AFEINTSRC_DFTRDY, bTRUE);
|
||||
AD5940_INTCClrFlag(AFEINTSRC_ALLINT);
|
||||
|
||||
AGPIOCfg_Type gpio;
|
||||
AD5940_StructInit(&gpio, sizeof(gpio));
|
||||
gpio.FuncSet = GP0_INT;
|
||||
gpio.OutputEnSet = AGPIO_Pin0;
|
||||
AD5940_AGPIOCfg(&gpio);
|
||||
|
||||
FIFOCfg_Type fifo;
|
||||
AD5940_StructInit(&fifo, sizeof(fifo));
|
||||
fifo.FIFOEn = bFALSE;
|
||||
fifo.FIFOMode = FIFOMODE_FIFO;
|
||||
fifo.FIFOSize = FIFOSIZE_2KB;
|
||||
fifo.FIFOSrc = FIFOSRC_DFT;
|
||||
fifo.FIFOThresh = 4;
|
||||
AD5940_FIFOCfg(&fifo);
|
||||
|
||||
SEQCfg_Type seq;
|
||||
seq.SeqMemSize = SEQMEMSIZE_4KB;
|
||||
seq.SeqBreakEn = bFALSE;
|
||||
seq.SeqIgnoreEn = bFALSE;
|
||||
seq.SeqCntCRCClr = bFALSE;
|
||||
seq.SeqEnable = bTRUE;
|
||||
seq.SeqWrTimer = 0;
|
||||
AD5940_SEQCfg(&seq);
|
||||
|
||||
apply_hsloop();
|
||||
|
||||
ADCBaseCfg_Type adc;
|
||||
adc.ADCMuxP = ADCMUXP_P_NODE;
|
||||
adc.ADCMuxN = ADCMUXN_N_NODE;
|
||||
adc.ADCPga = cfg->pga;
|
||||
AD5940_ADCBaseCfgS(&adc);
|
||||
|
||||
AD5940_AFECtrlS(AFECTRL_ALL, bFALSE);
|
||||
}
|
||||
|
||||
void eis_reconfigure(const EISConfig *cfg)
|
||||
{
|
||||
memcpy(&ctx.cfg, cfg, sizeof(EISConfig));
|
||||
resolve_config();
|
||||
apply_hsloop();
|
||||
}
|
||||
|
||||
/* ---------- internal helpers ---------- */
|
||||
|
||||
static void configure_freq(float freq_hz)
|
||||
{
|
||||
FreqParams_Type fp = AD5940_GetFreqParameters(freq_hz);
|
||||
|
||||
if (fp.HighPwrMode) {
|
||||
fp.DftSrc = DFTSRC_ADCRAW;
|
||||
fp.ADCSinc3Osr = ADCSINC3OSR_2;
|
||||
fp.ADCSinc2Osr = 0;
|
||||
fp.DftNum = DFTNUM_16384;
|
||||
}
|
||||
|
||||
AD5940_WriteReg(REG_AFE_WGFCW,
|
||||
AD5940_WGFreqWordCal(freq_hz, ctx.sys_clk));
|
||||
|
||||
ADCFilterCfg_Type filt;
|
||||
AD5940_StructInit(&filt, sizeof(filt));
|
||||
filt.ADCSinc3Osr = fp.ADCSinc3Osr;
|
||||
filt.ADCSinc2Osr = fp.ADCSinc2Osr;
|
||||
filt.ADCAvgNum = ADCAVGNUM_16;
|
||||
filt.ADCRate = ADCRATE_800KHZ;
|
||||
filt.BpNotch = bTRUE;
|
||||
filt.BpSinc3 = bFALSE;
|
||||
filt.Sinc2NotchEnable = bTRUE;
|
||||
filt.Sinc3ClkEnable = bTRUE;
|
||||
filt.Sinc2NotchClkEnable = bTRUE;
|
||||
filt.DFTClkEnable = bTRUE;
|
||||
filt.WGClkEnable = bTRUE;
|
||||
AD5940_ADCFilterCfgS(&filt);
|
||||
|
||||
DFTCfg_Type dft;
|
||||
dft.DftNum = fp.DftNum;
|
||||
dft.DftSrc = fp.DftSrc;
|
||||
dft.HanWinEn = bTRUE;
|
||||
AD5940_DFTCfgS(&dft);
|
||||
}
|
||||
|
||||
static int32_t sign_extend_18(uint32_t v)
|
||||
{
|
||||
return (v & (1UL << 17)) ? (int32_t)(v | 0xFFFC0000UL) : (int32_t)v;
|
||||
}
|
||||
|
||||
static void dft_measure(uint32_t mux_p, uint32_t mux_n, iImpCar_Type *out)
|
||||
{
|
||||
AD5940_ADCMuxCfgS(mux_p, mux_n);
|
||||
|
||||
AD5940_AFECtrlS(AFECTRL_WG | AFECTRL_ADCPWR, bTRUE);
|
||||
AD5940_Delay10us(25);
|
||||
|
||||
AD5940_INTCClrFlag(AFEINTSRC_DFTRDY);
|
||||
AD5940_AFECtrlS(AFECTRL_ADCCNV | AFECTRL_DFT, bTRUE);
|
||||
|
||||
uint32_t timeout = 10000000;
|
||||
while (AD5940_INTCTestFlag(AFEINTC_1, AFEINTSRC_DFTRDY) == bFALSE) {
|
||||
if (--timeout == 0) break;
|
||||
}
|
||||
|
||||
AD5940_AFECtrlS(AFECTRL_ADCCNV | AFECTRL_DFT |
|
||||
AFECTRL_WG | AFECTRL_ADCPWR, bFALSE);
|
||||
AD5940_INTCClrFlag(AFEINTSRC_DFTRDY);
|
||||
|
||||
out->Real = sign_extend_18(AD5940_ReadAfeResult(AFERESULT_DFTREAL));
|
||||
out->Image = sign_extend_18(AD5940_ReadAfeResult(AFERESULT_DFTIMAGE));
|
||||
out->Image = -out->Image;
|
||||
}
|
||||
|
||||
/* ---------- measurement ---------- */
|
||||
|
||||
int eis_measure_point(float freq_hz, EISPoint *out)
|
||||
{
|
||||
configure_freq(freq_hz);
|
||||
|
||||
iImpCar_Type v_rcal, v_rtia, v_tia, v_sense;
|
||||
|
||||
/* Phase 1: RTIA calibration through RCAL */
|
||||
SWMatrixCfg_Type sw;
|
||||
sw.Dswitch = ctx.rcal_sw_d;
|
||||
sw.Pswitch = ctx.rcal_sw_p;
|
||||
sw.Nswitch = ctx.rcal_sw_n;
|
||||
sw.Tswitch = ctx.rcal_sw_t;
|
||||
AD5940_SWMatrixCfgS(&sw);
|
||||
|
||||
AD5940_AFECtrlS(AFECTRL_HPREFPWR | AFECTRL_HSTIAPWR | AFECTRL_INAMPPWR |
|
||||
AFECTRL_EXTBUFPWR | AFECTRL_DACREFPWR | AFECTRL_HSDACPWR |
|
||||
AFECTRL_SINC2NOTCH, bTRUE);
|
||||
|
||||
dft_measure(ADCMUXP_P_NODE, ADCMUXN_N_NODE, &v_rcal);
|
||||
dft_measure(ADCMUXP_HSTIA_P, ADCMUXN_HSTIA_N, &v_rtia);
|
||||
|
||||
v_rtia.Real = -v_rtia.Real;
|
||||
v_rtia.Image = -v_rtia.Image;
|
||||
|
||||
fImpCar_Type rtia = AD5940_ComplexDivInt(&v_rtia, &v_rcal);
|
||||
rtia.Real *= ctx.rcal_ohms;
|
||||
rtia.Image *= ctx.rcal_ohms;
|
||||
|
||||
/* Phase 2: DUT — software 4-wire */
|
||||
sw.Dswitch = SWD_AIN3;
|
||||
sw.Pswitch = SWP_AIN3;
|
||||
sw.Nswitch = SWN_AIN0;
|
||||
sw.Tswitch = SWT_AIN0 | SWT_TRTIA;
|
||||
AD5940_SWMatrixCfgS(&sw);
|
||||
AD5940_Delay10us(50);
|
||||
|
||||
dft_measure(ADCMUXP_HSTIA_P, ADCMUXN_HSTIA_N, &v_tia);
|
||||
v_tia.Real = -v_tia.Real;
|
||||
v_tia.Image = -v_tia.Image;
|
||||
|
||||
dft_measure(ADCMUXP_AIN2, ADCMUXN_AIN1, &v_sense);
|
||||
|
||||
AD5940_AFECtrlS(AFECTRL_WG | AFECTRL_ADCPWR | AFECTRL_ADCCNV |
|
||||
AFECTRL_DFT | AFECTRL_SINC2NOTCH | AFECTRL_HSDACPWR |
|
||||
AFECTRL_HSTIAPWR | AFECTRL_INAMPPWR |
|
||||
AFECTRL_EXTBUFPWR, bFALSE);
|
||||
|
||||
sw.Dswitch = SWD_OPEN;
|
||||
sw.Pswitch = SWP_OPEN;
|
||||
sw.Nswitch = SWN_OPEN;
|
||||
sw.Tswitch = SWT_OPEN;
|
||||
AD5940_SWMatrixCfgS(&sw);
|
||||
|
||||
/* Z_DUT = V_sense × Rtia_cal / V_TIA */
|
||||
fImpCar_Type fv_sense = { (float)v_sense.Real, (float)v_sense.Image };
|
||||
fImpCar_Type fv_tia = { (float)v_tia.Real, (float)v_tia.Image };
|
||||
|
||||
fImpCar_Type num = AD5940_ComplexMulFloat(&fv_sense, &rtia);
|
||||
fImpCar_Type z = AD5940_ComplexDivFloat(&num, &fv_tia);
|
||||
|
||||
out->freq_hz = freq_hz;
|
||||
out->z_real = z.Real;
|
||||
out->z_imag = z.Image;
|
||||
out->mag_ohms = AD5940_ComplexMag(&z);
|
||||
out->phase_deg = AD5940_ComplexPhase(&z) * (float)(180.0 / M_PI);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int eis_sweep(EISPoint *out, uint32_t max_points)
|
||||
{
|
||||
uint32_t n = eis_calc_num_points(&ctx.cfg);
|
||||
if (n > max_points) n = max_points;
|
||||
|
||||
SoftSweepCfg_Type sweep;
|
||||
sweep.SweepEn = bTRUE;
|
||||
sweep.SweepStart = ctx.cfg.freq_start_hz;
|
||||
sweep.SweepStop = ctx.cfg.freq_stop_hz;
|
||||
sweep.SweepPoints = n;
|
||||
sweep.SweepLog = bTRUE;
|
||||
sweep.SweepIndex = 0;
|
||||
|
||||
printf("\n%10s %12s %10s %12s %12s\n",
|
||||
"Freq(Hz)", "|Z|(Ohm)", "Phase(deg)", "Re(Ohm)", "Im(Ohm)");
|
||||
printf("--------------------------------------------------------------\n");
|
||||
|
||||
eis_measure_point(ctx.cfg.freq_start_hz, &out[0]);
|
||||
printf("%10.1f %12.2f %10.2f %12.2f %12.2f\n",
|
||||
out[0].freq_hz, out[0].mag_ohms, out[0].phase_deg,
|
||||
out[0].z_real, out[0].z_imag);
|
||||
|
||||
for (uint32_t i = 1; i < n; i++) {
|
||||
float freq;
|
||||
AD5940_SweepNext(&sweep, &freq);
|
||||
eis_measure_point(freq, &out[i]);
|
||||
printf("%10.1f %12.2f %10.2f %12.2f %12.2f\n",
|
||||
out[i].freq_hz, out[i].mag_ohms, out[i].phase_deg,
|
||||
out[i].z_real, out[i].z_imag);
|
||||
}
|
||||
|
||||
AD5940_AFECtrlS(AFECTRL_ALL, bFALSE);
|
||||
return (int)n;
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
#ifndef EIS_H
|
||||
#define EIS_H
|
||||
|
||||
#include "ad5940.h"
|
||||
|
||||
#define EIS_MAX_POINTS 100
|
||||
|
||||
typedef enum {
|
||||
RTIA_200 = 0, RTIA_1K, RTIA_5K, RTIA_10K,
|
||||
RTIA_20K, RTIA_40K, RTIA_80K, RTIA_160K,
|
||||
RTIA_EXT_DE0,
|
||||
RTIA_COUNT
|
||||
} EISRtia;
|
||||
|
||||
typedef enum {
|
||||
RCAL_200R = 0, /* RCAL0 ↔ RCAL1 */
|
||||
RCAL_3K, /* RCAL0 ↔ AIN0 */
|
||||
RCAL_COUNT
|
||||
} EISRcal;
|
||||
|
||||
typedef struct {
|
||||
float freq_start_hz;
|
||||
float freq_stop_hz;
|
||||
uint16_t points_per_decade;
|
||||
|
||||
EISRtia rtia;
|
||||
EISRcal rcal;
|
||||
uint32_t pga;
|
||||
uint32_t excit_amp;
|
||||
} EISConfig;
|
||||
|
||||
typedef struct {
|
||||
float freq_hz;
|
||||
float mag_ohms;
|
||||
float phase_deg;
|
||||
float z_real;
|
||||
float z_imag;
|
||||
} EISPoint;
|
||||
|
||||
void eis_default_config(EISConfig *cfg);
|
||||
void eis_init(const EISConfig *cfg);
|
||||
void eis_reconfigure(const EISConfig *cfg);
|
||||
int eis_measure_point(float freq_hz, EISPoint *out);
|
||||
int eis_sweep(EISPoint *out, uint32_t max_points);
|
||||
uint32_t eis_calc_num_points(const EISConfig *cfg);
|
||||
|
||||
#endif
|
||||
94
main/eis4.c
94
main/eis4.c
|
|
@ -1,32 +1,106 @@
|
|||
#include <stdio.h>
|
||||
#include "ad5940.h"
|
||||
#include "ad5941_port.h"
|
||||
#include "eis.h"
|
||||
#include "ble.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "nvs_flash.h"
|
||||
|
||||
#define AD5941_EXPECTED_ADIID 0x4144
|
||||
|
||||
static EISConfig cfg;
|
||||
static EISPoint results[EIS_MAX_POINTS];
|
||||
static bool afe_inited;
|
||||
|
||||
static void do_sweep(void)
|
||||
{
|
||||
if (!afe_inited) {
|
||||
eis_init(&cfg);
|
||||
afe_inited = true;
|
||||
}
|
||||
|
||||
uint32_t n = eis_calc_num_points(&cfg);
|
||||
int got = eis_sweep(results, n);
|
||||
printf("Sweep complete: %d points\n", got);
|
||||
|
||||
ble_send_sweep_start(got, cfg.freq_start_hz, cfg.freq_stop_hz);
|
||||
for (int i = 0; i < got; i++) {
|
||||
ble_send_eis_point(i, &results[i]);
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
}
|
||||
ble_send_sweep_end();
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
esp_err_t ret = nvs_flash_init();
|
||||
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
||||
nvs_flash_erase();
|
||||
nvs_flash_init();
|
||||
}
|
||||
|
||||
printf("EIS4: AD5941 bring-up\n");
|
||||
|
||||
AD5940_MCUResourceInit(NULL);
|
||||
vTaskDelay(pdMS_TO_TICKS(50));
|
||||
|
||||
AD5940_HWReset();
|
||||
vTaskDelay(pdMS_TO_TICKS(200));
|
||||
|
||||
AD5940_Initialize();
|
||||
|
||||
uint32_t adiid = AD5940_ReadReg(REG_AFECON_ADIID);
|
||||
uint32_t chipid = AD5940_ReadReg(REG_AFECON_CHIPID);
|
||||
|
||||
printf("ADIID: 0x%04lX %s\n", adiid,
|
||||
adiid == AD5941_EXPECTED_ADIID ? "(OK)" : "(UNEXPECTED)");
|
||||
printf("CHIPID: 0x%04lX\n", chipid);
|
||||
adiid == AD5941_EXPECTED_ADIID ? "(OK)" : "(FAIL)");
|
||||
if (adiid != AD5941_EXPECTED_ADIID) return;
|
||||
|
||||
if (adiid != AD5941_EXPECTED_ADIID)
|
||||
printf("FAIL: cannot communicate with AD5941\n");
|
||||
else
|
||||
printf("AD5941 alive and responding\n");
|
||||
eis_default_config(&cfg);
|
||||
|
||||
ble_init();
|
||||
printf("Waiting for BLE connection...\n");
|
||||
ble_wait_for_connection();
|
||||
ble_send_config(&cfg);
|
||||
|
||||
BleCommand cmd;
|
||||
for (;;) {
|
||||
if (ble_recv_command(&cmd, UINT32_MAX) != 0)
|
||||
continue;
|
||||
|
||||
switch (cmd.type) {
|
||||
case CMD_SET_SWEEP:
|
||||
cfg.freq_start_hz = cmd.sweep.freq_start;
|
||||
cfg.freq_stop_hz = cmd.sweep.freq_stop;
|
||||
cfg.points_per_decade = cmd.sweep.ppd;
|
||||
eis_reconfigure(&cfg);
|
||||
printf("Sweep: %.0f-%.0f Hz, %u ppd\n",
|
||||
cfg.freq_start_hz, cfg.freq_stop_hz, cfg.points_per_decade);
|
||||
ble_send_config(&cfg);
|
||||
break;
|
||||
|
||||
case CMD_SET_RTIA:
|
||||
if (cmd.rtia < RTIA_COUNT) {
|
||||
cfg.rtia = cmd.rtia;
|
||||
eis_reconfigure(&cfg);
|
||||
printf("RTIA: %u\n", cfg.rtia);
|
||||
}
|
||||
ble_send_config(&cfg);
|
||||
break;
|
||||
|
||||
case CMD_SET_RCAL:
|
||||
if (cmd.rcal < RCAL_COUNT) {
|
||||
cfg.rcal = cmd.rcal;
|
||||
eis_reconfigure(&cfg);
|
||||
printf("RCAL: %u\n", cfg.rcal);
|
||||
}
|
||||
ble_send_config(&cfg);
|
||||
break;
|
||||
|
||||
case CMD_START_SWEEP:
|
||||
do_sweep();
|
||||
break;
|
||||
|
||||
case CMD_GET_CONFIG:
|
||||
ble_send_config(&cfg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
334
sdkconfig
334
sdkconfig
|
|
@ -650,16 +650,296 @@ CONFIG_APPTRACE_LOCK_ENABLE=y
|
|||
#
|
||||
# Bluetooth
|
||||
#
|
||||
# CONFIG_BT_ENABLED is not set
|
||||
CONFIG_BT_ENABLED=y
|
||||
# CONFIG_BT_BLUEDROID_ENABLED is not set
|
||||
CONFIG_BT_NIMBLE_ENABLED=y
|
||||
# CONFIG_BT_CONTROLLER_ONLY is not set
|
||||
CONFIG_BT_CONTROLLER_ENABLED=y
|
||||
# CONFIG_BT_CONTROLLER_DISABLED is not set
|
||||
|
||||
#
|
||||
# NimBLE Options
|
||||
#
|
||||
CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_INTERNAL=y
|
||||
# CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_DEFAULT is not set
|
||||
# CONFIG_BT_NIMBLE_LOG_LEVEL_NONE is not set
|
||||
# CONFIG_BT_NIMBLE_LOG_LEVEL_ERROR is not set
|
||||
# CONFIG_BT_NIMBLE_LOG_LEVEL_WARNING is not set
|
||||
CONFIG_BT_NIMBLE_LOG_LEVEL_INFO=y
|
||||
# CONFIG_BT_NIMBLE_LOG_LEVEL_DEBUG is not set
|
||||
CONFIG_BT_NIMBLE_LOG_LEVEL=1
|
||||
CONFIG_BT_NIMBLE_MAX_CONNECTIONS=1
|
||||
CONFIG_BT_NIMBLE_MAX_BONDS=3
|
||||
CONFIG_BT_NIMBLE_MAX_CCCDS=8
|
||||
CONFIG_BT_NIMBLE_L2CAP_COC_MAX_NUM=0
|
||||
CONFIG_BT_NIMBLE_PINNED_TO_CORE_0=y
|
||||
# CONFIG_BT_NIMBLE_PINNED_TO_CORE_1 is not set
|
||||
CONFIG_BT_NIMBLE_PINNED_TO_CORE=0
|
||||
CONFIG_BT_NIMBLE_HOST_TASK_STACK_SIZE=4096
|
||||
CONFIG_BT_NIMBLE_ROLE_CENTRAL=y
|
||||
CONFIG_BT_NIMBLE_ROLE_PERIPHERAL=y
|
||||
CONFIG_BT_NIMBLE_ROLE_BROADCASTER=y
|
||||
CONFIG_BT_NIMBLE_ROLE_OBSERVER=y
|
||||
CONFIG_BT_NIMBLE_GATT_CLIENT=y
|
||||
CONFIG_BT_NIMBLE_GATT_SERVER=y
|
||||
CONFIG_BT_NIMBLE_NVS_PERSIST=y
|
||||
# CONFIG_BT_NIMBLE_SMP_ID_RESET is not set
|
||||
CONFIG_BT_NIMBLE_SECURITY_ENABLE=y
|
||||
CONFIG_BT_NIMBLE_SM_LEGACY=y
|
||||
CONFIG_BT_NIMBLE_SM_SC=y
|
||||
# CONFIG_BT_NIMBLE_SM_SC_DEBUG_KEYS is not set
|
||||
CONFIG_BT_NIMBLE_LL_CFG_FEAT_LE_ENCRYPTION=y
|
||||
CONFIG_BT_NIMBLE_SM_LVL=0
|
||||
CONFIG_BT_NIMBLE_SM_SC_ONLY=0
|
||||
CONFIG_BT_NIMBLE_PRINT_ERR_NAME=y
|
||||
# CONFIG_BT_NIMBLE_DEBUG is not set
|
||||
# CONFIG_BT_NIMBLE_DYNAMIC_SERVICE is not set
|
||||
CONFIG_BT_NIMBLE_SVC_GAP_DEVICE_NAME="nimble"
|
||||
CONFIG_BT_NIMBLE_GAP_DEVICE_NAME_MAX_LEN=31
|
||||
CONFIG_BT_NIMBLE_ATT_PREFERRED_MTU=256
|
||||
CONFIG_BT_NIMBLE_ATT_MAX_PREP_ENTRIES=64
|
||||
CONFIG_BT_NIMBLE_SVC_GAP_APPEARANCE=0
|
||||
|
||||
#
|
||||
# Memory Settings
|
||||
#
|
||||
CONFIG_BT_NIMBLE_MSYS_1_BLOCK_COUNT=12
|
||||
CONFIG_BT_NIMBLE_MSYS_1_BLOCK_SIZE=256
|
||||
CONFIG_BT_NIMBLE_MSYS_2_BLOCK_COUNT=24
|
||||
CONFIG_BT_NIMBLE_MSYS_2_BLOCK_SIZE=320
|
||||
CONFIG_BT_NIMBLE_TRANSPORT_ACL_FROM_LL_COUNT=24
|
||||
CONFIG_BT_NIMBLE_TRANSPORT_ACL_SIZE=255
|
||||
CONFIG_BT_NIMBLE_TRANSPORT_EVT_SIZE=70
|
||||
CONFIG_BT_NIMBLE_TRANSPORT_EVT_COUNT=30
|
||||
CONFIG_BT_NIMBLE_TRANSPORT_EVT_DISCARD_COUNT=8
|
||||
CONFIG_BT_NIMBLE_L2CAP_COC_SDU_BUFF_COUNT=1
|
||||
# end of Memory Settings
|
||||
|
||||
CONFIG_BT_NIMBLE_GATT_MAX_PROCS=4
|
||||
# CONFIG_BT_NIMBLE_HS_FLOW_CTRL is not set
|
||||
CONFIG_BT_NIMBLE_RPA_TIMEOUT=900
|
||||
# CONFIG_BT_NIMBLE_MESH is not set
|
||||
CONFIG_BT_NIMBLE_CRYPTO_STACK_MBEDTLS=y
|
||||
CONFIG_BT_NIMBLE_HS_STOP_TIMEOUT_MS=2000
|
||||
CONFIG_BT_NIMBLE_ENABLE_CONN_REATTEMPT=y
|
||||
CONFIG_BT_NIMBLE_MAX_CONN_REATTEMPT=3
|
||||
# CONFIG_BT_NIMBLE_HANDLE_REPEAT_PAIRING_DELETION is not set
|
||||
CONFIG_BT_NIMBLE_50_FEATURE_SUPPORT=y
|
||||
CONFIG_BT_NIMBLE_LL_CFG_FEAT_LE_2M_PHY=y
|
||||
CONFIG_BT_NIMBLE_LL_CFG_FEAT_LE_CODED_PHY=y
|
||||
# CONFIG_BT_NIMBLE_EXT_ADV is not set
|
||||
CONFIG_BT_NIMBLE_EXT_SCAN=y
|
||||
CONFIG_BT_NIMBLE_ENABLE_PERIODIC_SYNC=y
|
||||
CONFIG_BT_NIMBLE_MAX_PERIODIC_SYNCS=0
|
||||
# CONFIG_BT_NIMBLE_GATT_CACHING is not set
|
||||
# CONFIG_BT_NIMBLE_INCL_SVC_DISCOVERY is not set
|
||||
CONFIG_BT_NIMBLE_WHITELIST_SIZE=12
|
||||
# CONFIG_BT_NIMBLE_TEST_THROUGHPUT_TEST is not set
|
||||
# CONFIG_BT_NIMBLE_BLUFI_ENABLE is not set
|
||||
CONFIG_BT_NIMBLE_USE_ESP_TIMER=y
|
||||
CONFIG_BT_NIMBLE_LEGACY_VHCI_ENABLE=y
|
||||
# CONFIG_BT_NIMBLE_BLE_GATT_BLOB_TRANSFER is not set
|
||||
|
||||
#
|
||||
# BLE Services
|
||||
#
|
||||
CONFIG_BT_NIMBLE_PROX_SERVICE=y
|
||||
CONFIG_BT_NIMBLE_ANS_SERVICE=y
|
||||
CONFIG_BT_NIMBLE_CTS_SERVICE=y
|
||||
CONFIG_BT_NIMBLE_HTP_SERVICE=y
|
||||
CONFIG_BT_NIMBLE_IPSS_SERVICE=y
|
||||
CONFIG_BT_NIMBLE_TPS_SERVICE=y
|
||||
CONFIG_BT_NIMBLE_IAS_SERVICE=y
|
||||
CONFIG_BT_NIMBLE_LLS_SERVICE=y
|
||||
CONFIG_BT_NIMBLE_SPS_SERVICE=y
|
||||
CONFIG_BT_NIMBLE_HR_SERVICE=y
|
||||
# CONFIG_BT_NIMBLE_HID_SERVICE is not set
|
||||
CONFIG_BT_NIMBLE_BAS_SERVICE=y
|
||||
# CONFIG_BT_NIMBLE_SVC_BAS_BATTERY_LEVEL_NOTIFY is not set
|
||||
CONFIG_BT_NIMBLE_DIS_SERVICE=y
|
||||
# CONFIG_BT_NIMBLE_SVC_DIS_MANUFACTURER_NAME is not set
|
||||
# CONFIG_BT_NIMBLE_SVC_DIS_SERIAL_NUMBER is not set
|
||||
# CONFIG_BT_NIMBLE_SVC_DIS_HARDWARE_REVISION is not set
|
||||
# CONFIG_BT_NIMBLE_SVC_DIS_FIRMWARE_REVISION is not set
|
||||
# CONFIG_BT_NIMBLE_SVC_DIS_SOFTWARE_REVISION is not set
|
||||
# CONFIG_BT_NIMBLE_SVC_DIS_SYSTEM_ID is not set
|
||||
# CONFIG_BT_NIMBLE_SVC_DIS_PNP_ID is not set
|
||||
# CONFIG_BT_NIMBLE_SVC_DIS_INCLUDED is not set
|
||||
CONFIG_BT_NIMBLE_GAP_SERVICE=y
|
||||
|
||||
#
|
||||
# GAP Appearance write permissions
|
||||
#
|
||||
# CONFIG_BT_NIMBLE_SVC_GAP_APPEAR_WRITE is not set
|
||||
CONFIG_BT_NIMBLE_SVC_GAP_APPEAR_WRITE_PERM=0
|
||||
CONFIG_BT_NIMBLE_SVC_GAP_APPEAR_WRITE_PERM_ENC=0
|
||||
CONFIG_BT_NIMBLE_SVC_GAP_APPEAR_WRITE_PERM_ATHN=0
|
||||
CONFIG_BT_NIMBLE_SVC_GAP_APPEAR_WRITE_PERM_ATHR=0
|
||||
# end of GAP Appearance write permissions
|
||||
|
||||
CONFIG_BT_NIMBLE_SVC_GAP_CAR_CHAR_NOT_SUPP=y
|
||||
# CONFIG_BT_NIMBLE_SVC_GAP_CAR_NOT_SUPP is not set
|
||||
# CONFIG_BT_NIMBLE_SVC_GAP_CAR_SUPP is not set
|
||||
CONFIG_BT_NIMBLE_SVC_GAP_CENT_ADDR_RESOLUTION=-1
|
||||
|
||||
#
|
||||
# GAP device name write permissions
|
||||
#
|
||||
# CONFIG_BT_NIMBLE_SVC_GAP_NAME_WRITE is not set
|
||||
# end of GAP device name write permissions
|
||||
|
||||
#
|
||||
# Peripheral Preferred Connection Parameters (PPCP) settings
|
||||
#
|
||||
CONFIG_BT_NIMBLE_SVC_GAP_PPCP_MAX_CONN_INTERVAL=0
|
||||
CONFIG_BT_NIMBLE_SVC_GAP_PPCP_MIN_CONN_INTERVAL=0
|
||||
CONFIG_BT_NIMBLE_SVC_GAP_PPCP_SLAVE_LATENCY=0
|
||||
CONFIG_BT_NIMBLE_SVC_GAP_PPCP_SUPERVISION_TMO=0
|
||||
# end of Peripheral Preferred Connection Parameters (PPCP) settings
|
||||
|
||||
CONFIG_BT_NIMBLE_SVC_GAP_NAME_WRITE_PERM=0
|
||||
CONFIG_BT_NIMBLE_SVC_GAP_NAME_WRITE_PERM_ENC=0
|
||||
CONFIG_BT_NIMBLE_SVC_GAP_NAME_WRITE_PERM_AUTHEN=0
|
||||
CONFIG_BT_NIMBLE_SVC_GAP_NAME_WRITE_PERM_AUTHOR=0
|
||||
# CONFIG_BT_NIMBLE_SVC_GAP_GATT_SECURITY_LEVEL is not set
|
||||
# CONFIG_BT_NIMBLE_SVC_GAP_RPA_ONLY is not set
|
||||
# end of BLE Services
|
||||
|
||||
# CONFIG_BT_NIMBLE_VS_SUPPORT is not set
|
||||
# CONFIG_BT_NIMBLE_ENC_ADV_DATA is not set
|
||||
# CONFIG_BT_NIMBLE_HIGH_DUTY_ADV_ITVL is not set
|
||||
# CONFIG_BT_NIMBLE_HOST_ALLOW_CONNECT_WITH_SCAN is not set
|
||||
# CONFIG_BT_NIMBLE_HOST_QUEUE_CONG_CHECK is not set
|
||||
# CONFIG_BT_NIMBLE_GATTC_PROC_PREEMPTION_PROTECT is not set
|
||||
# CONFIG_BT_NIMBLE_GATTC_AUTO_PAIR is not set
|
||||
|
||||
#
|
||||
# Host-controller Transport
|
||||
#
|
||||
CONFIG_UART_HW_FLOWCTRL_DISABLE=y
|
||||
# CONFIG_UART_HW_FLOWCTRL_CTS_RTS is not set
|
||||
CONFIG_BT_NIMBLE_HCI_UART_FLOW_CTRL=0
|
||||
CONFIG_BT_NIMBLE_HCI_UART_RTS_PIN=19
|
||||
CONFIG_BT_NIMBLE_HCI_UART_CTS_PIN=23
|
||||
# end of Host-controller Transport
|
||||
|
||||
CONFIG_BT_NIMBLE_EATT_CHAN_NUM=0
|
||||
# CONFIG_BT_NIMBLE_SUBRATE is not set
|
||||
# end of NimBLE Options
|
||||
|
||||
#
|
||||
# Controller Options
|
||||
#
|
||||
CONFIG_BT_CTRL_MODE_EFF=1
|
||||
CONFIG_BT_CTRL_BLE_MAX_ACT=6
|
||||
CONFIG_BT_CTRL_BLE_MAX_ACT_EFF=6
|
||||
CONFIG_BT_CTRL_BLE_STATIC_ACL_TX_BUF_NB=0
|
||||
CONFIG_BT_CTRL_PINNED_TO_CORE_0=y
|
||||
# CONFIG_BT_CTRL_PINNED_TO_CORE_1 is not set
|
||||
CONFIG_BT_CTRL_PINNED_TO_CORE=0
|
||||
CONFIG_BT_CTRL_HCI_MODE_VHCI=y
|
||||
# CONFIG_BT_CTRL_HCI_MODE_UART_H4 is not set
|
||||
CONFIG_BT_CTRL_HCI_TL=1
|
||||
CONFIG_BT_CTRL_ADV_DUP_FILT_MAX=30
|
||||
CONFIG_BT_BLE_CCA_MODE_NONE=y
|
||||
# CONFIG_BT_BLE_CCA_MODE_HW is not set
|
||||
# CONFIG_BT_BLE_CCA_MODE_SW is not set
|
||||
CONFIG_BT_BLE_CCA_MODE=0
|
||||
CONFIG_BT_CTRL_HW_CCA_VAL=75
|
||||
CONFIG_BT_CTRL_HW_CCA_EFF=0
|
||||
CONFIG_BT_CTRL_CE_LENGTH_TYPE_ORIG=y
|
||||
# CONFIG_BT_CTRL_CE_LENGTH_TYPE_CE is not set
|
||||
# CONFIG_BT_CTRL_CE_LENGTH_TYPE_SD is not set
|
||||
CONFIG_BT_CTRL_CE_LENGTH_TYPE_EFF=0
|
||||
CONFIG_BT_CTRL_TX_ANTENNA_INDEX_0=y
|
||||
# CONFIG_BT_CTRL_TX_ANTENNA_INDEX_1 is not set
|
||||
CONFIG_BT_CTRL_TX_ANTENNA_INDEX_EFF=0
|
||||
CONFIG_BT_CTRL_RX_ANTENNA_INDEX_0=y
|
||||
# CONFIG_BT_CTRL_RX_ANTENNA_INDEX_1 is not set
|
||||
CONFIG_BT_CTRL_RX_ANTENNA_INDEX_EFF=0
|
||||
# CONFIG_BT_CTRL_DFT_TX_POWER_LEVEL_N24 is not set
|
||||
# CONFIG_BT_CTRL_DFT_TX_POWER_LEVEL_N21 is not set
|
||||
# CONFIG_BT_CTRL_DFT_TX_POWER_LEVEL_N18 is not set
|
||||
# CONFIG_BT_CTRL_DFT_TX_POWER_LEVEL_N15 is not set
|
||||
# CONFIG_BT_CTRL_DFT_TX_POWER_LEVEL_N12 is not set
|
||||
# CONFIG_BT_CTRL_DFT_TX_POWER_LEVEL_N9 is not set
|
||||
# CONFIG_BT_CTRL_DFT_TX_POWER_LEVEL_N6 is not set
|
||||
# CONFIG_BT_CTRL_DFT_TX_POWER_LEVEL_N3 is not set
|
||||
# CONFIG_BT_CTRL_DFT_TX_POWER_LEVEL_N0 is not set
|
||||
# CONFIG_BT_CTRL_DFT_TX_POWER_LEVEL_P3 is not set
|
||||
# CONFIG_BT_CTRL_DFT_TX_POWER_LEVEL_P6 is not set
|
||||
CONFIG_BT_CTRL_DFT_TX_POWER_LEVEL_P9=y
|
||||
# CONFIG_BT_CTRL_DFT_TX_POWER_LEVEL_P12 is not set
|
||||
# CONFIG_BT_CTRL_DFT_TX_POWER_LEVEL_P15 is not set
|
||||
# CONFIG_BT_CTRL_DFT_TX_POWER_LEVEL_P18 is not set
|
||||
# CONFIG_BT_CTRL_DFT_TX_POWER_LEVEL_P20 is not set
|
||||
CONFIG_BT_CTRL_DFT_TX_POWER_LEVEL_EFF=11
|
||||
CONFIG_BT_CTRL_BLE_ADV_REPORT_FLOW_CTRL_SUPP=y
|
||||
CONFIG_BT_CTRL_BLE_ADV_REPORT_FLOW_CTRL_NUM=100
|
||||
CONFIG_BT_CTRL_BLE_ADV_REPORT_DISCARD_THRSHOLD=20
|
||||
CONFIG_BT_CTRL_BLE_SCAN_DUPL=y
|
||||
CONFIG_BT_CTRL_SCAN_DUPL_TYPE_DEVICE=y
|
||||
# CONFIG_BT_CTRL_SCAN_DUPL_TYPE_DATA is not set
|
||||
# CONFIG_BT_CTRL_SCAN_DUPL_TYPE_DATA_DEVICE is not set
|
||||
CONFIG_BT_CTRL_SCAN_DUPL_TYPE=0
|
||||
CONFIG_BT_CTRL_SCAN_DUPL_CACHE_SIZE=100
|
||||
CONFIG_BT_CTRL_DUPL_SCAN_CACHE_REFRESH_PERIOD=0
|
||||
# CONFIG_BT_CTRL_BLE_MESH_SCAN_DUPL_EN is not set
|
||||
# CONFIG_BT_CTRL_COEX_PHY_CODED_TX_RX_TLIM_EN is not set
|
||||
CONFIG_BT_CTRL_COEX_PHY_CODED_TX_RX_TLIM_DIS=y
|
||||
CONFIG_BT_CTRL_COEX_PHY_CODED_TX_RX_TLIM_EFF=0
|
||||
|
||||
#
|
||||
# MODEM SLEEP Options
|
||||
#
|
||||
# CONFIG_BT_CTRL_MODEM_SLEEP is not set
|
||||
# end of MODEM SLEEP Options
|
||||
|
||||
CONFIG_BT_CTRL_SLEEP_MODE_EFF=0
|
||||
CONFIG_BT_CTRL_SLEEP_CLOCK_EFF=0
|
||||
CONFIG_BT_CTRL_HCI_TL_EFF=1
|
||||
# CONFIG_BT_CTRL_AGC_RECORRECT_EN is not set
|
||||
# CONFIG_BT_CTRL_SCAN_BACKOFF_UPPERLIMITMAX is not set
|
||||
# CONFIG_BT_BLE_ADV_DATA_LENGTH_ZERO_AUX is not set
|
||||
CONFIG_BT_CTRL_CHAN_ASS_EN=y
|
||||
CONFIG_BT_CTRL_LE_PING_EN=y
|
||||
|
||||
#
|
||||
# BLE disconnects when Instant Passed (0x28) occurs
|
||||
#
|
||||
# CONFIG_BT_CTRL_BLE_LLCP_CONN_UPDATE is not set
|
||||
# CONFIG_BT_CTRL_BLE_LLCP_CHAN_MAP_UPDATE is not set
|
||||
# CONFIG_BT_CTRL_BLE_LLCP_PHY_UPDATE is not set
|
||||
# end of BLE disconnects when Instant Passed (0x28) occurs
|
||||
|
||||
# CONFIG_BT_CTRL_RUN_IN_FLASH_ONLY is not set
|
||||
CONFIG_BT_CTRL_DTM_ENABLE=y
|
||||
CONFIG_BT_CTRL_BLE_MASTER=y
|
||||
# CONFIG_BT_CTRL_BLE_TEST is not set
|
||||
CONFIG_BT_CTRL_BLE_SCAN=y
|
||||
CONFIG_BT_CTRL_BLE_SECURITY_ENABLE=y
|
||||
CONFIG_BT_CTRL_BLE_ADV=y
|
||||
# CONFIG_BT_CTRL_CHECK_CONNECT_IND_ACCESS_ADDRESS is not set
|
||||
|
||||
#
|
||||
# Controller debug log Options (Experimental)
|
||||
#
|
||||
# end of Controller debug log Options (Experimental)
|
||||
# end of Controller Options
|
||||
|
||||
#
|
||||
# Common Options
|
||||
#
|
||||
CONFIG_BT_ALARM_MAX_NUM=50
|
||||
# CONFIG_BT_BLE_LOG_SPI_OUT_ENABLED is not set
|
||||
# CONFIG_BT_BLE_LOG_UHCI_OUT_ENABLED is not set
|
||||
# end of Common Options
|
||||
|
||||
# CONFIG_BT_HCI_LOG_DEBUG_EN is not set
|
||||
# end of Bluetooth
|
||||
|
||||
# CONFIG_BLE_MESH is not set
|
||||
|
||||
#
|
||||
# Console Library
|
||||
#
|
||||
|
|
@ -789,7 +1069,8 @@ CONFIG_ESP_TLS_DYN_BUF_STRATEGY_SUPPORTED=y
|
|||
# Wireless Coexistence
|
||||
#
|
||||
CONFIG_ESP_COEX_ENABLED=y
|
||||
# CONFIG_ESP_COEX_EXTERNAL_COEXIST_ENABLE is not set
|
||||
CONFIG_ESP_COEX_SW_COEXIST_ENABLE=y
|
||||
# CONFIG_ESP_COEX_POWER_MANAGEMENT is not set
|
||||
# CONFIG_ESP_COEX_GPIO_DEBUG is not set
|
||||
# end of Wireless Coexistence
|
||||
|
||||
|
|
@ -2233,6 +2514,11 @@ CONFIG_WL_SECTOR_SIZE=4096
|
|||
#
|
||||
CONFIG_WIFI_PROV_SCAN_MAX_ENTRIES=16
|
||||
CONFIG_WIFI_PROV_AUTOSTOP_TIMEOUT=30
|
||||
# CONFIG_WIFI_PROV_BLE_BONDING is not set
|
||||
CONFIG_WIFI_PROV_BLE_SEC_CONN=y
|
||||
# CONFIG_WIFI_PROV_BLE_FORCE_ENCRYPTION is not set
|
||||
# CONFIG_WIFI_PROV_BLE_NOTIFY is not set
|
||||
# CONFIG_WIFI_PROV_KEEP_BLE_ON_AFTER_PROV is not set
|
||||
CONFIG_WIFI_PROV_STA_ALL_CHANNEL_SCAN=y
|
||||
# CONFIG_WIFI_PROV_STA_FAST_SCAN is not set
|
||||
# end of Wi-Fi Provisioning Manager
|
||||
|
|
@ -2275,8 +2561,48 @@ CONFIG_STACK_CHECK_NONE=y
|
|||
# CONFIG_ESP32_APPTRACE_DEST_TRAX is not set
|
||||
CONFIG_ESP32_APPTRACE_DEST_NONE=y
|
||||
CONFIG_ESP32_APPTRACE_LOCK_ENABLE=y
|
||||
# CONFIG_EXTERNAL_COEX_ENABLE is not set
|
||||
# CONFIG_ESP_WIFI_EXTERNAL_COEXIST_ENABLE is not set
|
||||
# CONFIG_BLUEDROID_ENABLED is not set
|
||||
CONFIG_NIMBLE_ENABLED=y
|
||||
CONFIG_NIMBLE_MEM_ALLOC_MODE_INTERNAL=y
|
||||
# CONFIG_NIMBLE_MEM_ALLOC_MODE_DEFAULT is not set
|
||||
CONFIG_NIMBLE_MAX_CONNECTIONS=1
|
||||
CONFIG_NIMBLE_MAX_BONDS=3
|
||||
CONFIG_NIMBLE_MAX_CCCDS=8
|
||||
CONFIG_NIMBLE_L2CAP_COC_MAX_NUM=0
|
||||
CONFIG_NIMBLE_PINNED_TO_CORE_0=y
|
||||
# CONFIG_NIMBLE_PINNED_TO_CORE_1 is not set
|
||||
CONFIG_NIMBLE_PINNED_TO_CORE=0
|
||||
CONFIG_NIMBLE_TASK_STACK_SIZE=4096
|
||||
CONFIG_BT_NIMBLE_TASK_STACK_SIZE=4096
|
||||
CONFIG_NIMBLE_ROLE_CENTRAL=y
|
||||
CONFIG_NIMBLE_ROLE_PERIPHERAL=y
|
||||
CONFIG_NIMBLE_ROLE_BROADCASTER=y
|
||||
CONFIG_NIMBLE_ROLE_OBSERVER=y
|
||||
CONFIG_NIMBLE_NVS_PERSIST=y
|
||||
CONFIG_NIMBLE_SM_LEGACY=y
|
||||
CONFIG_NIMBLE_SM_SC=y
|
||||
# CONFIG_NIMBLE_SM_SC_DEBUG_KEYS is not set
|
||||
CONFIG_BT_NIMBLE_SM_SC_LVL=0
|
||||
# CONFIG_NIMBLE_DEBUG is not set
|
||||
CONFIG_NIMBLE_SVC_GAP_DEVICE_NAME="nimble"
|
||||
CONFIG_NIMBLE_GAP_DEVICE_NAME_MAX_LEN=31
|
||||
CONFIG_NIMBLE_ATT_PREFERRED_MTU=256
|
||||
CONFIG_NIMBLE_SVC_GAP_APPEARANCE=0
|
||||
CONFIG_BT_NIMBLE_MSYS1_BLOCK_COUNT=12
|
||||
CONFIG_BT_NIMBLE_ACL_BUF_COUNT=24
|
||||
CONFIG_BT_NIMBLE_ACL_BUF_SIZE=255
|
||||
CONFIG_BT_NIMBLE_HCI_EVT_BUF_SIZE=70
|
||||
CONFIG_BT_NIMBLE_HCI_EVT_HI_BUF_COUNT=30
|
||||
CONFIG_BT_NIMBLE_HCI_EVT_LO_BUF_COUNT=8
|
||||
# CONFIG_NIMBLE_HS_FLOW_CTRL is not set
|
||||
CONFIG_NIMBLE_RPA_TIMEOUT=900
|
||||
# CONFIG_NIMBLE_MESH is not set
|
||||
CONFIG_NIMBLE_CRYPTO_STACK_MBEDTLS=y
|
||||
# CONFIG_BT_NIMBLE_COEX_PHY_CODED_TX_RX_TLIM_EN is not set
|
||||
CONFIG_BT_NIMBLE_COEX_PHY_CODED_TX_RX_TLIM_DIS=y
|
||||
CONFIG_SW_COEXIST_ENABLE=y
|
||||
CONFIG_ESP32_WIFI_SW_COEXIST_ENABLE=y
|
||||
CONFIG_ESP_WIFI_SW_COEXIST_ENABLE=y
|
||||
# CONFIG_CAM_CTLR_DVP_CAM_ISR_IRAM_SAFE is not set
|
||||
# CONFIG_GPTIMER_ISR_IRAM_SAFE is not set
|
||||
# CONFIG_MCPWM_ISR_IRAM_SAFE is not set
|
||||
|
|
|
|||
Loading…
Reference in New Issue