/*
* Copyright (c) 2018 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
*/
/** @file
* @brief Nordic UART Bridge Service (NUS) sample
*/
#include <uart_async_adapter.h>
#include <zephyr/types.h>
#include <zephyr/kernel.h>
#include <zephyr/drivers/uart.h>
#include <zephyr/usb/usb_device.h>
#include <zephyr/device.h>
#include <zephyr/devicetree.h>
#include <soc.h>
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/uuid.h>
#include <zephyr/bluetooth/gatt.h>
#include <zephyr/bluetooth/hci.h>
#include <bluetooth/services/nus.h>
#include <dk_buttons_and_leds.h>
#include <zephyr/settings/settings.h>
#include <stdio.h>
#include <string.h>
#include <zephyr/logging/log.h>
#include <zephyr/drivers/gpio.h>
#include<zephyr/sys/printk.h>
#include<zephyr/drivers/clock_control.h>
#include<zephyr/drivers/clock_control/nrf_clock_control.h>
#include <zephyr/drivers/i2c.h>
#include <zephyr/devicetree.h>
#include <zephyr/drivers/regulator.h>
#include <nrfx.h>
#include<zephyr/drivers/spi.h>
#define LOG_MODULE_NAME peripheral_uart
LOG_MODULE_REGISTER(LOG_MODULE_NAME);
#define STACKSIZE CONFIG_BT_NUS_THREAD_STACK_SIZE
#define PRIORITY 7
#define DEVICE_NAME CONFIG_BT_DEVICE_NAME
#define DEVICE_NAME_LEN (sizeof(DEVICE_NAME) - 1)
#define RUN_STATUS_LED DK_LED1
#define RUN_LED_BLINK_INTERVAL 1000
#define CON_STATUS_LED DK_LED2
#define KEY_PASSKEY_ACCEPT DK_BTN1_MSK
#define KEY_PASSKEY_REJECT DK_BTN2_MSK
#define UART_BUF_SIZE CONFIG_BT_NUS_UART_BUFFER_SIZE
#define UART_WAIT_FOR_BUF_DELAY K_MSEC(50)
#define UART_WAIT_FOR_RX CONFIG_BT_NUS_UART_RX_WAIT_TIME
#define RHS_CHIP_ID 32 // ROM reg 255
// 寄存器地址
#define REG_ADC_BIAS 0
#define REG_DSP_CTRL 1
#define REG_ZCHECK_CTRL 2
#define REG_ZCHECK_DAC 3
#define REG_RH1_SEL 4
#define REG_RH2_SEL 5
#define REG_RL_A_SEL 6
#define REG_RL_B_SEL 7
#define REG_AC_AMP_POWER 8
#define REG_FAST_SETTLE 10
#define REG_AMP_FL_SEL 12
#define REG_STIM_STEP 34
#define REG_STIM_BIAS 35
#define REG_CL_RECOV_V 36
#define REG_CL_RECOV_I 37
#define REG_DC_AMP_POWER 38
#define REG_COMP_MON 40
#define REG_STIM_EN_A 42 // 刺激使能 A
#define REG_STIM_EN_B 43 // 刺激使能 B
#define REG_STIM_ON 44
#define REG_STIM_POL 45
#define REG_CHARGE_REC_SW 46
#define REG_CL_RECOV_EN 48
#define REG_FAULT_CURR 50
// 初始化值 (手册 page 45, 30 kS/s, 7.5 kHz fH, 5 Hz fL)
#define INIT_ADC_BIAS 0x00C5 // MUX/ADC bias for 480 kS/s
#define INIT_DSP_CTRL 0x051A // DSP 4.665 Hz, absmode=0, twoscomp=0
#define INIT_RH1_SEL 0x0016
#define INIT_RH2_SEL 0x0017
#define INIT_RL_A_SEL 0x00A8 // 5 Hz
#define INIT_RL_B_SEL 0x000A // 1 kHz alternate
#define INIT_AC_POWER 0xFFFF
#define INIT_DC_POWER 0xFFFF // 重要:全开,避免 bug
#define INIT_FAST_SETTLE 0x0000
#define INIT_AMP_FL_SEL 0xFFFF // 全用 A (5 Hz)
#define INIT_STIM_STEP 0x00E2 // 1 uA/step
#define INIT_STIM_BIAS 0x00AA
#define INIT_CL_V 0x0080 // 0V
#define INIT_CL_I 0x4F00 // 1 nA
#define INIT_STIM_EN_A 0x0000 // 禁用刺激
#define INIT_STIM_EN_B 0x0000
#define INIT_STIM_ON 0x0000
#define INIT_STIM_POL 0x0000 // 负极性
#define INIT_CHARGE_REC_SW 0x0000
#define INIT_CL_EN 0x0000
static struct rhs2116_dev rhs1;
static struct rhs2116_dev rhs2;
// SPI 配置
// #define SPI_FREQ DT_PROP(DT_NODELABEL(spi3), spi_max_frequency) // 10 MHz
// #define SPI_OP SPI_WORD_SET(8) | SPI_OP_MODE_MASTER | SPI_MODE_CPOL0 | SPI_MODE_CPHA0
#define SPI_FREQ (10000000U) // 10 MHz
#define SPI_OP (SPI_WORD_SET(8) | SPI_OP_MODE_MASTER) // Mode 0: CPOL=0, CPHA=0
static uint8_t ble_ADC[250];
static uint8_t ble_Tx[250];
//static uint8_t ble_Tx1[250];
static uint16_t bag=0;
static uint16_t LASTbag=0;
//static int8_t counter=0;
static struct k_timer adc_timer; // 定时器实例
static void adc_timer_handler(struct k_timer *timer_id); // 前向声明
static struct k_work adc_work ;
#define LED0_NODE DT_ALIAS(led0)
static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(DT_ALIAS(led0), gpios);
static void exchange_func(struct bt_conn *conn, uint8_t att_err, struct bt_gatt_exchange_params *params);
#define BLE_NUS_THROUGHPUT_MAX
#define BLE_NUS_THROUGHPUT_TEST
#if defined(BLE_NUS_THROUGHPUT_MAX)
static K_SEM_DEFINE(nus_connection_sem,0,1);
static const char*phy2str(uint8_t phy)
{
switch (phy)
{
case 0:return"NO packets";
case BT_GAP_LE_PHY_1M:return"LE 1M";
case BT_GAP_LE_PHY_2M:return"LE 2M";
case BT_GAP_LE_PHY_CODED:return "LE Coded";
default: return "Unknown";
}
}
#endif
static K_SEM_DEFINE(ble_init_ok, 0, 1);
static struct bt_conn *current_conn;
static struct bt_conn *auth_conn;
static struct k_work adv_work;
static const struct device *uart = DEVICE_DT_GET(DT_CHOSEN(nordic_nus_uart));
static struct k_work_delayable uart_work;
struct uart_data_t {
void *fifo_reserved;
uint8_t data[UART_BUF_SIZE];
uint16_t len;
};
static K_FIFO_DEFINE(fifo_uart_tx_data);
static K_FIFO_DEFINE(fifo_uart_rx_data);
static const struct bt_data ad[] = {
BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_NAME, DEVICE_NAME_LEN),
};
static const struct bt_data sd[] = {
BT_DATA_BYTES(BT_DATA_UUID128_ALL, BT_UUID_NUS_VAL),
};
#ifdef CONFIG_UART_ASYNC_ADAPTER
UART_ASYNC_ADAPTER_INST_DEFINE(async_adapter);
#else
#define async_adapter NULL
#endif
// SPI 配置 (全局或静态)
static const struct spi_config spi_cfg = {
.frequency = SPI_FREQ, // 10 MHz
.operation = SPI_OP,
.slave = 0,
.cs = {0}, // CS 手动控制
};
struct rhs2116_dev {
const struct device *spi_dev;
struct gpio_dt_spec cs_gpios;
uint16_t regs[256]; // 寄存器缓存
};
static int rhs_write_reg(const struct device *spi_dev, struct gpio_dt_spec *cs, uint8_t reg, uint16_t val, bool update) {
uint8_t tx_buf[4] = {0x80, 0, (reg & 0xF0) >> 4, reg & 0x0F}; // WRITE: 10xx xxxx (MSB)
uint8_t cmd[4] = {0xA0 | (update ? 0x20 : 0), 0, reg >> 4, reg & 0x0F}; // U=1 if update
uint8_t val_h = val >> 8, val_l = val & 0xFF;
cmd[1] = val_h; cmd[2] = val_l; cmd[3] = val_l; // Echo lower 16
struct spi_buf tx = {.buf = cmd, .len = 4};
const struct spi_buf_set tx_set = {.buffers = &tx, .count = 1};
gpio_pin_set_dt(cs, 1); // CS high
int ret = spi_write(spi_dev, &spi_cfg, &tx_set); // Dummy for pipeline
gpio_pin_set_dt(cs, 0); // CS low
ret = spi_write(spi_dev, &spi_cfg, &tx_set);
gpio_pin_set_dt(cs, 1);
return ret;
}
static int rhs_read_reg(const struct device *spi_dev, struct gpio_dt_spec *cs, uint8_t reg, uint16_t *val) {
uint8_t cmd[4] = {0xC0, 0, reg >> 4, reg & 0x0F}; // READ: 11xx xxxx
uint8_t rx_buf[4];
struct spi_buf tx = {.buf = cmd, .len = 4};
struct spi_buf rx = {.buf = rx_buf, .len = 4}; // 4 bytes for 32-bit
struct spi_buf_set tx_set = {.buffers = &tx, .count = 1};
struct spi_buf_set rx_set = {.buffers = &rx, .count = 1};
gpio_pin_set_dt(cs, 1);
int ret = spi_transceive(spi_dev, &spi_cfg, &tx_set, &rx_set); // Pipeline read
gpio_pin_set_dt(cs, 0);
ret = spi_transceive(spi_dev, &spi_cfg, &tx_set, &rx_set);
gpio_pin_set_dt(cs, 1);
*val = (rx_buf[2] << 8) | rx_buf[3]; // Lower 16 bits
return ret;
}
static int rhs_init(struct rhs2116_dev *dev) {
// 清零寄存器缓存
memset(dev->regs, 0, sizeof(dev->regs));
// 手册初始化序列 (page 45)
rhs_write_reg(dev->spi_dev, &dev->cs_gpios, REG_DC_AMP_POWER, INIT_DC_POWER, false);
rhs_write_reg(dev->spi_dev, &dev->cs_gpios, REG_ADC_BIAS, INIT_ADC_BIAS, false);
rhs_write_reg(dev->spi_dev, &dev->cs_gpios, REG_DSP_CTRL, INIT_DSP_CTRL, false);
rhs_write_reg(dev->spi_dev, &dev->cs_gpios, REG_RH1_SEL, INIT_RH1_SEL, false);
rhs_write_reg(dev->spi_dev, &dev->cs_gpios, REG_RH2_SEL, INIT_RH2_SEL, false);
rhs_write_reg(dev->spi_dev, &dev->cs_gpios, REG_RL_A_SEL, INIT_RL_A_SEL, false);
rhs_write_reg(dev->spi_dev, &dev->cs_gpios, REG_RL_B_SEL, INIT_RL_B_SEL, false);
rhs_write_reg(dev->spi_dev, &dev->cs_gpios, REG_AC_AMP_POWER, INIT_AC_POWER, false);
rhs_write_reg(dev->spi_dev, &dev->cs_gpios, REG_FAST_SETTLE, INIT_FAST_SETTLE, true); // U=1
rhs_write_reg(dev->spi_dev, &dev->cs_gpios, REG_AMP_FL_SEL, INIT_AMP_FL_SEL, true); // U=1
rhs_write_reg(dev->spi_dev, &dev->cs_gpios, REG_STIM_STEP, INIT_STIM_STEP, false);
rhs_write_reg(dev->spi_dev, &dev->cs_gpios, REG_STIM_BIAS, INIT_STIM_BIAS, false);
rhs_write_reg(dev->spi_dev, &dev->cs_gpios, REG_CL_RECOV_V, INIT_CL_V, false);
rhs_write_reg(dev->spi_dev, &dev->cs_gpios, REG_CL_RECOV_I, INIT_CL_I, false);
rhs_write_reg(dev->spi_dev, &dev->cs_gpios, REG_STIM_EN_A, INIT_STIM_EN_A, false); // 禁用刺激
rhs_write_reg(dev->spi_dev, &dev->cs_gpios, REG_STIM_EN_B, INIT_STIM_EN_B, false);
rhs_write_reg(dev->spi_dev, &dev->cs_gpios, REG_STIM_ON, INIT_STIM_ON, true); // U=1
rhs_write_reg(dev->spi_dev, &dev->cs_gpios, REG_STIM_POL, INIT_STIM_POL, true); // U=1
rhs_write_reg(dev->spi_dev, &dev->cs_gpios, REG_CHARGE_REC_SW, INIT_CHARGE_REC_SW, true); // U=1
rhs_write_reg(dev->spi_dev, &dev->cs_gpios, REG_CL_RECOV_EN, INIT_CL_EN, true); // U=1
// 验证芯片 ID (ROM 255)
uint16_t chip_id;
rhs_read_reg(dev->spi_dev, &dev->cs_gpios, 255, &chip_id);
if (chip_id != RHS_CHIP_ID) return -1;
LOG_INF("RHS2116 initialized, ID=0x%04X", chip_id);
return 0;
}
static void rhs_sample_all(struct rhs2116_dev *dev1, struct rhs2116_dev *dev2, int16_t *samples) {
uint8_t cmd[4], rx[4];
struct spi_buf tx_buf = {.buf = cmd, .len = 4};
struct spi_buf rx_buf = {.buf = rx, .len = 4};
struct spi_buf_set tx_set = { .buffers = &tx_buf, .count = 1 };
struct spi_buf_set rx_set = { .buffers = &rx_buf, .count = 1 };
// Dummy for pipeline
gpio_pin_set_dt(&dev1->cs_gpios, 1);
spi_transceive(dev1->spi_dev, &spi_cfg, &tx_set, &rx_set);
gpio_pin_set_dt(&dev1->cs_gpios, 0);
for (int ch = 0; ch < 16; ch++) {
// CONVERT(ch): 00 C[5:0] 0000 0000 0000 0000, D=0 (AC only)
cmd[0] = 0x00;
cmd[1] = 0x00;
cmd[2] = (ch & 0x3F) << 2; // C[5:0] << 2
cmd[3] = 0x00;
gpio_pin_set_dt(&dev1->cs_gpios, 0);
spi_transceive(dev1->spi_dev, &spi_cfg, &tx_set, &rx_set);
gpio_pin_set_dt(&dev1->cs_gpios, 1);
samples[ch] = (int16_t)((rx[0] << 8) | rx[1]); // AC high 16-bit
// 辅助命令 (dummy READ(255) for pipeline, M=1 clear compliance)
cmd[0] = 0xC4; // READ + M=1
cmd[1] = 0x00;
cmd[2] = 0xFF; // Reg 255
cmd[3] = 0xFF;
gpio_pin_set_dt(&dev1->cs_gpios, 0);
spi_transceive(dev1->spi_dev, &spi_cfg, &tx_set, &rx_set);
gpio_pin_set_dt(&dev1->cs_gpios, 1);
}
// 类似采样 dev2 (通道 16-31), offset samples[ch+16]
// Dummy for pipeline on dev2
gpio_pin_set_dt(&dev2->cs_gpios, 1);
spi_transceive(dev2->spi_dev, &spi_cfg, &tx_set, &rx_set);
gpio_pin_set_dt(&dev2->cs_gpios, 0);
for (int ch = 0; ch < 16; ch++) {
// CONVERT(ch): 00 C[5:0] 0000 0000 0000 0000, D=0 (AC only)
cmd[0] = 0x00;
cmd[1] = 0x00;
cmd[2] = (ch & 0x3F) << 2; // C[5:0] << 2
cmd[3] = 0x00;
gpio_pin_set_dt(&dev2->cs_gpios, 0);
spi_transceive(dev2->spi_dev,&spi_cfg, &tx_set, &rx_set);
gpio_pin_set_dt(&dev2->cs_gpios, 1);
samples[ch + 16] = (int16_t)((rx[0] << 8) | rx[1]); // AC high 16-bit
// 辅助命令 (dummy READ(255) for pipeline, M=1 clear compliance)
cmd[0] = 0xC4; // READ + M=1
cmd[1] = 0x00;
cmd[2] = 0xFF; // Reg 255
cmd[3] = 0xFF;
gpio_pin_set_dt(&dev2->cs_gpios, 0);
spi_transceive(dev2->spi_dev, &spi_cfg, &tx_set, &rx_set);
gpio_pin_set_dt(&dev2->cs_gpios, 1);
}
}
static const struct gpio_dt_spec en_vstim_spec = GPIO_DT_SPEC_GET(DT_PATH(zephyr_user), vstim_gpios);
static const struct gpio_dt_spec en_power_spec = GPIO_DT_SPEC_GET(DT_PATH(zephyr_user), power_gpios);
// // I2C总线(从rtio_loopback参考)
// static const struct device *i2c_bus = DEVICE_DT_GET(DT_NODELABEL(i2c1));
// // LT3582 I2C地址(7位)
// #define LT3582_ADDR 0x45
// static int configure_lt3582(void) {
// struct i2c_msg msg;
// uint8_t buf[2];
// int ret;
// // 1. 写CMDR (0x04): SWOFF=1 (0x10) + PUSEQ=3 (0x03) = 0x13 (禁用开关,设序列)
// buf[0] = 0x04; // 寄存器地址
// buf[1] = 0x13; // 值
// msg.buf = buf;
// msg.len = 2;
// msg.flags = I2C_MSG_WRITE | I2C_MSG_STOP;
// ret = i2c_transfer(i2c_bus, LT3582_ADDR, &msg, 1);
// if (ret) {
// printk("LT3582 CMDR write failed: %d\n", ret);
// return ret;
// }
// printk("LT3582 CMDR set (SWOFF=1, PUSEQ=11)\n");
// // 2. 写REG0 (0x00): Vp=36 (0x24) for VOUTP=5V
// buf[0] = 0x00;
// buf[1] = 0x24;
// ret = i2c_transfer(i2c_bus, LT3582_ADDR, &msg, 1);
// if (ret) {
// printk("LT3582 REG0 write failed: %d\n", ret);
// return ret;
// }
// printk("LT3582 Vp set to 36 (VOUTP=5V)\n");
// // 3. 写REG1 (0x01): Vn=76 (0x4C) for VOUTN=-5V
// buf[0] = 0x01;
// buf[1] = 0x4C;
// ret = i2c_transfer(i2c_bus, LT3582_ADDR, &msg, 1);
// if (ret) {
// printk("LT3582 REG1 write failed: %d\n", ret);
// return ret;
// }
// printk("LT3582 Vn set to 76 (VOUTN=-5V)\n");
// // 4. 写CMDR (0x04): 清SWOFF=0 (0x00) + 保持PUSEQ=3 (0x03) = 0x03 (启用开关)
// buf[0] = 0x04;
// buf[1] = 0x03;
// ret = i2c_transfer(i2c_bus, LT3582_ADDR, &msg, 1);
// if (ret) {
// printk("LT3582 CMDR enable failed: %d\n", ret);
// return ret;
// }
// printk("LT3582 enabled (SWOFF=0)\n");
// return 0;
// }
// #define TX_RETRY_QUEUE_SIZE 10 // 重试队列深度
// static K_FIFO_DEFINE(tx_retry_fifo); // FIFO for retry
// struct tx_packet {
// uint8_t data[242];
// uint16_t len;
// };
// static void ADC_update(void)
// {
// //生成假数据(忽略ADS1299,模拟24字节/采样)
// for (uint8_t i = 0; i < 242; i++) {
// //ble_ADC[counter * 24+ i + 2] = i; // 假数据:每个通道固定值i(0-23),偏移2字节包头
// ble_ADC[i+2]=i;
// }
// //counter++; // 递增计数器
// //if (counter == 10) { // 累积10次(240字节 + 包头/序列号 = 242字节)
// // 复制到发送缓冲
// for (uint16_t i = 0; i < 242; i++) {
// ble_Tx[i] = ble_ADC[i];
// }
// ble_Tx[1] = (uint8_t)bag++; // 设置序列号(低8位),递增
// if (bag > 0xFF) bag = 0; // 循环0-255
// // 确保连续性(类似THI_update逻辑)
// if (LASTbag != (ble_Tx[1] - 1)) {
// ble_Tx[1] = (uint8_t)(LASTbag + 1);
// }
// LASTbag = ble_Tx[1];
// // 发送通过NUS(Zephyr API)
// //bt_nus_send(NULL, ble_Tx, 242);
// struct tx_packet *pkt = k_malloc(sizeof(struct tx_packet));
// if (!pkt) {
// printk("Malloc failed\n");
// return;
// }
// memcpy(pkt->data, ble_Tx, 242);
// pkt->len = 242;
// gpio_pin_toggle_dt(&led);
// int err = bt_nus_send(NULL, pkt->data, pkt->len);
// if (err) {
// // if (err == -ENOMEM) {
// // k_fifo_put(&tx_retry_fifo, pkt); // 入队重试
// //printk("ENOBUFS, queued for retry%d\n",err);}
// }
// else{
// // printk("ENOMEM, queued for retry%d\n",err);
// }
// // } //else {
// // printk("Send failed: %d\n", err);
// // k_free(pkt);
// // }
// // } else {
// // printk("Sent packet %d\n", LASTbag);
// // k_free(pkt);
// // }
// k_free(pkt);
// // counter = 0; // 重置计数器
// //}
// // 简单延时模拟采样间隔(可选,Zephyr中定时器已控制周期)
// //k_sleep(K_MSEC(1)); // 替换空循环,1ms稳定
// }
static void ADC_update(void)
{
//生成假数据(忽略ADS1299,模拟24字节/采样)
for (uint8_t i = 0; i < 194; i++) {
//ble_ADC[counter * 24+ i + 2] = i; // 假数据:每个通道固定值i(0-23),偏移2字节包头
// if (i < 121) {
// ble_ADC[i + 2] = 0; // 前一半(0~120):设为0
// } else {
// ble_ADC[i + 2] = 1; // 后一半(121~241):设为1
// }
// ble_ADC[i+2]=i;
if(ble_ADC[i+2]==255)
ble_ADC[i+2]=0;
else
ble_ADC[i+2]=255;
}
//counter++; // 递增计数器
//if (counter == 10) { // 累积10次(240字节 + 包头/序列号 = 242字节)
// 复制到发送缓冲
for (uint16_t i = 0; i < 194; i++) {
ble_Tx[i] = ble_ADC[i];
}
ble_Tx[1] = (uint8_t)bag++; // 设置序列号(低8位),递增
if (bag > 0xFF) bag = 0; // 循环0-255
// 确保连续性(类似THI_update逻辑)
if (LASTbag != (ble_Tx[1] - 1)) {
ble_Tx[1] = (uint8_t)(LASTbag + 1);
}
LASTbag = ble_Tx[1];
// 发送通过NUS(Zephyr API)
//bt_nus_send(NULL, ble_Tx, 242);
gpio_pin_toggle_dt(&led);
bt_nus_send(NULL, ble_Tx, 194);
// int err = bt_nus_send(NULL, ble_Tx, 242);
// if (err) {
// printk("Failed to send: %d\n", err); // 调试:错误如 -ENOMEM (资源不足,重试机制可加)
// } else {
// printk("Sent packet %d (242 bytes)\n", LASTbag); // 性能监控
// }
// counter = 0; // 重置计数器
//}
// 简单延时模拟采样间隔(可选,Zephyr中定时器已控制周期)
//k_sleep(K_MSEC(1)); // 替换空循环,1ms稳定
}
static void adc_timer_handler(struct k_timer *timer_id)
{
ARG_UNUSED(timer_id); // 避免未用警告
//ADC_update(); // 调用更新函数
k_work_submit(&adc_work);
}
static void adc_work_handler(struct k_work *work)
{
ARG_UNUSED(work);
ADC_update();
}
// static void uart_cb(const struct device *dev, struct uart_event *evt, void *user_data)
// {
// ARG_UNUSED(dev);
// // static uint8_t*current_buf;
// static bool buf_release;
// static size_t aborted_len;
// struct uart_data_t *buf;
// static uint8_t *aborted_buf;
// static bool disable_req;
// switch (evt->type) {
// case UART_TX_DONE:
// LOG_DBG("UART_TX_DONE");
// if ((evt->data.tx.len == 0) ||
// (!evt->data.tx.buf)) {
// return;
// }
// if (aborted_buf) {
// buf = CONTAINER_OF(aborted_buf, struct uart_data_t,
// data[0]);
// aborted_buf = NULL;
// aborted_len = 0;
// } else {
// buf = CONTAINER_OF(evt->data.tx.buf, struct uart_data_t,
// data[0]);
// }
// k_free(buf);
// buf = k_fifo_get(&fifo_uart_tx_data, K_NO_WAIT);
// if (!buf) {
// return;
// }
// if (uart_tx(uart, buf->data, buf->len, SYS_FOREVER_MS)) {
// LOG_WRN("Failed to send data over UART");
// }
// break;
// case UART_RX_RDY:
// LOG_DBG("UART_RX_RDY");
// buf = CONTAINER_OF(evt->data.rx.buf, struct uart_data_t, data[0]);
// buf->len += evt->data.rx.len;
// buf_release=false;
// if (disable_req) {
// return;
// }
// if ((evt->data.rx.buf[buf->len - 1] == '\n') ||
// (evt->data.rx.buf[buf->len - 1] == '\r')) {
// disable_req = true;
// uart_rx_disable(uart);
// }
// break;
// case UART_RX_DISABLED:
// LOG_DBG("UART_RX_DISABLED");
// disable_req = false;
// buf = k_malloc(sizeof(*buf));
// if (buf) {
// buf->len = 0;
// } else {
// LOG_WRN("Not able to allocate UART receive buffer");
// k_work_reschedule(&uart_work, UART_WAIT_FOR_BUF_DELAY);
// return;
// }
// uart_rx_enable(uart, buf->data, sizeof(buf->data),
// UART_WAIT_FOR_RX);
// break;
// case UART_RX_BUF_REQUEST:
// LOG_DBG("UART_RX_BUF_REQUEST");
// buf = k_malloc(sizeof(*buf));
// if (buf) {
// buf->len = 0;
// uart_rx_buf_rsp(uart, buf->data, sizeof(buf->data));
// } else {
// LOG_WRN("Not able to allocate UART receive buffer");
// }
// break;
// case UART_RX_BUF_RELEASED:
// LOG_DBG("UART_RX_BUF_RELEASED");
// buf = CONTAINER_OF(evt->data.rx_buf.buf, struct uart_data_t,
// data[0]);
// if (buf->len > 0) {
// k_fifo_put(&fifo_uart_rx_data, buf);
// } else {
// k_free(buf);
// }
// break;
// case UART_TX_ABORTED:
// LOG_DBG("UART_TX_ABORTED");
// if (!aborted_buf) {
// aborted_buf = (uint8_t *)evt->data.tx.buf;
// }
// aborted_len += evt->data.tx.len;
// buf = CONTAINER_OF((void *)aborted_buf, struct uart_data_t,
// data);
// uart_tx(uart, &buf->data[aborted_len],
// buf->len - aborted_len, SYS_FOREVER_MS);
// break;
// default:
// break;
// }
// }
// static void uart_work_handler(struct k_work *item)
// {
// struct uart_data_t *buf;
// buf = k_malloc(sizeof(*buf));
// if (buf) {
// buf->len = 0;
// } else {
// LOG_WRN("Not able to allocate UART receive buffer");
// k_work_reschedule(&uart_work, UART_WAIT_FOR_BUF_DELAY);
// return;
// }
// uart_rx_enable(uart, buf->data, sizeof(buf->data), UART_WAIT_FOR_RX);
// }
// static bool uart_test_async_api(const struct device *dev)
// {
// const struct uart_driver_api *api =
// (const struct uart_driver_api *)dev->api;
// return (api->callback_set != NULL);
// }
// static int uart_init(void)
// {
// int err;
// int pos;
// struct uart_data_t *rx;
// struct uart_data_t *tx;
// if (!device_is_ready(uart)) {
// return -ENODEV;
// }
// if (IS_ENABLED(CONFIG_USB_DEVICE_STACK)) {
// err = usb_enable(NULL);
// if (err && (err != -EALREADY)) {
// LOG_ERR("Failed to enable USB");
// return err;
// }
// }
// rx = k_malloc(sizeof(*rx));
// if (rx) {
// rx->len = 0;
// } else {
// return -ENOMEM;
// }
// k_work_init_delayable(&uart_work, uart_work_handler);
// if (IS_ENABLED(CONFIG_UART_ASYNC_ADAPTER) && !uart_test_async_api(uart)) {
// /* Implement API adapter */
// uart_async_adapter_init(async_adapter, uart);
// uart = async_adapter;
// }
// err = uart_callback_set(uart, uart_cb, NULL);
// if (err) {
// k_free(rx);
// LOG_ERR("Cannot initialize UART callback");
// return err;
// }
// if (IS_ENABLED(CONFIG_UART_LINE_CTRL)) {
// LOG_INF("Wait for DTR");
// while (true) {
// uint32_t dtr = 0;
// uart_line_ctrl_get(uart, UART_LINE_CTRL_DTR, &dtr);
// if (dtr) {
// break;
// }
// /* Give CPU resources to low priority threads. */
// k_sleep(K_MSEC(100));
// }
// LOG_INF("DTR set");
// err = uart_line_ctrl_set(uart, UART_LINE_CTRL_DCD, 1);
// if (err) {
// LOG_WRN("Failed to set DCD, ret code %d", err);
// }
// err = uart_line_ctrl_set(uart, UART_LINE_CTRL_DSR, 1);
// if (err) {
// LOG_WRN("Failed to set DSR, ret code %d", err);
// }
// }
// tx = k_malloc(sizeof(*tx));
// if (tx) {
// pos = snprintf(tx->data, sizeof(tx->data),
// "Starting Nordic UART service sample\r\n");
// if ((pos < 0) || (pos >= sizeof(tx->data))) {
// k_free(rx);
// k_free(tx);
// LOG_ERR("snprintf returned %d", pos);
// return -ENOMEM;
// }
// tx->len = pos;
// } else {
// k_free(rx);
// return -ENOMEM;
// }
// err = uart_tx(uart, tx->data, tx->len, SYS_FOREVER_MS);
// if (err) {
// k_free(rx);
// k_free(tx);
// LOG_ERR("Cannot display welcome message (err: %d)", err);
// return err;
// }
// err = uart_rx_enable(uart, rx->data, sizeof(rx->data), UART_WAIT_FOR_RX);
// if (err) {
// LOG_ERR("Cannot enable uart reception (err: %d)", err);
// /* Free the rx buffer only because the tx buffer will be handled in the callback */
// k_free(rx);
// }
// return err;
// }
static void adv_work_handler(struct k_work *work)
{
int err = bt_le_adv_start(BT_LE_ADV_CONN_FAST_2, ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd));
if (err) {
LOG_ERR("Advertising failed to start (err %d)", err);
return;
}
LOG_INF("Advertising successfully started");
}
static void advertising_start(void)
{
k_work_submit(&adv_work);
}
static void update_data_length(struct bt_conn *conn)
{
int err;
struct bt_conn_le_data_len_param my_data_len = {
.tx_max_len = BT_GAP_DATA_LEN_MAX,
.tx_max_time = BT_GAP_DATA_TIME_MAX,
};
err = bt_conn_le_data_len_update(conn, &my_data_len);
if (err) {
LOG_ERR("data_len_update failed (err %d)", err);
}
}
static struct bt_gatt_exchange_params exchange_params;
static void update_mtu(struct bt_conn *conn)
{
int err;
exchange_params.func = exchange_func;
err = bt_gatt_exchange_mtu(conn, &exchange_params);
if (err) {
LOG_ERR("bt_gatt_exchange_mtu failed (err %d)", err);
}
}
static void exchange_func(struct bt_conn *conn, uint8_t att_err,
struct bt_gatt_exchange_params *params)
{
LOG_INF("MTU exchange %s", att_err == 0 ? "successful" : "failed");
if (!att_err) {
uint16_t payload_mtu = bt_gatt_get_mtu(conn) - 3; // 3 bytes used for Attribute headers.
LOG_INF("New MTU: %d bytes", payload_mtu);
}
}
void on_le_data_len_updated(struct bt_conn *conn, struct bt_conn_le_data_len_info *info)
{
uint16_t tx_len = info->tx_max_len;
uint16_t tx_time = info->tx_max_time;
uint16_t rx_len = info->rx_max_len;
uint16_t rx_time = info->rx_max_time;
LOG_INF("Data length updated. Length %d/%d bytes, time %d/%d us", tx_len, rx_len, tx_time, rx_time);
}
// static void mtu_exchange_cb(struct bt_conn *conn, uint8_t err, struct bt_gatt_exchange_params *params)
// {
// if (err) {
// printk("MTU exchange failed (err %u)\n", err);
// } else {
// size_t mtu_size = bt_gatt_get_mtu(conn);
// printk("MTU exchange successful, negotiated MTU: %zu\n", mtu_size);
// // 期望 mtu_size = 247(如果 central 支持 >= 247)
// }
// }
// // 定义 MTU 交换参数
// static struct bt_gatt_exchange_params mtu_params = {
// .func = mtu_exchange_cb,
// };
// static struct bt_conn*current_conn=NULL;
static void connected(struct bt_conn *conn, uint8_t err)
{
char addr[BT_ADDR_LE_STR_LEN];
if (err) {
LOG_ERR("Connection failed, err 0x%02x %s", err, bt_hci_err_to_str(err));
return;
}
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
LOG_INF("Connected %s", addr);
// 先发起 MTU 交换,并检查返回值
// int ret = bt_gatt_exchange_mtu(conn, &mtu_params);
// if (ret) {
// printk("MTU exchange request failed (err %d)\n", ret);
// if (ret == -EALREADY) {
// // 已交换过,直接获取当前 MTU
// size_t mtu_size = bt_gatt_get_mtu(conn);
// printk("MTU already exchanged, current MTU: %zu\n", mtu_size);
// } else {
// // 其他错误处理,例如重试或日志
// // 可根据需要添加重试逻辑:atomic_clear_bit(conn->flags, BT_CONN_ATT_MTU_EXCHANGED); 然后重试(调试用,非推荐)
// }
// }
struct bt_le_conn_param param={
.interval_min=0x0006,
.interval_max=0x0006,
.latency=0x0000,
.timeout=0x00C8,
};
bt_conn_le_param_update(conn,¶m);
struct bt_conn_le_phy_param phy_param ={
.pref_tx_phy=BT_GAP_LE_PHY_2M,
.pref_rx_phy=BT_GAP_LE_PHY_2M,
.options=0
};
bt_conn_le_phy_update(conn,&phy_param);
current_conn = bt_conn_ref(conn);
if (!current_conn) {
printk("Failed to reference connection");
return;
}
printk("Connection referenced successfully");
// k_work_delayable_init(¶m_update_work,param_update_work_handler);
// k_work_schedule(¶m_update_work,K_MSEC(300));
//k_timer_start(&adc_timer,K_MSEC(1000),K_MSEC(1000));
dk_set_led_on(CON_STATUS_LED);
#if defined(BLE_NUS_THROUGHPUT_MAX)
k_sem_give(&nus_connection_sem);
#endif
//uint16_t mtu;
//bt_gatt_exchange_mtu(conn,&mtu_params);
//size_t mtu_size=bt_gatt_get_mtu(conn);
k_sleep(K_MSEC(1000)); // Delay added to avoid link layer collisions.
update_data_length(conn);
update_mtu(conn);
//update_phy(conn);
}
// static void param_update_work_handler(struct k_work *work) {
// // 请求数据长度扩展
// bt_conn_le_data_len_update(current_conn, BT_LE_DATA_LEN_PARAM(BT_LE_DATA_LEN_PARAM_MAX));
// // 请求 PHY 更新(2Mbps)
// bt_conn_le_phy_update(current_conn, BT_CONN_LE_PHY_PARAM_2M);
// }
static void disconnected(struct bt_conn *conn, uint8_t reason)
{
char addr[BT_ADDR_LE_STR_LEN];
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
LOG_INF("Disconnected: %s, reason 0x%02x %s", addr, reason, bt_hci_err_to_str(reason));
if (auth_conn) {
bt_conn_unref(auth_conn);
auth_conn = NULL;
}
if (current_conn) {
bt_conn_unref(current_conn);
current_conn = NULL;
dk_set_led_off(CON_STATUS_LED);
}
}
// static struct bt_conn_cb conn_callbacks = {
// .connected=connected,
// .disconnected=disconnected,
// };
// bt_conn_cb_register(&conn_callbacks);
static void recycled_cb(void)
{
LOG_INF("Connection object available from previous conn. Disconnect is complete!");
advertising_start();
}
#ifdef CONFIG_BT_NUS_SECURITY_ENABLED
static void security_changed(struct bt_conn *conn, bt_security_t level,
enum bt_security_err err)
{
char addr[BT_ADDR_LE_STR_LEN];
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
if (!err) {
LOG_INF("Security changed: %s level %u", addr, level);
} else {
LOG_WRN("Security failed: %s level %u err %d %s", addr, level, err,
bt_security_err_to_str(err));
}
}
#endif
#if defined(BLE_NUS_THROUGHPUT_MAX)
static bool le_param_req(struct bt_conn *conn, struct bt_le_conn_param *param)
{
LOG_INF("Connection parameters update request received.");
LOG_INF("Minimum interval: %d, Maximum interval: %d",
param->interval_min, param->interval_max);
LOG_INF("Latency: %d, Timeout: %d", param->latency, param->timeout);
return true;
}
static void le_param_updated(struct bt_conn *conn, uint16_t interval,
uint16_t latency, uint16_t timeout)
{
LOG_INF("Connection parameters updated."
" interval: %d, latency: %d, timeout: %d",
interval, latency, timeout);
}
static void le_phy_updated(struct bt_conn *conn,
struct bt_conn_le_phy_info *param)
{
LOG_INF("LE PHY updated: TX PHY %s, RX PHY %s",
phy2str(param->tx_phy), phy2str(param->rx_phy));
}
static void le_data_length_updated(struct bt_conn *conn,
struct bt_conn_le_data_len_info *info)
{
LOG_INF("LE data len updated: TX (len: %d time: %d)"
" RX (len: %d time: %d)", info->tx_max_len,
info->tx_max_time, info->rx_max_len, info->rx_max_time);
}
#endif
BT_CONN_CB_DEFINE(conn_callbacks) = {
.connected = connected,
.disconnected = disconnected,
.recycled = recycled_cb,
.le_data_len_updated = on_le_data_len_updated,
#if defined(BLE_NUS_THROUGHPUT_MAX)
.le_param_req = le_param_req,
.le_param_updated = le_param_updated,
.le_phy_updated = le_phy_updated,
.le_data_len_updated = le_data_length_updated,
#endif
#ifdef CONFIG_BT_NUS_SECURITY_ENABLED
.security_changed = security_changed,
#endif
};
#if defined(CONFIG_BT_NUS_SECURITY_ENABLED)
static void auth_passkey_display(struct bt_conn *conn, unsigned int passkey)
{
char addr[BT_ADDR_LE_STR_LEN];
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
LOG_INF("Passkey for %s: %06u", addr, passkey);
}
static void auth_passkey_confirm(struct bt_conn *conn, unsigned int passkey)
{
char addr[BT_ADDR_LE_STR_LEN];
auth_conn = bt_conn_ref(conn);
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
LOG_INF("Passkey for %s: %06u", addr, passkey);
if (IS_ENABLED(CONFIG_SOC_SERIES_NRF54HX) || IS_ENABLED(CONFIG_SOC_SERIES_NRF54LX)) {
LOG_INF("Press Button 0 to confirm, Button 1 to reject.");
} else {
LOG_INF("Press Button 1 to confirm, Button 2 to reject.");
}
}
static void auth_cancel(struct bt_conn *conn)
{
char addr[BT_ADDR_LE_STR_LEN];
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
LOG_INF("Pairing cancelled: %s", addr);
}
static void pairing_complete(struct bt_conn *conn, bool bonded)
{
char addr[BT_ADDR_LE_STR_LEN];
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
LOG_INF("Pairing completed: %s, bonded: %d", addr, bonded);
}
static void pairing_failed(struct bt_conn *conn, enum bt_security_err reason)
{
char addr[BT_ADDR_LE_STR_LEN];
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
LOG_INF("Pairing failed conn: %s, reason %d %s", addr, reason,
bt_security_err_to_str(reason));
}
static struct bt_conn_auth_cb conn_auth_callbacks = {
.passkey_display = auth_passkey_display,
.passkey_confirm = auth_passkey_confirm,
.cancel = auth_cancel,
};
static struct bt_conn_auth_info_cb conn_auth_info_callbacks = {
.pairing_complete = pairing_complete,
.pairing_failed = pairing_failed
};
#else
static struct bt_conn_auth_cb conn_auth_callbacks;
static struct bt_conn_auth_info_cb conn_auth_info_callbacks;
#endif
static void bt_receive_cb(struct bt_conn *conn, const uint8_t *const data,
uint16_t len)
{
// int err;
// char addr[BT_ADDR_LE_STR_LEN] = {0};
// bt_addr_le_to_str(bt_conn_get_dst(conn), addr, ARRAY_SIZE(addr));
// LOG_INF("Received data from: %s", addr);
// for (uint16_t pos = 0; pos != len;) {
// struct uart_data_t *tx = k_malloc(sizeof(*tx));
// if (!tx) {
// LOG_WRN("Not able to allocate UART send data buffer");
// return;
// }
// /* Keep the last byte of TX buffer for potential LF char. */
// size_t tx_data_size = sizeof(tx->data) - 1;
// if ((len - pos) > tx_data_size) {
// tx->len = tx_data_size;
// } else {
// tx->len = (len - pos);
// }
// memcpy(tx->data, &data[pos], tx->len);
// pos += tx->len;
// /* Append the LF character when the CR character triggered
// * transmission from the peer.
// */
// if ((pos == len) && (data[len - 1] == '\r')) {
// tx->data[tx->len] = '\n';
// tx->len++;
// }
// err = uart_tx(uart, tx->data, tx->len, SYS_FOREVER_MS);
// if (err) {
// k_fifo_put(&fifo_uart_tx_data, tx);
// }
// }
}
static struct bt_nus_cb nus_cb = {
.received = bt_receive_cb,
};
void error(void)
{
dk_set_leds_state(DK_ALL_LEDS_MSK, DK_NO_LEDS_MSK);
while (true) {
/* Spin for ever */
k_sleep(K_MSEC(1000));
}
}
#ifdef CONFIG_BT_NUS_SECURITY_ENABLED
static void num_comp_reply(bool accept)
{
if (accept) {
bt_conn_auth_passkey_confirm(auth_conn);
LOG_INF("Numeric Match, conn %p", (void *)auth_conn);
} else {
bt_conn_auth_cancel(auth_conn);
LOG_INF("Numeric Reject, conn %p", (void *)auth_conn);
}
bt_conn_unref(auth_conn);
auth_conn = NULL;
}
void button_changed(uint32_t button_state, uint32_t has_changed)
{
uint32_t buttons = button_state & has_changed;
if (auth_conn) {
if (buttons & KEY_PASSKEY_ACCEPT) {
num_comp_reply(true);
}
if (buttons & KEY_PASSKEY_REJECT) {
num_comp_reply(false);
}
}
}
#endif /* CONFIG_BT_NUS_SECURITY_ENABLED */
static void configure_gpio(void)
{
int err;
#ifdef CONFIG_BT_NUS_SECURITY_ENABLED
err = dk_buttons_init(button_changed);
if (err) {
LOG_ERR("Cannot init buttons (err: %d)", err);
}
#endif /* CONFIG_BT_NUS_SECURITY_ENABLED */
err = dk_leds_init();
if (err) {
LOG_ERR("Cannot init LEDs (err: %d)", err);
}
}
// 新增:采样线程函数
static void sampling_thread(void *arg1, void *arg2, void *arg3)
{
ARG_UNUSED(arg3); // 避免未用警告
struct rhs2116_dev *dev1 = (struct rhs2116_dev *)arg1;
struct rhs2116_dev *dev2 = (struct rhs2116_dev *)arg2;
int16_t samples[32];
while (1) {
rhs_sample_all(dev1, dev2, samples); // 采样 32 通道
// 输出示例(可替换为 bt_nus_send 打包发送)
for (int i = 0; i < 32; i++) {
printk("CH%d: %d (uV: %.3f)\n", i, samples[i], samples[i] * 0.195f);
// TODO: 打包 samples 到 ble_Tx 并 bt_nus_send(NULL, ble_Tx, len);
}
k_msleep(33); // ~30 kS/s 采样率
}
}
// 全局:线程栈和 ID 定义(文件作用域,避免 section 错误)
K_THREAD_STACK_DEFINE(sampling_thread_stack, 512); // 2048 字节 / sizeof(void*) = 512 words (ARM 32-bit)
struct k_thread sampling_thread_id; // 线程 ID 声明
int main(void)
{
int blink_status = 0;
int err = 0;
configure_gpio();
int ret;
// 3. 再使能TPS631010: GPIO EN_POWER = 高
ret = gpio_pin_configure_dt(&en_power_spec, GPIO_OUTPUT_ACTIVE);
if (ret < 0) {
printk("EN_POWER configure failed: %d\n", ret);
return -1;
}
gpio_pin_set_dt(&en_power_spec, 1); // 高电平
printk("EN_POWER enabled (TPS631010 active)\n");
// 1. 先使能LT3582: GPIO EN_Vstim = 高
ret = gpio_pin_configure_dt(&en_vstim_spec, GPIO_OUTPUT_ACTIVE);
if (ret < 0) {
printk("EN_Vstim configure failed: %d\n", ret);
return -1;
}
gpio_pin_set_dt(&en_vstim_spec, 1); // 高电平
printk("EN_Vstim enabled\n");
// k_msleep(10); // 短暂延时,确保稳定(可选)
// //2. 配置LT3582 I2C
// ret = configure_lt3582();
// if (ret < 0) {
// printk("LT3582 config failed\n");
// return -1;
// }
// k_msleep(100); // 等待电压稳定(根据手册软启动时间调整)
// // 3. 再使能TPS631010: GPIO EN_POWER = 高
// ret = gpio_pin_configure_dt(&en_power_spec, GPIO_OUTPUT_ACTIVE);
// if (ret < 0) {
// printk("EN_POWER configure failed: %d\n", ret);
// return -1;
// }
// gpio_pin_set_dt(&en_power_spec, 1); // 高电平
// printk("EN_POWER enabled (TPS631010 active)\n");
// err = uart_init();
// if (err) {
// error();
// }
if (IS_ENABLED(CONFIG_BT_NUS_SECURITY_ENABLED)) {
err = bt_conn_auth_cb_register(&conn_auth_callbacks);
if (err) {
LOG_ERR("Failed to register authorization callbacks. (err: %d)", err);
return 0;
}
err = bt_conn_auth_info_cb_register(&conn_auth_info_callbacks);
if (err) {
LOG_ERR("Failed to register authorization info callbacks. (err: %d)", err);
return 0;
}
}
err = bt_enable(NULL);
if (err) {
error();
}
LOG_INF("Bluetooth initialized");
const struct device *spi3 = DEVICE_DT_GET(DT_NODELABEL(spi3));
const struct device *spi4 = DEVICE_DT_GET(DT_NODELABEL(spi4));
// if (!device_is_ready(spi3) || !device_is_ready(spi4)) {
// printk("SPI not ready\n");
// return 0;
// //goto ble_only;
// }
// // 手动定义 CS GPIO (避免 DT_NODELABEL(rhs2116))
// struct gpio_dt_spec cs1 = {
// .port = DEVICE_DT_GET(DT_NODELABEL(gpio0)),
// .pin = 15,
// .dt_flags = GPIO_ACTIVE_LOW,
// };
// struct gpio_dt_spec cs2 = {
// .port = DEVICE_DT_GET(DT_NODELABEL(gpio0)),
// .pin = 3,
// .dt_flags = GPIO_ACTIVE_LOW,
// };
// struct rhs2116_dev rhs1 = {.spi_dev = spi3, .cs_gpios = cs1};
// struct rhs2116_dev rhs2 = {.spi_dev = spi4, .cs_gpios = cs2};
// gpio_pin_configure_dt(&rhs1.cs_gpios, GPIO_OUTPUT_ACTIVE);
// gpio_pin_configure_dt(&rhs2.cs_gpios, GPIO_OUTPUT_ACTIVE);
// err = rhs_init(&rhs1);
// if (err) { printk("RHS1 init failed %d\n", err); return 0; }
// err = rhs_init(&rhs2);
// if (err) { printk("RHS2 init failed %d\n", err); return 0; }
// k_thread_create(&sampling_thread_id, sampling_thread_stack, K_THREAD_STACK_SIZEOF(sampling_thread_stack),
// sampling_thread, &rhs1, &rhs2, NULL, 5, 0, K_FOREVER);
//ble_init:
k_sem_give(&ble_init_ok);
if (IS_ENABLED(CONFIG_SETTINGS)) {
settings_load();
}
err = bt_nus_init(&nus_cb);
if (err) {
LOG_ERR("Failed to initialize UART service (err: %d)", err);
return 0;
}
k_work_init(&adv_work, adv_work_handler);
k_work_init(&adc_work,adc_work_handler);
k_timer_init(&adc_timer,adc_timer_handler,NULL);
k_timer_start(&adc_timer,K_MSEC(3),K_MSEC(3));
advertising_start();
int rep;
//bool led_state = true;
if (!gpio_is_ready_dt(&led)) {
return 0;
}
rep = gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE);
if (rep < 0) {
return 0;
}
ble_ADC[0]=0x64;
for (;;) {
dk_set_led(RUN_STATUS_LED, (++blink_status) % 2);
//bt_nus_send(NULL, ble_Tx, 8);
k_sleep(K_MSEC(RUN_LED_BLINK_INTERVAL));
}
}
void ble_write_thread(void)
{
/* Don't go any further until BLE is initialized */
k_sem_take(&ble_init_ok, K_FOREVER);
struct uart_data_t nus_data = {
.len = 0,
};
for (;;) {
/* Wait indefinitely for data to be sent over bluetooth */
struct uart_data_t *buf = k_fifo_get(&fifo_uart_rx_data,
K_FOREVER);
int plen = MIN(sizeof(nus_data.data) - nus_data.len, buf->len);
int loc = 0;
while (plen > 0) {
memcpy(&nus_data.data[nus_data.len], &buf->data[loc], plen);
nus_data.len += plen;
loc += plen;
if (nus_data.len >= sizeof(nus_data.data) ||
(nus_data.data[nus_data.len - 1] == '\n') ||
(nus_data.data[nus_data.len - 1] == '\r')) {
if (bt_nus_send(NULL, nus_data.data, nus_data.len)) {
LOG_WRN("Failed to send data over BLE connection");
}
nus_data.len = 0;
}
plen = MIN(sizeof(nus_data.data), buf->len - loc);
}
k_free(buf);
}
}
// 启动采样线程(自动运行,无需手动启用)
// K_THREAD_DEFINE(sampling_thread_id, 2048, sampling_thread, &rhs1, &rhs2, NULL, 5, 0, 0);
// 参数解释:
// - sampling_thread_id: 线程 ID(全局变量,可用于后续控制,如 k_thread_abort())
// - 2048: 栈大小(字节,根据采样复杂度调整;32 通道采样建议 1-4KB)
// - sampling_thread: 线程入口函数
// - &rhs1, &rhs2: 参数传递给线程(arg1 和 arg2)
// - 5: 优先级(中等;BLE 线程通常更高,如 7)
// - 0, 0: 延迟和选项(默认)
// K_THREAD_DEFINE(ble_write_thread_id, STACKSIZE, ble_write_thread, NULL, NULL,
// NULL, PRIORITY, 0, 0);





