diff --git a/.vscode/settings.json b/.vscode/settings.json index 9b70645..55958d4 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -93,7 +93,12 @@ "heart_wave_sample_service.h": "c", "znordic_device_info_mgr.h": "c", "nrf_uart.h": "c", - "ads_cfg.h": "c" + "ads_cfg.h": "c", + "sdk_config.h": "c", + "app_ble_service.h": "c", + "nrfx_timer.h": "c", + "app_button.h": "c", + "nrf_drv_gpiote.h": "c" }, "files.encoding": "gbk" } \ No newline at end of file diff --git a/README.md b/README.md index 75e982e..c042055 100644 --- a/README.md +++ b/README.md @@ -2,278 +2,39 @@ ## 使用说明 -``` -https://iflytop1.feishu.cn/wiki/Fp0fwciUEibtm4kaUeXcraOCneg - -``` ``` -开发板IO资源说明: - -#define BSP_LED_0 13 -#define BSP_LED_1 14 -#define BSP_LED_2 15 -#define BSP_LED_3 16 - -#define BUTTON_1 11 // 上拉低电平有效 -#define BUTTON_2 12 // 上拉低电平有效 -#define BUTTON_3 24 // 上拉低电平有效 -#define BUTTON_4 25 // 上拉低电平有效 - -sdk\components\boards\pca10100.h - -清风开发板 - - AIN2 -> 光感 - -I2C -#define TWI_SCL_M 28 //I2C SCL引脚 -#define TWI_SDA_M 30 //I2C SDA引脚 - ------------------------------------- - - -PIN4 PIN30/PIN31 PIN28/PIN29 PIN11/PIN20 - - - - +TODO: + 1. 所有的文件操作如果失败系统会自动复位。(通过ZASSERT触发的复位操作) + 2. 电池电量校准 ``` ``` 设备行为: -1. 按下按键或者电极触发后开始广播 -2. 当电极没有触发,且蓝牙没有连接,且超时10s后,停止广播,进入低功耗模式 +开机条件 + 1.轻按按键 -3. 设备状态 +关机条件 + 1.长按按键3秒 + 2.蓝牙连接断开后10秒 - 关机(休眠) - 开机蓝牙未连接(广播中) - 蓝牙已连接 +开机: + 1.打开蓝牙广播 + 2.指示灯闪烁1s慢闪,蓝牙连接后指示灯常亮。 +关机: + 1.关闭蓝牙广播 -``` -``` -难点: - 1.采样间隔2ms (500HZ) - 2.数据往flash中写入时间消耗,cache选择多大,数据什么时候上报。 - 1. ADC:单次采样,阻塞拿数值(50us) - 2. 电池电量的采集ADC和电压采集ADC用的是同一个ADC +开始采集触发条件 + 1.设备开机 + 2.APP控制 + 3.当前没有在充电(硬件限制了此条件) - (这里先使用最简单的阻塞式ADC采集,电池ADC3次,采样ADC3次) +蜂鸣器触发条件: + 1. 开始采集,蜂鸣器响一声 + 2. 传感器脱落,每隔10秒,蜂鸣器响三声, -``` - -``` -屏幕驱动: -https://github.com/libdriver/ssd1306 -1306驱动和1312是一样的,只不过1312默认是镜像的 - -``` - -``` - -UI元素: -------------------- -1. 不同大小的字体 -2. 进度条 -3. [X] -4. APP -------------------- - - -1. 进度条 -2. 圈,x -3. 时间 -4. LOGO -5. [X] -6. HR -7. APP查看结果 -8. 年月日/时分秒 -9. 不同大小的字体 - - -xxx -+xx - - - LOGO - 进度条 - - 年月日 - 时分秒 - - - 保持静止 - ___________ - [===== ] - ------------ - - 心电图 - [===== ] - - [X] - 不足30秒 - - 正在保存 - [===== ] - - APP - 查看结果 -``` - - -``` -存储: -1帧 -2byte -200帧 -400byte -1秒 -400byte -30秒 -12kbyte -120秒 -48kbyte - ----------------------------- -2Mbit -256Kbyte - -640秒 /120 = 5条记录 - -256kbyte - -256byte索引 - -[ - ID:[年月日] - packetOFF:[] - usage[]: - date:[] -] -48kbyte --> 一个扇区 - -256/4k = 64个扇区 10s数据 - -openStorage(年月日) -writeData(){ - -// 数据量是否大于最大数值 - -// 是否还有空间 -// 擦除旧的空间 -// 写入数据 -// 写入缓存 - -// 是否刷新缓存? - -找到空闲扇区,写入数据。 -找不到空闲扇区,按照顺序释放旧的扇区 -重新寻找扇区 -} - -// 倍数读取 -readData(){ - 1. 判断数据在哪个扇区 - 3. 读取扇区数据信息 - 2. 读取数据 - 3. 拷贝数据 -} - -// Header - -[ - usage: - fileHeaderdata: - fileId: - dataoff: - datalen: -] - -{ - fileUUID:年月日时分秒 - sector:[1,2,3,4,5] - datalen: 100 - //分辨率 - //总时长 - //采样率 -} - - -``` - -``` -硬件异常: - 1. eeprom读写失败 - 2. 电池电量低 -``` - -``` -编程注意事项: -1. 使用了app_timer后,如果在系统中某个位置延时时间过程,会导致系统重启 - -TODO: -1. eeprom的文件扇区信息没有存储,也就是说每次电池用没了之后,数据会丢失 -2. 如果要实现不丢数据,需要在eeprom中存储文件扇区信息,同时由于扇区的大小大于256字节,所以需要优化eeprom的写入函数。 - -单导蓝牙使用注意事项: - - 1. 开机后 - 开启广播 - 2. 关机 - 关闭广播 - 关机条件: - 1. 蓝牙断开 - 2. 设备未操作 - 3. 30s内无任何蓝牙指令(连接) - - - 1. 蓝牙的广播的启停独立控制和设备开机关机逻辑分开 - 开启广播:开机时候,如果当前没有开启广播,则打开广播 - 关闭广播: 关机后30s内无连接关闭广播 - 断开连接后30s关闭广播 - - 2. 蓝牙状态指示灯: - 1. 蓝牙广播打开:指示灯闪烁 - 2. 蓝牙广播关闭:指示灯关闭 - - 3. 采样时不支持电量上报 - 4. 采样时不支持记录查询相关指令 - 5. 不支持删除采样记录 - -``` - -``` -任务: - 16. 解决断开连接,再次唤醒,屏幕无显示的BUG OK TESTOK - 1. 提取休眠时间到宏配置中 OK - 9. 支持数据实时上报 OK TEST1/2OK,有数据,但数据是否正确,校验起来不方便 - 12. 支持数据上传 OK TESTOK - 15. 检查设备状态 OK TESTOK - 14. 支持掉落事件 OK TESTOK - - 6. 支持电池电量采集 OK - 8. 采集完30秒,蜂鸣器滴一声,采集完成,蜂鸣器滴一声 OK - 16. 调整UI位置 - 11. 死机后一直重启的BUG OK - 12. 修改蓝牙名称 OK - --------------------------------------------------------------- - 2. UI添加蓝牙状态 - 3. UI添加上传状态 - 4. UI添加心率计算 - 5. UI添加心脏跳动效果 - 7. 校准电池电量采集 - 7. 添加心率 - 10. 添加OTA支持 - 11. 数据掉电不丢失 - 12. 优化定时器周期 - 13. 支持低电量事件 - 14. 添加设备激活逻辑,根据设备是否通过过时间来判断当前是否彻底断电。 - 15. 优化蜂鸣器的声音 - ``` \ No newline at end of file diff --git a/app/app.uvoptx b/app/app.uvoptx index eabbfe4..2c9aab7 100644 --- a/app/app.uvoptx +++ b/app/app.uvoptx @@ -439,6 +439,18 @@ 0 0 + + 1 + 7 + 1 + 0 + 0 + 0 + .\src\app_ble_service.c + app_ble_service.c + 0 + 0 + @@ -449,7 +461,7 @@ 0 2 - 7 + 8 1 0 0 @@ -469,7 +481,7 @@ 0 3 - 8 + 9 1 0 0 @@ -481,7 +493,7 @@ 3 - 9 + 10 1 0 0 @@ -501,7 +513,7 @@ 0 4 - 10 + 11 1 0 0 @@ -521,7 +533,7 @@ 0 5 - 11 + 12 1 0 0 @@ -533,7 +545,7 @@ 5 - 12 + 13 1 0 0 @@ -545,7 +557,7 @@ 5 - 13 + 14 1 0 0 @@ -557,7 +569,7 @@ 5 - 14 + 15 1 0 0 @@ -569,7 +581,7 @@ 5 - 15 + 16 1 0 0 @@ -581,7 +593,7 @@ 5 - 16 + 17 1 0 0 @@ -593,7 +605,7 @@ 5 - 17 + 18 1 0 0 @@ -605,7 +617,7 @@ 5 - 18 + 19 1 0 0 @@ -625,7 +637,7 @@ 0 6 - 19 + 20 1 0 0 @@ -645,7 +657,7 @@ 0 7 - 20 + 21 1 0 0 @@ -657,7 +669,7 @@ 7 - 21 + 22 1 0 0 @@ -669,7 +681,7 @@ 7 - 22 + 23 1 0 0 @@ -681,7 +693,7 @@ 7 - 23 + 24 1 0 0 @@ -693,7 +705,7 @@ 7 - 24 + 25 1 0 0 @@ -705,7 +717,7 @@ 7 - 25 + 26 1 0 0 @@ -717,7 +729,7 @@ 7 - 26 + 27 1 0 0 @@ -729,7 +741,7 @@ 7 - 27 + 28 1 0 0 @@ -741,7 +753,7 @@ 7 - 28 + 29 1 0 0 @@ -753,7 +765,7 @@ 7 - 29 + 30 1 0 0 @@ -765,7 +777,7 @@ 7 - 30 + 31 1 0 0 @@ -777,7 +789,7 @@ 7 - 31 + 32 1 0 0 @@ -789,7 +801,7 @@ 7 - 32 + 33 1 0 0 @@ -801,7 +813,7 @@ 7 - 33 + 34 1 0 0 @@ -813,7 +825,7 @@ 7 - 34 + 35 1 0 0 @@ -825,7 +837,7 @@ 7 - 35 + 36 1 0 0 @@ -837,7 +849,7 @@ 7 - 36 + 37 1 0 0 @@ -849,7 +861,7 @@ 7 - 37 + 38 1 0 0 @@ -861,7 +873,7 @@ 7 - 38 + 39 1 0 0 @@ -873,7 +885,7 @@ 7 - 39 + 40 1 0 0 @@ -893,7 +905,7 @@ 0 8 - 40 + 41 1 0 0 @@ -905,7 +917,7 @@ 8 - 41 + 42 1 0 0 @@ -917,7 +929,7 @@ 8 - 42 + 43 1 0 0 @@ -929,7 +941,7 @@ 8 - 43 + 44 1 0 0 @@ -941,7 +953,7 @@ 8 - 44 + 45 1 0 0 @@ -953,7 +965,7 @@ 8 - 45 + 46 1 0 0 @@ -965,7 +977,7 @@ 8 - 46 + 47 1 0 0 @@ -977,7 +989,7 @@ 8 - 47 + 48 1 0 0 @@ -989,7 +1001,7 @@ 8 - 48 + 49 1 0 0 @@ -1001,7 +1013,7 @@ 8 - 49 + 50 1 0 0 @@ -1013,7 +1025,7 @@ 8 - 50 + 51 1 0 0 @@ -1025,7 +1037,7 @@ 8 - 51 + 52 1 0 0 @@ -1037,7 +1049,7 @@ 8 - 52 + 53 1 0 0 @@ -1049,7 +1061,7 @@ 8 - 53 + 54 1 0 0 @@ -1061,7 +1073,7 @@ 8 - 54 + 55 1 0 0 @@ -1073,7 +1085,7 @@ 8 - 55 + 56 1 0 0 @@ -1085,7 +1097,7 @@ 8 - 56 + 57 1 0 0 @@ -1097,7 +1109,7 @@ 8 - 57 + 58 1 0 0 @@ -1109,7 +1121,7 @@ 8 - 58 + 59 1 0 0 @@ -1121,7 +1133,7 @@ 8 - 59 + 60 1 0 0 @@ -1133,7 +1145,7 @@ 8 - 60 + 61 1 0 0 @@ -1145,7 +1157,7 @@ 8 - 61 + 62 1 0 0 @@ -1157,7 +1169,7 @@ 8 - 62 + 63 1 0 0 @@ -1169,7 +1181,7 @@ 8 - 63 + 64 1 0 0 @@ -1181,7 +1193,7 @@ 8 - 64 + 65 1 0 0 @@ -1193,7 +1205,7 @@ 8 - 65 + 66 1 0 0 @@ -1205,7 +1217,7 @@ 8 - 66 + 67 1 0 0 @@ -1225,7 +1237,7 @@ 0 9 - 67 + 68 1 0 0 @@ -1237,7 +1249,7 @@ 9 - 68 + 69 1 0 0 @@ -1249,7 +1261,7 @@ 9 - 69 + 70 1 0 0 @@ -1261,7 +1273,7 @@ 9 - 70 + 71 1 0 0 @@ -1273,7 +1285,7 @@ 9 - 71 + 72 1 0 0 @@ -1285,7 +1297,7 @@ 9 - 72 + 73 1 0 0 @@ -1305,7 +1317,7 @@ 0 10 - 73 + 74 1 0 0 @@ -1317,7 +1329,7 @@ 10 - 74 + 75 1 0 0 @@ -1329,7 +1341,7 @@ 10 - 75 + 76 1 0 0 @@ -1349,7 +1361,7 @@ 0 11 - 76 + 77 1 0 0 @@ -1361,7 +1373,7 @@ 11 - 77 + 78 1 0 0 @@ -1373,7 +1385,7 @@ 11 - 78 + 79 1 0 0 @@ -1393,7 +1405,7 @@ 0 12 - 79 + 80 1 0 0 @@ -1413,7 +1425,7 @@ 0 13 - 80 + 81 1 0 0 @@ -1425,7 +1437,7 @@ 13 - 81 + 82 1 0 0 diff --git a/app/app.uvprojx b/app/app.uvprojx index 1121919..907dea7 100644 --- a/app/app.uvprojx +++ b/app/app.uvprojx @@ -413,6 +413,11 @@ 1 ..\libznordic\src\zdatachannel_service.c + + app_ble_service.c + 1 + .\src\app_ble_service.c + @@ -4172,6 +4177,11 @@ 1 ..\libznordic\src\zdatachannel_service.c + + app_ble_service.c + 1 + .\src\app_ble_service.c + diff --git a/app/config/sdk_config.h b/app/config/sdk_config.h index b5f7a21..bc77afc 100644 --- a/app/config/sdk_config.h +++ b/app/config/sdk_config.h @@ -7794,7 +7794,7 @@ // <268435456=> 1000000 baud #ifndef NRF_LOG_BACKEND_UART_BAUDRATE -#define NRF_LOG_BACKEND_UART_BAUDRATE 251658240 +#define NRF_LOG_BACKEND_UART_BAUDRATE 30801920 #endif // NRF_LOG_BACKEND_UART_TEMP_BUFFER_SIZE - Size of buffer for partially processed strings. @@ -9971,7 +9971,7 @@ // NRF_CLI_BLE_UART_CONFIG_LOG_ENABLED - Enables logging in the module. //========================================================== #ifndef NRF_CLI_BLE_UART_CONFIG_LOG_ENABLED -#define NRF_CLI_BLE_UART_CONFIG_LOG_ENABLED 0 +#define NRF_CLI_BLE_UART_CONFIG_LOG_ENABLED 1 #endif // NRF_CLI_BLE_UART_CONFIG_LOG_LEVEL - Default Severity level diff --git a/app/src/app_ble_service.c b/app/src/app_ble_service.c new file mode 100644 index 0000000..923e224 --- /dev/null +++ b/app/src/app_ble_service.c @@ -0,0 +1,57 @@ +#include "app_ble_service.h" + +#include "app_scheduler.h" +#include "zdatachannel_service.h" +#include "znordic.h" +static zdatachannel_init_t zdatachannle_init; + +static uint8_t rxbufcache[256]; +static bool is_rxbufcache_used = false; + +static void prvf_process_ble_rx_data(void* p_event_data, uint16_t event_size); + +/******************************************************************************* + * 蓝牙服务注册 * + *******************************************************************************/ +ZDATACHANNEL_DEF(m_zhrs, 2 /*优先级*/, 1 /*client num*/); +/** + * @brief 蓝牙消息回调 + */ +static void zdatachannel_data_handler(zdatachannel_evt_t* p_evt) { + if (p_evt->type != ZDATACHANNEL_EVT_RX_DATA) { + return; + } + + // 消息正在被处理中,丢弃新来的消息 + if (is_rxbufcache_used) return; + if (p_evt->params.rx_data.length > sizeof(rxbufcache)) return; + + memcpy(rxbufcache, p_evt->params.rx_data.p_data, p_evt->params.rx_data.length); + uint32_t suc = app_sched_event_put(rxbufcache, p_evt->params.rx_data.length, prvf_process_ble_rx_data); + if (suc == 0) { + is_rxbufcache_used = true; + } +} + +/******************************************************************************* + * 消息处理 * + *******************************************************************************/ +static void prvf_process_ble_rx_data(void* p_event_data, uint16_t data_size) { + ZLOGI("rx:"); + NRF_LOG_HEXDUMP_INFO(p_event_data, data_size); +} + +void AppBleService_startAdv() { zble_module_start_adv(); } +void AppBleService_stopAdv() { zble_module_stop_adv(); } + +void AppBleService_onServiceInitCB() { + ZLOGI("init zdatachannel service"); + zdatachannel_init_t zdatachannle_init; + memset(&zdatachannle_init, 0, sizeof(zdatachannle_init)); + zdatachannle_init.data_handler = zdatachannel_data_handler; + ZERROR_CHECK(zdatachannel_init(&m_zhrs, &zdatachannle_init)); +} + +void AppBleService_init() { + // +} diff --git a/app/src/app_ble_service.h b/app/src/app_ble_service.h new file mode 100644 index 0000000..761a2b2 --- /dev/null +++ b/app/src/app_ble_service.h @@ -0,0 +1,13 @@ +#pragma once +#include + +/** + * @brief + * zble_module_init 方法将此回调注册进去 + */ +void AppBleService_onServiceInitCB(); + + +void AppBleService_init(); +void AppBleService_uninit(); +void AppBleService_startAdv(); diff --git a/app/src/app_event.h b/app/src/app_event.h new file mode 100644 index 0000000..27b2237 --- /dev/null +++ b/app/src/app_event.h @@ -0,0 +1,35 @@ +#pragma once +#include +#include + +#define LITTLE_DATA_BLOCK_FRAME_NUM 4 // 每四帧回调一次 + +typedef enum { + kevent_sensor_drop = 0, // 导联连接事件 + kevent_tmr_scheduler, // 定时器调度事件 + kevent_capture_data_block_event, // 每采集一定数据后回调一次 + kevent_capture_little_data_block_event, // 传感器小数据块回调事件 +} app_event_type_t; + +typedef struct { + uint32_t data0; + uint32_t data1; + uint32_t data2; +} one_frame_data_t; + +typedef struct { + app_event_type_t eventType; + union { + struct { + uint32_t frameIndex; + one_frame_data_t data[LITTLE_DATA_BLOCK_FRAME_NUM]; + } little_data_block; + + struct { + uint8_t* data; // 不保证数据对齐 + int len; + } block_sensor_data; + } val; +} app_event_t; + +void app_event_process_cb(void* p_event_data, uint16_t event_size); \ No newline at end of file diff --git a/app/src/ble_cmd_process_service.c b/app/src/bak/ble_cmd_process_service.c similarity index 100% rename from app/src/ble_cmd_process_service.c rename to app/src/bak/ble_cmd_process_service.c diff --git a/app/src/ble_cmd_process_service.h b/app/src/bak/ble_cmd_process_service.h similarity index 100% rename from app/src/ble_cmd_process_service.h rename to app/src/bak/ble_cmd_process_service.h diff --git a/app/src/bak/heart_wave_sample_service.c b/app/src/bak/heart_wave_sample_service.c new file mode 100644 index 0000000..49ff56c --- /dev/null +++ b/app/src/bak/heart_wave_sample_service.c @@ -0,0 +1,152 @@ +#include "heart_wave_sample_service.h" + +#include "app_event.h" +#include "nrfx_timer.h" +#include "one_conduction_board.h" + +static const nrfx_timer_t m_timer = NRFX_TIMER_INSTANCE(1); /**< Timer used for channel sweeps and tx with duty cycle. */ +static bool m_timer_started = false; /**< True if timer is running. */ + +static uint16_t m_capture_buffer_a[128]; +static uint16_t m_capture_buffer_b[128]; + +static uint16_t* m_capture_buffer; +static uint16_t m_capture_buffer_index = 0; + +volatile static float m_sensor_display_data = 0; // 0->100 +static uint32_t m_start_capture_tp; +static uint32_t m_frameindex = 0; + +static void swap_buffer() { + if (m_capture_buffer == NULL) { + m_capture_buffer = m_capture_buffer_a; + m_capture_buffer_index = 0; + return; + } + + if (m_capture_buffer == m_capture_buffer_a) { + m_capture_buffer = m_capture_buffer_b; + } else { + m_capture_buffer = m_capture_buffer_a; + } + m_capture_buffer_index = 0; + return; +} +static float amp_val(uint16_t val, uint16_t valcener, float amp) { + float valf = (float)val - valcener; + valf = valf * amp; + valf += valcener; + + if (valf >= 100) { + valf = 100; + } + + if (valf <= 0) { + valf = 0; + } + return valf; +} + +typedef struct { + float value; + float efectiveFactor; +} filter_t; + +filter_t m_filter = {0, 0.8}; + +static float Filter(filter_t* filter, float newInput) { + float newv = ((float)filter->value * (1.0f - filter->efectiveFactor)) + ((float)newInput * filter->efectiveFactor); + filter->value = newv; + return newv; +} + +void nrfx_timer_event_handler(nrf_timer_event_t event_type, void* p_context) { // + uint16_t val = SingleLeadECG_ecg_plod_get_ecg_val(); // 12bit + m_frameindex++; + + /******************************************************************************* + * 显示数据计算并赋值 * + *******************************************************************************/ + float val_af100 = (float)val / 4096.0f * 100; + val_af100 = amp_val(val_af100, 50, 1.8f); + val_af100 = Filter(&m_filter, val_af100); + m_sensor_display_data = val_af100; + + /******************************************************************************* + * 采样数据缓存 * + *******************************************************************************/ + if (m_capture_buffer == NULL) { + swap_buffer(); + } + + if (m_capture_buffer_index < 128) { + m_capture_buffer[m_capture_buffer_index++] = val; + } + + if (m_capture_buffer_index == 128) { + app_event_t evt; + evt.eventType = kevent_capture_256data_event; + evt.val.capture_data_cache = (uint8_t*)m_capture_buffer; + swap_buffer(); + app_sched_event_put(&evt, sizeof(evt), app_event_process_cb); + } + + /******************************************************************************* + * 实时采样数据事件上报 * + *******************************************************************************/ + { + app_event_t evt; + evt.eventType = kevent_capture_1data_event; + evt.val.frame_data.frameIndex = m_frameindex; + evt.val.frame_data.data = val; + swap_buffer(); + app_sched_event_put(&evt, sizeof(evt), app_event_process_cb); + } +} + +void hwss_init(void) { + if (m_timer_started) { + return; + } + /** + * @brief 初始化定时器 + */ + nrfx_err_t err; + nrfx_timer_config_t timer_cfg = { + .frequency = NRF_TIMER_FREQ_125kHz, + .mode = NRF_TIMER_MODE_TIMER, + .bit_width = NRF_TIMER_BIT_WIDTH_24, + .p_context = NULL, + .interrupt_priority = NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY, + }; + + err = nrfx_timer_init(&m_timer, &timer_cfg, nrfx_timer_event_handler); + if (err != NRFX_SUCCESS) { + NRF_LOG_ERROR("nrfx_timer_init failed with: %d\n", err); + } + uint32_t timer_ticks = nrfx_timer_ms_to_ticks(&m_timer, 5); // 200HZ + nrfx_timer_extended_compare(&m_timer, NRF_TIMER_CC_CHANNEL0, timer_ticks, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, true); + m_timer_started = true; +} +void hwss_uninit(void) { nrfx_timer_disable(&m_timer); } + +void hwss_start_capture(void) { + m_start_capture_tp = znordic_getpower_on_s(); + swap_buffer(); + m_frameindex = 0; + nrfx_timer_enable(&m_timer); +} +void hwss_stop_capture(void) { + nrfx_timer_disable(&m_timer); + m_frameindex = 0; +} + +float hwss_read_val(void) { + __disable_irq(); + float val = m_sensor_display_data; + __enable_irq(); + return val; +} +float hwss_read_heart_rate(void) { return 0; } + +int hwss_has_captured_time_ms() { return (znordic_getpower_on_s() - m_start_capture_tp) * 1000; } diff --git a/app/src/bak/heart_wave_sample_service.h b/app/src/bak/heart_wave_sample_service.h new file mode 100644 index 0000000..65e18dc --- /dev/null +++ b/app/src/bak/heart_wave_sample_service.h @@ -0,0 +1,15 @@ +#pragma once +#include "one_conduction_board.h" + +// 每256个字节触发一次回调 +typedef void (*heart_wave_sample_service_callback_t)(uint16_t *p_data, uint16_t length); + +void hwss_init(void); +void hwss_uninit(void); + +void hwss_start_capture(void); +void hwss_stop_capture(void); + +float hwss_read_val(void); +float hwss_read_heart_rate(void); +int hwss_has_captured_time_ms(); diff --git a/app/src/board/three_lead_board.c b/app/src/bak/three_lead_board.c similarity index 99% rename from app/src/board/three_lead_board.c rename to app/src/bak/three_lead_board.c index df1a802..bf27630 100644 --- a/app/src/board/three_lead_board.c +++ b/app/src/bak/three_lead_board.c @@ -113,6 +113,11 @@ void ThreeLeadECG_led_green_set_state(bool state) { } } +void ThreeLeadECG_led_green_toggle(){ + nrf_gpio_pin_toggle(LED_GREEN_PIN); +} + + /******************************************************************************* * BATTERY * *******************************************************************************/ diff --git a/app/src/board/three_lead_board.h b/app/src/bak/three_lead_board.h similarity index 97% rename from app/src/board/three_lead_board.h rename to app/src/bak/three_lead_board.h index fef15fd..e630954 100644 --- a/app/src/board/three_lead_board.h +++ b/app/src/bak/three_lead_board.h @@ -29,6 +29,7 @@ void ThreeLeadECG_beep_set_state(bool state); *******************************************************************************/ void ThreeLeadECG_led_init(); void ThreeLeadECG_led_green_set_state(bool state); +void ThreeLeadECG_led_green_toggle(); /******************************************************************************* * BATTERY * *******************************************************************************/ diff --git a/app/src/basic/ads1293/ads1293.c b/app/src/basic/ads1293/ads1293.c index 5e76713..8016b43 100644 --- a/app/src/basic/ads1293/ads1293.c +++ b/app/src/basic/ads1293/ads1293.c @@ -85,6 +85,17 @@ void ads1293_read_ecg(ads1293_t* ads, uint32_t ch, uint32_t* data) { *data = ((uint32_t)readbak[0] << 16) + ((uint32_t)readbak[1] << 8) + ((uint32_t)readbak[2] << 0); } +void ads1293_read_ecgs(ads1293_t* ads, uint32_t* data /*3*/) { + uint8_t add = 0; + add = TI_ADS1293_DATA_CH1_ECG_H_REG; + uint8_t readbak[9] = {0}; + ads1293_spi_autoinc_readreg(ads, add, readbak, 9); + + data[0] = ((uint32_t)readbak[0] << 16) + ((uint32_t)readbak[1] << 8) + ((uint32_t)readbak[2] << 0); + data[1] = ((uint32_t)readbak[3] << 16) + ((uint32_t)readbak[4] << 8) + ((uint32_t)readbak[5] << 0); + data[2] = ((uint32_t)readbak[6] << 16) + ((uint32_t)readbak[7] << 8) + ((uint32_t)readbak[8] << 0); +} + void ads1293_start_conversion(ads1293_t* ads) { uint8_t data = 0; data = 0x01; @@ -96,4 +107,15 @@ void ads1293_start_power_off(ads1293_t* ads) { ads1293_spi_writereg(ads, TI_ADS1293_CONFIG_REG, data); } -uint8_t ads1293_read_error_lod(ads1293_t* ads) { return ads1293_spi_readreg(ads, TI_ADS1293_ERROR_LOD_REG); } \ No newline at end of file +uint8_t ads1293_read_error_lod(ads1293_t* ads) { return ads1293_spi_readreg(ads, TI_ADS1293_ERROR_LOD_REG); } + +void ads1293_start_conversion(ads1293_t* ads) { + uint8_t data = 0; + data = 0x01; + ads1293_spi_writereg(ads, TI_ADS1293_CONFIG_REG, data); +} +void ads1293_stop_conversion(ads1293_t* ads){ + uint8_t data = 0; + data = 0x04; + ads1293_spi_writereg(ads, TI_ADS1293_CONFIG_REG, data); +} \ No newline at end of file diff --git a/app/src/basic/ads1293/ads1293.h b/app/src/basic/ads1293/ads1293.h index 107e102..3f5ddbc 100644 --- a/app/src/basic/ads1293/ads1293.h +++ b/app/src/basic/ads1293/ads1293.h @@ -118,7 +118,12 @@ void ads1293_spi_autoinc_writereg(ads1293_t* ads, uint8_t addr, uint8_t* data, u void ads1293_spi_autoinc_readreg(ads1293_t* ads, uint8_t addr, uint8_t* data, uint8_t len); void ads1293_spi_stream_readreg(ads1293_t* ads, uint8_t* data, uint8_t len); -void ads1293_read_ecg(ads1293_t* ads, uint32_t ch, uint32_t* data); +void ads1293_read_ecg(ads1293_t* ads, uint32_t ch, uint32_t* data); +void ads1293_read_ecgs(ads1293_t* ads, uint32_t* data /*3*/); + uint8_t ads1293_read_error_lod(ads1293_t* ads); +void ads1293_start_conversion(ads1293_t* ads); +void ads1293_stop_conversion(ads1293_t* ads); + #endif // HEADER_FILE_TI_ADS1293_H diff --git a/app/src/basic/config.h b/app/src/basic/config.h index 48cec86..a4438b1 100644 --- a/app/src/basic/config.h +++ b/app/src/basic/config.h @@ -19,4 +19,9 @@ #define SAMPLE_PRECISION 12 #define AUTOMATIC_SLEEP_TIME 15000 -#define SAMPLE_MIN_TIME_S (30.0) \ No newline at end of file +#define SAMPLE_MIN_TIME_S (30.0) + +/******************************************************************************* + * 优先级 * + *******************************************************************************/ + diff --git a/app/src/board/TI_ADS1293_register_settings.h b/app/src/board/TI_ADS1293_register_settings.h deleted file mode 100644 index e95e613..0000000 --- a/app/src/board/TI_ADS1293_register_settings.h +++ /dev/null @@ -1,101 +0,0 @@ -//---------------------------------------------------------------------------- -// Description: This file contains the initialization values for the -// ADS1293 registers. -// -// MSP430/ADS1293 Interface Code Library v1.0 -// -// Vishy Natarajan -// Texas Instruments Inc. -// April 2013 -// Built with IAR Embedded Workbench Version: 5.5x -//------------------------------------------------------------------------------ -// Change Log: -//------------------------------------------------------------------------------ -// Version: 1.00 -// Comments: Initial Release Version -//------------------------------------------------------------------------------ -#ifndef HEADER_FILE_TI_ADS1293_REGISTER_SETTINGS_H - -#define HEADER_FILE_TI_ADS1293_REGISTER_SETTINGS_H - -/************************************************************ -* TI ADS1293 REGISTER SET INITIALIZATION VALUES -************************************************************/ - -#define TI_ADS1293_CONFIG_REG_VALUE (0x00) /* Main Configuration */ - -#define TI_ADS1293_FLEX_CH1_CN_REG_VALUE (0x0A) /* Flex Routing Swich Control for Channel 1 */ -#define TI_ADS1293_FLEX_CH2_CN_REG_VALUE (0x1A) /* Flex Routing Swich Control for Channel 2 */ -#define TI_ADS1293_FLEX_CH3_CN_REG_VALUE (0x00) /* Flex Routing Swich Control for Channel 3 */ -#define TI_ADS1293_FLEX_PACE_CN_REG_VALUE (0x00) /* Flex Routing Swich Control for Pace Channel */ -#define TI_ADS1293_FLEX_VBAT_CN_REG_VALUE (0x00) /* Flex Routing Swich Control for Battery Monitoriing */ - -#define TI_ADS1293_LOD_CN_REG_VALUE (0x08) /* Lead Off Detect Control */ -#define TI_ADS1293_LOD_EN_REG_VALUE (0x00) /* Lead Off Detect Enable */ -#define TI_ADS1293_LOD_CURRENT_REG_VALUE (0x00) /* Lead Off Detect Current */ -#define TI_ADS1293_LOD_AC_CN_REG_VALUE (0x00) /* AC Lead Off Detect Current */ - -#define TI_ADS1293_CMDET_EN_REG_VALUE (0x07) /* Common Mode Detect Enable */ -#define TI_ADS1293_CMDET_CN_REG_VALUE (0x00) /* Commond Mode Detect Control */ -#define TI_ADS1293_RLD_CN_REG_VALUE (0x04) /* Right Leg Drive Control */ - -#define TI_ADS1293_WILSON_EN1_REG_VALUE (0x00) /* Wilson Reference Input one Selection */ -#define TI_ADS1293_WILSON_EN2_REG_VALUE (0x00) /* Wilson Reference Input two Selection */ -#define TI_ADS1293_WILSON_EN3_REG_VALUE (0x00) /* Wilson Reference Input three Selection */ -#define TI_ADS1293_WILSON_CN_REG_VALUE (0x00) /* Wilson Reference Input Control */ - -#define TI_ADS1293_REF_CN_REG_VALUE (0x00) /* Internal Reference Voltage Control */ - -#define TI_ADS1293_OSC_CN_REG_VALUE (0x04) /* Clock Source and Output Clock Control */ - -#define TI_ADS1293_AFE_RES_REG_VALUE (0x00) /* Analog Front-End Frequency and Resolution */ -#define TI_ADS1293_AFE_SHDN_CN_REG_VALUE (0x00) /* Analog Front-End Shutdown Control */ -#define TI_ADS1293_AFE_FAULT_CN_REG_VALUE (0x00) /* Analog Front-End Fault Detection Control */ -#define TI_ADS1293_AFE_DITHER_EN_REG_VALUE (0x00) /* Enable Dithering in Signma-Delta */ -#define TI_ADS1293_AFE_PACE_CN_REG_VALUE (0x05) /* Analog Pace Channel Output Routing Control */ - -//#define TI_ADS1293_ERROR_LOD_REG_VALUE (0x00) /* Lead Off Detect Error Status */ -//#define TI_ADS1293_ERROR_STATUS_REG_VALUE (0x72) /* Other Error Status */ -//#define TI_ADS1293_ERROR_RANGE1_REG_VALUE (0x12) /* Channel 1 Amplifier Out of Range Status */ -//#define TI_ADS1293_ERROR_RANGE2_REG_VALUE (0x12) /* Channel 1 Amplifier Out of Range Status */ -//#define TI_ADS1293_ERROR_RANGE3_REG_VALUE (0x36) /* Channel 1 Amplifier Out of Range Status */ -//#define TI_ADS1293_ERROR_SYNC_REG_VALUE (0x00) /* Synchronization Error */ - - -#define TI_ADS1293_R2_RATE_REG_VALUE (0x02) /* R2 Decimation Rate */ -#define TI_ADS1293_R3_RATE1_REG_VALUE (0x02) /* R3 Decimation Rate for Channel 1 */ -#define TI_ADS1293_R3_RATE2_REG_VALUE (0x02) /* R3 Decimation Rate for Channel 2 */ -#define TI_ADS1293_R3_RATE3_REG_VALUE (0x02) /* R3 Decimation Rate for Channel 3 */ -#define TI_ADS1293_P_DRATE_REG_VALUE (0x00) /* 2x Pace Data Rate for all channels */ -#define TI_ADS1293_DIS_EFILTER_REG_VALUE (0x00) /* ECG Filters Disabled */ -#define TI_ADS1293_DRDYB_SRC_REG_VALUE (0x08) /* Data Ready Pin Source */ -#define TI_ADS1293_SYNCOUTB_SRC_REG_VALUE (0x00) /* Sync Out Pin Source */ -#define TI_ADS1293_MASK_DRDYB_REG_VALUE (0x00) /* Optional Mask Control for DRDYB Output */ -#define TI_ADS1293_MASK_ERR_REG_VALUE (0x00) /* Mask Error on ALARMB Pin */ - -#define TI_ADS1293_ALARM_FILTER_REG_VALUE (0x33) /* Digital Filter for Analog Alarm Signals */ -#define TI_ADS1293_CH_CNFG_REG_VALUE (0x30) /* Configure Channel for Loop Read Back Mode */ - -//#define TI_ADS1293_DATA_STATUS_REG_VALUE (0x00) /* ECG and Pace Data Ready Status */ -//#define TI_ADS1293_DATA_CH1_PACE_H_REG_VALUE (0x00) /* Channel1 Pace Data High [15:8] */ -//#define TI_ADS1293_DATA_CH1_PACE_L_REG_VALUE (0x00) /* Channel1 Pace Data Low [7:0] */ -//#define TI_ADS1293_DATA_CH2_PACE_H_REG_VALUE (0x00) /* Channel2 Pace Data High [15:8] */ -//#define TI_ADS1293_DATA_CH2_PACE_L_REG_VALUE (0x00) /* Channel2 Pace Data Low [7:0] */ -//#define TI_ADS1293_DATA_CH3_PACE_H_REG_VALUE (0x00) /* Channel3 Pace Data High [15:8] */ -//#define TI_ADS1293_DATA_CH3_PACE_L_REG_VALUE (0x00) /* Channel3 Pace Data Low [7:0] */ -//#define TI_ADS1293_DATA_CH1_ECG_H_REG_VALUE (0x00) /* Channel1 ECG Data High [23:16] */ -//#define TI_ADS1293_DATA_CH1_ECG_M_REG_VALUE (0x00) /* Channel1 ECG Data Medium [15:8] */ -//#define TI_ADS1293_DATA_CH1_ECG_L_REG_VALUE (0x00) /* Channel1 ECG Data Low [7:0] */ -//#define TI_ADS1293_DATA_CH2_ECG_H_REG_VALUE (0x00) /* Channel2 ECG Data High [23:16] */ -//#define TI_ADS1293_DATA_CH2_ECG_M_REG_VALUE (0x00) /* Channel2 ECG Data Medium [15:8] */ -//#define TI_ADS1293_DATA_CH2_ECG_L_REG_VALUE (0x00) /* Channel2 ECG Data Low [7:0] */ -//#define TI_ADS1293_DATA_CH3_ECG_H_REG_VALUE (0x00) /* Channel3 ECG Data High [23:16] */ -//#define TI_ADS1293_DATA_CH3_ECG_M_REG_VALUE (0x00) /* Channel3 ECG Data Medium [15:8] */ -//#define TI_ADS1293_DATA_CH3_ECG_L_REG_VALUE (0x00) /* Channel3 ECG Data Low [7:0] */ - -#define TI_ADS1293_REVID_REG_VALUE (0x40) /* Revision ID */ -#define TI_ADS1293_DATA_LOOP_REG_VALUE (0x50) /* Loop Read Back Address */ - -// Useful definitions -#define ADS1293_START_CONV (0x01) // Start Conversion Bit -#endif \ No newline at end of file diff --git a/app/src/board/ads_cfg.h b/app/src/board/ads_cfg.h deleted file mode 100644 index 2d97f6e..0000000 --- a/app/src/board/ads_cfg.h +++ /dev/null @@ -1,148 +0,0 @@ -#pragma once -#include - -typedef struct { - uint8_t add; - uint8_t data; -} adscfg_t; -#if 1 -static adscfg_t ads0cfg[] = { - {0x00, 0x00}, // - {0x01, 0x0a}, // - {0x02, 0x1a}, // - {0x03, 0x00}, // - {0x04, 0x00}, // - {0x05, 0x00}, // - {0x06, 0x04}, // - {0x07, 0x0f}, // - {0x08, 0xff}, // - {0x09, 0x00}, // - {0x0a, 0x07}, // - {0x0b, 0x00}, // - {0x0c, 0x04}, // - {0x0d, 0x00}, // - {0x0e, 0x00}, // - {0x0f, 0x00}, // - {0x10, 0x00}, // - {0x11, 0x00}, // - {0x12, 0x04}, // - {0x13, 0x00}, // - {0x14, 0x00}, // - {0x15, 0x00}, // - {0x16, 0x00}, // - {0x17, 0x05}, // - {0x18, 0x00}, // - {0x19, 0x00}, // - {0x1a, 0x00}, // - {0x1b, 0x00}, // - {0x1c, 0x00}, // - {0x1d, 0x00}, // - {0x21, 0x02}, // - {0x22, 0x02}, // - {0x23, 0x02}, // - {0x24, 0x02}, // - {0x25, 0x00}, // - {0x26, 0x00}, // - {0x27, 0x08}, // - {0x28, 0x00}, // - {0x29, 0x00}, // - {0x2a, 0x00}, // - {0x2b, 0x00}, // - {0x2c, 0x00}, // - {0x2d, 0x00}, // - {0x2e, 0x33}, // - {0x2f, 0x30}, // - {0x30, 0x00}, // - {0x31, 0x00}, // - {0x32, 0x00}, // - {0x33, 0x00}, // - {0x34, 0x00}, // - {0x35, 0x00}, // - {0x36, 0x00}, // - {0x37, 0x00}, // - {0x38, 0x00}, // - {0x39, 0x00}, // - {0x3a, 0x00}, // - {0x3b, 0x00}, // - {0x3c, 0x00}, // - {0x3d, 0x00}, // - {0x3e, 0x00}, // - {0x3f, 0x00}, // - {0x40, 0xff}, // - {0x50, 0x00}, // - {0x60, 0x00}, // - {0x62, 0x00}, // -}; - -static adscfg_t ads1cfg[] = { - {0x00, 0x00}, // - {0x01, 0x0c}, // - {0x02, 0x14}, // - {0x03, 0x04}, // - {0x04, 0x00}, // - {0x05, 0x00}, // - {0x06, 0x02}, // - {0x07, 0x0f}, // - {0x08, 0x13}, // - {0x09, 0x01}, // - {0x0a, 0x0f}, // - {0x0b, 0x00}, // - {0x0c, 0x00}, // - {0x0d, 0x00}, // - {0x0e, 0x00}, // - {0x0f, 0x00}, // - {0x10, 0x01}, // - - {0x11, 0x00}, // - {0x12, 0x07}, // - {0x13, 0x00}, // - {0x14, 0x00}, // - {0x15, 0x00}, // - {0x16, 0x00}, // - {0x17, 0x05}, // - {0x18, 0x00}, // - {0x19, 0x00}, // - {0x1a, 0x00}, // - {0x1b, 0x00}, // - {0x1c, 0x00}, // - {0x1d, 0x00}, // - {0x21, 0x02}, // - {0x22, 0x02}, // - {0x23, 0x02}, // - {0x24, 0x02}, // - - {0x25, 0x00}, // - {0x26, 0x00}, // - {0x27, 0x08}, // - {0x28, 0x08}, // - {0x29, 0x00}, // - {0x2a, 0x00}, // - {0x2b, 0x00}, // - {0x2c, 0x00}, // - {0x2d, 0x00}, // - {0x2e, 0x33}, // - {0x2f, 0x30}, // - {0x30, 0x00}, // - {0x31, 0x00}, // - {0x32, 0x00}, // - {0x33, 0x00}, // - {0x34, 0x00}, // - {0x35, 0x00}, // - - {0x36, 0x00}, // - {0x37, 0x00}, // - {0x38, 0x00}, // - {0x39, 0x00}, // - {0x3a, 0x00}, // - {0x3b, 0x00}, // - {0x3c, 0x00}, // - {0x3d, 0x00}, // - {0x3e, 0x00}, // - {0x3f, 0x00}, // - {0x40, 0xff}, // - {0x50, 0x00}, // - {0x60, 0x00}, // - {0x62, 0x00}, // - -}; -#endif \ No newline at end of file diff --git a/app/src/board/board.c b/app/src/board/board.c new file mode 100644 index 0000000..e69de29 diff --git a/app/src/board/board.h b/app/src/board/board.h new file mode 100644 index 0000000..28f4bb0 --- /dev/null +++ b/app/src/board/board.h @@ -0,0 +1,61 @@ +#pragma once + +/******************************************************************************* + * ADS * + *******************************************************************************/ + +#define ADS1293_SPI_SCK_PIN (32 + 9) +#define ADS1293_SPI_MOSI_PIN 15 +#define ADS1293_SPI_MISO_PIN 20 +#define ADS1293_SPI_CS0_PIN 3 +#define ADS1293_SPI_CS1_PIN 29 +#define ADS1293_READY_PIN 31 +#define LINE_DET_PIN 10 + +/** + * @brief SDCARD + */ +#define SDCARD_SPI_SCK_PIN 4 // SDCARD SCK +#define SDCARD_SPI_CS_PIN 5 // SDCARD CS +#define SDCARD_SPI_MISO_PIN 11 // SDCARD MISO +#define SDCARD_SPI_MOSI_PIN 17 // SDCARD MOSI + +#define SDCARD_USBDRIVER_IC_JUNCTION_CTRL_NOE_PIN 1 // flash连接控制引脚 +#define SDCARD_USBDRIVER_IC_RESET_PIN 28 // flash复位引脚 +#define SDCARD_POWER_CTRL_PIN 30 // flash供电控制引脚 + +/******************************************************************************* + * 外设分配 * + *******************************************************************************/ +#define ADS1293_SPI_INSTANCE 2 +#define BEEP_PWM_INSTANCE 0 +#define BATTERY_ADC_CHANNEL 1 // 不重复即可 + +/******************************************************************************* + * LIGHT * + *******************************************************************************/ + +#define LED_GREEN_PIN 9 + +/******************************************************************************* + * 按键 * + *******************************************************************************/ +#define BUTTON_PIN 0 + +/******************************************************************************* + * 蜂鸣器 * + *******************************************************************************/ +#define BEEP_PIN 18 + +/******************************************************************************* + * 电池电量 * + *******************************************************************************/ +#define BATTERY_ADC_PIN NRF_SAADC_INPUT_AIN0 + +/******************************************************************************* + * 应用程序配置 * + *******************************************************************************/ + +#define HEART_WAVE_SAMPLE_SERVICE_CACHE_SIZE (3 * 3 * 256) +#define FILE_MAX_COUNT 1 +#define SDCARD_MAX_FILE_SIZE (4 * 1024 * 1024) \ No newline at end of file diff --git a/app/src/board/board_battery_state.c b/app/src/board/board_battery_state.c new file mode 100644 index 0000000..2e27006 --- /dev/null +++ b/app/src/board/board_battery_state.c @@ -0,0 +1,36 @@ + +#include "board_battery_state.h" + +void BoardBattery_init() {} +void BoardBattery_load() { + nrf_drv_saadc_config_t adccfg = NRFX_SAADC_DEFAULT_CONFIG; + adccfg.resolution = NRF_SAADC_RESOLUTION_12BIT; // 4096 等于满采样率 + ZERROR_CHECK(nrf_drv_saadc_init(&adccfg, NULL)); + + nrf_saadc_channel_config_t channel_config = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(BATTERY_ADC_PIN); + channel_config.acq_time = NRF_SAADC_ACQTIME_20US; + ZERROR_CHECK(nrfx_saadc_channel_init(BATTERY_ADC_CHANNEL, &channel_config)); +} +void BoardBattery_unload() { nrf_drv_saadc_uninit(); } + +int16_t BoardBattery_get_adc_val() { + int16_t val = znrf_adc_channel_read_val(BATTERY_ADC_CHANNEL); + return val; +} +int16_t BoardBattery_get_battery_level() { + static const float maxv = 4.0; + static const float minv = 3.3; + + float voltage = BoardBattery_get_adc_val() / 4096.0 * 3.3 / 2.0 * 3; + if (voltage > maxv) voltage = maxv; + if (voltage < minv) voltage = minv; + + float percent = (voltage - minv) / (maxv - minv) * 100 + (float)0.1 /*加0.1是为了避免999.999时显示电量为90*/; + int16_t percent_int = (int16_t)percent; + if (percent_int < 10 && percent_int != 0) { + percent_int = 3; + } else { + percent_int = percent_int / 10 * 10; + } + return percent_int; +} diff --git a/app/src/board/board_battery_state.h b/app/src/board/board_battery_state.h new file mode 100644 index 0000000..fb19830 --- /dev/null +++ b/app/src/board/board_battery_state.h @@ -0,0 +1,15 @@ +#pragma once + +#include +#include + +#include "board/board.h" +#include "znordic.h" + +void BoardBattery_init(); +void BoardBattery_load(); +void BoardBattery_unload(); + +int16_t BoardBattery_get_adc_val(); +int16_t BoardBattery_val(); +int16_t BoardBattery_get_battery_level(); // 0->100 diff --git a/app/src/board/board_beep_ctrl.c b/app/src/board/board_beep_ctrl.c new file mode 100644 index 0000000..8eb2e21 --- /dev/null +++ b/app/src/board/board_beep_ctrl.c @@ -0,0 +1,93 @@ +#include "board_beep_ctrl.h" +#define BEEP_TIMER_INTERVAL (200) + +APP_TIMER_DEF(m_beep_tmr); // +static nrf_drv_pwm_t m_beep_pwm0 = NRF_DRV_PWM_INSTANCE(BEEP_PWM_INSTANCE); +static nrf_pwm_values_individual_t m_beep_pwm0_seq_values = {0}; +static nrf_pwm_sequence_t const m_beep_pwm0_seq = { + .values.p_individual = &m_beep_pwm0_seq_values, + .length = NRF_PWM_VALUES_LENGTH(m_beep_pwm0_seq_values), + .repeats = 0, + .end_delay = 0, +}; +static nrf_drv_pwm_config_t const m_beep_pwm0_config0 = { + .output_pins = {BEEP_PIN}, + .irq_priority = APP_IRQ_PRIORITY_LOWEST, + .base_clock = NRF_PWM_CLK_125kHz, + .count_mode = NRF_PWM_MODE_UP, + .top_value = 46, // 125kHz / 46 = 2.717k + .load_mode = NRF_PWM_LOAD_INDIVIDUAL, + .step_mode = NRF_PWM_STEP_AUTO, +}; +BoardBeepEffect_t m_beep_effect = kBoardBeepEffect_none; +static m_beep_cnt = 0; + +static void beep_tmr_handler(void *context) { + if (m_beep_effect == kBoardBeepEffect_none) { + BoardBeepCtrl_set(false); + } else if (m_beep_effect == kBoardBeepEffect_oneShortBeep) { + if (m_beep_cnt == 0) { + BoardBeepCtrl_set(true); + } else if (m_beep_cnt >= 1) { + BoardBeepCtrl_set(false); + app_timer_stop(m_beep_tmr); + m_beep_effect = kBoardBeepEffect_none; + } + } else if (m_beep_effect == kBoardBeepEffect_threeShortBeep) { + if (m_beep_cnt % 2 == 0) { + BoardBeepCtrl_set(true); + } else if (m_beep_cnt % 2 == 1) { + BoardBeepCtrl_set(false); + } else if (m_beep_cnt >= 6) { + BoardBeepCtrl_set(false); + app_timer_stop(m_beep_tmr); + m_beep_effect = kBoardBeepEffect_none; + } + } else if (m_beep_effect == kBoardBeepEffect_continuousShortBeep) { + // 每隔1秒响三声 + ZASSERT(BEEP_TIMER_INTERVAL == 200); + if (m_beep_cnt <= 6) { + if (m_beep_cnt % 2 == 0) { + BoardBeepCtrl_set(true); + } else if (m_beep_cnt % 2 == 1) { + BoardBeepCtrl_set(false); + } + } else { + if (BEEP_TIMER_INTERVAL * m_beep_cnt >= 1000) { + m_beep_cnt = 0; + } + } + } + m_beep_cnt++; +} + +void BoardBeepCtrl_init(void) { app_timer_create(&m_beep_tmr, APP_TIMER_MODE_REPEATED, beep_tmr_handler); } +void BoardBeepCtrl_load() { APP_ERROR_CHECK(nrfx_pwm_init(&m_beep_pwm0, &m_beep_pwm0_config0, NULL)); } + +void BoardBeepCtrl_unload() { + BoardBeepCtrl_set(0); + nrfx_pwm_uninit(&m_beep_pwm0); +} + +void BoardBeepCtrl_set(uint8_t state) { + if (state) { + m_beep_pwm0_seq_values.channel_0 = m_beep_pwm0_config0.top_value / 2; // 设置占空比,数值最大不超过 top_value + nrfx_pwm_simple_playback(&m_beep_pwm0, &m_beep_pwm0_seq, 1, NRF_DRV_PWM_FLAG_LOOP); + } else { + nrfx_pwm_stop(&m_beep_pwm0, true); + } +} + +void BoardBeepCtrl_setEffect(BoardBeepEffect_t effect) { + m_beep_effect = effect; + + app_timer_stop(m_beep_tmr); + m_beep_cnt = 0; + if (m_beep_effect == kBoardBeepEffect_none) { + BoardBeepCtrl_set(false); + } + + else { + app_timer_start(m_beep_tmr, APP_TIMER_TICKS(BEEP_TIMER_INTERVAL), NULL); + } +} diff --git a/app/src/board/board_beep_ctrl.h b/app/src/board/board_beep_ctrl.h new file mode 100644 index 0000000..28d8a11 --- /dev/null +++ b/app/src/board/board_beep_ctrl.h @@ -0,0 +1,24 @@ +#pragma once + +#include +#include + +#include "board/board.h" +#include "znordic.h" + +typedef enum { + kBoardBeepEffect_none = 0, + // 响一声 + kBoardBeepEffect_oneShortBeep, + // 响三声 + kBoardBeepEffect_threeShortBeep, + // 持续短鸣报警 + kBoardBeepEffect_continuousShortBeep, +} BoardBeepEffect_t; + +void BoardBeepCtrl_init(void); +void BoardBeepCtrl_load(); +void BoardBeepCtrl_unload(); + +void BoardBeepCtrl_set(uint8_t beep); +void BoardBeepCtrl_setEffect(BoardBeepEffect_t effect); diff --git a/app/src/board/board_button.c b/app/src/board/board_button.c new file mode 100644 index 0000000..65c620f --- /dev/null +++ b/app/src/board/board_button.c @@ -0,0 +1,24 @@ +#include "board_button.h" + +#include "app_button.h" +#include "board.h" +#include "znordic.h" + +#define BUTTON_DETECTION_DELAY APP_TIMER_TICKS(50) +static board_button_cb_t m_cb; +// +void button_process_handler(uint8_t pin_no, uint8_t button_action) {} + +static app_button_cfg_t buttons[] = { + {BUTTON_PIN, false, NRF_GPIO_PIN_PULLUP, button_process_handler}, +}; +void BoardButton_Init(board_button_cb_t cb) { // + ZASSERT(app_button_init(buttons, ARRAY_SIZE(buttons), BUTTON_DETECTION_DELAY)); +} +void BoardButton_load() { ZASSERT(app_button_enable()); } +void BoardButton_unload() { ZASSERT(app_button_disable()); } + +void BoardButton_enable_sense() { + app_button_disable(); + nrf_gpio_cfg_sense_input(BUTTON_PIN, NRF_GPIO_PIN_PULLUP, NRF_GPIO_PIN_SENSE_LOW); +} diff --git a/app/src/board/board_button.h b/app/src/board/board_button.h new file mode 100644 index 0000000..705c830 --- /dev/null +++ b/app/src/board/board_button.h @@ -0,0 +1,18 @@ +#pragma once + +#include +#include + +#include "board/board.h" + +typedef enum { + kButton_mainButton, +} ButtonIndex_t; + +typedef void (*board_button_cb_t)(ButtonIndex_t pin_no, uint8_t button_action); + +void BoardButton_Init(board_button_cb_t cb); // main中初始化一遍 +void BoardButton_load(); +void BoardButton_unload(); + +void BoardButton_enable_sense(); // 低功耗睡眠前调用该方法 \ No newline at end of file diff --git a/app/src/board/board_light_ctrl.c b/app/src/board/board_light_ctrl.c new file mode 100644 index 0000000..476fd17 --- /dev/null +++ b/app/src/board/board_light_ctrl.c @@ -0,0 +1,70 @@ +#include "board_light_ctrl.h" + +#include "board.h" +#include "znordic.h" + +#define BLINK_CNT 1 +#define BLINK_PERIOD_MS (1000) + +static LightEffect m_light_effect; +static bool m_led_green_light_state; +static int m_blink_cnt; +APP_TIMER_DEF(m_green_light_effect_tmr); + +static void BoardLight_effect_tmr_handler(void *p_context) { // + if (m_light_effect == kLightEffect_close) { + if (m_led_green_light_state) { + BoardLight_setGreenLightState(false); + } + } else if (m_light_effect == kLightEffect_open) { + if (!m_led_green_light_state) { + BoardLight_setGreenLightState(true); + } + } else if (m_light_effect == kLightEffect_slowFlash) { + if (m_blink_cnt % 1 == 0) { + BoardLight_toggleGreenLightState(); + } + } + m_blink_cnt++; +} + +void BoardLight_Init() { + znrf_gpio_cfg_output(LED_GREEN_PIN, NRF_GPIO_PIN_NOPULL); + + ZERROR_CHECK(app_timer_create(&m_green_light_effect_tmr, APP_TIMER_MODE_REPEATED, BoardLight_effect_tmr_handler)); +} +void BoardLight_load() {} +void BoardLight_unload() {} + +void BoardLight_setGreenLightState(bool state) { + if (state) { + nrf_gpio_pin_set(LED_GREEN_PIN); + m_led_green_light_state = true; + } else { + nrf_gpio_pin_clear(LED_GREEN_PIN); + m_led_green_light_state = false; + } +} + +void BoardLight_toggleGreenLightState() { nrf_gpio_pin_toggle(LED_GREEN_PIN); } + +void BoardLight_setGreenLightEffect(LightEffect effect) { + m_light_effect = effect; + + switch (effect) { + case kLightEffect_close: + app_timer_stop(m_green_light_effect_tmr); + BoardLight_setGreenLightState(false); + break; + case kLightEffect_open: + app_timer_stop(m_green_light_effect_tmr); + BoardLight_setGreenLightState(true); + break; + case kLightEffect_slowFlash: + app_timer_start(m_green_light_effect_tmr, APP_TIMER_TICKS(BLINK_PERIOD_MS), NULL); + break; + default: + break; + } + return; +} diff --git a/app/src/board/board_light_ctrl.h b/app/src/board/board_light_ctrl.h new file mode 100644 index 0000000..e5016a5 --- /dev/null +++ b/app/src/board/board_light_ctrl.h @@ -0,0 +1,23 @@ +#pragma once + +#include +#include + +#include "board/board.h" + +typedef enum { + + kLightEffect_close, + kLightEffect_open, + kLightEffect_slowFlash, + +} LightEffect; + +void BoardLight_Init(); // main中初始化一遍 +void BoardLight_load(); +void BoardLight_unload(); + +void BoardLight_setGreenLightState(bool state); // 尽量不要直接使用该函数 +void BoardLight_toggleGreenLightState(); // 尽量不要直接使用该函数 + +void BoardLight_setGreenLightEffect(LightEffect effect); diff --git a/app/src/board/board_sdcard_driver.c b/app/src/board/board_sdcard_driver.c new file mode 100644 index 0000000..98fd49b --- /dev/null +++ b/app/src/board/board_sdcard_driver.c @@ -0,0 +1,176 @@ +#include "board/board_sdcard_driver.h" + +#include "board/board.h" +#include "znordic.h" +/******************************************************************************* + * 结构体定义 * + *******************************************************************************/ +typedef enum { + kConnectToInternal, + kConnectToExt, +} ConnectTo_t; + +FATFS m_fs; +ConnectTo_t m_connectTo = kConnectToNone; +static bool m_sdcard_inited; + +NRF_BLOCK_DEV_SDC_DEFINE( // + m_block_dev_sdc, // + NRF_BLOCK_DEV_SDC_CONFIG(SDC_SECTOR_SIZE, // + APP_SDCARD_CONFIG(SDCARD_SPI_MOSI_PIN, // + SDCARD_SPI_MISO_PIN, // + SDCARD_SPI_SCK_PIN, // + SDCARD_SPI_CS_PIN)), + NFR_BLOCK_DEV_INFO_CONFIG("IFLYTOP", "SDC", "1.00")); + +/** + * + * @warning: + * SD卡和单片机是一直连接着的,SD卡和读卡器是通过一个电子开关隔离开的的。 + * 所以如果SD卡切换到读卡器,单片机需要先将SPI引脚初始化成输入高阻,然后再切换到读卡器。避免引脚竞争。 + * 此处代码需要谨慎修改,容易造成硬件损坏。 + * + * SDCARD_POWER_CTRL_PIN:低电平有效 + * SDCARD_USBDRIVER_IC_JUNCTION_CTRL_NOE_PIN:0:连接读卡器 1:连接单片机 + * + */ +void Board_sdcardInit() { + if (!m_sdcard_inited) return; + /** + * @brief SDCARD SPI 引脚初始化 + */ + nrf_gpio_cfg_sense_input(SDCARD_SPI_CS_PIN, NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_NOSENSE); + nrf_gpio_cfg_sense_input(SDCARD_SPI_MISO_PIN, NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_NOSENSE); + nrf_gpio_cfg_sense_input(SDCARD_SPI_MOSI_PIN, NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_NOSENSE); + nrf_gpio_cfg_sense_input(SDCARD_SPI_SCK_PIN, NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_NOSENSE); + /** + * @brief SD卡 USB读卡器IC复位引脚 + * 引脚一直配置成高即可 + */ + znrf_gpio_cfg_output(SDCARD_USBDRIVER_IC_RESET_PIN, NRF_GPIO_PIN_NOPULL); + nrf_gpio_pin_write(SDCARD_USBDRIVER_IC_RESET_PIN, 1); + /** + * @brief 初始化 SD卡连接切换引脚 + */ + znrf_gpio_cfg_output(SDCARD_USBDRIVER_IC_JUNCTION_CTRL_NOE_PIN, NRF_GPIO_PIN_NOPULL); + nrf_gpio_pin_write(SDCARD_USBDRIVER_IC_JUNCTION_CTRL_NOE_PIN, 0); // OE = 0 + /** + * @brief SDCARD电源控制引脚 + */ + znrf_gpio_cfg_output(SDCARD_POWER_CTRL_PIN, NRF_GPIO_PIN_NOPULL); + nrf_gpio_pin_write(SDCARD_POWER_CTRL_PIN, 0); // POWER = 0 打开电源 + m_connectTo = kConnectToExt; + + static diskio_blkdev_t drives[] = // + {DISKIO_BLOCKDEV_CONFIG(NRF_BLOCKDEV_BASE_ADDR(m_block_dev_sdc, block_dev), NULL)}; + diskio_blockdev_register(drives, ARRAY_SIZE(drives)); + m_sdcard_inited = true; +} + +void Board_sdcardConnectToExt() { + /** + * @brief + */ + if (m_connectTo == kConnectToExt) { + return; + } + + /** + * @brief + * 0. 卸载文件系统 + * 2. 配置SPI引脚成输入 + * 3. 切换引脚连接 + * 4. 通过给SD卡重启上电,复位SD卡状态 + */ + + /** + * @brief 卸载文件系统 + * + * PS:这里会自动卸载SPI驱动 + */ + + f_mount(NULL, "", 1); // 卸载文件系统 + disk_uninitialize(0); // 卸载磁盘驱动 + + /** + * @brief 配置SPI引脚成输入 + */ + nrf_gpio_cfg_sense_input(SDCARD_SPI_CS_PIN, NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_NOSENSE); + nrf_gpio_cfg_sense_input(SDCARD_SPI_MISO_PIN, NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_NOSENSE); + nrf_gpio_cfg_sense_input(SDCARD_SPI_MOSI_PIN, NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_NOSENSE); + nrf_gpio_cfg_sense_input(SDCARD_SPI_SCK_PIN, NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_NOSENSE); + + /** + * @brief 关闭SD卡电源 + */ + nrf_gpio_pin_write(SDCARD_POWER_CTRL_PIN, 1); + + /** + * @brief 切换引脚连接 + */ + nrf_gpio_pin_write(SDCARD_USBDRIVER_IC_JUNCTION_CTRL_NOE_PIN, 0); + + /** + * @brief 打开SD卡电源 + */ + nrf_delay_ms(30); // 让SD卡通过断电复位一会 + nrf_gpio_pin_write(SDCARD_POWER_CTRL_PIN, 0); // 开 + m_connectTo = kConnectToExt; +} +void Board_sdcardConnectToInternal() { + if (m_connectTo == kConnectToInternal) { + return; + } + + /** + * @brief + * 0. 断开SD卡电源 + * 1. 断开SD卡与读卡器的连接 + * 2. 打开SD电源 + * 3. 挂载SD卡 + */ + + /** + * @brief 断开SD卡电源 + */ + nrf_gpio_pin_write(SDCARD_POWER_CTRL_PIN, 1); + + /** + * @brief 断开SD卡与读卡器的连接 + */ + nrf_gpio_pin_write(SDCARD_USBDRIVER_IC_JUNCTION_CTRL_NOE_PIN, 1); + + /** + * @brief 打开SD电源 + */ + nrf_delay_ms(30); // 让SD卡通过断电复位一会 + nrf_gpio_pin_write(SDCARD_POWER_CTRL_PIN, 0); // 开 + + /** + * @brief 挂载SD卡 + */ + DSTATUS disk_state = STA_NOINIT; + for (uint32_t retries = 3; retries && disk_state; --retries) { + disk_state = disk_initialize(0); + } + if (disk_state != 0) { + NRF_LOG_INFO("Disk initialization failed. %d", disk_state); + ZASSERT(0); + } + NRF_LOG_INFO("Disk initialization succeeded."); + FRESULT ff_result; + ff_result = f_mount(&m_fs, "", 1); + if (ff_result) { + NRF_LOG_INFO("Mount failed."); + ZASSERT(0); + } + uint32_t blocks_per_mb = (1024uL * 1024uL) / m_block_dev_sdc.block_dev.p_ops->geometry(&m_block_dev_sdc.block_dev)->blk_size; + uint32_t capacity = m_block_dev_sdc.block_dev.p_ops->geometry(&m_block_dev_sdc.block_dev)->blk_count / blocks_per_mb; + + ZLOGI("Mount success"); + NRF_LOG_INFO("Capacity: %d MB", capacity); + + m_connectTo == kConnectToInternal; +} + +BoardSdcardConnectTo_t Board_sdcardGetConnectTo() { return m_connectTo; } \ No newline at end of file diff --git a/app/src/board/board_sdcard_driver.h b/app/src/board/board_sdcard_driver.h new file mode 100644 index 0000000..d706a47 --- /dev/null +++ b/app/src/board/board_sdcard_driver.h @@ -0,0 +1,19 @@ +#pragma once + +#include +#include + +#include "board/board.h" + +typedef enum { + kConnectToNone = 0, + kConnectToInternal, + kConnectToExt, +} BoardSdcardConnectTo_t; + +void Board_sdcardInit(); // main中初始化一遍 + +void Board_sdcardConnectToExt(); // SD卡连接到外部SD卡读卡器 +void Board_sdcardConnectToInternal(); // SD卡连接到单片机 + +BoardSdcardConnectTo_t Board_sdcardGetConnectTo(); diff --git a/app/src/device_state.c b/app/src/device_state.c index 243c1b5..77c8394 100644 --- a/app/src/device_state.c +++ b/app/src/device_state.c @@ -10,18 +10,5 @@ void ds_change_to_state(device_state_t state) { m_device_state = state; m_change_to_cur_state_tp = znordic_getpower_on_ms(); } - uint32_t ds_cur_state_haspassed_ms() { return znordic_haspassed_ms(m_change_to_cur_state_tp); } device_state_t ds_now_state() { return m_device_state; } - -static sample_capture_state_t m_sample_capture_state; - -sample_capture_state_t* sample_capture_state_get() { // - return &m_sample_capture_state; -} -void sample_capture_state_reset() { // - m_sample_capture_state.is_over30s = false; -}; -void sample_capture_state_set_is_over30s(bool over30s) { // - m_sample_capture_state.is_over30s = over30s; -} diff --git a/app/src/device_state.h b/app/src/device_state.h index 9a6f645..b322f9e 100644 --- a/app/src/device_state.h +++ b/app/src/device_state.h @@ -1,87 +1,28 @@ #pragma once -#include #include - -typedef enum { - kplod_connected_event = 0, // 导联连接事件 - kplod_disconnected_event, // 导联断开事件 - kplod_connecting_event, // 导联连接中事件 - - kplod_start_charge_event, // 充电事件 - kplod_charging_event, // 充电中 - kplod_end_charge_event, // 充电结束事件 - - kevent_tmr_scheduler_event, // 定时器调度事件 - - kevent_capture_256data_event, // 采样数据回调 - kevent_capture_1data_event, // 单次采样数据回调 -} app_event_type_t; - -typedef struct { - app_event_type_t eventType; - union { - uint32_t plod_connected_accumulation_time; // 导联连接累计时间 - uint8_t* capture_data_cache; // 实时采样数据,数据长度为256字节 - struct { - uint32_t frameIndex; - uint16_t data; - } frame_data; - } val; -} app_event_t; - +#include typedef enum { // 待机 kdevice_state_standby = 0, - // 开机 - kdevice_state_poweron, - // 首页 - kdevice_state_home, - // 提示用户保持静止 - kdevice_state_keep_still, - // 采集中 - kdevice_state_sampling, - // 采集完成 - kdevice_state_sampling_complete, - // 采集异常 - kdevice_state_sampling_error, - // 充电中 - kdevice_state_charging, + // Ready + kdevice_state_ready = 1, + // sample + kdevice_state_sampling = 2, } device_state_t; -static const char* device_state_to_str(device_state_t ds) { +static const char* ds2str(device_state_t ds) { switch (ds) { case kdevice_state_standby: return "standby"; - case kdevice_state_poweron: - return "poweron"; - case kdevice_state_home: - return "home"; - case kdevice_state_keep_still: - return "keep_still"; + case kdevice_state_ready: + return "ready"; case kdevice_state_sampling: return "sampling"; - case kdevice_state_sampling_complete: - return "sampling_complete"; - case kdevice_state_sampling_error: - return "sampling_error"; - case kdevice_state_charging: - return "charging"; default: - return "unknow"; + return "unknown"; } } -void app_event_process_cb(void* p_event_data, uint16_t event_size); - void ds_change_to_state(device_state_t state); uint32_t ds_cur_state_haspassed_ms(); -device_state_t ds_now_state(); - -typedef struct { - bool is_over30s; -} sample_capture_state_t; - -sample_capture_state_t* sample_capture_state_get(); - -void sample_capture_state_reset(); -void sample_capture_state_set_is_over30s(bool over30s); +device_state_t ds_now_state(); \ No newline at end of file diff --git a/app/src/heart_wave_sample_service.c b/app/src/heart_wave_sample_service.c index 49ff56c..dc7f48c 100644 --- a/app/src/heart_wave_sample_service.c +++ b/app/src/heart_wave_sample_service.c @@ -1,152 +1,280 @@ #include "heart_wave_sample_service.h" - +// +#include "znordic.h" +// +#include "app_button.h" #include "app_event.h" +#include "basic/ads1293/ads1293.h" +#include "nrf_drv_gpiote.h" #include "nrfx_timer.h" -#include "one_conduction_board.h" -static const nrfx_timer_t m_timer = NRFX_TIMER_INSTANCE(1); /**< Timer used for channel sweeps and tx with duty cycle. */ -static bool m_timer_started = false; /**< True if timer is running. */ +#define SENSOR0_ID 0 +#define SENSOR1_ID 3 +#define SENSOR2_ID 4 -static uint16_t m_capture_buffer_a[128]; -static uint16_t m_capture_buffer_b[128]; +/******************************************************************************* + * STRUCT * + *******************************************************************************/ +typedef struct { + uint8_t add; + uint8_t data; +} adscfg_t; -static uint16_t* m_capture_buffer; -static uint16_t m_capture_buffer_index = 0; +/******************************************************************************* + * CONFIG * + *******************************************************************************/ -volatile static float m_sensor_display_data = 0; // 0->100 -static uint32_t m_start_capture_tp; -static uint32_t m_frameindex = 0; +static adscfg_t m_prvads0cfg[] = // + {{0x00, 0x00}, {0x01, 0x19}, {0x02, 0x11}, {0x03, 0x00}, {0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x0f}, {0x08, 0xff}, {0x09, 0x00}, {0x0a, 0x07}, {0x0b, 0x07}, {0x0c, 0x74}, {0x0d, 0x01}, {0x0e, 0x02}, {0x0f, 0x03}, {0x10, 0x04}, + {0x11, 0x00}, {0x12, 0x05}, {0x13, 0x39}, {0x14, 0x36}, {0x15, 0x06}, {0x16, 0x00}, {0x17, 0x05}, {0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00}, {0x1c, 0x00}, {0x1d, 0x00}, {0x21, 0x01}, {0x22, 0x20}, {0x23, 0x20}, {0x24, 0x02}, + {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x08}, {0x28, 0x08}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00}, {0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x33}, {0x2f, 0x30}, {0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00}, {0x34, 0x00}, {0x35, 0x00}, + {0x36, 0x00}, {0x37, 0x00}, {0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00}, {0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00}, {0x40, 0xff}, {0x50, 0x00}, {0x60, 0x00}, {0x62, 0x00}}; -static void swap_buffer() { - if (m_capture_buffer == NULL) { - m_capture_buffer = m_capture_buffer_a; - m_capture_buffer_index = 0; - return; - } +static adscfg_t m_prvads1cfg[] = // + {{0x00, 0x00}, {0x01, 0x19}, {0x02, 0x11}, {0x03, 0x00}, {0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x0f}, {0x08, 0xff}, {0x09, 0x00}, {0x0a, 0x07}, {0x0b, 0x07}, {0x0c, 0x74}, {0x0d, 0x01}, {0x0e, 0x02}, {0x0f, 0x03}, {0x10, 0x04}, + {0x11, 0x00}, {0x12, 0x05}, {0x13, 0x39}, {0x14, 0x36}, {0x15, 0x06}, {0x16, 0x00}, {0x17, 0x05}, {0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00}, {0x1c, 0x00}, {0x1d, 0x00}, {0x21, 0x01}, {0x22, 0x20}, {0x23, 0x20}, {0x24, 0x02}, + {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x08}, {0x28, 0x08}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00}, {0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x33}, {0x2f, 0x30}, {0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00}, {0x34, 0x00}, {0x35, 0x00}, + {0x36, 0x00}, {0x37, 0x00}, {0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00}, {0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00}, {0x40, 0xff}, {0x50, 0x00}, {0x60, 0x00}, {0x62, 0x00}}; +/******************************************************************************* + * VARIABLE * + *******************************************************************************/ +static ads1293_t m_ads1293_0; // U2 +static ads1293_t m_ads1293_1; // U3 +static const nrf_drv_spi_t spi = NRF_DRV_SPI_INSTANCE(ADS1293_SPI_INSTANCE); /**< SPI instance. */ +static bool m_ads1293_driver_is_inited = false; +static uint32_t m_frame_index; +static bool m_work_flag; + +static uint8_t m_frame_buffer_a[HEART_WAVE_SAMPLE_SERVICE_CACHE_SIZE]; +static uint8_t m_frame_buffer_b[HEART_WAVE_SAMPLE_SERVICE_CACHE_SIZE]; +static uint8_t* m_frame_buffer; +static int32_t m_frame_buffer_index; + +static one_frame_data_t m_sensor_little_frame_cache[LITTLE_DATA_BLOCK_FRAME_NUM]; +static uint32_t m_little_frame_index; + +/******************************************************************************* + * 函数声明 * + *******************************************************************************/ + +// READY_PIN 中断回调函数 +static void ads1293_ready_pin_irq(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action); +// 缓冲区切换BUFFER +static void prvf_buffer_switch(void); - if (m_capture_buffer == m_capture_buffer_a) { - m_capture_buffer = m_capture_buffer_b; +/******************************************************************************* + * FUNCTION * + *******************************************************************************/ +static void prvf_buffer_switch(void) { + if (m_frame_buffer == m_frame_buffer_a) { + m_frame_buffer = m_frame_buffer_b; + m_frame_buffer_index = 0; } else { - m_capture_buffer = m_capture_buffer_a; + m_frame_buffer = m_frame_buffer_a; + m_frame_buffer_index = 0; } - m_capture_buffer_index = 0; - return; } -static float amp_val(uint16_t val, uint16_t valcener, float amp) { - float valf = (float)val - valcener; - valf = valf * amp; - valf += valcener; - if (valf >= 100) { - valf = 100; +static inline bool prvf_buffer_is_full(void) { + if (m_frame_buffer_index >= HEART_WAVE_SAMPLE_SERVICE_CACHE_SIZE) { + return true; } + return false; +} - if (valf <= 0) { - valf = 0; +static inline void prvf_buffer_push_one_byte(uint8_t byte) { + if (m_frame_buffer_index >= HEART_WAVE_SAMPLE_SERVICE_CACHE_SIZE) { + return; } - return valf; + m_frame_buffer[m_frame_buffer_index] = byte; + m_frame_buffer_index++; } -typedef struct { - float value; - float efectiveFactor; -} filter_t; +static inline void prvf_trigger_capture_data_block_event(uint8_t* data, int datalen) { + static app_event_t event; + event.eventType = kevent_capture_data_block_event; + event.val.block_sensor_data.data = data; + event.val.block_sensor_data.len = datalen; + app_sched_event_put(&event, sizeof(app_event_t), app_event_process_cb); +} -filter_t m_filter = {0, 0.8}; +static inline void prvf_little_block_cache_push_one_frame(uint32_t data0, uint32_t data1, uint32_t data2) { + if (m_little_frame_index >= LITTLE_DATA_BLOCK_FRAME_NUM) { + return; + } + m_sensor_little_frame_cache[m_little_frame_index].data0 = data0; + m_sensor_little_frame_cache[m_little_frame_index].data1 = data1; + m_sensor_little_frame_cache[m_little_frame_index].data2 = data2; + m_little_frame_index++; +} -static float Filter(filter_t* filter, float newInput) { - float newv = ((float)filter->value * (1.0f - filter->efectiveFactor)) + ((float)newInput * filter->efectiveFactor); - filter->value = newv; - return newv; +static inline bool prvf_light_block_cache_is_full(void) { + if (m_little_frame_index >= LITTLE_DATA_BLOCK_FRAME_NUM) { + return true; + } + return false; +} +static inline void prvf_light_block_cache_clear(void) { m_little_frame_index = 0; } +static inline void prvf_light_block_trigger_event() { + static app_event_t event; + event.eventType = kevent_capture_little_data_block_event; + memcpy(event.val.little_data_block.data, m_sensor_little_frame_cache, LITTLE_DATA_BLOCK_FRAME_NUM); + event.val.little_data_block.frameIndex = m_frame_index - LITTLE_DATA_BLOCK_FRAME_NUM; + app_sched_event_put(&event, sizeof(app_event_t), app_event_process_cb); } +static void ads1293_spi_tx_rx_0(uint8_t* tx, uint8_t* rx, uint8_t len) { + if (!m_ads1293_driver_is_inited) { + return; + } -void nrfx_timer_event_handler(nrf_timer_event_t event_type, void* p_context) { // - uint16_t val = SingleLeadECG_ecg_plod_get_ecg_val(); // 12bit - m_frameindex++; + nrf_gpio_pin_clear(ADS1293_SPI_CS0_PIN); + nrf_drv_spi_transfer(&spi, tx, len, rx, len); + nrf_gpio_pin_set(ADS1293_SPI_CS0_PIN); +} +static void ads1293_spi_tx_rx_1(uint8_t* tx, uint8_t* rx, uint8_t len) { + if (!m_ads1293_driver_is_inited) { + return; + } + nrf_gpio_pin_clear(ADS1293_SPI_CS1_PIN); + nrf_drv_spi_transfer(&spi, tx, len, rx, len); + nrf_gpio_pin_set(ADS1293_SPI_CS1_PIN); +} +static ads1293_init() { /******************************************************************************* - * 显示数据计算并赋值 * + * SPI初始化 * *******************************************************************************/ - float val_af100 = (float)val / 4096.0f * 100; - val_af100 = amp_val(val_af100, 50, 1.8f); - val_af100 = Filter(&m_filter, val_af100); - m_sensor_display_data = val_af100; + static nrf_drv_spi_config_t spi_config = NRF_DRV_SPI_DEFAULT_CONFIG; + spi_config.ss_pin = NRF_DRV_SPI_PIN_NOT_USED; // NRF_DRV_SPI_PIN_NOT_USED + spi_config.miso_pin = ADS1293_SPI_MISO_PIN; + spi_config.mosi_pin = ADS1293_SPI_MOSI_PIN; + spi_config.sck_pin = ADS1293_SPI_SCK_PIN; + spi_config.frequency = NRF_DRV_SPI_FREQ_8M; + spi_config.mode = NRF_DRV_SPI_MODE_3; + // spi_config.mode = + ZERROR_CHECK(nrf_drv_spi_init(&spi, &spi_config, NULL, NULL)); - /******************************************************************************* - * 采样数据缓存 * - *******************************************************************************/ - if (m_capture_buffer == NULL) { - swap_buffer(); - } + znrf_gpio_cfg_output(ADS1293_SPI_CS0_PIN, NRF_GPIO_PIN_NOPULL); + znrf_gpio_cfg_output(ADS1293_SPI_CS1_PIN, NRF_GPIO_PIN_NOPULL); + nrf_gpio_pin_set(ADS1293_SPI_CS0_PIN); + nrf_gpio_pin_set(ADS1293_SPI_CS1_PIN); - if (m_capture_buffer_index < 128) { - m_capture_buffer[m_capture_buffer_index++] = val; - } + m_ads1293_0.spi_tx_rx = ads1293_spi_tx_rx_0; + m_ads1293_0.id = 0; + m_ads1293_1.spi_tx_rx = ads1293_spi_tx_rx_1; + m_ads1293_1.id = 1; + + ads1293_spi_init(&m_ads1293_0, ads1293_spi_tx_rx_0); + ads1293_spi_init(&m_ads1293_1, ads1293_spi_tx_rx_1); + + uint8_t revid = ads1293_spi_readreg(&m_ads1293_0, TI_ADS1293_REVID_REG); + ZLOGI("ads1293_0 revid: %d\n", revid); + revid = ads1293_spi_readreg(&m_ads1293_1, TI_ADS1293_REVID_REG); + ZLOGI("ads1293_1 revid: %d\n", revid); - if (m_capture_buffer_index == 128) { - app_event_t evt; - evt.eventType = kevent_capture_256data_event; - evt.val.capture_data_cache = (uint8_t*)m_capture_buffer; - swap_buffer(); - app_sched_event_put(&evt, sizeof(evt), app_event_process_cb); + ads1293_spi_writereg(&m_ads1293_0, TI_ADS1293_CONFIG_REG, 0); + + for (uint16_t i = 0; i < ZARRAY_SIZE(m_prvads0cfg); i++) { + ads1293_spi_writereg_and_check(&m_ads1293_0, m_prvads0cfg[i].add, m_prvads0cfg[i].data); + } + for (uint16_t i = 0; i < ZARRAY_SIZE(m_prvads1cfg); i++) { + ads1293_spi_writereg_and_check(&m_ads1293_1, m_prvads1cfg[i].add, m_prvads1cfg[i].data); } + m_ads1293_driver_is_inited = true; - /******************************************************************************* - * 实时采样数据事件上报 * - *******************************************************************************/ + /** + * @brief READY引脚中断初始化 + */ { - app_event_t evt; - evt.eventType = kevent_capture_1data_event; - evt.val.frame_data.frameIndex = m_frameindex; - evt.val.frame_data.data = val; - swap_buffer(); - app_sched_event_put(&evt, sizeof(evt), app_event_process_cb); + // nrf_gpio_cfg_input(ADS1293_READY_PIN, NRF_GPIO_PIN_PULLUP); + ZERROR_CHECK(nrfx_gpiote_init()); + nrf_drv_gpiote_in_config_t inConfig = GPIOTE_CONFIG_IN_SENSE_TOGGLE(false); // 双边沿中断触发 + inConfig.pull = NRF_GPIO_PIN_PULLUP; // 默认上拉 + inConfig.sense = NRF_GPIOTE_POLARITY_LOTOHI; // 上升沿触发 + + ZERROR_CHECK(nrfx_gpiote_in_init(ADS1293_READY_PIN, &inConfig, ads1293_ready_pin_irq)); + nrfx_gpiote_in_event_enable(ADS1293_READY_PIN, true); } } -void hwss_init(void) { - if (m_timer_started) { +/** + * @brief 数据准备号中断回调函数 + * + * @param pin + * @param action + */ +static void ads1293_ready_pin_irq(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action) { + if (!m_work_flag) { return; } + m_frame_index++; + // 检查缓冲区是否为空 + if (!m_frame_buffer) prvf_buffer_switch(); + + static uint32_t sample[6]; + ads1293_read_ecgs(&m_ads1293_0, &sample[0]); + ads1293_read_ecgs(&m_ads1293_1, &sample[3]); + + static uint8_t cache[9]; + cache[0] = (sample[SENSOR0_ID] >> 0) & 0xff; + cache[1] = (sample[SENSOR0_ID] >> 8) & 0xff; + cache[2] = (sample[SENSOR0_ID] >> 16) & 0xff; + + cache[3] = (sample[SENSOR1_ID] >> 0) & 0xff; + cache[4] = (sample[SENSOR1_ID] >> 8) & 0xff; + cache[5] = (sample[SENSOR1_ID] >> 16) & 0xff; + + cache[6] = (sample[SENSOR2_ID] >> 0) & 0xff; + cache[7] = (sample[SENSOR2_ID] >> 8) & 0xff; + cache[8] = (sample[SENSOR2_ID] >> 16) & 0xff; + /** - * @brief 初始化定时器 + * @brief 缓存数据,并触发数据块事件 */ - nrfx_err_t err; - nrfx_timer_config_t timer_cfg = { - .frequency = NRF_TIMER_FREQ_125kHz, - .mode = NRF_TIMER_MODE_TIMER, - .bit_width = NRF_TIMER_BIT_WIDTH_24, - .p_context = NULL, - .interrupt_priority = NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY, - }; - - err = nrfx_timer_init(&m_timer, &timer_cfg, nrfx_timer_event_handler); - if (err != NRFX_SUCCESS) { - NRF_LOG_ERROR("nrfx_timer_init failed with: %d\n", err); + for (int i = 0; i < 9; i++) { + if (prvf_buffer_is_full()) { + prvf_trigger_capture_data_block_event(m_frame_buffer, HEART_WAVE_SAMPLE_SERVICE_CACHE_SIZE); + prvf_buffer_switch(); + } + prvf_buffer_push_one_byte(cache[i]); } - uint32_t timer_ticks = nrfx_timer_ms_to_ticks(&m_timer, 5); // 200HZ - nrfx_timer_extended_compare(&m_timer, NRF_TIMER_CC_CHANNEL0, timer_ticks, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, true); - m_timer_started = true; -} -void hwss_uninit(void) { nrfx_timer_disable(&m_timer); } -void hwss_start_capture(void) { - m_start_capture_tp = znordic_getpower_on_s(); - swap_buffer(); - m_frameindex = 0; - nrfx_timer_enable(&m_timer); + /** + * @brief 缓存数据,并触发小数据块事件 + */ + prvf_little_block_cache_push_one_frame(sample[SENSOR0_ID], sample[SENSOR1_ID], sample[SENSOR2_ID]); + if (prvf_light_block_cache_is_full()) { + prvf_light_block_trigger_event(); + prvf_light_block_cache_clear(); + } } -void hwss_stop_capture(void) { - nrfx_timer_disable(&m_timer); - m_frameindex = 0; + +static ads1293_uninit() { + hwss_stop_capture(); + m_ads1293_driver_is_inited = false; + nrf_drv_spi_uninit(&spi); } -float hwss_read_val(void) { - __disable_irq(); - float val = m_sensor_display_data; - __enable_irq(); - return val; +void hwss_init(void) { + /** + * @brief 初始化ads1293硬件接口 + */ + ads1293_init(); +} +void hwss_uninit(void) { + /** + * @brief 反初始化ads1293硬件接口 + */ + ads1293_uninit(); } -float hwss_read_heart_rate(void) { return 0; } -int hwss_has_captured_time_ms() { return (znordic_getpower_on_s() - m_start_capture_tp) * 1000; } +void hwss_start_capture(void) { + m_work_flag = true; + ads1293_start_conversion(&m_ads1293_0); + ads1293_start_conversion(&m_ads1293_1); +} +void hwss_stop_capture(void) { + m_work_flag = false; + ads1293_stop_conversion(&m_ads1293_0); + ads1293_stop_conversion(&m_ads1293_1); +} \ No newline at end of file diff --git a/app/src/heart_wave_sample_service.h b/app/src/heart_wave_sample_service.h index 65e18dc..d569724 100644 --- a/app/src/heart_wave_sample_service.h +++ b/app/src/heart_wave_sample_service.h @@ -1,15 +1,31 @@ +/** + * @file heart_wave_sample_service.h + * @author zhaohe (h_zhaohe@163.com) + * @brief 心电波形采样服务 + * @version 0.1 + * @date 2024-02-01 + * + * @copyright Copyright (c) 2024 + * + */ #pragma once -#include "one_conduction_board.h" - -// 每256个字节触发一次回调 -typedef void (*heart_wave_sample_service_callback_t)(uint16_t *p_data, uint16_t length); +#include "app_event.h" +#include "board/board.h" +/** + * @brief 初始化 + */ void hwss_init(void); +/** + * @brief unint + */ void hwss_uninit(void); +/** + * @brief 开始采集 + */ void hwss_start_capture(void); -void hwss_stop_capture(void); - -float hwss_read_val(void); -float hwss_read_heart_rate(void); -int hwss_has_captured_time_ms(); +/** + * @brief 停止采集 + */ +void hwss_stop_capture(void); \ No newline at end of file diff --git a/app/src/main.bak.c b/app/src/main.bak.c new file mode 100644 index 0000000..9c7aab1 --- /dev/null +++ b/app/src/main.bak.c @@ -0,0 +1,372 @@ +#include "znordic.h" +// +#include +#include +#include +#include +// +#include "app_uart.h" +#include "basic/ads1293/ads1293.h" +#include "zble_module.h" +#include "zdatachannel_service.h" +#include "znordic_device_info_mgr.h" + +#if defined(UART_PRESENT) +#include "nrf_uart.h" +#endif +#if defined(UARTE_PRESENT) +#include "nrf_uarte.h" +#endif + +#if 0 + +int main() { return 0; } +#endif + +#if 1 + +#define ADS1293_SPI_SCK_PIN (32 + 9) +#define ADS1293_SPI_MOSI_PIN 15 +#define ADS1293_SPI_MISO_PIN 20 +#define ADS1293_SPI_CS0_PIN 3 +#define ADS1293_SPI_CS1_PIN 29 +#define ADS1293_READY_PIN 31 +#define LINE_DET_PIN 10 + +#define UART_TX_BUF_SIZE 256 /**< UART TX buffer size. */ +#define UART_RX_BUF_SIZE 256 /**< UART RX buffer size. */ + +#include "board/ads_cfg.h" +void uart_error_handle(app_uart_evt_t* p_event) {} + +/**@brief Function for initializing the UART. */ +static void uart_init(void) { + ret_code_t err_code; + + app_uart_comm_params_t const comm_params = { + .rx_pin_no = UART_PIN_DISCONNECTED, + .tx_pin_no = 0, + .rts_pin_no = UART_PIN_DISCONNECTED, + .cts_pin_no = UART_PIN_DISCONNECTED, + .flow_control = APP_UART_FLOW_CONTROL_DISABLED, + .use_parity = false, + .baud_rate = UART_BAUDRATE_BAUDRATE_Baud115200, + }; + APP_UART_FIFO_INIT(&comm_params, UART_RX_BUF_SIZE, UART_TX_BUF_SIZE, uart_error_handle, APP_IRQ_PRIORITY_HIGHEST, err_code); + APP_ERROR_CHECK(err_code); +} + +/******************************************************************************* + * 3导联-ADS1293-测试 * + *******************************************************************************/ +APP_TIMER_DEF(m_init_tmr); +APP_TIMER_DEF(m_report_tmr); +ZDATACHANNEL_DEF(m_zhrs, 2 /**/, 1 /*client num*/); +static const nrf_drv_spi_t spi = NRF_DRV_SPI_INSTANCE(2); /**< SPI instance. */ +static ads1293_t m_ads1293_0; // U2 +static ads1293_t m_ads1293_1; // U3 +static void zdatachanel_send_log(const char* fmt, ...); +static void three_lead_ecg_ecg_init(); + +uint32_t get_ready_pin_state_get() { return nrf_gpio_pin_read(ADS1293_READY_PIN); } + +static void on_service_init(void) { + ZLOGI("init zdatachannel service"); + zdatachannel_init_t zdatachannle_init; + memset(&zdatachannle_init, 0, sizeof(zdatachannle_init)); + zdatachannle_init.data_handler = NULL; + ZERROR_CHECK(zdatachannel_init(&m_zhrs, &zdatachannle_init)); +} +static int changecount = 0; +void dump_state() { + static uint32_t last = 0; + uint32_t nows = znordic_rtc_gettime_s(); + if (nows != last) { + zdatachanel_send_log("%d\n", changecount); + + uint8_t leadoffstate = ads1293_spi_readreg(&m_ads1293_0, TI_ADS1293_ERROR_LOD_REG); + zdatachanel_send_log("%d%d%d%d_%d%d%d%d\n", // + leadoffstate >> 7 & 0x1, leadoffstate >> 6 & 0x1, leadoffstate >> 5 & 0x1, leadoffstate >> 4 & 0x1, // + leadoffstate >> 3 & 0x1, leadoffstate >> 2 & 0x1, leadoffstate >> 1 & 0x1, leadoffstate >> 0 & 0x1); // + + last = nows; + changecount = 0; + } +} + +int main() { + APP_SCHED_INIT(APP_TIMER_SCHED_EVENT_DATA_SIZE, 20); + znordic_init(); + static zble_module_cfg_t cfg = // + { + .deviceName = "ThreeLeadECG", + .on_service_init = on_service_init, + }; + zble_module_init(&cfg); + NRF_LOG_INFO("compile time :%s", __TIME__); + uart_init(); + + nrf_gpio_cfg_input(LINE_DET_PIN, NRF_GPIO_PIN_PULLUP); + three_lead_ecg_ecg_init(); + ads1293_spi_writereg(&m_ads1293_0, TI_ADS1293_CONFIG_REG, 0x01); + ads1293_spi_writereg(&m_ads1293_1, TI_ADS1293_CONFIG_REG, 0x01); + + while (true) { + app_sched_execute(); + if (NRF_LOG_PROCESS() == false) { + // nrf_pwr_mgmt_run(); + } + static bool state = false; + bool now = get_ready_pin_state_get(); + if (state != now) { + state = now; + changecount++; + + if (now) { + uint32_t val = 0; + ads1293_read_ecg(&m_ads1293_0, 1, &val); + zdatachanel_send_log("%d\n", val); + } + } + // dump_state(); + } +} + +static void ads1293_spi_tx_rx_0(uint8_t* tx, uint8_t* rx, uint8_t len) { + nrf_gpio_pin_clear(ADS1293_SPI_CS0_PIN); + nrf_drv_spi_transfer(&spi, tx, len, rx, len); + nrf_gpio_pin_set(ADS1293_SPI_CS0_PIN); +} +static void ads1293_spi_tx_rx_1(uint8_t* tx, uint8_t* rx, uint8_t len) { + nrf_gpio_pin_clear(ADS1293_SPI_CS1_PIN); + nrf_drv_spi_transfer(&spi, tx, len, rx, len); + nrf_gpio_pin_set(ADS1293_SPI_CS1_PIN); +} + +static void ads1293_spi_writereg_and_check(ads1293_t* ads, uint8_t addr, uint8_t data) { + uint8_t readbak = 0; + // readonly add + if (addr == 0x19 || addr == 0x1a || addr == 0x1b || addr == 0x1c || addr == 0x40 || addr == 0x30) { + return; + } + ads1293_spi_writereg_and_readbak(ads, addr, data, &readbak); + if (readbak != data) { + zdatachanel_send_log("ads_%d write %x failed,w:%x readbak:%x\n", ads->id, addr, data, readbak); + } +} + +static adscfg_t prvads0cfg[] = { + {0x00, 0x00}, // + {0x01, 0x19}, // + {0x02, 0x11}, // + {0x03, 0x00}, // + {0x04, 0x00}, // + {0x05, 0x00}, // + {0x06, 0x00}, // + {0x07, 0x0f}, // + {0x08, 0xff}, // + {0x09, 0x00}, // + {0x0a, 0x07}, // + {0x0b, 0x07}, // + {0x0c, 0x74}, // + {0x0d, 0x01}, // + {0x0e, 0x02}, // + {0x0f, 0x03}, // + {0x10, 0x04}, // + {0x11, 0x00}, // + {0x12, 0x05}, // + {0x13, 0x39}, // + {0x14, 0x36}, // + {0x15, 0x06}, // + {0x16, 0x00}, // + {0x17, 0x05}, // + {0x18, 0x00}, // + {0x19, 0x00}, // + {0x1a, 0x00}, // + {0x1b, 0x00}, // + {0x1c, 0x00}, // + {0x1d, 0x00}, // + {0x21, 0x01}, // + {0x22, 0x20}, // + {0x23, 0x20}, // + {0x24, 0x02}, // + {0x25, 0x00}, // + {0x26, 0x00}, // + {0x27, 0x08}, // + {0x28, 0x08}, // + {0x29, 0x00}, // + {0x2a, 0x00}, // + {0x2b, 0x00}, // + {0x2c, 0x00}, // + {0x2d, 0x00}, // + {0x2e, 0x33}, // + {0x2f, 0x30}, // + {0x30, 0x00}, // + {0x31, 0x00}, // + {0x32, 0x00}, // + {0x33, 0x00}, // + {0x34, 0x00}, // + {0x35, 0x00}, // + {0x36, 0x00}, // + {0x37, 0x00}, // + {0x38, 0x00}, // + {0x39, 0x00}, // + {0x3a, 0x00}, // + {0x3b, 0x00}, // + {0x3c, 0x00}, // + {0x3d, 0x00}, // + {0x3e, 0x00}, // + {0x3f, 0x00}, // + {0x40, 0xff}, // + {0x50, 0x00}, // + {0x60, 0x00}, // + {0x62, 0x00} // +}; + +static adscfg_t prvads1cfg[] = { + {0x00, 0x00}, // + {0x01, 0x0c}, // + {0x02, 0x14}, // + {0x03, 0x00}, // + {0x04, 0x00}, // + {0x05, 0x00}, // + {0x06, 0x00}, // + {0x07, 0x0f}, // + {0x08, 0xff}, // + {0x09, 0x00}, // + {0x0a, 0x00}, // + {0x0b, 0x07}, // + {0x0c, 0x78}, // + {0x0d, 0x00}, // + {0x0e, 0x00}, // + {0x0f, 0x00}, // + {0x10, 0x04}, // + {0x11, 0x00}, // + {0x12, 0x07}, // + {0x13, 0x3b}, // + {0x14, 0x24}, // + {0x15, 0x04}, // + {0x16, 0x00}, // + {0x17, 0x05}, // + {0x18, 0x00}, // + {0x19, 0x00}, // + {0x1a, 0x00}, // + {0x1b, 0x00}, // + {0x1c, 0x00}, // + {0x1d, 0x00}, // + {0x21, 0x01}, // + {0x22, 0x20}, // + {0x23, 0x20}, // + {0x24, 0x02}, // + {0x25, 0x00}, // + {0x26, 0x00}, // + {0x27, 0x08}, // + {0x28, 0x40}, // + {0x29, 0x00}, // + {0x2a, 0x00}, // + {0x2b, 0x00}, // + {0x2c, 0x00}, // + {0x2d, 0x00}, // + {0x2e, 0x33}, // + {0x2f, 0x30}, // + {0x30, 0x00}, // + {0x31, 0x00}, // + {0x32, 0x00}, // + {0x33, 0x00}, // + {0x34, 0x00}, // + {0x35, 0x00}, // + {0x36, 0x00}, // + {0x37, 0x00}, // + {0x38, 0x00}, // + {0x39, 0x00}, // + {0x3a, 0x00}, // + {0x3b, 0x00}, // + {0x3c, 0x00}, // + {0x3d, 0x00}, // + {0x3e, 0x00}, // + {0x3f, 0x00}, // + {0x40, 0xff}, // + {0x50, 0x00}, // + {0x60, 0x00}, // + {0x62, 0x00}, // +}; + +void config_lod(uint8_t aclvl_lod, uint8_t selac_lod, uint8_t shdn_lod, uint8_t acad_lod) { + uint8_t reg = 0; + reg |= aclvl_lod; + reg |= selac_lod << 2; + reg |= shdn_lod << 3; + reg |= acad_lod << 4; + ads1293_spi_writereg(&m_ads1293_0, TI_ADS1293_LOD_CN_REG, reg); +} + +void enable_lod(void) { + uint8_t reg = ads1293_spi_readreg(&m_ads1293_0, TI_ADS1293_CONFIG_REG); + reg |= 1 << 3; + ads1293_spi_writereg(&m_ads1293_0, TI_ADS1293_LOD_EN_REG, reg); +} + +void three_lead_ecg_ecg_init() { + nrf_drv_spi_config_t spi_config = NRF_DRV_SPI_DEFAULT_CONFIG; + spi_config.ss_pin = NRF_DRV_SPI_PIN_NOT_USED; // NRF_DRV_SPI_PIN_NOT_USED + spi_config.miso_pin = ADS1293_SPI_MISO_PIN; + spi_config.mosi_pin = ADS1293_SPI_MOSI_PIN; + spi_config.sck_pin = ADS1293_SPI_SCK_PIN; + spi_config.frequency = NRF_DRV_SPI_FREQ_8M; + spi_config.mode = NRF_DRV_SPI_MODE_3; + // spi_config.mode = + ZERROR_CHECK(nrf_drv_spi_init(&spi, &spi_config, NULL, NULL)); + + znrf_gpio_cfg_output(ADS1293_SPI_CS0_PIN, NRF_GPIO_PIN_NOPULL); + znrf_gpio_cfg_output(ADS1293_SPI_CS1_PIN, NRF_GPIO_PIN_NOPULL); + nrf_gpio_cfg_input(ADS1293_READY_PIN, NRF_GPIO_PIN_PULLUP); + + nrf_gpio_pin_set(ADS1293_SPI_CS0_PIN); + nrf_gpio_pin_set(ADS1293_SPI_CS1_PIN); + + m_ads1293_0.spi_tx_rx = ads1293_spi_tx_rx_0; + m_ads1293_0.id = 0; + // m_ads1293_1.spi_tx_rx = ads1293_spi_tx_rx_1; + // m_ads1293_1.id = 1; + + ads1293_spi_init(&m_ads1293_0, ads1293_spi_tx_rx_0); + ads1293_spi_init(&m_ads1293_1, ads1293_spi_tx_rx_1); + + uint8_t revid = ads1293_spi_readreg(&m_ads1293_0, TI_ADS1293_REVID_REG); + zdatachanel_send_log("ads1293_0 revid: %d\n", revid); + revid = ads1293_spi_readreg(&m_ads1293_1, TI_ADS1293_REVID_REG); + zdatachanel_send_log("ads1293_1 revid: %d\n", revid); + + zdatachanel_send_log("reset ads1293_0\n"); + ads1293_spi_writereg(&m_ads1293_0, TI_ADS1293_CONFIG_REG, 0); + nrf_delay_ms(1000); + + for (uint16_t i = 0; i < ZARRAY_SIZE(prvads0cfg); i++) { + ads1293_spi_writereg_and_check(&m_ads1293_0, prvads0cfg[i].add, prvads0cfg[i].data); + } + for (uint16_t i = 0; i < ZARRAY_SIZE(prvads1cfg); i++) { + ads1293_spi_writereg_and_check(&m_ads1293_1, prvads1cfg[i].add, prvads1cfg[i].data); + } + + // ads1293_spi_writereg(&m_ads1293_1, TI_ADS1293_CONFIG_REG, 0x01); +} + +static void zdatachanel_send_log(const char* fmt, ...) { + static char tx[256] = {0}; + int len = 0; + va_list args; + va_start(args, fmt); + len = vsprintf(tx, fmt, args); + len = strlen(tx); + int ret_val; + if (len >= 0) { + for (uint16_t i = 0; i < len; i++) { + do { + ret_val = app_uart_put(tx[i]); + } while (ret_val != NRF_SUCCESS); + } + return; + } + va_end(args); +} +#endif \ No newline at end of file diff --git a/app/src/main.c b/app/src/main.c index 9c7aab1..0d8b1ed 100644 --- a/app/src/main.c +++ b/app/src/main.c @@ -5,368 +5,31 @@ #include #include // -#include "app_uart.h" +#include "app_ble_service.h" #include "basic/ads1293/ads1293.h" #include "zble_module.h" #include "zdatachannel_service.h" #include "znordic_device_info_mgr.h" +// -#if defined(UART_PRESENT) -#include "nrf_uart.h" -#endif -#if defined(UARTE_PRESENT) -#include "nrf_uarte.h" -#endif - -#if 0 - -int main() { return 0; } -#endif - -#if 1 - -#define ADS1293_SPI_SCK_PIN (32 + 9) -#define ADS1293_SPI_MOSI_PIN 15 -#define ADS1293_SPI_MISO_PIN 20 -#define ADS1293_SPI_CS0_PIN 3 -#define ADS1293_SPI_CS1_PIN 29 -#define ADS1293_READY_PIN 31 -#define LINE_DET_PIN 10 - -#define UART_TX_BUF_SIZE 256 /**< UART TX buffer size. */ -#define UART_RX_BUF_SIZE 256 /**< UART RX buffer size. */ - -#include "board/ads_cfg.h" -void uart_error_handle(app_uart_evt_t* p_event) {} - -/**@brief Function for initializing the UART. */ -static void uart_init(void) { - ret_code_t err_code; - - app_uart_comm_params_t const comm_params = { - .rx_pin_no = UART_PIN_DISCONNECTED, - .tx_pin_no = 0, - .rts_pin_no = UART_PIN_DISCONNECTED, - .cts_pin_no = UART_PIN_DISCONNECTED, - .flow_control = APP_UART_FLOW_CONTROL_DISABLED, - .use_parity = false, - .baud_rate = UART_BAUDRATE_BAUDRATE_Baud115200, - }; - APP_UART_FIFO_INIT(&comm_params, UART_RX_BUF_SIZE, UART_TX_BUF_SIZE, uart_error_handle, APP_IRQ_PRIORITY_HIGHEST, err_code); - APP_ERROR_CHECK(err_code); -} - -/******************************************************************************* - * 3导联-ADS1293-测试 * - *******************************************************************************/ -APP_TIMER_DEF(m_init_tmr); -APP_TIMER_DEF(m_report_tmr); -ZDATACHANNEL_DEF(m_zhrs, 2 /**/, 1 /*client num*/); -static const nrf_drv_spi_t spi = NRF_DRV_SPI_INSTANCE(2); /**< SPI instance. */ -static ads1293_t m_ads1293_0; // U2 -static ads1293_t m_ads1293_1; // U3 -static void zdatachanel_send_log(const char* fmt, ...); -static void three_lead_ecg_ecg_init(); - -uint32_t get_ready_pin_state_get() { return nrf_gpio_pin_read(ADS1293_READY_PIN); } - -static void on_service_init(void) { - ZLOGI("init zdatachannel service"); - zdatachannel_init_t zdatachannle_init; - memset(&zdatachannle_init, 0, sizeof(zdatachannle_init)); - zdatachannle_init.data_handler = NULL; - ZERROR_CHECK(zdatachannel_init(&m_zhrs, &zdatachannle_init)); -} -static int changecount = 0; -void dump_state() { - static uint32_t last = 0; - uint32_t nows = znordic_rtc_gettime_s(); - if (nows != last) { - zdatachanel_send_log("%d\n", changecount); - - uint8_t leadoffstate = ads1293_spi_readreg(&m_ads1293_0, TI_ADS1293_ERROR_LOD_REG); - zdatachanel_send_log("%d%d%d%d_%d%d%d%d\n", // - leadoffstate >> 7 & 0x1, leadoffstate >> 6 & 0x1, leadoffstate >> 5 & 0x1, leadoffstate >> 4 & 0x1, // - leadoffstate >> 3 & 0x1, leadoffstate >> 2 & 0x1, leadoffstate >> 1 & 0x1, leadoffstate >> 0 & 0x1); // - - last = nows; - changecount = 0; - } +APP_TIMER_DEF(state_machine_scheduler_tmr); +static void test_tx_timer_cb(void* p_context) { // + ZLOGI("test_tx_timer_cb"); + ThreeLeadECG_led_green_toggle(); } - int main() { APP_SCHED_INIT(APP_TIMER_SCHED_EVENT_DATA_SIZE, 20); znordic_init(); static zble_module_cfg_t cfg = // { .deviceName = "ThreeLeadECG", - .on_service_init = on_service_init, + .on_service_init = AppBleService_onServiceInitCB, }; zble_module_init(&cfg); + AppBleService_startAdv(); + ThreeLeadECG_led_init(); + ZERROR_CHECK(app_timer_create(&state_machine_scheduler_tmr, APP_TIMER_MODE_REPEATED, test_tx_timer_cb)); + ZERROR_CHECK(app_timer_start(state_machine_scheduler_tmr, APP_TIMER_TICKS(1000), NULL)); NRF_LOG_INFO("compile time :%s", __TIME__); - uart_init(); - - nrf_gpio_cfg_input(LINE_DET_PIN, NRF_GPIO_PIN_PULLUP); - three_lead_ecg_ecg_init(); - ads1293_spi_writereg(&m_ads1293_0, TI_ADS1293_CONFIG_REG, 0x01); - ads1293_spi_writereg(&m_ads1293_1, TI_ADS1293_CONFIG_REG, 0x01); - - while (true) { - app_sched_execute(); - if (NRF_LOG_PROCESS() == false) { - // nrf_pwr_mgmt_run(); - } - static bool state = false; - bool now = get_ready_pin_state_get(); - if (state != now) { - state = now; - changecount++; - - if (now) { - uint32_t val = 0; - ads1293_read_ecg(&m_ads1293_0, 1, &val); - zdatachanel_send_log("%d\n", val); - } - } - // dump_state(); - } -} - -static void ads1293_spi_tx_rx_0(uint8_t* tx, uint8_t* rx, uint8_t len) { - nrf_gpio_pin_clear(ADS1293_SPI_CS0_PIN); - nrf_drv_spi_transfer(&spi, tx, len, rx, len); - nrf_gpio_pin_set(ADS1293_SPI_CS0_PIN); -} -static void ads1293_spi_tx_rx_1(uint8_t* tx, uint8_t* rx, uint8_t len) { - nrf_gpio_pin_clear(ADS1293_SPI_CS1_PIN); - nrf_drv_spi_transfer(&spi, tx, len, rx, len); - nrf_gpio_pin_set(ADS1293_SPI_CS1_PIN); -} - -static void ads1293_spi_writereg_and_check(ads1293_t* ads, uint8_t addr, uint8_t data) { - uint8_t readbak = 0; - // readonly add - if (addr == 0x19 || addr == 0x1a || addr == 0x1b || addr == 0x1c || addr == 0x40 || addr == 0x30) { - return; - } - ads1293_spi_writereg_and_readbak(ads, addr, data, &readbak); - if (readbak != data) { - zdatachanel_send_log("ads_%d write %x failed,w:%x readbak:%x\n", ads->id, addr, data, readbak); - } -} - -static adscfg_t prvads0cfg[] = { - {0x00, 0x00}, // - {0x01, 0x19}, // - {0x02, 0x11}, // - {0x03, 0x00}, // - {0x04, 0x00}, // - {0x05, 0x00}, // - {0x06, 0x00}, // - {0x07, 0x0f}, // - {0x08, 0xff}, // - {0x09, 0x00}, // - {0x0a, 0x07}, // - {0x0b, 0x07}, // - {0x0c, 0x74}, // - {0x0d, 0x01}, // - {0x0e, 0x02}, // - {0x0f, 0x03}, // - {0x10, 0x04}, // - {0x11, 0x00}, // - {0x12, 0x05}, // - {0x13, 0x39}, // - {0x14, 0x36}, // - {0x15, 0x06}, // - {0x16, 0x00}, // - {0x17, 0x05}, // - {0x18, 0x00}, // - {0x19, 0x00}, // - {0x1a, 0x00}, // - {0x1b, 0x00}, // - {0x1c, 0x00}, // - {0x1d, 0x00}, // - {0x21, 0x01}, // - {0x22, 0x20}, // - {0x23, 0x20}, // - {0x24, 0x02}, // - {0x25, 0x00}, // - {0x26, 0x00}, // - {0x27, 0x08}, // - {0x28, 0x08}, // - {0x29, 0x00}, // - {0x2a, 0x00}, // - {0x2b, 0x00}, // - {0x2c, 0x00}, // - {0x2d, 0x00}, // - {0x2e, 0x33}, // - {0x2f, 0x30}, // - {0x30, 0x00}, // - {0x31, 0x00}, // - {0x32, 0x00}, // - {0x33, 0x00}, // - {0x34, 0x00}, // - {0x35, 0x00}, // - {0x36, 0x00}, // - {0x37, 0x00}, // - {0x38, 0x00}, // - {0x39, 0x00}, // - {0x3a, 0x00}, // - {0x3b, 0x00}, // - {0x3c, 0x00}, // - {0x3d, 0x00}, // - {0x3e, 0x00}, // - {0x3f, 0x00}, // - {0x40, 0xff}, // - {0x50, 0x00}, // - {0x60, 0x00}, // - {0x62, 0x00} // -}; - -static adscfg_t prvads1cfg[] = { - {0x00, 0x00}, // - {0x01, 0x0c}, // - {0x02, 0x14}, // - {0x03, 0x00}, // - {0x04, 0x00}, // - {0x05, 0x00}, // - {0x06, 0x00}, // - {0x07, 0x0f}, // - {0x08, 0xff}, // - {0x09, 0x00}, // - {0x0a, 0x00}, // - {0x0b, 0x07}, // - {0x0c, 0x78}, // - {0x0d, 0x00}, // - {0x0e, 0x00}, // - {0x0f, 0x00}, // - {0x10, 0x04}, // - {0x11, 0x00}, // - {0x12, 0x07}, // - {0x13, 0x3b}, // - {0x14, 0x24}, // - {0x15, 0x04}, // - {0x16, 0x00}, // - {0x17, 0x05}, // - {0x18, 0x00}, // - {0x19, 0x00}, // - {0x1a, 0x00}, // - {0x1b, 0x00}, // - {0x1c, 0x00}, // - {0x1d, 0x00}, // - {0x21, 0x01}, // - {0x22, 0x20}, // - {0x23, 0x20}, // - {0x24, 0x02}, // - {0x25, 0x00}, // - {0x26, 0x00}, // - {0x27, 0x08}, // - {0x28, 0x40}, // - {0x29, 0x00}, // - {0x2a, 0x00}, // - {0x2b, 0x00}, // - {0x2c, 0x00}, // - {0x2d, 0x00}, // - {0x2e, 0x33}, // - {0x2f, 0x30}, // - {0x30, 0x00}, // - {0x31, 0x00}, // - {0x32, 0x00}, // - {0x33, 0x00}, // - {0x34, 0x00}, // - {0x35, 0x00}, // - {0x36, 0x00}, // - {0x37, 0x00}, // - {0x38, 0x00}, // - {0x39, 0x00}, // - {0x3a, 0x00}, // - {0x3b, 0x00}, // - {0x3c, 0x00}, // - {0x3d, 0x00}, // - {0x3e, 0x00}, // - {0x3f, 0x00}, // - {0x40, 0xff}, // - {0x50, 0x00}, // - {0x60, 0x00}, // - {0x62, 0x00}, // -}; - -void config_lod(uint8_t aclvl_lod, uint8_t selac_lod, uint8_t shdn_lod, uint8_t acad_lod) { - uint8_t reg = 0; - reg |= aclvl_lod; - reg |= selac_lod << 2; - reg |= shdn_lod << 3; - reg |= acad_lod << 4; - ads1293_spi_writereg(&m_ads1293_0, TI_ADS1293_LOD_CN_REG, reg); -} - -void enable_lod(void) { - uint8_t reg = ads1293_spi_readreg(&m_ads1293_0, TI_ADS1293_CONFIG_REG); - reg |= 1 << 3; - ads1293_spi_writereg(&m_ads1293_0, TI_ADS1293_LOD_EN_REG, reg); -} - -void three_lead_ecg_ecg_init() { - nrf_drv_spi_config_t spi_config = NRF_DRV_SPI_DEFAULT_CONFIG; - spi_config.ss_pin = NRF_DRV_SPI_PIN_NOT_USED; // NRF_DRV_SPI_PIN_NOT_USED - spi_config.miso_pin = ADS1293_SPI_MISO_PIN; - spi_config.mosi_pin = ADS1293_SPI_MOSI_PIN; - spi_config.sck_pin = ADS1293_SPI_SCK_PIN; - spi_config.frequency = NRF_DRV_SPI_FREQ_8M; - spi_config.mode = NRF_DRV_SPI_MODE_3; - // spi_config.mode = - ZERROR_CHECK(nrf_drv_spi_init(&spi, &spi_config, NULL, NULL)); - - znrf_gpio_cfg_output(ADS1293_SPI_CS0_PIN, NRF_GPIO_PIN_NOPULL); - znrf_gpio_cfg_output(ADS1293_SPI_CS1_PIN, NRF_GPIO_PIN_NOPULL); - nrf_gpio_cfg_input(ADS1293_READY_PIN, NRF_GPIO_PIN_PULLUP); - - nrf_gpio_pin_set(ADS1293_SPI_CS0_PIN); - nrf_gpio_pin_set(ADS1293_SPI_CS1_PIN); - - m_ads1293_0.spi_tx_rx = ads1293_spi_tx_rx_0; - m_ads1293_0.id = 0; - // m_ads1293_1.spi_tx_rx = ads1293_spi_tx_rx_1; - // m_ads1293_1.id = 1; - - ads1293_spi_init(&m_ads1293_0, ads1293_spi_tx_rx_0); - ads1293_spi_init(&m_ads1293_1, ads1293_spi_tx_rx_1); - - uint8_t revid = ads1293_spi_readreg(&m_ads1293_0, TI_ADS1293_REVID_REG); - zdatachanel_send_log("ads1293_0 revid: %d\n", revid); - revid = ads1293_spi_readreg(&m_ads1293_1, TI_ADS1293_REVID_REG); - zdatachanel_send_log("ads1293_1 revid: %d\n", revid); - - zdatachanel_send_log("reset ads1293_0\n"); - ads1293_spi_writereg(&m_ads1293_0, TI_ADS1293_CONFIG_REG, 0); - nrf_delay_ms(1000); - - for (uint16_t i = 0; i < ZARRAY_SIZE(prvads0cfg); i++) { - ads1293_spi_writereg_and_check(&m_ads1293_0, prvads0cfg[i].add, prvads0cfg[i].data); - } - for (uint16_t i = 0; i < ZARRAY_SIZE(prvads1cfg); i++) { - ads1293_spi_writereg_and_check(&m_ads1293_1, prvads1cfg[i].add, prvads1cfg[i].data); - } - - // ads1293_spi_writereg(&m_ads1293_1, TI_ADS1293_CONFIG_REG, 0x01); -} - -static void zdatachanel_send_log(const char* fmt, ...) { - static char tx[256] = {0}; - int len = 0; - va_list args; - va_start(args, fmt); - len = vsprintf(tx, fmt, args); - len = strlen(tx); - int ret_val; - if (len >= 0) { - for (uint16_t i = 0; i < len; i++) { - do { - ret_val = app_uart_put(tx[i]); - } while (ret_val != NRF_SUCCESS); - } - return; - } - va_end(args); + znordic_loop(); } -#endif \ No newline at end of file diff --git a/app/src/sample_data_manager_service.c b/app/src/sample_data_manager_service.c new file mode 100644 index 0000000..4d74b02 --- /dev/null +++ b/app/src/sample_data_manager_service.c @@ -0,0 +1,155 @@ +#include "sample_data_manager_service.h" + +#include "board/board.h" +#include "board/board_sdcard_driver.h" +#include "znordic.h" +/******************************************************************************* + * 全局变量 * + *******************************************************************************/ +static FIL m_default_file_handler; +static sample_data_fileinfo_list_t m_sample_fileinfo_list; +static sample_data_fileinfo_t m_sample_fileinfo[FILE_MAX_COUNT]; + +/******************************************************************************* + * 接口层 * + *******************************************************************************/ + +static void read_file_info() { + /** + * @brief + * + * fdate: + * bit15:9 + * Year origin from 1980 (0..127) + * bit8:5 + * Month (1..12) + * bit4:0 + * Day of the month(1..31) + * ftime: + * bit15:11 + * Hour (0..23) + * bit10:5 + * Minute (0..59) + * bit4:0 + * Second / 2 (0..29) + */ + FILINFO fno; + FRESULT ff_result = f_stat("0.bin", &fno); + m_sample_fileinfo_list.fileinfo[0] = &m_sample_fileinfo[0]; + + if (ff_result == FR_OK) { + static sample_data_filename_t _filename; + _filename.year = (fno.fdate >> 9) + 1980 - 2000; + _filename.month = (fno.fdate >> 5) & 0x0F; + _filename.day = fno.fdate & 0x1F; + _filename.hour = (fno.ftime >> 11); + _filename.min = (fno.ftime >> 5) & 0x3F; + _filename.sec = (fno.ftime & 0x1F) * 2; + m_sample_fileinfo_list.fileinfo[0]->size = fno.fsize; + m_sample_fileinfo_list.count = 1; + } else { + m_sample_fileinfo_list.fileinfo[0]->size = 0; + m_sample_fileinfo_list.count = 0; + } +} + +/** + * @brief 文件驱动管理 + */ +void sample_data_mgr_init() { + Board_sdcardInit(); + + // 先连接到单片机,读取下文件状态信息 + sample_data_mgr_change_to_local_mode(); + sample_data_mgr_change_to_ext_mode(); +} +void sample_data_mgr_loadDriver() { + // donothing +} +void sample_data_mgr_unloadDriver() { + // donothin +} +typedef struct { + uint8_t filename[8]; + uint32_t filesize; + +} disk_state_t; + +/** + * @brief 存储器连接单片机 + */ +void sample_data_mgr_change_to_local_mode() { + Board_sdcardConnectToInternal(); + read_file_info(); +} +/** + * @brief 存储器连接外部typec + */ +void sample_data_mgr_change_to_ext_mode() { + if (Board_sdcardGetConnectTo() == kConnectToInternal) { + read_file_info(); + return; + } + Board_sdcardConnectToExt(); +} + +/** + * @brief 打开文件 + * + * @param filename + * @param flag + * @return int32_t + */ + +static FIL m_default_file_handler; +static bool m_is_open; +int32_t sample_data_mgr_open(sample_data_filename_t* filename, wrflag_t flag) { + FRESULT ff_result = f_open(&m_default_file_handler, (const TCHAR*)"0.bin", FA_CREATE_ALWAYS | FA_READ | FA_WRITE); + ZASSERT(ff_result == FR_OK); + m_is_open = true; + return 1; +} +int32_t sample_data_mgr_close(int32_t fd) { + ZASSERT(m_is_open); + FRESULT ff_result = f_close(&m_default_file_handler); + ZASSERT(ff_result == FR_OK); + m_is_open = false; + return 0; +} +int32_t sample_data_mgr_write(int32_t fd, const uint8_t* data, int32_t size) { + ZASSERT(m_is_open); + UINT write_size; + FRESULT ff_result = f_write(&m_default_file_handler, data, size, &write_size); + ZASSERT(ff_result == FR_OK); + return write_size; +} +int32_t sample_data_mgr_read(int32_t fd, uint8_t* data, int32_t size) { + ZASSERT(m_is_open); + UINT read_size; + FRESULT ff_result = f_read(&m_default_file_handler, data, size, &read_size); + ZASSERT(ff_result == FR_OK); + return read_size; +} +int32_t sample_data_mgr_get_file_size_by_fd(int32_t fd) { + ZASSERT(m_is_open); + return f_size(&m_default_file_handler); +} + +int32_t sample_data_mgr_delete_file(sample_data_filename_t* filename) { + if (Board_sdcardGetConnectTo() == kConnectToExt) { + /** + * @brief + * 由于设备空闲阶段,SD卡连接的是外部读卡器,所以无法删除文件 + */ + ZLOGW("unsupport now"); + return 0; + } + f_unlink((const TCHAR*)"0.bin"); + return 0; +} + +sample_data_fileinfo_list_t* sample_data_mgr_get_fileinfo_list() { // + return &m_sample_fileinfo_list; +} +bool sample_data_mgr_storage_is_full() { return m_sample_fileinfo_list.count >= FILE_MAX_COUNT; } +int32_t sample_data_mgr_get_file_num() { return m_sample_fileinfo_list.count; } diff --git a/app/src/sample_data_manager_service.h b/app/src/sample_data_manager_service.h new file mode 100644 index 0000000..a6f7b95 --- /dev/null +++ b/app/src/sample_data_manager_service.h @@ -0,0 +1,78 @@ +/** + * @file sample_data_manager_service.h + * @author zhaohe (h_zhaohe@domain.com) + * @brief 采样数据存储服务 + * @version 0.1 + * @date 2024-02-01 + * + * @copyright Copyright (c) 2024 + * + */ +#pragma once + +#include +#include + +#include "board/board.h" + +typedef struct { + uint8_t year; // from 2000 + uint8_t month; // 1-12 + uint8_t day; // 1-31 + uint8_t hour; // 0-23 + uint8_t min; // 0-59 + uint8_t sec; // 0-59 + uint8_t placeholder[2]; +} sample_data_filename_t; + +typedef struct { + uint8_t filename[8]; + int32_t fileuuid; + int32_t size; +} sample_data_fileinfo_t; + +typedef enum { + kwrflag_read_only, + kwrflag_write_only, +} wrflag_t; + +typedef struct { + sample_data_fileinfo_t* fileinfo[FILE_MAX_COUNT]; + int count; +} sample_data_fileinfo_list_t; + +/** + * @brief 文件驱动管理 + */ +void sample_data_mgr_init(); +void sample_data_mgr_loadDriver(); +void sample_data_mgr_unloadDriver(); +/******************************************************************************* + * 模式切换操作 * + *******************************************************************************/ + +/** + * @brief 存储器连接单片机 + */ +void sample_data_mgr_change_to_local_mode(); +/** + * @brief 存储器连接外部typec + */ +void sample_data_mgr_change_to_ext_mode(); + +/******************************************************************************* + * FILE_OPERATION * + *******************************************************************************/ +int32_t sample_data_mgr_open(sample_data_filename_t* filename, wrflag_t flag); +int32_t sample_data_mgr_close(int32_t fd); +int32_t sample_data_mgr_write(int32_t fd, const uint8_t* data, int32_t size); +int32_t sample_data_mgr_read(int32_t fd, uint8_t* data, int32_t size); +int32_t sample_data_mgr_get_file_size_by_fd(int32_t fd); + +/******************************************************************************* + * 文件管理操作 * + *******************************************************************************/ +int32_t sample_data_mgr_delete_file(sample_data_filename_t* filename); +sample_data_fileinfo_list_t* sample_data_mgr_get_fileinfo_list(); +bool sample_data_mgr_storage_is_full(); +int32_t sample_data_mgr_get_file_num(); diff --git a/libznordic b/libznordic index 92a15d4..2e46516 160000 --- a/libznordic +++ b/libznordic @@ -1 +1 @@ -Subproject commit 92a15d47cbe16579d92ba8385ddbeaeb37778506 +Subproject commit 2e46516dec82a92dd796312c6787f35e5adf7922