43 changed files with 25878 additions and 0 deletions
-
11.gitignore
-
18.gitmodules
-
245.vscode/c_cpp_properties.json
-
114.vscode/settings.json
-
379app/RTE/Device/nRF52833_xxAA/arm_startup_nrf52833.s
-
329app/RTE/Device/nRF52833_xxAA/system_nrf52.c
-
1660app/app.uvoptx
-
7882app/app.uvprojx
-
12168app/config/sdk_config.h
-
369app/src/ads1293_simple_tester.c
-
537app/src/app_ble_service.c
-
15app/src/app_ble_service.h
-
52app/src/app_event.h
-
23app/src/app_event_distribute.c
-
15app/src/app_event_distribute.h
-
129app/src/basic/ads1293/ads1293.c
-
142app/src/basic/ads1293/ads1293.h
-
3app/src/basic/version.h
-
0app/src/board/board.c
-
72app/src/board/board.h
-
36app/src/board/board_battery_state.c
-
14app/src/board/board_battery_state.h
-
102app/src/board/board_beep_ctrl.c
-
24app/src/board/board_beep_ctrl.h
-
34app/src/board/board_button.c
-
23app/src/board/board_button.h
-
79app/src/board/board_light_ctrl.c
-
23app/src/board/board_light_ctrl.h
-
172app/src/board/board_sdcard_driver.c
-
19app/src/board/board_sdcard_driver.h
-
357app/src/device_ctrl_service.c
-
44app/src/device_ctrl_service.h
-
455app/src/heart_wave_sample_service.c
-
35app/src/heart_wave_sample_service.h
-
43app/src/main.c
-
171app/src/sample_data_manager_service.c
-
78app/src/sample_data_manager_service.h
-
1bootloader
-
1dynamic_electrocardiograph_ble_server
-
1ify_hrs_protocol
-
1libznordic
-
1pemkey
-
1sdk
@ -0,0 +1,11 @@ |
|||
_build |
|||
app.uvguix.* |
|||
JLinkLog.txt |
|||
JLinkSettings.ini |
|||
RTE_Components.h |
|||
EventRecorderStub.scvd |
|||
app/.vscode |
|||
.vscode/uv4.log.lock |
|||
.vscode/keil-assistant.log |
|||
bin2/bl_temp.hex |
|||
bin2/settings.hex |
@ -0,0 +1,18 @@ |
|||
[submodule "sdk"] |
|||
path = sdk |
|||
url = zwsd@192.168.1.3:p_dynamic_electrocardiograph/nrf5_sdk_17_1_0.git |
|||
[submodule "bootloader"] |
|||
path = bootloader |
|||
url = zwsd@192.168.1.3:p_dynamic_electrocardiograph/bootloader.git |
|||
[submodule "pemkey"] |
|||
path = pemkey |
|||
url = zwsd@192.168.1.3:p_dynamic_electrocardiograph/pemkey.git |
|||
[submodule "dynamic_electrocardiograph_ble_server"] |
|||
path = dynamic_electrocardiograph_ble_server |
|||
url = zwsd@192.168.1.3:p_dynamic_electrocardiograph/dynamic_electrocardiograph_ble_server.git |
|||
[submodule "libznordic"] |
|||
path = libznordic |
|||
url = zwsd@192.168.1.3:p_dynamic_electrocardiograph/libznordic.git |
|||
[submodule "ify_hrs_protocol"] |
|||
path = ify_hrs_protocol |
|||
url = zwsd@192.168.1.3:p_dynamic_electrocardiograph/ify_hrs_protocol.git |
@ -0,0 +1,245 @@ |
|||
{ |
|||
"configurations": [ |
|||
{ |
|||
"name": "nrf52833_xxaa", |
|||
"includePath": [ |
|||
"libznordic\\include", |
|||
"sdk/external/fatfs/src/", |
|||
"sdk/external/fatfs/src/", |
|||
"sdk/external/fatfs/port/", |
|||
"sdk/components/libraries/block_dev/sdc/", |
|||
"sdk/components/libraries/block_dev/", |
|||
"sdk\\config", |
|||
"app\\src", |
|||
"sdk\\components", |
|||
"sdk\\components\\ble\\ble_advertising", |
|||
"sdk\\components\\ble\\ble_dtm", |
|||
"sdk\\components\\ble\\ble_link_ctx_manager", |
|||
"sdk\\components\\ble\\ble_racp", |
|||
"sdk\\components\\ble\\ble_services\\ble_ancs_c", |
|||
"sdk\\components\\ble\\ble_services\\ble_ans_c", |
|||
"sdk\\components\\ble\\ble_services\\ble_bas", |
|||
"sdk\\components\\ble\\ble_services\\ble_bas_c", |
|||
"sdk\\components\\ble\\ble_services\\ble_cscs", |
|||
"sdk\\components\\ble\\ble_services\\ble_cts_c", |
|||
"sdk\\components\\ble\\ble_services\\ble_dfu", |
|||
"sdk\\components\\ble\\ble_services\\ble_dis", |
|||
"sdk\\components\\ble\\ble_services\\ble_gls", |
|||
"sdk\\components\\ble\\ble_services\\ble_hids", |
|||
"sdk\\components\\ble\\ble_services\\ble_hrs", |
|||
"sdk\\components\\ble\\ble_services\\ble_hrs_c", |
|||
"sdk\\components\\ble\\ble_services\\ble_hts", |
|||
"sdk\\components\\ble\\ble_services\\ble_ias", |
|||
"sdk\\components\\ble\\ble_services\\ble_ias_c", |
|||
"sdk\\components\\ble\\ble_services\\ble_lbs", |
|||
"sdk\\components\\ble\\ble_services\\ble_lbs_c", |
|||
"sdk\\components\\ble\\ble_services\\ble_lls", |
|||
"sdk\\components\\ble\\ble_services\\ble_nus", |
|||
"sdk\\components\\ble\\ble_services\\ble_nus_c", |
|||
"sdk\\components\\ble\\ble_services\\ble_rscs", |
|||
"sdk\\components\\ble\\ble_services\\ble_rscs_c", |
|||
"sdk\\components\\ble\\ble_services\\ble_tps", |
|||
"sdk\\components\\ble\\common", |
|||
"sdk\\components\\ble\\nrf_ble_gatt", |
|||
"sdk\\components\\ble\\nrf_ble_qwr", |
|||
"sdk\\components\\ble\\peer_manager", |
|||
"sdk\\components\\boards", |
|||
"sdk\\components\\libraries\\atomic", |
|||
"sdk\\components\\libraries\\atomic_fifo", |
|||
"sdk\\components\\libraries\\atomic_flags", |
|||
"sdk\\components\\libraries\\balloc", |
|||
"sdk\\components\\libraries\\bootloader\\ble_dfu", |
|||
"sdk\\components\\libraries\\bsp", |
|||
"sdk\\components\\libraries\\button", |
|||
"sdk\\components\\libraries\\cli", |
|||
"sdk\\components\\libraries\\crc16", |
|||
"sdk\\components\\libraries\\crc32", |
|||
"sdk\\components\\libraries\\crypto", |
|||
"sdk\\components\\libraries\\csense", |
|||
"sdk\\components\\libraries\\csense_drv", |
|||
"sdk\\components\\libraries\\delay", |
|||
"sdk\\components\\libraries\\ecc", |
|||
"sdk\\components\\libraries\\experimental_section_vars", |
|||
"sdk\\components\\libraries\\experimental_task_manager", |
|||
"sdk\\components\\libraries\\fds", |
|||
"sdk\\components\\libraries\\fifo", |
|||
"sdk\\components\\libraries\\fstorage", |
|||
"sdk\\components\\libraries\\gfx", |
|||
"sdk\\components\\libraries\\gpiote", |
|||
"sdk\\components\\libraries\\hardfault", |
|||
"sdk\\components\\libraries\\hci", |
|||
"sdk\\components\\libraries\\led_softblink", |
|||
"sdk\\components\\libraries\\log", |
|||
"sdk\\components\\libraries\\log\\src", |
|||
"sdk\\components\\libraries\\low_power_pwm", |
|||
"sdk\\components\\libraries\\mem_manager", |
|||
"sdk\\components\\libraries\\memobj", |
|||
"sdk\\components\\libraries\\mpu", |
|||
"sdk\\components\\libraries\\mutex", |
|||
"sdk\\components\\libraries\\pwm", |
|||
"sdk\\components\\libraries\\pwr_mgmt", |
|||
"sdk\\components\\libraries\\queue", |
|||
"sdk\\components\\libraries\\ringbuf", |
|||
"sdk\\components\\libraries\\scheduler", |
|||
"sdk\\components\\libraries\\sdcard", |
|||
"sdk\\components\\libraries\\slip", |
|||
"sdk\\components\\libraries\\sortlist", |
|||
"sdk\\components\\libraries\\spi_mngr", |
|||
"sdk\\components\\libraries\\stack_guard", |
|||
"sdk\\components\\libraries\\strerror", |
|||
"sdk\\components\\libraries\\svc", |
|||
"sdk\\components\\libraries\\timer", |
|||
"sdk\\components\\libraries\\twi_mngr", |
|||
"sdk\\components\\libraries\\twi_sensor", |
|||
"sdk\\components\\libraries\\uart", |
|||
"sdk\\components\\libraries\\usbd", |
|||
"sdk\\components\\libraries\\usbd\\class\\audio", |
|||
"sdk\\components\\libraries\\usbd\\class\\cdc", |
|||
"sdk\\components\\libraries\\usbd\\class\\cdc\\acm", |
|||
"sdk\\components\\libraries\\usbd\\class\\hid", |
|||
"sdk\\components\\libraries\\usbd\\class\\hid\\generic", |
|||
"sdk\\components\\libraries\\usbd\\class\\hid\\kbd", |
|||
"sdk\\components\\libraries\\usbd\\class\\hid\\mouse", |
|||
"sdk\\components\\libraries\\usbd\\class\\msc", |
|||
"sdk\\components\\libraries\\util", |
|||
"sdk\\components\\nfc\\ndef\\conn_hand_parser", |
|||
"sdk\\components\\nfc\\ndef\\conn_hand_parser\\ac_rec_parser", |
|||
"sdk\\components\\nfc\\ndef\\conn_hand_parser\\ble_oob_advdata_parser", |
|||
"sdk\\components\\nfc\\ndef\\conn_hand_parser\\le_oob_rec_parser", |
|||
"sdk\\components\\nfc\\ndef\\connection_handover\\ac_rec", |
|||
"sdk\\components\\nfc\\ndef\\connection_handover\\ble_oob_advdata", |
|||
"sdk\\components\\nfc\\ndef\\connection_handover\\ble_pair_lib", |
|||
"sdk\\components\\nfc\\ndef\\connection_handover\\ble_pair_msg", |
|||
"sdk\\components\\nfc\\ndef\\connection_handover\\common", |
|||
"sdk\\components\\nfc\\ndef\\connection_handover\\ep_oob_rec", |
|||
"sdk\\components\\nfc\\ndef\\connection_handover\\hs_rec", |
|||
"sdk\\components\\nfc\\ndef\\connection_handover\\le_oob_rec", |
|||
"sdk\\components\\nfc\\ndef\\generic\\message", |
|||
"sdk\\components\\nfc\\ndef\\generic\\record", |
|||
"sdk\\components\\nfc\\ndef\\launchapp", |
|||
"sdk\\components\\nfc\\ndef\\parser\\message", |
|||
"sdk\\components\\nfc\\ndef\\parser\\record", |
|||
"sdk\\components\\nfc\\ndef\\text", |
|||
"sdk\\components\\nfc\\ndef\\uri", |
|||
"sdk\\components\\nfc\\platform", |
|||
"sdk\\components\\nfc\\t2t_lib", |
|||
"sdk\\components\\nfc\\t2t_parser", |
|||
"sdk\\components\\nfc\\t4t_lib", |
|||
"sdk\\components\\nfc\\t4t_parser\\apdu", |
|||
"sdk\\components\\nfc\\t4t_parser\\cc_file", |
|||
"sdk\\components\\nfc\\t4t_parser\\hl_detection_procedure", |
|||
"sdk\\components\\nfc\\t4t_parser\\tlv", |
|||
"sdk\\components\\softdevice\\common", |
|||
"sdk\\components\\softdevice\\s140\\headers", |
|||
"sdk\\components\\softdevice\\s140\\headers\\nrf52", |
|||
"sdk\\external\\fprintf", |
|||
"sdk\\external\\segger_rtt", |
|||
"sdk\\external\\utf_converter", |
|||
"sdk\\integration\\nrfx", |
|||
"sdk\\integration\\nrfx\\legacy", |
|||
"sdk\\modules\\nrfx", |
|||
"sdk\\modules\\nrfx\\drivers\\include", |
|||
"sdk\\modules\\nrfx\\hal", |
|||
"app\\config\\", |
|||
"app\\config", |
|||
"app", |
|||
"sdk\\modules\\nrfx\\soc", |
|||
"sdk\\modules\\nrfx\\drivers\\src", |
|||
"sdk\\modules\\nrfx\\drivers\\src\\prs", |
|||
"sdk\\modules\\nrfx\\mdk\\", |
|||
"sdk\\components\\toolchain\\cmsis\\include\\", |
|||
"sdk\\components\\libraries\\bootloader\\" |
|||
], |
|||
"defines": [ |
|||
"BL_SETTINGS_ACCESS_ONLY", |
|||
"NRF_DFU_SVCI_ENABLED", |
|||
"NRF_DFU_TRANSPORT_BLE=1", |
|||
"CONFIG_NFCT_PINS_AS_GPIOS", |
|||
"APP_TIMER_V2", |
|||
"APP_TIMER_V2_RTC1_ENABLED", |
|||
"BOARD_PCA10100", |
|||
"FLOAT_ABI_HARD", |
|||
"NRF52833_XXAA", |
|||
"NRF_SD_BLE_API_VERSION=7", |
|||
"S140", |
|||
"SOFTDEVICE_PRESENT", |
|||
"__HEAP_SIZE=2048", |
|||
"__STACK_SIZE=4096", |
|||
"__CC_ARM", |
|||
"__arm__", |
|||
"__align(x)=", |
|||
"__ALIGNOF__(x)=", |
|||
"__alignof__(x)=", |
|||
"__asm(x)=", |
|||
"__forceinline=", |
|||
"__restrict=", |
|||
"__global_reg(n)=", |
|||
"__inline=", |
|||
"__int64=long long", |
|||
"__INTADDR__(expr)=0", |
|||
"__irq=", |
|||
"__packed=", |
|||
"__pure=", |
|||
"__smc(n)=", |
|||
"__svc(n)=", |
|||
"__svc_indirect(n)=", |
|||
"__svc_indirect_r7(n)=", |
|||
"__value_in_regs=", |
|||
"__weak=", |
|||
"__writeonly=", |
|||
"__declspec(x)=", |
|||
"__attribute__(x)=", |
|||
"__nonnull__(x)=", |
|||
"__register=", |
|||
"__breakpoint(x)=", |
|||
"__cdp(x,y,z)=", |
|||
"__clrex()=", |
|||
"__clz(x)=0U", |
|||
"__current_pc()=0U", |
|||
"__current_sp()=0U", |
|||
"__disable_fiq()=", |
|||
"__disable_irq()=", |
|||
"__dmb(x)=", |
|||
"__dsb(x)=", |
|||
"__enable_fiq()=", |
|||
"__enable_irq()=", |
|||
"__fabs(x)=0.0", |
|||
"__fabsf(x)=0.0f", |
|||
"__force_loads()=", |
|||
"__force_stores()=", |
|||
"__isb(x)=", |
|||
"__ldrex(x)=0U", |
|||
"__ldrexd(x)=0U", |
|||
"__ldrt(x)=0U", |
|||
"__memory_changed()=", |
|||
"__nop()=", |
|||
"__pld(...)=", |
|||
"__pli(...)=", |
|||
"__qadd(x,y)=0", |
|||
"__qdbl(x)=0", |
|||
"__qsub(x,y)=0", |
|||
"__rbit(x)=0U", |
|||
"__rev(x)=0U", |
|||
"__return_address()=0U", |
|||
"__ror(x,y)=0U", |
|||
"__schedule_barrier()=", |
|||
"__semihost(x,y)=0", |
|||
"__sev()=", |
|||
"__sqrt(x)=0.0", |
|||
"__sqrtf(x)=0.0f", |
|||
"__ssat(x,y)=0", |
|||
"__strex(x,y)=0U", |
|||
"__strexd(x,y)=0", |
|||
"__strt(x,y)=", |
|||
"__swp(x,y)=0U", |
|||
"__usat(x,y)=0U", |
|||
"__wfe()=", |
|||
"__wfi()=", |
|||
"__yield()=", |
|||
"__vfp_status(x,y)=0" |
|||
], |
|||
"intelliSenseMode": "${default}" |
|||
} |
|||
], |
|||
"version": 4 |
|||
} |
@ -0,0 +1,114 @@ |
|||
{ |
|||
"files.associations": { |
|||
"*.hpp": "cpp", |
|||
"ble_hci.h": "c", |
|||
"ble_advdata.h": "c", |
|||
"ble_advertising.h": "c", |
|||
"ble_conn_params.h": "c", |
|||
"nrf_sdh.h": "c", |
|||
"nrf_sdh_soc.h": "c", |
|||
"nrf_sdh_ble.h": "c", |
|||
"nrf_ble_gatt.h": "c", |
|||
"nrf_ble_qwr.h": "c", |
|||
"app_timer.h": "c", |
|||
"nordic_common.h": "c", |
|||
"nrf.h": "c", |
|||
"nrf52833.h": "c", |
|||
"nrf52833_bitfields.h": "c", |
|||
"system_nrf52833.h": "c", |
|||
"app_util_platform.h": "c", |
|||
"string.h": "c", |
|||
"ble_nus.h": "c", |
|||
"app_uart.h": "c", |
|||
"bsp_btn_ble.h": "c", |
|||
"nrf_pwr_mgmt.h": "c", |
|||
"core_cm4.h": "c", |
|||
"nrf52_to_nrf52833.h": "c", |
|||
"compare": "c", |
|||
"type_traits": "c", |
|||
"stdint.h": "c", |
|||
"sys.h": "c", |
|||
"nrf_log.h": "c", |
|||
"version.h": "c", |
|||
"zble_module.h": "c", |
|||
"pca10112.h": "c", |
|||
"pca10100.h": "c", |
|||
"board.h": "c", |
|||
"stdio.h": "c", |
|||
"nrf_log_ctrl.h": "c", |
|||
"nrf_log_default_backends.h": "c", |
|||
"nrf_delay.h": "c", |
|||
"zhrs_service.h": "c", |
|||
"ble_srv_common.h": "c", |
|||
"zdatachannel_service.h": "c", |
|||
"ble_link_ctx_manager.h": "c", |
|||
"nrf_drv_saadc.h": "c", |
|||
"project_cfg.h": "c", |
|||
"nrf_block_dev_sdc.h": "c", |
|||
"nrf_drv_pwm.h": "c", |
|||
"nrfx_config.h": "c", |
|||
"nrf_drv_wdt.h": "c", |
|||
"app_sdcard.h": "c", |
|||
"diskio_blkdev.h": "c", |
|||
"three_conduction_main.h": "c", |
|||
"one_conduction_main.h": "c", |
|||
"one_conduction_board.h": "c", |
|||
"driver_ssd1306.h": "c", |
|||
"driver_ssd1306_font.h": "c", |
|||
"driver_ssd1306_basic.h": "c", |
|||
"driver_ssd1306_interface.h": "c", |
|||
"three_lead_board.h": "c", |
|||
"znordic.h": "c", |
|||
"ads1293.h": "c", |
|||
"app_scheduler.h": "c", |
|||
"stdbool.h": "c", |
|||
"stdlib.h": "c", |
|||
"zble_nus_c.h": "c", |
|||
"ble.h": "c", |
|||
"ble_gattc.h": "c", |
|||
"ble_gatt.h": "c", |
|||
"ble_gap.h": "c", |
|||
"sdk_common.h": "c", |
|||
"app_error.h": "c", |
|||
"ble_gatts.h": "c", |
|||
"sdk_macros.h": "c", |
|||
"app_util.h": "c", |
|||
"ble_types.h": "c", |
|||
"ble_db_discovery.h": "c", |
|||
"ble_gatt_db.h": "c", |
|||
"nrf_ble_gq.h": "c", |
|||
"ti_ads1293_register_settings.h": "c", |
|||
"typeinfo": "c", |
|||
"fontlib.h": "c", |
|||
"font.h": "c", |
|||
"display_manager.h": "c", |
|||
"wave_drawer.h": "c", |
|||
"sample_data_manager.h": "c", |
|||
"zeeprom_fs.h": "c", |
|||
"config.h": "c", |
|||
"stdarg.h": "c", |
|||
"nrf_uarte.h": "c", |
|||
"heart_rate_sensor_protocol.h": "c", |
|||
"ble_cmd_process_service.h": "c", |
|||
"heart_wave_sample_service.h": "c", |
|||
"znordic_device_info_mgr.h": "c", |
|||
"nrf_uart.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", |
|||
"device_ctrl_service.h": "c", |
|||
"board_battery_state.h": "c", |
|||
"board_sdcard_driver.h": "c", |
|||
"board_button.h": "c", |
|||
"app_event_distribute.h": "c", |
|||
"board_beep_ctrl.h": "c", |
|||
"nrf_soc.h": "c", |
|||
"sample_data_manager_service.h": "c", |
|||
"app_event.h": "c", |
|||
"compiler_abstraction.h": "c" |
|||
}, |
|||
"files.encoding": "gbk" |
|||
} |
@ -0,0 +1,379 @@ |
|||
; Copyright (c) 2009-2021 ARM Limited. All rights reserved. |
|||
; |
|||
; SPDX-License-Identifier: Apache-2.0 |
|||
; |
|||
; Licensed under the Apache License, Version 2.0 (the License); you may |
|||
; not use this file except in compliance with the License. |
|||
; You may obtain a copy of the License at |
|||
; |
|||
; www.apache.org/licenses/LICENSE-2.0 |
|||
; |
|||
; Unless required by applicable law or agreed to in writing, software |
|||
; distributed under the License is distributed on an AS IS BASIS, WITHOUT |
|||
; WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
; See the License for the specific language governing permissions and |
|||
; limitations under the License. |
|||
; |
|||
; NOTICE: This file has been modified by Nordic Semiconductor ASA. |
|||
|
|||
IF :DEF: __STARTUP_CONFIG |
|||
#ifdef __STARTUP_CONFIG |
|||
#include "startup_config.h" |
|||
#ifndef __STARTUP_CONFIG_STACK_ALIGNEMENT |
|||
#define __STARTUP_CONFIG_STACK_ALIGNEMENT 3 |
|||
#endif |
|||
#endif |
|||
ENDIF |
|||
|
|||
IF :DEF: __STARTUP_CONFIG |
|||
Stack_Size EQU __STARTUP_CONFIG_STACK_SIZE |
|||
ELIF :DEF: __STACK_SIZE |
|||
Stack_Size EQU __STACK_SIZE |
|||
ELSE |
|||
Stack_Size EQU 8192 |
|||
ENDIF |
|||
|
|||
IF :DEF: __STARTUP_CONFIG |
|||
Stack_Align EQU __STARTUP_CONFIG_STACK_ALIGNEMENT |
|||
ELSE |
|||
Stack_Align EQU 3 |
|||
ENDIF |
|||
|
|||
AREA STACK, NOINIT, READWRITE, ALIGN=Stack_Align |
|||
Stack_Mem SPACE Stack_Size |
|||
__initial_sp |
|||
|
|||
IF :DEF: __STARTUP_CONFIG |
|||
Heap_Size EQU __STARTUP_CONFIG_HEAP_SIZE |
|||
ELIF :DEF: __HEAP_SIZE |
|||
Heap_Size EQU __HEAP_SIZE |
|||
ELSE |
|||
Heap_Size EQU 8192 |
|||
ENDIF |
|||
|
|||
AREA HEAP, NOINIT, READWRITE, ALIGN=3 |
|||
__heap_base |
|||
Heap_Mem SPACE Heap_Size |
|||
__heap_limit |
|||
|
|||
PRESERVE8 |
|||
THUMB |
|||
|
|||
; Vector Table Mapped to Address 0 at Reset |
|||
|
|||
AREA RESET, DATA, READONLY |
|||
EXPORT __Vectors |
|||
EXPORT __Vectors_End |
|||
EXPORT __Vectors_Size |
|||
|
|||
__Vectors DCD __initial_sp ; Top of Stack |
|||
DCD Reset_Handler |
|||
DCD NMI_Handler |
|||
DCD HardFault_Handler |
|||
DCD MemoryManagement_Handler |
|||
DCD BusFault_Handler |
|||
DCD UsageFault_Handler |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD SVC_Handler |
|||
DCD DebugMon_Handler |
|||
DCD 0 ; Reserved |
|||
DCD PendSV_Handler |
|||
DCD SysTick_Handler |
|||
|
|||
; External Interrupts |
|||
DCD POWER_CLOCK_IRQHandler |
|||
DCD RADIO_IRQHandler |
|||
DCD UARTE0_UART0_IRQHandler |
|||
DCD SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQHandler |
|||
DCD SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1_IRQHandler |
|||
DCD NFCT_IRQHandler |
|||
DCD GPIOTE_IRQHandler |
|||
DCD SAADC_IRQHandler |
|||
DCD TIMER0_IRQHandler |
|||
DCD TIMER1_IRQHandler |
|||
DCD TIMER2_IRQHandler |
|||
DCD RTC0_IRQHandler |
|||
DCD TEMP_IRQHandler |
|||
DCD RNG_IRQHandler |
|||
DCD ECB_IRQHandler |
|||
DCD CCM_AAR_IRQHandler |
|||
DCD WDT_IRQHandler |
|||
DCD RTC1_IRQHandler |
|||
DCD QDEC_IRQHandler |
|||
DCD COMP_LPCOMP_IRQHandler |
|||
DCD SWI0_EGU0_IRQHandler |
|||
DCD SWI1_EGU1_IRQHandler |
|||
DCD SWI2_EGU2_IRQHandler |
|||
DCD SWI3_EGU3_IRQHandler |
|||
DCD SWI4_EGU4_IRQHandler |
|||
DCD SWI5_EGU5_IRQHandler |
|||
DCD TIMER3_IRQHandler |
|||
DCD TIMER4_IRQHandler |
|||
DCD PWM0_IRQHandler |
|||
DCD PDM_IRQHandler |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD MWU_IRQHandler |
|||
DCD PWM1_IRQHandler |
|||
DCD PWM2_IRQHandler |
|||
DCD SPIM2_SPIS2_SPI2_IRQHandler |
|||
DCD RTC2_IRQHandler |
|||
DCD I2S_IRQHandler |
|||
DCD FPU_IRQHandler |
|||
DCD USBD_IRQHandler |
|||
DCD UARTE1_IRQHandler |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD PWM3_IRQHandler |
|||
DCD 0 ; Reserved |
|||
DCD SPIM3_IRQHandler |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
DCD 0 ; Reserved |
|||
|
|||
__Vectors_End |
|||
|
|||
__Vectors_Size EQU __Vectors_End - __Vectors |
|||
|
|||
AREA |.text|, CODE, READONLY |
|||
|
|||
; Reset Handler |
|||
|
|||
|
|||
Reset_Handler PROC |
|||
EXPORT Reset_Handler [WEAK] |
|||
IMPORT SystemInit |
|||
IMPORT __main |
|||
|
|||
|
|||
LDR R0, =SystemInit |
|||
BLX R0 |
|||
LDR R0, =__main |
|||
BX R0 |
|||
ENDP |
|||
|
|||
; Dummy Exception Handlers (infinite loops which can be modified) |
|||
|
|||
NMI_Handler PROC |
|||
EXPORT NMI_Handler [WEAK] |
|||
B . |
|||
ENDP |
|||
HardFault_Handler\ |
|||
PROC |
|||
EXPORT HardFault_Handler [WEAK] |
|||
B . |
|||
ENDP |
|||
MemoryManagement_Handler\ |
|||
PROC |
|||
EXPORT MemoryManagement_Handler [WEAK] |
|||
B . |
|||
ENDP |
|||
BusFault_Handler\ |
|||
PROC |
|||
EXPORT BusFault_Handler [WEAK] |
|||
B . |
|||
ENDP |
|||
UsageFault_Handler\ |
|||
PROC |
|||
EXPORT UsageFault_Handler [WEAK] |
|||
B . |
|||
ENDP |
|||
SVC_Handler PROC |
|||
EXPORT SVC_Handler [WEAK] |
|||
B . |
|||
ENDP |
|||
DebugMon_Handler\ |
|||
PROC |
|||
EXPORT DebugMon_Handler [WEAK] |
|||
B . |
|||
ENDP |
|||
PendSV_Handler PROC |
|||
EXPORT PendSV_Handler [WEAK] |
|||
B . |
|||
ENDP |
|||
SysTick_Handler PROC |
|||
EXPORT SysTick_Handler [WEAK] |
|||
B . |
|||
ENDP |
|||
|
|||
Default_Handler PROC |
|||
|
|||
EXPORT POWER_CLOCK_IRQHandler [WEAK] |
|||
EXPORT RADIO_IRQHandler [WEAK] |
|||
EXPORT UARTE0_UART0_IRQHandler [WEAK] |
|||
EXPORT SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQHandler [WEAK] |
|||
EXPORT SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1_IRQHandler [WEAK] |
|||
EXPORT NFCT_IRQHandler [WEAK] |
|||
EXPORT GPIOTE_IRQHandler [WEAK] |
|||
EXPORT SAADC_IRQHandler [WEAK] |
|||
EXPORT TIMER0_IRQHandler [WEAK] |
|||
EXPORT TIMER1_IRQHandler [WEAK] |
|||
EXPORT TIMER2_IRQHandler [WEAK] |
|||
EXPORT RTC0_IRQHandler [WEAK] |
|||
EXPORT TEMP_IRQHandler [WEAK] |
|||
EXPORT RNG_IRQHandler [WEAK] |
|||
EXPORT ECB_IRQHandler [WEAK] |
|||
EXPORT CCM_AAR_IRQHandler [WEAK] |
|||
EXPORT WDT_IRQHandler [WEAK] |
|||
EXPORT RTC1_IRQHandler [WEAK] |
|||
EXPORT QDEC_IRQHandler [WEAK] |
|||
EXPORT COMP_LPCOMP_IRQHandler [WEAK] |
|||
EXPORT SWI0_EGU0_IRQHandler [WEAK] |
|||
EXPORT SWI1_EGU1_IRQHandler [WEAK] |
|||
EXPORT SWI2_EGU2_IRQHandler [WEAK] |
|||
EXPORT SWI3_EGU3_IRQHandler [WEAK] |
|||
EXPORT SWI4_EGU4_IRQHandler [WEAK] |
|||
EXPORT SWI5_EGU5_IRQHandler [WEAK] |
|||
EXPORT TIMER3_IRQHandler [WEAK] |
|||
EXPORT TIMER4_IRQHandler [WEAK] |
|||
EXPORT PWM0_IRQHandler [WEAK] |
|||
EXPORT PDM_IRQHandler [WEAK] |
|||
EXPORT MWU_IRQHandler [WEAK] |
|||
EXPORT PWM1_IRQHandler [WEAK] |
|||
EXPORT PWM2_IRQHandler [WEAK] |
|||
EXPORT SPIM2_SPIS2_SPI2_IRQHandler [WEAK] |
|||
EXPORT RTC2_IRQHandler [WEAK] |
|||
EXPORT I2S_IRQHandler [WEAK] |
|||
EXPORT FPU_IRQHandler [WEAK] |
|||
EXPORT USBD_IRQHandler [WEAK] |
|||
EXPORT UARTE1_IRQHandler [WEAK] |
|||
EXPORT PWM3_IRQHandler [WEAK] |
|||
EXPORT SPIM3_IRQHandler [WEAK] |
|||
POWER_CLOCK_IRQHandler |
|||
RADIO_IRQHandler |
|||
UARTE0_UART0_IRQHandler |
|||
SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQHandler |
|||
SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1_IRQHandler |
|||
NFCT_IRQHandler |
|||
GPIOTE_IRQHandler |
|||
SAADC_IRQHandler |
|||
TIMER0_IRQHandler |
|||
TIMER1_IRQHandler |
|||
TIMER2_IRQHandler |
|||
RTC0_IRQHandler |
|||
TEMP_IRQHandler |
|||
RNG_IRQHandler |
|||
ECB_IRQHandler |
|||
CCM_AAR_IRQHandler |
|||
WDT_IRQHandler |
|||
RTC1_IRQHandler |
|||
QDEC_IRQHandler |
|||
COMP_LPCOMP_IRQHandler |
|||
SWI0_EGU0_IRQHandler |
|||
SWI1_EGU1_IRQHandler |
|||
SWI2_EGU2_IRQHandler |
|||
SWI3_EGU3_IRQHandler |
|||
SWI4_EGU4_IRQHandler |
|||
SWI5_EGU5_IRQHandler |
|||
TIMER3_IRQHandler |
|||
TIMER4_IRQHandler |
|||
PWM0_IRQHandler |
|||
PDM_IRQHandler |
|||
MWU_IRQHandler |
|||
PWM1_IRQHandler |
|||
PWM2_IRQHandler |
|||
SPIM2_SPIS2_SPI2_IRQHandler |
|||
RTC2_IRQHandler |
|||
I2S_IRQHandler |
|||
FPU_IRQHandler |
|||
USBD_IRQHandler |
|||
UARTE1_IRQHandler |
|||
PWM3_IRQHandler |
|||
SPIM3_IRQHandler |
|||
B . |
|||
ENDP |
|||
ALIGN |
|||
|
|||
; User Initial Stack & Heap |
|||
|
|||
IF :DEF:__MICROLIB |
|||
|
|||
EXPORT __initial_sp |
|||
EXPORT __heap_base |
|||
EXPORT __heap_limit |
|||
|
|||
ELSE |
|||
|
|||
IMPORT __use_two_region_memory |
|||
EXPORT __user_initial_stackheap |
|||
|
|||
__user_initial_stackheap PROC |
|||
|
|||
LDR R0, = Heap_Mem |
|||
LDR R1, = (Stack_Mem + Stack_Size) |
|||
LDR R2, = (Heap_Mem + Heap_Size) |
|||
LDR R3, = Stack_Mem |
|||
BX LR |
|||
ENDP |
|||
|
|||
ALIGN |
|||
|
|||
ENDIF |
|||
|
|||
END |
@ -0,0 +1,329 @@ |
|||
/* |
|||
|
|||
Copyright (c) 2009-2021 ARM Limited. All rights reserved. |
|||
|
|||
SPDX-License-Identifier: Apache-2.0 |
|||
|
|||
Licensed under the Apache License, Version 2.0 (the License); you may |
|||
not use this file except in compliance with the License. |
|||
You may obtain a copy of the License at |
|||
|
|||
www.apache.org/licenses/LICENSE-2.0 |
|||
|
|||
Unless required by applicable law or agreed to in writing, software |
|||
distributed under the License is distributed on an AS IS BASIS, WITHOUT |
|||
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
See the License for the specific language governing permissions and |
|||
limitations under the License. |
|||
|
|||
NOTICE: This file has been modified by Nordic Semiconductor ASA. |
|||
|
|||
*/ |
|||
|
|||
/* NOTE: Template files (including this one) are application specific and therefore expected to |
|||
be copied into the application project folder prior to its use! */ |
|||
|
|||
#include <stdint.h> |
|||
#include <stdbool.h> |
|||
#include "nrf.h" |
|||
#include "nrf_peripherals.h" |
|||
#include "nrf52_erratas.h" |
|||
#include "system_nrf52.h" |
|||
#include "system_nrf52_approtect.h" |
|||
|
|||
#define __SYSTEM_CLOCK_64M (64000000UL) |
|||
|
|||
|
|||
#if defined ( __CC_ARM ) |
|||
uint32_t SystemCoreClock __attribute__((used)) = __SYSTEM_CLOCK_64M; |
|||
#elif defined ( __ICCARM__ ) |
|||
__root uint32_t SystemCoreClock = __SYSTEM_CLOCK_64M; |
|||
#elif defined ( __GNUC__ ) |
|||
uint32_t SystemCoreClock __attribute__((used)) = __SYSTEM_CLOCK_64M; |
|||
#endif |
|||
|
|||
/* Select correct reset pin */ |
|||
/* Handle DEVELOP_IN-targets first as they take precedence over the later macros */ |
|||
#if defined (DEVELOP_IN_NRF52805) \ |
|||
|| defined (DEVELOP_IN_NRF52810) \ |
|||
|| defined (DEVELOP_IN_NRF52811) \ |
|||
|| defined (DEVELOP_IN_NRF52832) |
|||
#define RESET_PIN 21 |
|||
#elif defined (DEVELOP_IN_NRF52820) \ |
|||
|| defined (DEVELOP_IN_NRF52833) \ |
|||
|| defined (DEVELOP_IN_NRF52840) |
|||
#define RESET_PIN 18 |
|||
#elif defined (NRF52805_XXAA) \ |
|||
|| defined (NRF52810_XXAA) \ |
|||
|| defined (NRF52811_XXAA) \ |
|||
|| defined (NRF52832_XXAA) \ |
|||
|| defined (NRF52832_XXAB) |
|||
#define RESET_PIN 21 |
|||
#elif defined (NRF52820_XXAA) \ |
|||
|| defined (NRF52833_XXAA) \ |
|||
|| defined (NRF52840_XXAA) |
|||
#define RESET_PIN 18 |
|||
#else |
|||
#error "A supported device macro must be defined." |
|||
#endif |
|||
|
|||
/* -- NVMC utility functions -- */ |
|||
/* Waits until NVMC is done with the current pending action */ |
|||
void nvmc_wait(void) |
|||
{ |
|||
while (NRF_NVMC->READY == NVMC_READY_READY_Busy){} |
|||
} |
|||
|
|||
/* Configure the NVMC to "mode". |
|||
Mode must be an enumerator of field NVMC_CONFIG_WEN */ |
|||
void nvmc_config(uint32_t mode) |
|||
{ |
|||
NRF_NVMC->CONFIG = mode << NVMC_CONFIG_WEN_Pos; |
|||
nvmc_wait(); |
|||
} |
|||
|
|||
void SystemCoreClockUpdate(void) |
|||
{ |
|||
SystemCoreClock = __SYSTEM_CLOCK_64M; |
|||
} |
|||
|
|||
void SystemInit(void) |
|||
{ |
|||
/* Enable SWO trace functionality. If ENABLE_SWO is not defined, SWO pin will be used as GPIO (see Product |
|||
Specification to see which one). */ |
|||
#if defined (ENABLE_SWO) && defined(CLOCK_TRACECONFIG_TRACEMUX_Pos) |
|||
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; |
|||
NRF_CLOCK->TRACECONFIG |= CLOCK_TRACECONFIG_TRACEMUX_Serial << CLOCK_TRACECONFIG_TRACEMUX_Pos; |
|||
NRF_P0->PIN_CNF[18] = (GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos) | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos); |
|||
#endif |
|||
|
|||
/* Enable Trace functionality. If ENABLE_TRACE is not defined, TRACE pins will be used as GPIOs (see Product |
|||
Specification to see which ones). */ |
|||
#if defined (ENABLE_TRACE) && defined(CLOCK_TRACECONFIG_TRACEMUX_Pos) |
|||
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; |
|||
NRF_CLOCK->TRACECONFIG |= CLOCK_TRACECONFIG_TRACEMUX_Parallel << CLOCK_TRACECONFIG_TRACEMUX_Pos; |
|||
NRF_P0->PIN_CNF[14] = (GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos) | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos); |
|||
NRF_P0->PIN_CNF[15] = (GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos) | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos); |
|||
NRF_P0->PIN_CNF[16] = (GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos) | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos); |
|||
NRF_P0->PIN_CNF[18] = (GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos) | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos); |
|||
NRF_P0->PIN_CNF[20] = (GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos) | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos); |
|||
#endif |
|||
|
|||
#if NRF52_ERRATA_12_ENABLE_WORKAROUND |
|||
/* Workaround for Errata 12 "COMP: Reference ladder not correctly calibrated" found at the Errata document |
|||
for your device located at https://infocenter.nordicsemi.com/index.jsp */ |
|||
if (nrf52_errata_12()){ |
|||
*(volatile uint32_t *)0x40013540 = (*(uint32_t *)0x10000324 & 0x00001F00) >> 8; |
|||
} |
|||
#endif |
|||
|
|||
#if NRF52_ERRATA_16_ENABLE_WORKAROUND |
|||
/* Workaround for Errata 16 "System: RAM may be corrupt on wakeup from CPU IDLE" found at the Errata document |
|||
for your device located at https://infocenter.nordicsemi.com/index.jsp */ |
|||
if (nrf52_errata_16()){ |
|||
*(volatile uint32_t *)0x4007C074 = 3131961357ul; |
|||
} |
|||
#endif |
|||
|
|||
#if NRF52_ERRATA_31_ENABLE_WORKAROUND |
|||
/* Workaround for Errata 31 "CLOCK: Calibration values are not correctly loaded from FICR at reset" found at the Errata document |
|||
for your device located at https://infocenter.nordicsemi.com/index.jsp */ |
|||
if (nrf52_errata_31()){ |
|||
*(volatile uint32_t *)0x4000053C = ((*(volatile uint32_t *)0x10000244) & 0x0000E000) >> 13; |
|||
} |
|||
#endif |
|||
|
|||
#if NRF52_ERRATA_32_ENABLE_WORKAROUND |
|||
/* Workaround for Errata 32 "DIF: Debug session automatically enables TracePort pins" found at the Errata document |
|||
for your device located at https://infocenter.nordicsemi.com/index.jsp */ |
|||
if (nrf52_errata_32()){ |
|||
CoreDebug->DEMCR &= ~CoreDebug_DEMCR_TRCENA_Msk; |
|||
} |
|||
#endif |
|||
|
|||
#if NRF52_ERRATA_36_ENABLE_WORKAROUND |
|||
/* Workaround for Errata 36 "CLOCK: Some registers are not reset when expected" found at the Errata document |
|||
for your device located at https://infocenter.nordicsemi.com/index.jsp */ |
|||
if (nrf52_errata_36()){ |
|||
NRF_CLOCK->EVENTS_DONE = 0; |
|||
NRF_CLOCK->EVENTS_CTTO = 0; |
|||
NRF_CLOCK->CTIV = 0; |
|||
} |
|||
#endif |
|||
|
|||
#if NRF52_ERRATA_37_ENABLE_WORKAROUND |
|||
/* Workaround for Errata 37 "RADIO: Encryption engine is slow by default" found at the Errata document |
|||
for your device located at https://infocenter.nordicsemi.com/index.jsp */ |
|||
if (nrf52_errata_37()){ |
|||
*(volatile uint32_t *)0x400005A0 = 0x3; |
|||
} |
|||
#endif |
|||
|
|||
#if NRF52_ERRATA_57_ENABLE_WORKAROUND |
|||
/* Workaround for Errata 57 "NFCT: NFC Modulation amplitude" found at the Errata document |
|||
for your device located at https://infocenter.nordicsemi.com/index.jsp */ |
|||
if (nrf52_errata_57()){ |
|||
*(volatile uint32_t *)0x40005610 = 0x00000005; |
|||
*(volatile uint32_t *)0x40005688 = 0x00000001; |
|||
*(volatile uint32_t *)0x40005618 = 0x00000000; |
|||
*(volatile uint32_t *)0x40005614 = 0x0000003F; |
|||
} |
|||
#endif |
|||
|
|||
#if NRF52_ERRATA_66_ENABLE_WORKAROUND |
|||
/* Workaround for Errata 66 "TEMP: Linearity specification not met with default settings" found at the Errata document |
|||
for your device located at https://infocenter.nordicsemi.com/index.jsp */ |
|||
if (nrf52_errata_66()){ |
|||
NRF_TEMP->A0 = NRF_FICR->TEMP.A0; |
|||
NRF_TEMP->A1 = NRF_FICR->TEMP.A1; |
|||
NRF_TEMP->A2 = NRF_FICR->TEMP.A2; |
|||
NRF_TEMP->A3 = NRF_FICR->TEMP.A3; |
|||
NRF_TEMP->A4 = NRF_FICR->TEMP.A4; |
|||
NRF_TEMP->A5 = NRF_FICR->TEMP.A5; |
|||
NRF_TEMP->B0 = NRF_FICR->TEMP.B0; |
|||
NRF_TEMP->B1 = NRF_FICR->TEMP.B1; |
|||
NRF_TEMP->B2 = NRF_FICR->TEMP.B2; |
|||
NRF_TEMP->B3 = NRF_FICR->TEMP.B3; |
|||
NRF_TEMP->B4 = NRF_FICR->TEMP.B4; |
|||
NRF_TEMP->B5 = NRF_FICR->TEMP.B5; |
|||
NRF_TEMP->T0 = NRF_FICR->TEMP.T0; |
|||
NRF_TEMP->T1 = NRF_FICR->TEMP.T1; |
|||
NRF_TEMP->T2 = NRF_FICR->TEMP.T2; |
|||
NRF_TEMP->T3 = NRF_FICR->TEMP.T3; |
|||
NRF_TEMP->T4 = NRF_FICR->TEMP.T4; |
|||
} |
|||
#endif |
|||
|
|||
#if NRF52_ERRATA_98_ENABLE_WORKAROUND |
|||
/* Workaround for Errata 98 "NFCT: Not able to communicate with the peer" found at the Errata document |
|||
for your device located at https://infocenter.nordicsemi.com/index.jsp */ |
|||
if (nrf52_errata_98()){ |
|||
*(volatile uint32_t *)0x4000568Cul = 0x00038148ul; |
|||
} |
|||
#endif |
|||
|
|||
#if NRF52_ERRATA_103_ENABLE_WORKAROUND && defined(CCM_MAXPACKETSIZE_MAXPACKETSIZE_Pos) |
|||
/* Workaround for Errata 103 "CCM: Wrong reset value of CCM MAXPACKETSIZE" found at the Errata document |
|||
for your device located at https://infocenter.nordicsemi.com/index.jsp */ |
|||
if (nrf52_errata_103()){ |
|||
NRF_CCM->MAXPACKETSIZE = 0xFBul; |
|||
} |
|||
#endif |
|||
|
|||
#if NRF52_ERRATA_108_ENABLE_WORKAROUND |
|||
/* Workaround for Errata 108 "RAM: RAM content cannot be trusted upon waking up from System ON Idle or System OFF mode" found at the Errata document |
|||
for your device located at https://infocenter.nordicsemi.com/index.jsp */ |
|||
if (nrf52_errata_108()){ |
|||
*(volatile uint32_t *)0x40000EE4ul = *(volatile uint32_t *)0x10000258ul & 0x0000004Ful; |
|||
} |
|||
#endif |
|||
|
|||
#if NRF52_ERRATA_115_ENABLE_WORKAROUND |
|||
/* Workaround for Errata 115 "RAM: RAM content cannot be trusted upon waking up from System ON Idle or System OFF mode" found at the Errata document |
|||
for your device located at https://infocenter.nordicsemi.com/index.jsp */ |
|||
if (nrf52_errata_115()){ |
|||
*(volatile uint32_t *)0x40000EE4 = (*(volatile uint32_t *)0x40000EE4 & 0xFFFFFFF0) | (*(uint32_t *)0x10000258 & 0x0000000F); |
|||
} |
|||
#endif |
|||
|
|||
#if NRF52_ERRATA_120_ENABLE_WORKAROUND |
|||
/* Workaround for Errata 120 "QSPI: Data read or written is corrupted" found at the Errata document |
|||
for your device located at https://infocenter.nordicsemi.com/index.jsp */ |
|||
if (nrf52_errata_120()){ |
|||
*(volatile uint32_t *)0x40029640ul = 0x200ul; |
|||
} |
|||
#endif |
|||
|
|||
#if NRF52_ERRATA_136_ENABLE_WORKAROUND |
|||
/* Workaround for Errata 136 "System: Bits in RESETREAS are set when they should not be" found at the Errata document |
|||
for your device located at https://infocenter.nordicsemi.com/index.jsp */ |
|||
if (nrf52_errata_136()){ |
|||
if (NRF_POWER->RESETREAS & POWER_RESETREAS_RESETPIN_Msk){ |
|||
NRF_POWER->RESETREAS = ~POWER_RESETREAS_RESETPIN_Msk; |
|||
} |
|||
} |
|||
#endif |
|||
|
|||
#if NRF52_ERRATA_182_ENABLE_WORKAROUND |
|||
/* Workaround for Errata 182 "RADIO: Fixes for anomalies #102, #106, and #107 do not take effect" found at the Errata document |
|||
for your device located at https://infocenter.nordicsemi.com/index.jsp */ |
|||
if (nrf52_errata_182()){ |
|||
*(volatile uint32_t *) 0x4000173C |= (0x1 << 10); |
|||
} |
|||
#endif |
|||
|
|||
#if NRF52_ERRATA_217_ENABLE_WORKAROUND |
|||
/* Workaround for Errata 217 "RAM: RAM content cannot be trusted upon waking up from System ON Idle or System OFF mode" found at the Errata document |
|||
for your device located at https://infocenter.nordicsemi.com/index.jsp */ |
|||
if (nrf52_errata_217()){ |
|||
*(volatile uint32_t *)0x40000EE4ul |= 0x0000000Ful; |
|||
} |
|||
#endif |
|||
|
|||
/* Enable the FPU if the compiler used floating point unit instructions. __FPU_USED is a MACRO defined by the |
|||
* compiler. Since the FPU consumes energy, remember to disable FPU use in the compiler if floating point unit |
|||
* operations are not used in your code. */ |
|||
#if (__FPU_USED == 1) |
|||
SCB->CPACR |= (3UL << 20) | (3UL << 22); |
|||
__DSB(); |
|||
__ISB(); |
|||
#endif |
|||
|
|||
nrf52_handle_approtect(); |
|||
|
|||
#if NRF52_CONFIGURATION_249_ENABLE && (defined(NRF52805_XXAA) || defined(NRF52810_XXAA) || defined(NRF52811_XXAA)) |
|||
if (nrf52_configuration_249() && (NRF_UICR->NRFMDK[0] == 0xFFFFFFFF || NRF_UICR->NRFMDK[1] == 0xFFFFFFFF)) |
|||
{ |
|||
nvmc_config(NVMC_CONFIG_WEN_Wen); |
|||
NRF_UICR->NRFMDK[0] = 0; |
|||
nvmc_wait(); |
|||
NRF_UICR->NRFMDK[1] = 0; |
|||
nvmc_wait(); |
|||
nvmc_config(NVMC_CONFIG_WEN_Ren); |
|||
} |
|||
#endif |
|||
|
|||
/* Configure NFCT pins as GPIOs if NFCT is not to be used in your code. If CONFIG_NFCT_PINS_AS_GPIOS is not defined, |
|||
two GPIOs (see Product Specification to see which ones) will be reserved for NFC and will not be available as |
|||
normal GPIOs. */ |
|||
#if defined (CONFIG_NFCT_PINS_AS_GPIOS) && defined(NFCT_PRESENT) |
|||
if ((NRF_UICR->NFCPINS & UICR_NFCPINS_PROTECT_Msk) == (UICR_NFCPINS_PROTECT_NFC << UICR_NFCPINS_PROTECT_Pos)){ |
|||
nvmc_config(NVMC_CONFIG_WEN_Wen); |
|||
NRF_UICR->NFCPINS &= ~UICR_NFCPINS_PROTECT_Msk; |
|||
nvmc_wait(); |
|||
nvmc_config(NVMC_CONFIG_WEN_Ren); |
|||
NVIC_SystemReset(); |
|||
} |
|||
#endif |
|||
|
|||
/* Configure GPIO pads as pPin Reset pin if Pin Reset capabilities desired. If CONFIG_GPIO_AS_PINRESET is not |
|||
defined, pin reset will not be available. One GPIO (see Product Specification to see which one) will then be |
|||
reserved for PinReset and not available as normal GPIO. */ |
|||
#if defined (CONFIG_GPIO_AS_PINRESET) |
|||
if (((NRF_UICR->PSELRESET[0] & UICR_PSELRESET_CONNECT_Msk) != (UICR_PSELRESET_CONNECT_Connected << UICR_PSELRESET_CONNECT_Pos)) || |
|||
((NRF_UICR->PSELRESET[1] & UICR_PSELRESET_CONNECT_Msk) != (UICR_PSELRESET_CONNECT_Connected << UICR_PSELRESET_CONNECT_Pos))){ |
|||
nvmc_config(NVMC_CONFIG_WEN_Wen); |
|||
NRF_UICR->PSELRESET[0] = RESET_PIN; |
|||
nvmc_wait(); |
|||
NRF_UICR->PSELRESET[1] = RESET_PIN; |
|||
nvmc_wait(); |
|||
nvmc_config(NVMC_CONFIG_WEN_Ren); |
|||
NVIC_SystemReset(); |
|||
} |
|||
#endif |
|||
|
|||
/* When developing for nRF52810 on an nRF52832, or nRF52811 on an nRF52840, |
|||
make sure NFC pins are mapped as GPIO. */ |
|||
#if defined (DEVELOP_IN_NRF52832) && defined(NRF52810_XXAA) \ |
|||
|| defined (DEVELOP_IN_NRF52840) && defined(NRF52811_XXAA) |
|||
if ((*((uint32_t *)0x1000120C) & (1 << 0)) != 0){ |
|||
nvmc_config(NVMC_CONFIG_WEN_Wen); |
|||
*((uint32_t *)0x1000120C) = 0; |
|||
nvmc_wait(); |
|||
nvmc_config(NVMC_CONFIG_WEN_Ren); |
|||
NVIC_SystemReset(); |
|||
} |
|||
#endif |
|||
|
|||
SystemCoreClockUpdate(); |
|||
} |
1660
app/app.uvoptx
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
7882
app/app.uvprojx
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
12168
app/config/sdk_config.h
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,369 @@ |
|||
#include "znordic.h" |
|||
// |
|||
#include <stdarg.h> |
|||
#include <stdio.h> |
|||
#include <stdlib.h> |
|||
#include <string.h> |
|||
// |
|||
#include "app_ble_service.h" |
|||
#include "app_event_distribute.h" |
|||
#include "basic/ads1293/ads1293.h" |
|||
#include "board/board.h" |
|||
#include "device_ctrl_service.h" |
|||
#include "nrf_drv_gpiote.h" |
|||
#include "sample_data_manager_service.h" |
|||
#include "zble_module.h" |
|||
#include "zdatachannel_service.h" |
|||
#include "znordic_device_info_mgr.h" |
|||
// |
|||
ZDATACHANNEL_DEF(m_zhrs, 2 /*优先级*/, 1 /*client num*/); |
|||
static const nrf_drv_spi_t spi = NRF_DRV_SPI_INSTANCE(ADS1293_SPI_INSTANCE); /**< SPI instance. */ |
|||
static ads1293_t m_ads1293_0; // U2 |
|||
static ads1293_t m_ads1293_1; |
|||
typedef struct { |
|||
uint8_t add; |
|||
uint8_t data; |
|||
} adscfg_t; |
|||
|
|||
static adscfg_t m_prvads0cfg_cache[65]; |
|||
static adscfg_t m_prvads1cfg_cache[65]; |
|||
|
|||
static void zdatachannel_data_handler(zdatachannel_evt_t* p_evt) {} |
|||
void blechannel_service_init() { |
|||
ZLOGI("init zdatachannel service"); |
|||
static 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)); |
|||
} |
|||
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 |
|||
readbak = data; |
|||
if (addr >= 0x18 && addr <= 0x1E) { |
|||
return; |
|||
} |
|||
if (addr >= 0x30 && addr <= 0x3f) { |
|||
return; |
|||
} |
|||
if (addr == 0x40) { |
|||
return; |
|||
} |
|||
if (addr == 0x50) { |
|||
return; |
|||
} |
|||
ads1293_spi_writereg_and_readbak(ads, addr, data, &readbak); |
|||
if (readbak != data) { |
|||
ZLOGE("ads_%d write %x failed,w:%x readbak:%x\n", ads->id, addr, data, readbak); |
|||
} |
|||
} |
|||
static void tryloadcfg_from_fatfs(const char* file, adscfg_t* cfg, uint16_t cfgsize, uint16_t* cfg_ret_size) { |
|||
// |
|||
*cfg_ret_size = 0; |
|||
|
|||
static FIL fd; |
|||
FRESULT ff_result = f_open(&fd, (const TCHAR*)file, FA_READ); |
|||
if (ff_result != FR_OK) { |
|||
ZLOGE("open %s failed\n", file); |
|||
return; |
|||
} |
|||
|
|||
char line[128]; |
|||
int niterm = 0; |
|||
f_gets(line, 128, &fd); |
|||
|
|||
while (f_gets(line, 128, &fd)) { |
|||
uint32_t addr; |
|||
uint32_t value; |
|||
sscanf(line, "%x,%x", &addr, &value); |
|||
cfg[niterm].add = addr; |
|||
cfg[niterm].data = value; |
|||
niterm++; |
|||
|
|||
if (niterm >= cfgsize) { |
|||
break; |
|||
} |
|||
} |
|||
*cfg_ret_size = niterm; |
|||
ZLOGI("load %s cfg size:%d\n", file, niterm); |
|||
f_close(&fd); |
|||
} |
|||
|
|||
uint32_t get_ready_pin_state_get() { return nrf_gpio_pin_read(ADS1293_READY_PIN); } |
|||
|
|||
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 adscfg_t m_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}, |
|||
}; |
|||
|
|||
static void ads1293_init() { |
|||
/******************************************************************************* |
|||
* SPI初始化 * |
|||
*******************************************************************************/ |
|||
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)); |
|||
|
|||
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); |
|||
|
|||
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); |
|||
|
|||
ads1293_spi_writereg(&m_ads1293_0, TI_ADS1293_CONFIG_REG, 0); |
|||
|
|||
uint16_t cfgsize = 0; |
|||
tryloadcfg_from_fatfs("0.cfg", m_prvads0cfg_cache, ZARRAY_SIZE(m_prvads0cfg_cache), &cfgsize); |
|||
if (cfgsize > 0) { |
|||
ZLOGI("load 0.cfg from fatfs\n"); |
|||
|
|||
if (memcmp(m_prvads0cfg_cache, m_prvads0cfg, sizeof(m_prvads0cfg)) != 0) { |
|||
ZLOGI("0.cfg is different from default\n"); |
|||
} else { |
|||
ZLOGI("0.cfg is same as default\n"); |
|||
} |
|||
|
|||
for (uint16_t i = 0; i < cfgsize; i++) { |
|||
ads1293_spi_writereg_and_check(&m_ads1293_0, m_prvads0cfg_cache[i].add, m_prvads0cfg_cache[i].data); |
|||
} |
|||
} else { |
|||
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); |
|||
} |
|||
} |
|||
|
|||
tryloadcfg_from_fatfs("1.cfg", m_prvads1cfg_cache, ZARRAY_SIZE(m_prvads1cfg_cache), &cfgsize); |
|||
if (cfgsize > 0) { |
|||
ZLOGI("load 1.cfg from fatfs\n"); |
|||
|
|||
if (memcmp(m_prvads1cfg_cache, m_prvads1cfg, sizeof(m_prvads1cfg)) != 0) { |
|||
ZLOGI("1.cfg is different from default\n"); |
|||
} else { |
|||
ZLOGI("1.cfg is same as default\n"); |
|||
} |
|||
|
|||
for (uint16_t i = 0; i < cfgsize; i++) { |
|||
ads1293_spi_writereg_and_check(&m_ads1293_1, m_prvads1cfg_cache[i].add, m_prvads1cfg_cache[i].data); |
|||
} |
|||
} else { |
|||
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); |
|||
} |
|||
} |
|||
} |
|||
|
|||
static void onServiceInitCB() { |
|||
ZLOGI("init zdatachannel service"); |
|||
static 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 setup(); |
|||
int main() { |
|||
APP_SCHED_INIT(APP_MAX_EVEN_SIZE, APP_EVENT_QUEUE_SIZE); |
|||
znordic_init(); |
|||
NRF_LOG_INFO("compile time :%s", __TIME__); |
|||
ZLOGI("CUSTOMER :%d", NRF_UICR->CUSTOMER[0]); |
|||
/******************************************************************************* |
|||
* 蓝牙服务初始化 * |
|||
*******************************************************************************/ |
|||
static zble_module_cfg_t cfg; |
|||
cfg.deviceName = "ADS1293_TESTER"; |
|||
cfg.on_service_init = onServiceInitCB; |
|||
zble_module_init(&cfg); |
|||
AppBleService_init(); |
|||
|
|||
setup(); |
|||
} |
|||
|
|||
static ads1293_error_t error0; |
|||
static ads1293_error_t error1; |
|||
static uint8_t txcache[128]; |
|||
|
|||
void send_ads1293_error_state(ads1293_error_t* e0, ads1293_error_t* e1) { // |
|||
|
|||
txcache[0] = 0xA1; |
|||
txcache[1] = 0x01; |
|||
memcpy(txcache + 2, e0, sizeof(ads1293_error_t)); |
|||
memcpy(txcache + 2 + sizeof(ads1293_error_t), e1, sizeof(ads1293_error_t)); |
|||
|
|||
zdatachannel_data_send2(txcache, 2 + sizeof(ads1293_error_t) * 2); |
|||
} |
|||
|
|||
void capture_error_state() { |
|||
ads1293_read_error(&m_ads1293_0, &error0); |
|||
ads1293_read_error(&m_ads1293_1, &error1); |
|||
|
|||
#if 0 |
|||
error0.estatus =1; |
|||
error0.error_range1 =2; |
|||
error0.error_range2 =3; |
|||
error0.error_range3 =4; |
|||
error0.error_sync =5; |
|||
error0.error_misc =6; |
|||
|
|||
error1.estatus =21; |
|||
error1.error_range1 =22; |
|||
error1.error_range2 =23; |
|||
error1.error_range3 =24; |
|||
error1.error_sync =25; |
|||
error1.error_misc =26; |
|||
#endif |
|||
|
|||
send_ads1293_error_state(&error0, &error1); |
|||
} |
|||
#pragma pack(1) |
|||
typedef struct { |
|||
uint32_t sample0; |
|||
} one_ch_cache_t; |
|||
typedef struct { |
|||
uint8_t h1; |
|||
uint8_t h2; |
|||
one_ch_cache_t data[3]; |
|||
uint8_t e1; |
|||
uint8_t e2; |
|||
} one_frame_cache_t; |
|||
|
|||
typedef struct { |
|||
one_frame_cache_t frame[8]; |
|||
} one_packet_t; |
|||
|
|||
#pragma unpack() |
|||
|
|||
one_packet_t txpacket; |
|||
int cache_data_size = 0; |
|||
|
|||
void trigger_capture() { |
|||
static uint32_t sample[6]; |
|||
static uint8_t readystatus[2] = {0}; |
|||
ads1293_read_ecgs(&m_ads1293_0, &sample[0]); |
|||
ads1293_read_ecgs(&m_ads1293_1, &sample[3]); |
|||
|
|||
// static int i = 0; |
|||
// static int j = 0; |
|||
// i++; |
|||
// if (i % 8 == 0) { |
|||
// j++; |
|||
// } |
|||
// sample[0] = j; |
|||
// sample[3] = j; |
|||
// sample[4] = j; |
|||
|
|||
// TI_ADS1293_DATA_STATUS_REG |
|||
// readystatus[0] = ads1293_read_ready_status(&m_ads1293_0); |
|||
// readystatus[1] = ads1293_read_ready_status(&m_ads1293_1); |
|||
|
|||
{ |
|||
txpacket.frame[cache_data_size].h1 = 0xA2; |
|||
txpacket.frame[cache_data_size].h2 = 0x2; |
|||
txpacket.frame[cache_data_size].data[0].sample0 = sample[0]; |
|||
txpacket.frame[cache_data_size].data[1].sample0 = sample[3]; |
|||
txpacket.frame[cache_data_size].data[2].sample0 = sample[4]; |
|||
txpacket.frame[cache_data_size].e1 = 0x2; |
|||
txpacket.frame[cache_data_size].e2 = 0xA2; |
|||
|
|||
cache_data_size++; |
|||
if (cache_data_size == 8) { |
|||
zdatachannel_data_send2((uint8_t*)&txpacket, sizeof(one_packet_t)); |
|||
cache_data_size = 0; |
|||
} |
|||
} |
|||
} |
|||
uint32_t m_changecount = 0; |
|||
static void ads1293_ready_pin_irq(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action) { // |
|||
m_changecount++; |
|||
trigger_capture(); |
|||
} |
|||
|
|||
void setup() { |
|||
// |
|||
|
|||
zble_module_start_adv(); |
|||
SampleDataMgr_init(); |
|||
SampleDataMgr_changeToLocalMode(); |
|||
ads1293_init(); |
|||
SampleDataMgr_changeToExtMode(); |
|||
|
|||
ads1293_start_conversion(&m_ads1293_0); |
|||
ads1293_start_conversion(&m_ads1293_1); |
|||
|
|||
nrf_gpio_cfg_input(ADS1293_READY_PIN, NRF_GPIO_PIN_PULLUP); |
|||
|
|||
{ |
|||
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_HITOLO; // 下降沿触发 |
|||
ZERROR_CHECK(nrfx_gpiote_in_init(ADS1293_READY_PIN, &inConfig, ads1293_ready_pin_irq)); |
|||
nrfx_gpiote_in_event_enable(ADS1293_READY_PIN, true); |
|||
} |
|||
|
|||
while (true) { |
|||
app_sched_execute(); |
|||
NRF_LOG_PROCESS(); |
|||
|
|||
static bool state = false; |
|||
static uint32_t last_ticket = 0; |
|||
|
|||
bool now = get_ready_pin_state_get(); |
|||
uint32_t nowticket = znordic_getpower_on_s(); |
|||
|
|||
// if (state != now) { |
|||
// state = now; |
|||
// m_changecount++; |
|||
// if (now) { |
|||
// // trigger_capture(); |
|||
// } |
|||
// } |
|||
|
|||
if (last_ticket != nowticket) { |
|||
last_ticket = nowticket; |
|||
ZLOGI("%d changecount:%d\n", znordic_getpower_on_ms(), m_changecount); |
|||
|
|||
capture_error_state(); |
|||
m_changecount = 0; |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,537 @@ |
|||
#include "app_ble_service.h" |
|||
|
|||
#include "../../ify_hrs_protocol/heart_rate_sensor_protocol.h" |
|||
#include "app_event.h" |
|||
#include "app_event_distribute.h" |
|||
#include "app_scheduler.h" |
|||
#include "board/board.h" |
|||
#include "board/board_battery_state.h" |
|||
#include "device_ctrl_service.h" |
|||
#include "heart_wave_sample_service.h" |
|||
#include "sample_data_manager_service.h" |
|||
#include "zble_module.h" |
|||
#include "zdatachannel_service.h" |
|||
#include "znordic.h" |
|||
#include "znordic_device_info_mgr.h" |
|||
|
|||
static uint8_t rxbufcache[256]; |
|||
static bool is_rxbufcache_used = false; // 接收到的消息是否正在被处理中 |
|||
static bool m_realtime_report_state = false; // 实时上报状态 |
|||
|
|||
static uint8_t m_txbuf[256]; |
|||
static uint8_t m_reportbuf[256]; |
|||
|
|||
APP_TIMER_DEF(m_record_upload_tmr); // 数据上报定时器 |
|||
APP_TIMER_DEF(m_record_upload_finish_packet_report_tmr); // 数据上报完成上报定时器 |
|||
|
|||
static void prvf_process_ble_rx_data(void* p_event_data, uint16_t event_size); |
|||
static void process_ble_rx_data(void* p_event_data, uint16_t event_size); |
|||
static void RecordUpload_tmr_cb(void* p_context); |
|||
|
|||
/******************************************************************************* |
|||
* 蓝牙服务注册 * |
|||
*******************************************************************************/ |
|||
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, process_ble_rx_data); |
|||
if (suc == 0) { |
|||
is_rxbufcache_used = true; |
|||
} |
|||
} |
|||
/******************************************************************************* |
|||
* UTILS * |
|||
*******************************************************************************/ |
|||
int ble_start_realtime_report() { |
|||
m_realtime_report_state = true; |
|||
return 0; |
|||
} |
|||
int ble_stop_realtime_report() { |
|||
m_realtime_report_state = false; |
|||
return 0; |
|||
} |
|||
|
|||
static void send_error_receipt(ify_hrs_packet_t* rxpacket, int32_t errorcode) { |
|||
ify_hrs_packet_t* txheader = (ify_hrs_packet_t*)m_txbuf; |
|||
error_receipt_t* receipt = (error_receipt_t*)txheader->data; |
|||
uint16_t sendlen = sizeof(ify_hrs_packet_t) + sizeof(error_receipt_t); |
|||
|
|||
txheader->cmd = rxpacket->cmd; |
|||
txheader->frame_index = rxpacket->frame_index; |
|||
txheader->frame_type = kifyhrs_pt_error_receipt; |
|||
|
|||
txheader->frame_type = kifyhrs_pt_error_receipt; |
|||
receipt->errorcode = kifyhrs_ecode_cmd_not_support; |
|||
zdatachannel_data_send2(m_txbuf, sendlen); |
|||
} |
|||
|
|||
static void send_success_receipt(ify_hrs_packet_t* rxpacket, int32_t emptydatasize) { |
|||
ify_hrs_packet_t* txheader = (ify_hrs_packet_t*)m_txbuf; |
|||
uint16_t sendlen = sizeof(ify_hrs_packet_t) + emptydatasize; |
|||
|
|||
txheader->cmd = rxpacket->cmd; |
|||
txheader->frame_index = rxpacket->frame_index; |
|||
txheader->frame_type = kifyhrs_pt_cmd_receipt; |
|||
|
|||
zdatachannel_data_send2(m_txbuf, sendlen); |
|||
} |
|||
|
|||
static void prvf_try_report_sensor_drop_event(uint8_t dropstate0, uint8_t dropstate1) { |
|||
sensor_drop_event_report_packet_t* reportpacket = (sensor_drop_event_report_packet_t*)m_reportbuf; |
|||
reportpacket->cmd = ify_hrs_report_sensor_drop_detect; |
|||
reportpacket->frame_index = 0; |
|||
reportpacket->frame_type = kifyhrs_pt_report; |
|||
reportpacket->drop_state0 = dropstate0; |
|||
reportpacket->drop_state1 = dropstate1; |
|||
|
|||
uint16_t sendlen = sizeof(sensor_drop_event_report_packet_t); |
|||
zdatachannel_data_send2(m_reportbuf, sendlen); |
|||
return; |
|||
} |
|||
|
|||
static void prvf_try_report_sample_end_event() { |
|||
ify_hrs_packet_t* reportpacket = (ify_hrs_packet_t*)m_reportbuf; |
|||
reportpacket->cmd = ify_hrs_report_sample_finish_end; |
|||
reportpacket->frame_index = 0; |
|||
reportpacket->frame_type = kifyhrs_pt_report; |
|||
|
|||
uint16_t sendlen = sizeof(ify_hrs_packet_t); |
|||
zdatachannel_data_send2(m_reportbuf, sendlen); |
|||
return; |
|||
} |
|||
|
|||
void prvf_report_sample_data(uint32_t frameIndex, one_frame_data_t* data, int32_t ndata) { |
|||
if (!m_realtime_report_state) { |
|||
return; |
|||
} |
|||
|
|||
heartrate_report_packet_t* reportpacket = (heartrate_report_packet_t*)m_reportbuf; |
|||
reportpacket->cmd = ify_hrs_report_heartrate_data; |
|||
reportpacket->frame_index = 0; |
|||
reportpacket->frame_type = kifyhrs_pt_report; |
|||
reportpacket->sample_data_index = frameIndex; |
|||
|
|||
/** |
|||
* @brief 第一导联数据 |
|||
*/ |
|||
for (int i = 0; i < ndata; i++) { |
|||
|
|||
reportpacket->data[i * 9 + 0] = ((data[i].data0)) >> 0; |
|||
reportpacket->data[i * 9 + 1] = ((data[i].data0)) >> 8; |
|||
reportpacket->data[i * 9 + 2] = ((data[i].data0)) >> 16; |
|||
|
|||
reportpacket->data[i * 9 + 3] = ((data[i].data1)) >> 0; |
|||
reportpacket->data[i * 9 + 4] = ((data[i].data1)) >> 8; |
|||
reportpacket->data[i * 9 + 5] = ((data[i].data1)) >> 16; |
|||
|
|||
reportpacket->data[i * 9 + 6] = ((data[i].data2)) >> 0; |
|||
reportpacket->data[i * 9 + 7] = ((data[i].data2)) >> 8; |
|||
reportpacket->data[i * 9 + 8] = ((data[i].data2)) >> 16; |
|||
} |
|||
uint16_t sendlen = sizeof(heartrate_report_packet_t) + ndata * 9; |
|||
zdatachannel_data_send2(m_reportbuf, sendlen); |
|||
return; |
|||
} |
|||
|
|||
/******************************************************************************* |
|||
* 记录读取服务 * |
|||
*******************************************************************************/ |
|||
|
|||
static int m_upload_fd; |
|||
static uint8_t m_datacache[256]; |
|||
static int m_remaindatalen = 0; |
|||
static uint32_t m_report_data_sumcheckcode = 0; |
|||
static bool m_isupload_data_state = false; |
|||
|
|||
void RecordUpload_report_finish_event(uint32_t sumcheckcode) { |
|||
ify_hrs_packet_t* txheader = (ify_hrs_packet_t*)m_txbuf; |
|||
uint16_t sendlen = sizeof(ify_hrs_packet_t) + 4; |
|||
|
|||
txheader->cmd = ify_hrs_report_record_upload_end; // 6A |
|||
txheader->frame_index = 0; |
|||
txheader->frame_type = kifyhrs_pt_report; |
|||
|
|||
// txheader->data[0] = errorcode; |
|||
*(uint32_t*)txheader->data = sumcheckcode; |
|||
|
|||
zdatachannel_data_send2(m_txbuf, sendlen); |
|||
return; |
|||
} |
|||
|
|||
int RecordUpload_ble_stop_upload_record() { |
|||
m_isupload_data_state = false; |
|||
app_timer_stop(m_record_upload_tmr); |
|||
return 0; |
|||
} |
|||
/** |
|||
* @brief 数据上报定时器回调 |
|||
* |
|||
* @param p_context |
|||
*/ |
|||
static void RecordUpload_finish_packet_report_tmr_cb(void* p_context) { // |
|||
RecordUpload_report_finish_event(m_report_data_sumcheckcode); |
|||
} |
|||
|
|||
static void RecordUpload_tmr_cb(void* p_context) { // |
|||
|
|||
if (!m_isupload_data_state) return; |
|||
|
|||
// sample_data_mgr_read |
|||
if (m_remaindatalen == 0) { |
|||
memset(m_datacache, 0, sizeof(m_datacache)); |
|||
int32_t rdsize = SampleDataMgr_read(m_upload_fd, m_datacache, sizeof(m_datacache)); |
|||
if (rdsize <= 0) { |
|||
ZLOGI("read file end,stop upload"); |
|||
ZERROR_CHECK(app_timer_start(m_record_upload_finish_packet_report_tmr, APP_TIMER_TICKS(30), (void*)m_report_data_sumcheckcode)); |
|||
RecordUpload_ble_stop_upload_record(); |
|||
return; |
|||
} |
|||
m_remaindatalen = rdsize; |
|||
} |
|||
if (m_remaindatalen == 0) { |
|||
return; |
|||
} |
|||
|
|||
int32_t mtusize = zble_module_get_mtu_size(); |
|||
mtusize = mtusize < 128 ? mtusize : 128; |
|||
|
|||
uint8_t* data = m_datacache + (sizeof(m_datacache) - m_remaindatalen); |
|||
int len = m_remaindatalen > mtusize ? mtusize : m_remaindatalen; |
|||
|
|||
ZLOGI("upload %d %d %d", len, m_remaindatalen, mtusize); |
|||
if (!zdatachannel_is_connected()) { |
|||
ZLOGI("ble is disconnected,stop upload"); |
|||
RecordUpload_ble_stop_upload_record(); |
|||
return; |
|||
} |
|||
|
|||
uint32_t suc = zdatachannel_block_data_send2(data, len); |
|||
if (suc != NRF_SUCCESS) { |
|||
if (suc == NRF_ERROR_INVALID_STATE) { |
|||
// 未使能notify |
|||
ZLOGI("ble unenable notify,stop upload"); |
|||
RecordUpload_ble_stop_upload_record(); |
|||
return; |
|||
} else if (suc == NRF_ERROR_BUSY || suc == NRF_ERROR_RESOURCES) { |
|||
// 等待下次发送 |
|||
return; |
|||
} else { |
|||
ZLOGI("ble send error,stop upload %x", suc); |
|||
RecordUpload_ble_stop_upload_record(); |
|||
return; |
|||
} |
|||
} |
|||
for (uint32_t i = 0; i < len; i++) { |
|||
m_report_data_sumcheckcode += data[i]; |
|||
} |
|||
m_remaindatalen -= len; |
|||
} |
|||
|
|||
int RecordUpload_start(sample_data_filename_t* recordid) { |
|||
// |
|||
// 启动 |
|||
// |
|||
SampleDataMgr_changeToLocalMode(); |
|||
|
|||
m_upload_fd = SampleDataMgr_open(recordid, kwrflag_read_only); |
|||
if (m_upload_fd <= 0) { |
|||
return kifyhrs_ecode_no_record_find; |
|||
} |
|||
|
|||
ZERROR_CHECK(app_timer_start(m_record_upload_tmr, APP_TIMER_TICKS(2), NULL)); |
|||
m_isupload_data_state = true; |
|||
m_remaindatalen = 0; |
|||
m_report_data_sumcheckcode = 0; |
|||
return 0; |
|||
} |
|||
int RecordUpload_stop_upload() { |
|||
m_isupload_data_state = false; |
|||
SampleDataMgr_changeToExtMode(); |
|||
app_timer_stop(m_record_upload_tmr); |
|||
return 0; |
|||
} |
|||
bool RecordUpload_is_uploading() { return m_isupload_data_state; } |
|||
|
|||
/******************************************************************************* |
|||
* 消息处理 * |
|||
*******************************************************************************/ |
|||
static void process_ble_rx_data(void* p_event_data, uint16_t event_size) { // |
|||
prvf_process_ble_rx_data(p_event_data, event_size); |
|||
is_rxbufcache_used = false; |
|||
} |
|||
|
|||
static void prvf_process_ble_rx_data(void* p_event_data, uint16_t len) { |
|||
ify_hrs_packet_t* rxheader = (ify_hrs_packet_t*)p_event_data; |
|||
ify_hrs_packet_t* txheader = (ify_hrs_packet_t*)m_txbuf; |
|||
ify_hrs_cmd_t cmd = (ify_hrs_cmd_t)rxheader->cmd; |
|||
memset(m_txbuf, 0, sizeof(m_txbuf)); |
|||
|
|||
ZLOGI("rx cmd:%d index:%d datalen:%d", cmd, rxheader->frame_index, len - sizeof(ify_hrs_packet_t)); |
|||
NRF_LOG_HEXDUMP_INFO(p_event_data, len); |
|||
|
|||
txheader->cmd = rxheader->cmd; |
|||
txheader->frame_index = rxheader->frame_index; |
|||
txheader->frame_type = kifyhrs_pt_cmd_receipt; |
|||
|
|||
if (cmd == ify_hrs_cmd_read_device_version) { |
|||
device_version_info_receipt_t* receipt = (device_version_info_receipt_t*)txheader->data; |
|||
uint16_t sendlen = sizeof(ify_hrs_packet_t) + sizeof(device_version_info_receipt_t); |
|||
|
|||
receipt->blestack_version = device_info_read_blestack_version(); |
|||
receipt->bootloader_version = device_info_read_bootloader_version(); |
|||
receipt->firmware_version = device_info_read_firmware_version(); |
|||
receipt->hardware_version = device_info_read_hardware_version(); |
|||
zdatachannel_data_send2(m_txbuf, sendlen); |
|||
} |
|||
|
|||
else if (cmd == ify_hrs_cmd_read_sensor_info) { |
|||
sensor_info_receipt_t* receipt = (sensor_info_receipt_t*)txheader->data; |
|||
uint16_t sendlen = sizeof(ify_hrs_packet_t) + sizeof(sensor_info_receipt_t); |
|||
|
|||
receipt->sensor_num = APP_SENSOR_NUM; |
|||
receipt->sensor_precision = SAMPLE_PRECISION; |
|||
receipt->sensor_sample_rate = SAMPLE_RATE / 10; |
|||
receipt->sensor0_pos = kifyhrs_sensor_pos_II; |
|||
receipt->sensor1_pos = kifyhrs_sensor_pos_V1; |
|||
receipt->sensor2_pos = kifyhrs_sensor_pos_V5; |
|||
|
|||
zdatachannel_data_send2(m_txbuf, sendlen); |
|||
} |
|||
|
|||
else if (cmd == ify_hrs_cmd_read_device_state) { |
|||
device_state_receipt_t* receipt = (device_state_receipt_t*)txheader->data; |
|||
uint16_t sendlen = sizeof(ify_hrs_packet_t) + sizeof(device_state_receipt_t); |
|||
|
|||
receipt->drop_state0 = hwss_get_drop_state0(); |
|||
receipt->drop_state1 = hwss_get_drop_state1(); |
|||
|
|||
receipt->drop_state1 = 0x00; |
|||
receipt->device_state0.sampling_state = (DeviceCtrl_now_state() == kdevice_state_sampling); |
|||
receipt->device_state0.report_state = m_realtime_report_state; |
|||
receipt->device_state0.low_battery = (BoardBattery_get_battery_level() < 20); |
|||
receipt->device_state0.full_storge = (SampleDataMgr_storageIsFull()); |
|||
|
|||
receipt->device_state1 = 0; |
|||
receipt->powerlevel = BoardBattery_get_battery_level(); |
|||
receipt->storage_item_num = SampleDataMgr_getFileNum(); |
|||
|
|||
zdatachannel_data_send2(m_txbuf, sendlen); |
|||
} |
|||
|
|||
else if (cmd == ify_hrs_cmd_read_time) { |
|||
read_time_receipt_t* receipt = (read_time_receipt_t*)txheader->data; |
|||
uint16_t sendlen = sizeof(ify_hrs_packet_t) + sizeof(read_time_receipt_t); |
|||
static ztm_t ztm; |
|||
znordic_rtc_gettime(&ztm); |
|||
|
|||
receipt->year = (ztm.tm_year + 1900 - 2000); |
|||
receipt->month = ztm.tm_mon + 1; |
|||
receipt->day = ztm.tm_mday; |
|||
receipt->hour = ztm.tm_hour; |
|||
receipt->minute = ztm.tm_min; |
|||
receipt->second = ztm.tm_sec; |
|||
zdatachannel_data_send2(m_txbuf, sendlen); |
|||
} |
|||
|
|||
else if (cmd == ify_hrs_cmd_sync_time) { |
|||
sync_time_cmd_t* cmd = (sync_time_cmd_t*)rxheader->data; |
|||
uint16_t sendlen = sizeof(ify_hrs_packet_t); |
|||
|
|||
znordic_rtc_settime(cmd->year + 2000, cmd->month, cmd->day, cmd->hour, cmd->minute, cmd->second); |
|||
zdatachannel_data_send2(m_txbuf, sendlen); |
|||
} |
|||
|
|||
else if (cmd == ify_hrs_cmd_start_capture) { |
|||
// hwss_start_capture(); |
|||
|
|||
if (RecordUpload_is_uploading()) { |
|||
ZLOGI("uploading,can not start capture"); |
|||
send_error_receipt(rxheader, kifyhrs_ecode_device_busy); |
|||
} |
|||
|
|||
DeviceCtrl_startSample(); |
|||
send_success_receipt(rxheader, 0); |
|||
} |
|||
|
|||
else if (cmd == ify_hrs_cmd_stop_capture) { |
|||
// hwss_stop_capture(); |
|||
DeviceCtrl_stopSample(); |
|||
send_success_receipt(rxheader, 0); |
|||
} |
|||
|
|||
else if (cmd == ify_hrs_cmd_start_realtime_report) { |
|||
// unsupport cmd |
|||
int ecode = ble_start_realtime_report(); |
|||
if (ecode == 0) { |
|||
send_success_receipt(rxheader, 8); // 凑8个字节,使这个回执的字节长度同上报包长度一致,方便调试 |
|||
} else { |
|||
send_error_receipt(rxheader, ecode); |
|||
} |
|||
} |
|||
|
|||
else if (cmd == ify_hrs_cmd_stop_realtime_report) { |
|||
int ecode = ble_stop_realtime_report(); |
|||
if (ecode == 0) { |
|||
send_success_receipt(rxheader, 0); |
|||
} else { |
|||
send_error_receipt(rxheader, ecode); |
|||
} |
|||
} |
|||
|
|||
else if (cmd == ify_hrs_cmd_read_records_info) { |
|||
// 指令 10-读取采样记录头部信息 |
|||
read_record_info_cmd_t* cmd = (read_record_info_cmd_t*)rxheader->data; |
|||
read_record_info_receipt_t* receipt = (read_record_info_receipt_t*)txheader->data; |
|||
uint16_t sendlen = sizeof(ify_hrs_packet_t) + sizeof(read_record_info_receipt_t); |
|||
|
|||
uint8_t recordoff = cmd->record_index; |
|||
|
|||
// 采样时不支持 |
|||
if (hwss_is_capturing()) { |
|||
send_error_receipt(rxheader, kifyhrs_ecode_device_busy); |
|||
return; |
|||
} |
|||
|
|||
sample_data_fileinfo_list_t* recordlist = SampleDataMgr_getFileinfoList(); |
|||
if (recordoff >= recordlist->count) { |
|||
send_error_receipt(rxheader, kifyhrs_ecode_no_record_find); |
|||
return; |
|||
} |
|||
|
|||
sample_data_fileinfo_t* fileinfo = recordlist->fileinfo[recordoff]; |
|||
memcpy(receipt->record_id, fileinfo->filename, 6); |
|||
receipt->frameNum = fileinfo->size / APP_BYTE_EACH_FRAME; |
|||
receipt->dataSize = fileinfo->size; |
|||
receipt->sensorNum = APP_SENSOR_NUM; |
|||
receipt->captureRate = SAMPLE_RATE / 10; |
|||
receipt->capturePrecision = SAMPLE_PRECISION; |
|||
receipt->compressAlgorithm = 0; |
|||
|
|||
zdatachannel_data_send2(m_txbuf, sendlen); |
|||
|
|||
} |
|||
|
|||
else if (cmd == ify_hrs_cmd_del_record) { |
|||
// 指令 11-删除采样记录 |
|||
del_record_cmd_t* cmd = (del_record_cmd_t*)rxheader->data; |
|||
|
|||
static sample_data_filename_t filename; |
|||
memset(&filename, 0, sizeof(filename)); |
|||
memcpy(&filename, cmd->record_id, sizeof(cmd->record_id)); |
|||
|
|||
send_error_receipt(rxheader, kifyhrs_ecode_cmd_not_support); |
|||
} |
|||
|
|||
else if (cmd == ify_hrs_cmd_start_upload_record) { |
|||
// 指令 12-上传采集记录 |
|||
// send_error_receipt(rxheader, kifyhrs_ecode_cmd_not_support); |
|||
|
|||
start_upload_record_cmd_t* cmd = (start_upload_record_cmd_t*)rxheader->data; |
|||
|
|||
static sample_data_filename_t filename; |
|||
memset(&filename, 0, sizeof(filename)); |
|||
memcpy(&filename, cmd->record_id, sizeof(cmd->record_id)); |
|||
|
|||
// 采样时不支持 |
|||
if (DeviceCtrl_now_state() != kdevice_state_ready) { |
|||
send_error_receipt(rxheader, kifyhrs_ecode_device_busy); |
|||
return; |
|||
} |
|||
|
|||
int ecode = RecordUpload_start(&filename); |
|||
if (0 == 0) { |
|||
send_success_receipt(rxheader, 0); |
|||
} else { |
|||
send_error_receipt(rxheader, 0); |
|||
} |
|||
} |
|||
|
|||
else if (cmd == ify_hrs_cmd_stop_upload_record) { |
|||
RecordUpload_stop_upload(); |
|||
send_success_receipt(rxheader, 0); |
|||
} |
|||
|
|||
else if (cmd == ify_hrs_cmd_enter_ota) { |
|||
send_error_receipt(rxheader, kifyhrs_ecode_cmd_not_support); |
|||
} |
|||
|
|||
else if (cmd == ify_hrs_cmd_read_sn) { |
|||
read_sn_receipt_t* receipt = (read_sn_receipt_t*)txheader->data; |
|||
uint16_t sendlen = sizeof(ify_hrs_packet_t) + sizeof(read_sn_receipt_t); |
|||
device_info_read_sn((sn_t*)&receipt->sn); |
|||
zdatachannel_data_send2(m_txbuf, sendlen); |
|||
} |
|||
|
|||
else if (cmd == ify_hrs_cmd_reset) { |
|||
NVIC_SystemReset(); |
|||
} |
|||
// |
|||
else { |
|||
send_error_receipt(rxheader, kifyhrs_ecode_cmd_not_support); |
|||
} |
|||
} |
|||
static const char* dropstate(uint8_t drop0, uint8_t drop1) { |
|||
static char state[128]; |
|||
sprintf(state, "drop0:%d%d%d%d-%d%d%d%d drop1:%d%d%d%d-%d%d%d%d", // |
|||
drop0 & 0x80 ? 1 : 0, drop0 & 0x40 ? 1 : 0, drop0 & 0x20 ? 1 : 0, drop0 & 0x10 ? 1 : 0, // |
|||
drop0 & 0x08 ? 1 : 0, drop0 & 0x04 ? 1 : 0, drop0 & 0x02 ? 1 : 0, drop0 & 0x01 ? 1 : 0, // |
|||
drop1 & 0x80 ? 1 : 0, drop1 & 0x40 ? 1 : 0, drop1 & 0x20 ? 1 : 0, drop1 & 0x10 ? 1 : 0, // |
|||
drop1 & 0x08 ? 1 : 0, drop1 & 0x04 ? 1 : 0, drop1 & 0x02 ? 1 : 0, drop1 & 0x01 ? 1 : 0 // |
|||
); |
|||
return state; |
|||
} |
|||
void AppBleService_onServiceInitCB() { |
|||
ZLOGI("init zdatachannel service"); |
|||
static 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)); |
|||
} |
|||
|
|||
static void app_event_listener(void* p_event_data, uint16_t event_size) { // |
|||
app_event_t* event = (app_event_t*)p_event_data; |
|||
if (event->eventType == kevent_sensor_drop) { |
|||
prvf_try_report_sensor_drop_event(event->val.sensor_drop.drop0, event->val.sensor_drop.drop1); |
|||
} else if (event->eventType == kevent_tmr_scheduler) { |
|||
static int cnt = 0; |
|||
cnt++; |
|||
if (DeviceCtrl_now_state() == kdevice_state_sampling && cnt % 10 == 0) { |
|||
// uint8_t drop0 = hwss_get_drop_state0(); |
|||
// uint8_t drop1 = hwss_get_drop_state1(); |
|||
// ZLOGI("[%d] drop %s", znordic_getpower_on_ms(), dropstate(drop0, drop1)); |
|||
// prvf_try_report_sensor_drop_event(drop0, drop1); |
|||
} |
|||
|
|||
} else if (event->eventType == kevent_sample_stop_event) { |
|||
prvf_try_report_sample_end_event(); |
|||
} else if (event->eventType == kevent_capture_little_data_block_event) { |
|||
// 上报采样数据 |
|||
if (m_realtime_report_state) { |
|||
// 上报采样数据 |
|||
prvf_report_sample_data(event->val.little_data_block.frameIndex, // |
|||
event->val.little_data_block.data, LITTLE_DATA_BLOCK_FRAME_NUM); |
|||
} |
|||
} |
|||
} |
|||
|
|||
bool m_ble_cmder_is_inited = false; |
|||
void AppBleService_init() { |
|||
AppEvent_regListener(app_event_listener); |
|||
|
|||
if (!m_ble_cmder_is_inited) { |
|||
ZERROR_CHECK(app_timer_create(&m_record_upload_tmr, APP_TIMER_MODE_REPEATED, RecordUpload_tmr_cb)); |
|||
ZERROR_CHECK(app_timer_create(&m_record_upload_finish_packet_report_tmr, APP_TIMER_MODE_SINGLE_SHOT, RecordUpload_finish_packet_report_tmr_cb)); |
|||
} |
|||
m_ble_cmder_is_inited = true; |
|||
} |
@ -0,0 +1,15 @@ |
|||
#pragma once |
|||
#include <stdint.h> |
|||
|
|||
/** |
|||
* @brief |
|||
* zble_module_init 方法将此回调注册进去 |
|||
*/ |
|||
void AppBleService_onServiceInitCB(); |
|||
|
|||
void AppBleService_init(); |
|||
void AppBleService_uninit(); |
|||
|
|||
void AppBleService_try_report_one_sample_data(uint32_t frameIndex, uint16_t data); |
|||
void AppBleService_try_report_sensor_drop_event(uint8_t dropstate0, uint8_t dropstate1); |
|||
void AppBleService_report_sample_finish_event(); |
@ -0,0 +1,52 @@ |
|||
#pragma once |
|||
#include <stdbool.h> |
|||
#include <stdint.h> |
|||
#include "board/board.h" |
|||
|
|||
|
|||
typedef enum { |
|||
kevent_sensor_drop = 0, // 导联连接事件 |
|||
kevent_tmr_scheduler, // 定时器调度事件 |
|||
kevent_capture_data_block_event, // 每采集一定数据后回调一次 |
|||
kevent_capture_little_data_block_event, // 传感器小数据块回调事件 |
|||
kevent_button_push_event, // 按键按下事件 |
|||
kevent_button_release_event, // 按键释放事件 |
|||
|
|||
kevent_start_sample_cmd_event, // 开始采集事件 |
|||
kevent_stop_sample_cmd_event, // 停止采集事件 |
|||
|
|||
kevent_sample_start_event, // 开始采集事件 |
|||
kevent_sample_stop_event, // 停止采集事件 |
|||
|
|||
kevent_ble_connect_event, // 蓝牙连接事件 |
|||
kevent_ble_disconnect_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; |
|||
|
|||
struct { |
|||
uint8_t drop0; |
|||
uint8_t drop1; |
|||
} sensor_drop; |
|||
} val; |
|||
} app_event_t; |
|||
|
|||
void app_event_process_cb(void* p_event_data, uint16_t event_size); |
@ -0,0 +1,23 @@ |
|||
#include "app_event_distribute.h" |
|||
|
|||
#include "app_event.h" |
|||
#include "app_scheduler.h" |
|||
|
|||
static AppEventListener m_listener[10]; |
|||
static int m_listener_num = 0; |
|||
|
|||
static void app_event_process_cb(void* p_event_data, uint16_t event_size) { |
|||
for (int i = 0; i < m_listener_num; i++) { |
|||
if (m_listener[i].cbfunc) { |
|||
m_listener[i].cbfunc(p_event_data, event_size); |
|||
} |
|||
} |
|||
} |
|||
|
|||
void AppEvent_regListener(app_event_listener_t listener) { // |
|||
m_listener[m_listener_num++].cbfunc = listener; |
|||
} |
|||
|
|||
void AppEvent_pushEvent(app_event_t* event) { // |
|||
app_sched_event_put(event, sizeof(app_event_t), app_event_process_cb); |
|||
} |
@ -0,0 +1,15 @@ |
|||
#pragma once |
|||
#include <stdbool.h> |
|||
#include <stdint.h> |
|||
|
|||
#include "app_event.h" |
|||
|
|||
|
|||
typedef void (*app_event_listener_t)(void* p_event_data, uint16_t event_size); |
|||
|
|||
typedef struct { |
|||
app_event_listener_t cbfunc; |
|||
} AppEventListener; |
|||
|
|||
void AppEvent_regListener(app_event_listener_t listener); |
|||
void AppEvent_pushEvent(app_event_t* event); |
@ -0,0 +1,129 @@ |
|||
/* |
|||
* ADS1293.h |
|||
* |
|||
* Created on: Jun 6, 2022 |
|||
* Author: Hans Hüttmann |
|||
*/ |
|||
#include "ads1293.h" |
|||
|
|||
#include <stdbool.h> |
|||
#include <stdlib.h> |
|||
#include <string.h> |
|||
|
|||
static uint8_t txcache[256]; |
|||
static uint8_t rxcache[256]; |
|||
|
|||
void ads1293_spi_init(ads1293_t* ads, ads1293_spi_tx_rx_t spi_tx_rx) { ads->spi_tx_rx = spi_tx_rx; } |
|||
|
|||
void ads1293_spi_writereg(ads1293_t* ads, uint8_t addr, uint8_t data) { |
|||
uint8_t txcache[2]; |
|||
txcache[0] = ADS1293_WRITE_BIT & addr; |
|||
txcache[1] = data; |
|||
ads->spi_tx_rx(txcache, NULL, 2); |
|||
} |
|||
uint8_t ads1293_spi_readreg(ads1293_t* ads, uint8_t addr) { |
|||
uint8_t txcache[2]; |
|||
txcache[0] = ADS1293_READ_BIT | addr; |
|||
txcache[1] = 0; |
|||
uint8_t rxcache[2]; |
|||
ads->spi_tx_rx(txcache, rxcache, 2); |
|||
return rxcache[1]; |
|||
} |
|||
void ads1293_spi_writereg_and_readbak(ads1293_t* ads, uint8_t addr, uint8_t data, uint8_t* readbak) { |
|||
ads1293_spi_writereg(ads, addr, data); |
|||
*readbak = ads1293_spi_readreg(ads, addr); |
|||
} |
|||
|
|||
void ads1293_spi_autoinc_writereg(ads1293_t* ads, uint8_t addr, uint8_t* data, uint8_t len) { // |
|||
len = len > 255 ? 255 : len; |
|||
uint8_t addbyte = ADS1293_WRITE_BIT & addr; |
|||
|
|||
txcache[0] = addbyte; |
|||
memcpy(txcache + 1, data, len); |
|||
|
|||
ads->spi_tx_rx(txcache, NULL, len + 1); |
|||
} |
|||
void ads1293_spi_autoinc_readreg(ads1293_t* ads, uint8_t addr, uint8_t* data, uint8_t len) { |
|||
len = len > 255 ? 255 : len; |
|||
uint8_t addbyte = ADS1293_READ_BIT | addr; |
|||
|
|||
txcache[0] = addbyte; |
|||
memset(txcache + 1, 0, len); |
|||
|
|||
ads->spi_tx_rx(txcache, rxcache, len + 1); |
|||
|
|||
memcpy(data, rxcache + 1, len); |
|||
} |
|||
void ads1293_spi_stream_readreg(ads1293_t* ads, uint8_t* data, uint8_t len) { |
|||
len = len > 255 ? 255 : len; |
|||
|
|||
memset(txcache, 0, len); |
|||
memset(rxcache, 0, len); |
|||
|
|||
uint8_t addbyte = ADS1293_READ_BIT | TI_ADS1293_DATA_LOOP_REG; |
|||
|
|||
ads->spi_tx_rx(&addbyte, rxcache, len); |
|||
memcpy(data, rxcache, len); |
|||
} |
|||
|
|||
void ads1293_read_ecg(ads1293_t* ads, uint32_t ch, uint32_t* data) { |
|||
uint8_t add = 0; |
|||
if (ch == 1) { |
|||
add = TI_ADS1293_DATA_CH1_ECG_H_REG; |
|||
} else if (ch == 2) { |
|||
add = TI_ADS1293_DATA_CH2_ECG_H_REG; |
|||
} else if (ch == 3) { |
|||
add = TI_ADS1293_DATA_CH3_ECG_H_REG; |
|||
} else { |
|||
return; |
|||
} |
|||
|
|||
uint8_t readbak[3] = {0}; |
|||
ads1293_spi_autoinc_readreg(ads, add, readbak, 3); |
|||
|
|||
*data = 0; |
|||
*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_read_error(ads1293_t* ads, ads1293_error_t* error) { |
|||
error->lod = 0; |
|||
error->estatus = 0; |
|||
error->error_range1 = 0; |
|||
error->error_range2 = 0; |
|||
error->error_range3 = 0; |
|||
error->error_sync = 0; |
|||
error->error_misc = 0; |
|||
|
|||
ads1293_spi_autoinc_readreg(ads, TI_ADS1293_ERROR_LOD_REG, (uint8_t*)error, 7); |
|||
} |
|||
|
|||
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); |
|||
} |
|||
void ads1293_start_power_off(ads1293_t* ads) { |
|||
uint8_t data = 0; |
|||
data |= 0x01 << 2; |
|||
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); } |
|||
|
|||
uint8_t ads1293_read_ready_status(ads1293_t* ads) { return ads1293_spi_readreg(ads, TI_ADS1293_DATA_STATUS_REG); } |
@ -0,0 +1,142 @@ |
|||
//---------------------------------------------------------------------------- |
|||
// Description: This file contains definitions specific to the ADS1293. |
|||
// All the ADS1293 registers are defined as well as some common masks |
|||
// for these 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_H |
|||
|
|||
#define HEADER_FILE_TI_ADS1293_H |
|||
|
|||
#include <stdint.h> |
|||
|
|||
/************************************************************ |
|||
* TI ADS1293 REGISTER SET ADDRESSES |
|||
************************************************************/ |
|||
|
|||
#define TI_ADS1293_CONFIG_REG (0x00) /* Main Configuration */ |
|||
|
|||
#define TI_ADS1293_FLEX_CH1_CN_REG (0x01) /* Flex Routing Swich Control for Channel 1 */ |
|||
#define TI_ADS1293_FLEX_CH2_CN_REG (0x02) /* Flex Routing Swich Control for Channel 2 */ |
|||
#define TI_ADS1293_FLEX_CH3_CN_REG (0x03) /* Flex Routing Swich Control for Channel 3 */ |
|||
#define TI_ADS1293_FLEX_PACE_CN_REG (0x04) /* Flex Routing Swich Control for Pace Channel */ |
|||
#define TI_ADS1293_FLEX_VBAT_CN_REG (0x05) /* Flex Routing Swich Control for Battery Monitoriing */ |
|||
|
|||
#define TI_ADS1293_LOD_CN_REG (0x06) /* Lead Off Detect Control */ |
|||
#define TI_ADS1293_LOD_EN_REG (0x07) /* Lead Off Detect Enable */ |
|||
#define TI_ADS1293_LOD_CURRENT_REG (0x08) /* Lead Off Detect Current */ |
|||
#define TI_ADS1293_LOD_AC_CN_REG (0x09) /* AC Lead Off Detect Current */ |
|||
|
|||
#define TI_ADS1293_CMDET_EN_REG (0x0A) /* Common Mode Detect Enable */ |
|||
#define TI_ADS1293_CMDET_CN_REG (0x0B) /* Commond Mode Detect Control */ |
|||
#define TI_ADS1293_RLD_CN_REG (0x0C) /* Right Leg Drive Control */ |
|||
|
|||
#define TI_ADS1293_WILSON_EN1_REG (0x0D) /* Wilson Reference Input one Selection */ |
|||
#define TI_ADS1293_WILSON_EN2_REG (0x0E) /* Wilson Reference Input two Selection */ |
|||
#define TI_ADS1293_WILSON_EN3_REG (0x0F) /* Wilson Reference Input three Selection */ |
|||
#define TI_ADS1293_WILSON_CN_REG (0x10) /* Wilson Reference Input Control */ |
|||
|
|||
#define TI_ADS1293_REF_CN_REG (0x11) /* Internal Reference Voltage Control */ |
|||
|
|||
#define TI_ADS1293_OSC_CN_REG (0x12) /* Clock Source and Output Clock Control */ |
|||
|
|||
#define TI_ADS1293_AFE_RES_REG (0x13) /* Analog Front-End Frequency and Resolution */ |
|||
#define TI_ADS1293_AFE_SHDN_CN_REG (0x14) /* Analog Front-End Shutdown Control */ |
|||
#define TI_ADS1293_AFE_FAULT_CN_REG (0x15) /* Analog Front-End Fault Detection Control */ |
|||
#define TI_ADS1293_AFE_DITHER_EN_REG (0x16) /* Enable Dithering in Signma-Delta */ |
|||
#define TI_ADS1293_AFE_PACE_CN_REG (0x17) /* Analog Pace Channel Output Routing Control */ |
|||
|
|||
#define TI_ADS1293_ERROR_LOD_REG (0x18) /* Lead Off Detect Error Status */ |
|||
#define TI_ADS1293_ERROR_STATUS_REG (0x19) /* Other Error Status */ |
|||
#define TI_ADS1293_ERROR_RANGE1_REG (0x1A) /* Channel 1 Amplifier Out of Range Status */ |
|||
#define TI_ADS1293_ERROR_RANGE2_REG (0x1B) /* Channel 1 Amplifier Out of Range Status */ |
|||
#define TI_ADS1293_ERROR_RANGE3_REG (0x1C) /* Channel 1 Amplifier Out of Range Status */ |
|||
#define TI_ADS1293_ERROR_SYNC_REG (0x1D) /* Synchronization Error */ |
|||
|
|||
#define TI_ADS1293_R2_RATE_REG (0x21) /* R2 Decimation Rate */ |
|||
#define TI_ADS1293_R3_RATE1_REG (0x22) /* R3 Decimation Rate for Channel 1 */ |
|||
#define TI_ADS1293_R3_RATE2_REG (0x23) /* R3 Decimation Rate for Channel 2 */ |
|||
#define TI_ADS1293_R3_RATE3_REG (0x24) /* R3 Decimation Rate for Channel 3 */ |
|||
#define TI_ADS1293_P_DRATE_REG (0x25) /* 2x Pace Data Rate */ |
|||
#define TI_ADS1293_DIS_EFILTER_REG (0x26) /* ECG Filter Disable */ |
|||
#define TI_ADS1293_DRDYB_SRC_REG (0x27) /* Data Ready Pin Source */ |
|||
#define TI_ADS1293_SYNCOUTB_SRC_REG (0x28) /* Sync Out Pin Source */ |
|||
#define TI_ADS1293_MASK_DRDYB_REG (0x29) /* Optional Mask Control for DRDYB Output */ |
|||
#define TI_ADS1293_MASK_ERR_REG (0x2A) /* Mask Error on ALARMB Pin */ |
|||
|
|||
#define TI_ADS1293_ALARM_FILTER_REG (0x2E) /* Digital Filter for Analog Alarm Signals */ |
|||
#define TI_ADS1293_CH_CNFG_REG (0x2F) /* Configure Channel for Loop Read Back Mode */ |
|||
|
|||
#define TI_ADS1293_DATA_STATUS_REG (0x30) /* ECG and Pace Data Ready Status */ |
|||
#define TI_ADS1293_DATA_CH1_PACE_H_REG (0x31) /* Channel1 Pace Data High [15:8] */ |
|||
#define TI_ADS1293_DATA_CH1_PACE_L_REG (0x32) /* Channel1 Pace Data Low [7:0] */ |
|||
#define TI_ADS1293_DATA_CH2_PACE_H_REG (0x33) /* Channel2 Pace Data High [15:8] */ |
|||
#define TI_ADS1293_DATA_CH2_PACE_L_REG (0x34) /* Channel2 Pace Data Low [7:0] */ |
|||
#define TI_ADS1293_DATA_CH3_PACE_H_REG (0x35) /* Channel3 Pace Data High [15:8] */ |
|||
#define TI_ADS1293_DATA_CH3_PACE_L_REG (0x36) /* Channel3 Pace Data Low [7:0] */ |
|||
#define TI_ADS1293_DATA_CH1_ECG_H_REG (0x37) /* Channel1 ECG Data High [23:16] */ |
|||
#define TI_ADS1293_DATA_CH1_ECG_M_REG (0x38) /* Channel1 ECG Data Medium [15:8] */ |
|||
#define TI_ADS1293_DATA_CH1_ECG_L_REG (0x39) /* Channel1 ECG Data Low [7:0] */ |
|||
#define TI_ADS1293_DATA_CH2_ECG_H_REG (0x3A) /* Channel2 ECG Data High [23:16] */ |
|||
#define TI_ADS1293_DATA_CH2_ECG_M_REG (0x3B) /* Channel2 ECG Data Medium [15:8] */ |
|||
#define TI_ADS1293_DATA_CH2_ECG_L_REG (0x3C) /* Channel2 ECG Data Low [7:0] */ |
|||
#define TI_ADS1293_DATA_CH3_ECG_H_REG (0x3D) /* Channel3 ECG Data High [23:16] */ |
|||
#define TI_ADS1293_DATA_CH3_ECG_M_REG (0x3E) /* Channel3 ECG Data Medium [15:8] */ |
|||
#define TI_ADS1293_DATA_CH3_ECG_L_REG (0x3F) /* Channel3 ECG Data Low [7:0] */ |
|||
|
|||
#define TI_ADS1293_REVID_REG (0x40) /* Revision ID */ |
|||
#define TI_ADS1293_DATA_LOOP_REG (0x50) /* Loop Read Back Address */ |
|||
|
|||
// Useful definitions |
|||
#define ADS1293_READ_BIT (0x80) |
|||
#define ADS1293_WRITE_BIT (0x7F) |
|||
|
|||
typedef void (*ads1293_spi_tx_rx_t)(uint8_t* tx, uint8_t* rx, uint8_t len); |
|||
typedef struct { |
|||
ads1293_spi_tx_rx_t spi_tx_rx; |
|||
int id; |
|||
} ads1293_t; |
|||
|
|||
void ads1293_spi_init(ads1293_t* ads, ads1293_spi_tx_rx_t spi_tx_rx); |
|||
|
|||
void ads1293_spi_writereg_and_readbak(ads1293_t* ads, uint8_t addr, uint8_t data, uint8_t* readbak); |
|||
void ads1293_spi_writereg(ads1293_t* ads, uint8_t addr, uint8_t data); |
|||
uint8_t ads1293_spi_readreg(ads1293_t* ads, uint8_t addr); |
|||
|
|||
void ads1293_spi_autoinc_writereg(ads1293_t* ads, uint8_t addr, uint8_t* data, uint8_t len); |
|||
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_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); |
|||
|
|||
uint8_t ads1293_read_ready_status(ads1293_t* ads); |
|||
|
|||
typedef struct { |
|||
uint8_t lod; |
|||
uint8_t estatus; |
|||
uint8_t error_range1; |
|||
uint8_t error_range2; |
|||
uint8_t error_range3; |
|||
uint8_t error_sync; |
|||
uint8_t error_misc; |
|||
} ads1293_error_t; |
|||
void ads1293_read_error(ads1293_t* ads, ads1293_error_t* error); |
|||
|
|||
#endif // HEADER_FILE_TI_ADS1293_H |
@ -0,0 +1,3 @@ |
|||
#pragma once |
|||
#define VERSION 1 |
|||
#define MANUFACTURER_NAME "iflytop" |
@ -0,0 +1,72 @@ |
|||
#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 CLK |
|||
#define SDCARD_SPI_CS_PIN 5 // SDCARD CS DATA3 |
|||
#define SDCARD_SPI_MISO_PIN 11 // SDCARD MISO DATA0 |
|||
#define SDCARD_SPI_MOSI_PIN 17 // SDCARD MOSI CMD |
|||
|
|||
#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 18 |
|||
|
|||
/******************************************************************************* |
|||
* 蜂鸣器 * |
|||
*******************************************************************************/ |
|||
#define BEEP_PIN 0 |
|||
|
|||
/******************************************************************************* |
|||
* 电池电量 * |
|||
*******************************************************************************/ |
|||
#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 (uint32_t)(3.5 * 1024 * 1024 * 1024) |
|||
// |
|||
#define SAMPLE_RATE 400 |
|||
#define LITTLE_DATA_BLOCK_FRAME_NUM 4 // 每两帧回调一次,对应100HZ |
|||
#define SAMPLE_PRECISION 24 |
|||
|
|||
#define APP_MAX_EVEN_SIZE MAX(APP_TIMER_SCHED_EVENT_DATA_SIZE, sizeof(app_event_t)) |
|||
#define APP_EVENT_QUEUE_SIZE 100 |
|||
|
|||
#define APP_AUTO_SLEEP_TIMEOUT_MS (10 * 1000) |
|||
#define APP_BYTE_EACH_FRAME 9 |
|||
#define APP_SENSOR_NUM 3 |
@ -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; |
|||
} |
@ -0,0 +1,14 @@ |
|||
#pragma once |
|||
|
|||
#include <stdbool.h> |
|||
#include <stdint.h> |
|||
|
|||
#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_get_battery_level(); // 0->100 |
@ -0,0 +1,102 @@ |
|||
#include "board_beep_ctrl.h" |
|||
#define BEEP_TIMER_INTERVAL (150) |
|||
|
|||
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 | NRF_DRV_PWM_PIN_INVERTED, // |
|||
NRF_DRV_PWM_PIN_NOT_USED, |
|||
NRF_DRV_PWM_PIN_NOT_USED, |
|||
NRF_DRV_PWM_PIN_NOT_USED, |
|||
}, |
|||
.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 uint32_t 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 < 6) { |
|||
if (m_beep_cnt % 2 == 0) { |
|||
BoardBeepCtrl_set(true); |
|||
} else if (m_beep_cnt % 2 == 1) { |
|||
BoardBeepCtrl_set(false); |
|||
} |
|||
} else { |
|||
BoardBeepCtrl_set(false); |
|||
app_timer_stop(m_beep_tmr); |
|||
m_beep_effect = kBoardBeepEffect_none; |
|||
} |
|||
|
|||
} else if (m_beep_effect == kBoardBeepEffect_continuousShortBeep) { |
|||
// 每隔1秒响三声 |
|||
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 >= 10000) { |
|||
m_beep_cnt = 0; |
|||
return; |
|||
} |
|||
} |
|||
} |
|||
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); |
|||
} |
|||
} |
@ -0,0 +1,24 @@ |
|||
#pragma once |
|||
|
|||
#include <stdbool.h> |
|||
#include <stdint.h> |
|||
|
|||
#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); |
@ -0,0 +1,34 @@ |
|||
#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) { |
|||
if (m_cb) { |
|||
m_cb(kButton_mainButton, (ButtonAction_t)button_action); |
|||
} |
|||
} |
|||
|
|||
static app_button_cfg_t buttons[] = { |
|||
{BUTTON_PIN, true, NRF_GPIO_PIN_PULLUP, button_process_handler}, |
|||
}; |
|||
void BoardButton_Init(board_button_cb_t cb) { // |
|||
m_cb = cb; |
|||
// ZERROR_CHECK(app_button_init(buttons, ARRAY_SIZE(buttons), BUTTON_DETECTION_DELAY)); |
|||
} |
|||
void BoardButton_load() { |
|||
// ZERROR_CHECK(app_button_enable()); |
|||
} |
|||
void BoardButton_unload() { |
|||
// ZERROR_CHECK(app_button_disable()); |
|||
} |
|||
|
|||
void BoardButton_enable_sense() { |
|||
// app_button_disable(); |
|||
nrf_gpio_cfg_sense_input(BUTTON_PIN, NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_SENSE_LOW); |
|||
// nrf_gpio_cfg_sense_input(BUTTON_PIN, NRF_GPIO_PIN_PULLDOWN, NRF_GPIO_PIN_SENSE_HIGH); |
|||
} |
@ -0,0 +1,23 @@ |
|||
#pragma once |
|||
|
|||
#include <stdbool.h> |
|||
#include <stdint.h> |
|||
|
|||
#include "board/board.h" |
|||
|
|||
typedef enum { |
|||
kButton_mainButton, |
|||
} ButtonIndex_t; |
|||
|
|||
typedef enum { |
|||
kButtonAction_push = 1, |
|||
kButtonAction_release = 0, |
|||
} ButtonAction_t; |
|||
|
|||
typedef void (*board_button_cb_t)(ButtonIndex_t pin_no, ButtonAction_t button_action); |
|||
|
|||
void BoardButton_Init(board_button_cb_t cb); // main中初始化一遍 |
|||
void BoardButton_load(); |
|||
void BoardButton_unload(); |
|||
|
|||
void BoardButton_enable_sense(); // 低功耗睡眠前调用该方法 |
@ -0,0 +1,79 @@ |
|||
#include "board_light_ctrl.h" |
|||
|
|||
#include "board.h" |
|||
#include "znordic.h" |
|||
|
|||
#define BLINK_CNT 1 |
|||
#define BLINK_PERIOD_MS (100) |
|||
|
|||
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 < 2) { |
|||
if (m_blink_cnt % 2 == 0) { |
|||
BoardLight_setGreenLightState(true); |
|||
} else if (m_blink_cnt % 2 == 1) { |
|||
BoardLight_setGreenLightState(false); |
|||
} |
|||
} else { |
|||
if (BLINK_PERIOD_MS * m_blink_cnt >= 1000) { |
|||
m_blink_cnt = 0; |
|||
return; |
|||
} |
|||
} |
|||
} |
|||
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; |
|||
} |
@ -0,0 +1,23 @@ |
|||
#pragma once |
|||
|
|||
#include <stdbool.h> |
|||
#include <stdint.h> |
|||
|
|||
#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); |
@ -0,0 +1,172 @@ |
|||
#include "board/board_sdcard_driver.h" |
|||
|
|||
#include "board/board.h" |
|||
#include "znordic.h" |
|||
/******************************************************************************* |
|||
* 结构体定义 * |
|||
*******************************************************************************/ |
|||
|
|||
FATFS m_fs; |
|||
BoardSdcardConnectTo_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_PULLUP); |
|||
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_PULLUP); |
|||
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_PULLUP); |
|||
nrf_gpio_pin_write(SDCARD_POWER_CTRL_PIN, 0); // POWER = 0 打开电源 |
|||
m_connectTo = kConnectToNone; |
|||
|
|||
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); |
|||
nrf_delay_ms(100); // 让SD卡通过断电复位一会 |
|||
nrf_gpio_pin_write(SDCARD_POWER_CTRL_PIN, 0); // 开 |
|||
/** |
|||
* @brief 切换引脚连接 |
|||
*/ |
|||
nrf_gpio_pin_write(SDCARD_USBDRIVER_IC_JUNCTION_CTRL_NOE_PIN, 0); |
|||
|
|||
nrf_gpio_pin_write(SDCARD_USBDRIVER_IC_RESET_PIN, 0); |
|||
nrf_delay_ms(30); |
|||
nrf_gpio_pin_write(SDCARD_USBDRIVER_IC_RESET_PIN, 1); |
|||
|
|||
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 = 10; 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; } |
@ -0,0 +1,19 @@ |
|||
#pragma once |
|||
|
|||
#include <stdbool.h> |
|||
#include <stdint.h> |
|||
|
|||
#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(); |
@ -0,0 +1,357 @@ |
|||
#include "device_ctrl_service.h" |
|||
|
|||
#include "app_event_distribute.h" |
|||
#include "board/board_battery_state.h" |
|||
#include "board/board_beep_ctrl.h" |
|||
#include "board/board_button.h" |
|||
#include "board/board_light_ctrl.h" |
|||
#include "board/board_sdcard_driver.h" |
|||
#include "heart_wave_sample_service.h" |
|||
#include "sample_data_manager_service.h" |
|||
#include "zble_module.h" |
|||
#include "zdatachannel_service.h" |
|||
// |
|||
APP_TIMER_DEF(m_state_machine_driver_tmr); // 状态机驱动定时器 |
|||
static device_state_t m_device_state = kdevice_state_standby; // 设备状态 |
|||
static uint32_t m_change_to_cur_state_tp = 0; // 切换到当前状态的时间戳 |
|||
static int m_sample_data_fd = -1; // 采集数据文件描述符 |
|||
|
|||
/******************************************************************************* |
|||
* 函数列表 * |
|||
*******************************************************************************/ |
|||
|
|||
void DeviceCtrl_change_to_state(device_state_t state); |
|||
uint32_t DeviceCtrl_cur_state_haspassed_ms(); |
|||
device_state_t DeviceCtrl_now_state(); |
|||
|
|||
/******************************************************************************* |
|||
* 事件路由 * |
|||
*******************************************************************************/ |
|||
|
|||
static void state_machine_driver_tmr_cb(void* p_context) { // |
|||
static app_event_t appevent; |
|||
appevent.eventType = kevent_tmr_scheduler; |
|||
AppEvent_pushEvent(&appevent); |
|||
} |
|||
/** |
|||
* @brief 按键事件处理 |
|||
*/ |
|||
static void board_button_cb(ButtonIndex_t pin_no, ButtonAction_t button_action) { // |
|||
static app_event_t event; |
|||
event.eventType = button_action == kButtonAction_push ? kevent_button_push_event : kevent_button_release_event; |
|||
AppEvent_pushEvent(&event); |
|||
} |
|||
|
|||
static void zble_event_listener(zble_event_t* ble_event) { // |
|||
static app_event_t event; |
|||
if (ble_event->eventType == kzble_event_connected) { |
|||
event.eventType = kevent_ble_connect_event; |
|||
AppEvent_pushEvent(&event); |
|||
} else if (ble_event->eventType == kzble_event_disconnected) { |
|||
event.eventType = kevent_ble_disconnect_event; |
|||
AppEvent_pushEvent(&event); |
|||
} |
|||
} |
|||
|
|||
/******************************************************************************* |
|||
* 事件处理 * |
|||
*******************************************************************************/ |
|||
static bool m_ispoweron = false; |
|||
// static bool m_drop_state_triggered = false; |
|||
static void poweroff() { |
|||
if (!m_ispoweron) return; |
|||
BoardBeepCtrl_unload(); |
|||
BoardLight_unload(); |
|||
BoardBattery_unload(); |
|||
BoardButton_unload(); |
|||
SampleDataMgr_unloadDriver(); |
|||
// hwss_unload(); |
|||
DeviceCtrl_change_to_state(kdevice_state_standby); |
|||
zble_module_stop_adv(); |
|||
BoardLight_setGreenLightEffect(kLightEffect_close); |
|||
|
|||
// 进入深度睡眠前,使能唤醒引脚 |
|||
BoardButton_enable_sense(); |
|||
app_timer_stop_all(); |
|||
// 系统进入深度睡眠 |
|||
sd_power_system_off(); |
|||
NVIC_SystemReset(); |
|||
m_ispoweron = false; |
|||
} |
|||
static void poweron() { |
|||
if (m_ispoweron) { |
|||
return; |
|||
} |
|||
|
|||
BoardBeepCtrl_load(); |
|||
BoardLight_load(); |
|||
BoardBattery_load(); |
|||
BoardButton_load(); |
|||
SampleDataMgr_loadDriver(); |
|||
DeviceCtrl_change_to_state(kdevice_state_ready); |
|||
zble_module_start_adv(); |
|||
BoardLight_setGreenLightEffect(kLightEffect_slowFlash); |
|||
m_ispoweron = true; |
|||
} |
|||
|
|||
static sample_data_filename_t* cratefilename() { |
|||
static ztm_t tm; |
|||
static sample_data_filename_t sampledata_file_name; |
|||
memset(&sampledata_file_name, 0, sizeof(sampledata_file_name)); |
|||
znordic_rtc_gettime(&tm); |
|||
|
|||
sampledata_file_name.year = tm.tm_year + 1900 - 2000; |
|||
sampledata_file_name.month = tm.tm_mon + 1; |
|||
sampledata_file_name.day = tm.tm_mday; |
|||
sampledata_file_name.hour = tm.tm_hour; |
|||
sampledata_file_name.min = tm.tm_min; |
|||
sampledata_file_name.sec = tm.tm_sec; |
|||
return &sampledata_file_name; |
|||
} |
|||
|
|||
static void prvf_change_to_standby_state() { |
|||
poweroff(); |
|||
DeviceCtrl_change_to_state(kdevice_state_standby); |
|||
} |
|||
static void prvf_change_to_ready_state() { |
|||
poweron(); |
|||
DeviceCtrl_change_to_state(kdevice_state_ready); |
|||
BoardBeepCtrl_setEffect(kBoardBeepEffect_threeShortBeep); |
|||
} |
|||
#if 0 |
|||
static const char* dropstate(uint8_t drop0, uint8_t drop1) { |
|||
static char state[128]; |
|||
sprintf(state, "drop0:%d%d%d%d-%d%d%d%d drop1:%d%d%d%d-%d%d%d%d", // |
|||
drop0 & 0x80 ? 1 : 0, drop0 & 0x40 ? 1 : 0, drop0 & 0x20 ? 1 : 0, drop0 & 0x10 ? 1 : 0, // |
|||
drop0 & 0x08 ? 1 : 0, drop0 & 0x04 ? 1 : 0, drop0 & 0x02 ? 1 : 0, drop0 & 0x01 ? 1 : 0, // |
|||
drop1 & 0x80 ? 1 : 0, drop1 & 0x40 ? 1 : 0, drop1 & 0x20 ? 1 : 0, drop1 & 0x10 ? 1 : 0, // |
|||
drop1 & 0x08 ? 1 : 0, drop1 & 0x04 ? 1 : 0, drop1 & 0x02 ? 1 : 0, drop1 & 0x01 ? 1 : 0 // |
|||
); |
|||
return state; |
|||
} |
|||
#endif |
|||
static void prvf_change_to_sample_state() { // |
|||
if (m_device_state == kdevice_state_sampling) { |
|||
return; |
|||
} |
|||
DeviceCtrl_change_to_state(kdevice_state_sampling); |
|||
} |
|||
|
|||
static void app_event_listener(void* p_event_data, uint16_t event_size) { // |
|||
app_event_t* event = (app_event_t*)p_event_data; |
|||
// static bool inited; |
|||
// if (!inited) { |
|||
// nrf_gpio_cfg_input(BUTTON_PIN, NRF_GPIO_PIN_NOPULL); |
|||
// inited = true; |
|||
// } |
|||
// ZLOGI("button %d", nrf_gpio_pin_read(BUTTON_PIN)); |
|||
|
|||
/******************************************************************************* |
|||
* 状态无关事件处理 * |
|||
*******************************************************************************/ |
|||
if (event->eventType == kevent_ble_connect_event) { |
|||
BoardLight_setGreenLightEffect(kLightEffect_open); |
|||
return; |
|||
} else if (event->eventType == kevent_ble_disconnect_event) { |
|||
BoardLight_setGreenLightEffect(kLightEffect_slowFlash); |
|||
return; |
|||
} |
|||
|
|||
/******************************************************************************* |
|||
* 状态机 * |
|||
*******************************************************************************/ |
|||
// ZLOGI("state %d", m_device_state); |
|||
if (m_device_state == kdevice_state_standby) { |
|||
// 休眠模式现在是深度睡眠,所以永远不会触发这个回调 |
|||
} |
|||
|
|||
// |
|||
else if (m_device_state == kdevice_state_ready) { |
|||
/******************************************************************************* |
|||
* 永不休眠 * |
|||
*******************************************************************************/ |
|||
#if 0 |
|||
if (!zble_module_is_connected() && DeviceCtrl_cur_state_haspassed_ms() > APP_AUTO_SLEEP_TIMEOUT_MS) { |
|||
ZLOGI("auto sleep"); |
|||
prvf_change_to_standby_state(); |
|||
} |
|||
#endif |
|||
|
|||
if (event->eventType == kevent_start_sample_cmd_event) { |
|||
ZLOGI("start sample"); |
|||
// SD卡连接到单片机 |
|||
SampleDataMgr_changeToLocalMode(); |
|||
hwss_load(); |
|||
// 创建文件 |
|||
m_sample_data_fd = SampleDataMgr_open(cratefilename(), kwrflag_write_only); |
|||
ZASSERT(m_sample_data_fd > 0); |
|||
// 切换到采集状态 |
|||
prvf_change_to_sample_state(); |
|||
// 开始采集 |
|||
hwss_start_capture(); |
|||
|
|||
{ |
|||
static app_event_t event; |
|||
event.eventType = kevent_sample_start_event; |
|||
AppEvent_pushEvent(&event); |
|||
} |
|||
|
|||
BoardBeepCtrl_setEffect(kBoardBeepEffect_oneShortBeep); |
|||
} |
|||
} |
|||
// |
|||
else if (m_device_state == kdevice_state_sampling) { |
|||
// 采集的字节长度超过最大字节长度,停止采集 |
|||
|
|||
if (event->eventType == kevent_capture_data_block_event) { |
|||
SampleDataMgr_write(m_sample_data_fd, (uint8_t*)event->val.block_sensor_data.data, event->val.block_sensor_data.len); |
|||
} |
|||
|
|||
uint8_t drop0 = hwss_get_drop_state0(); |
|||
uint8_t drop1 = hwss_get_drop_state1(); |
|||
|
|||
if ((drop0 || drop1) && event->eventType == kevent_tmr_scheduler) { |
|||
// ZLOGI("[%d] drop %s", znordic_getpower_on_ms(), dropstate(drop0, drop1)); |
|||
} |
|||
|
|||
bool stopcapture = false; |
|||
if (SampleDataMgr_getFileSizeByFd(m_sample_data_fd) > SDCARD_MAX_FILE_SIZE) { |
|||
ZLOGI("stop sample because file size is too large"); |
|||
stopcapture = true; |
|||
} else if (event->eventType == kevent_stop_sample_cmd_event) { |
|||
ZLOGI("stop sample because stop sample event"); |
|||
stopcapture = true; |
|||
} |
|||
|
|||
if (stopcapture) { |
|||
// 关闭文件 |
|||
SampleDataMgr_close(m_sample_data_fd); |
|||
// SD卡连接到外部typec |
|||
SampleDataMgr_changeToExtMode(); |
|||
// 停止采集 |
|||
hwss_stop_capture(); |
|||
// 卸载心电采集服务 |
|||
hwss_unload(); |
|||
// 切换到待机状态 |
|||
prvf_change_to_ready_state(); |
|||
|
|||
{ |
|||
static app_event_t event; |
|||
event.eventType = kevent_sample_stop_event; |
|||
AppEvent_pushEvent(&event); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
void DeviceCtrl_startSample() { |
|||
ZLOGI("start sample"); |
|||
static app_event_t event; |
|||
event.eventType = kevent_start_sample_cmd_event; |
|||
AppEvent_pushEvent(&event); |
|||
} |
|||
void DeviceCtrl_stopSample() { |
|||
ZLOGI("stop sample"); |
|||
static app_event_t event; |
|||
event.eventType = kevent_stop_sample_cmd_event; |
|||
AppEvent_pushEvent(&event); |
|||
} |
|||
|
|||
/******************************************************************************* |
|||
* EXTERN * |
|||
*******************************************************************************/ |
|||
|
|||
void DeviceCtrl_init() { |
|||
// 蜂鸣器初始化 |
|||
BoardBeepCtrl_init(); |
|||
// 板载指示灯初始化 |
|||
BoardLight_Init(); |
|||
// 按键初始化 |
|||
BoardButton_Init(board_button_cb); |
|||
// 电池初始化 |
|||
BoardBattery_init(); |
|||
// SD卡初始化 |
|||
SampleDataMgr_init(); |
|||
// 心电采集服务初始化 |
|||
hwss_init(); |
|||
// 注册事件监听 |
|||
AppEvent_regListener(app_event_listener); |
|||
// 监听蓝牙事件 |
|||
zble_module_reglistener(zble_event_listener); |
|||
// 切换到待机状态 |
|||
prvf_change_to_ready_state(); |
|||
|
|||
|
|||
// BoardBeepCtrl_init(); |
|||
// BoardBeepCtrl_load(); |
|||
// BoardBeepCtrl_setEffect(kBoardBeepEffect_continuousShortBeep); |
|||
|
|||
ZERROR_CHECK(app_timer_create(&m_state_machine_driver_tmr, APP_TIMER_MODE_REPEATED, state_machine_driver_tmr_cb)); |
|||
ZERROR_CHECK(app_timer_start(m_state_machine_driver_tmr, APP_TIMER_TICKS(100), NULL)); // 200HZ采样 |
|||
} |
|||
|
|||
/******************************************************************************* |
|||
* UTILS * |
|||
*******************************************************************************/ |
|||
void DeviceCtrl_change_to_state(device_state_t state) { |
|||
ZLOGI("change state from %s to %s", ds2str(m_device_state), ds2str(state)); |
|||
m_device_state = state; |
|||
m_change_to_cur_state_tp = znordic_getpower_on_ms(); |
|||
} |
|||
uint32_t DeviceCtrl_cur_state_haspassed_ms() { return znordic_haspassed_ms(m_change_to_cur_state_tp); } |
|||
device_state_t DeviceCtrl_now_state() { return m_device_state; } |
|||
|
|||
#if 0 |
|||
static void DeviceCtrl_test() { |
|||
/** |
|||
* @brief |
|||
* 1. 测试蜂鸣器 |
|||
* 2. 测试按键 |
|||
* 3. 测试LED |
|||
* 4. 测试指示灯 |
|||
* . SD卡 |
|||
* 5. 测试电池电量采集 |
|||
*/ |
|||
#if 0 |
|||
//蜂鸣器测试 |
|||
BoardBeepCtrl_init(); |
|||
BoardBeepCtrl_load(); |
|||
BoardBeepCtrl_setEffect(kBoardBeepEffect_continuousShortBeep); |
|||
#endif |
|||
|
|||
#if 1 |
|||
// BoardButton_Init(board_button_cb); |
|||
|
|||
#endif |
|||
|
|||
#if 0 |
|||
BoardLight_Init(); |
|||
BoardLight_load(); |
|||
BoardLight_setGreenLightEffect(kLightEffect_slowFlash); |
|||
#endif |
|||
#if 0 |
|||
Board_sdcardInit(); |
|||
Board_sdcardConnectToInternal(); |
|||
Board_sdcardConnectToExt(); |
|||
|
|||
Board_sdcardConnectToInternal(); |
|||
Board_sdcardConnectToExt(); |
|||
|
|||
#endif |
|||
#if 0 |
|||
sample_data_mgr_init(); |
|||
sample_data_mgr_loadDriver(); |
|||
sample_data_mgr_change_to_local_mode(); |
|||
|
|||
sample_data_filename_t filename; |
|||
int fd = sample_data_mgr_open(&filename, kwrflag_write_only); |
|||
sample_data_mgr_write(fd, "123456", 6); |
|||
sample_data_mgr_close(fd); |
|||
sample_data_mgr_change_to_ext_mode(); |
|||
#endif |
|||
#if 1 |
|||
// 蜂鸣器测试 |
|||
|
|||
#endif |
|||
} |
|||
#endif |
@ -0,0 +1,44 @@ |
|||
/** |
|||
* @file device_ctrl_service.h |
|||
* @author zhaohe (h_zhaohe@domain.com) |
|||
* @brief É豸¿ØÖÆ·þÎñ |
|||
* @version 0.1 |
|||
* @date 2024-02-01 |
|||
* |
|||
* @copyright Copyright (c) 2024 |
|||
* |
|||
*/ |
|||
#pragma once |
|||
#include "znordic.h" |
|||
|
|||
typedef enum { |
|||
// ´ý»ú |
|||
kdevice_state_standby = 0, |
|||
// Ready |
|||
kdevice_state_ready = 1, |
|||
// sample |
|||
kdevice_state_sampling = 2, |
|||
} device_state_t; |
|||
|
|||
static const char* ds2str(device_state_t ds) { |
|||
switch (ds) { |
|||
case kdevice_state_standby: |
|||
return "standby"; |
|||
case kdevice_state_ready: |
|||
return "ready"; |
|||
case kdevice_state_sampling: |
|||
return "sampling"; |
|||
default: |
|||
return "unknown"; |
|||
} |
|||
} |
|||
|
|||
void DeviceCtrl_change_to_state(device_state_t state); |
|||
uint32_t DeviceCtrl_cur_state_haspassed_ms(); |
|||
device_state_t DeviceCtrl_now_state(); |
|||
|
|||
void DeviceCtrl_startSample(); |
|||
void DeviceCtrl_stopSample(); |
|||
void DeviceCtrl_schdeule(); |
|||
|
|||
void DeviceCtrl_init() ; |
@ -0,0 +1,455 @@ |
|||
#include "heart_wave_sample_service.h" |
|||
// |
|||
#include "znordic.h" |
|||
// |
|||
#include "app_button.h" |
|||
#include "app_event.h" |
|||
#include "app_event_distribute.h" |
|||
#include "basic/ads1293/ads1293.h" |
|||
#include "nrf_drv_gpiote.h" |
|||
#include "nrfx_timer.h" |
|||
|
|||
#define SENSOR0_ID 0 |
|||
#define SENSOR1_ID 3 |
|||
#define SENSOR2_ID 4 |
|||
static const nrfx_timer_t m_timer = NRFX_TIMER_INSTANCE(1); /**< Timer used for channel sweeps and tx with duty cycle. */ |
|||
|
|||
/******************************************************************************* |
|||
* STRUCT * |
|||
*******************************************************************************/ |
|||
typedef struct { |
|||
uint8_t add; |
|||
uint8_t data; |
|||
} adscfg_t; |
|||
|
|||
/******************************************************************************* |
|||
* CONFIG * |
|||
*******************************************************************************/ |
|||
|
|||
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 adscfg_t m_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}, |
|||
}; |
|||
|
|||
static adscfg_t m_prvads0cfg_cache[65]; |
|||
static adscfg_t m_prvads1cfg_cache[65]; |
|||
/******************************************************************************* |
|||
* 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 uint32_t m_frame_filter_index; |
|||
static bool m_work_flag; |
|||
|
|||
#define FRAME_FILTER_INDEX_NUM 10 |
|||
|
|||
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; |
|||
|
|||
static uint8_t m_lodstate0; |
|||
static uint8_t m_lodstate1; |
|||
|
|||
volatile static bool m_drop_state_triggered = false; |
|||
|
|||
/******************************************************************************* |
|||
* 函数声明 * |
|||
*******************************************************************************/ |
|||
|
|||
// 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); |
|||
|
|||
/******************************************************************************* |
|||
* 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_frame_buffer = m_frame_buffer_a; |
|||
m_frame_buffer_index = 0; |
|||
} |
|||
} |
|||
|
|||
static inline bool prvf_buffer_is_full(void) { |
|||
if (m_frame_buffer_index >= HEART_WAVE_SAMPLE_SERVICE_CACHE_SIZE) { |
|||
return true; |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
static inline void prvf_buffer_push_one_byte(uint8_t byte) { |
|||
if (m_frame_buffer_index >= HEART_WAVE_SAMPLE_SERVICE_CACHE_SIZE) { |
|||
return; |
|||
} |
|||
m_frame_buffer[m_frame_buffer_index] = byte; |
|||
m_frame_buffer_index++; |
|||
} |
|||
|
|||
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; |
|||
AppEvent_pushEvent(&event); |
|||
} |
|||
|
|||
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 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 * sizeof(one_frame_data_t)); |
|||
|
|||
for (uint32_t i = 0; i < LITTLE_DATA_BLOCK_FRAME_NUM; i++) { |
|||
event.val.little_data_block.data[i].data0 = m_sensor_little_frame_cache[i].data0; |
|||
event.val.little_data_block.data[i].data1 = m_sensor_little_frame_cache[i].data1; |
|||
event.val.little_data_block.data[i].data2 = m_sensor_little_frame_cache[i].data2; |
|||
// event.val.little_data_block.data[0].data0 = 1111111111; |
|||
// event.val.little_data_block.data[0].data1 = 2222222222; |
|||
// event.val.little_data_block.data[0].data2 = 3333333333; |
|||
} |
|||
|
|||
event.val.little_data_block.frameIndex = m_frame_index - LITTLE_DATA_BLOCK_FRAME_NUM; |
|||
AppEvent_pushEvent(&event); |
|||
} |
|||
|
|||
static inline void prvf_trigger_sensor_drop_event(uint8_t drop0, uint8_t drop1) { |
|||
static app_event_t event; |
|||
event.eventType = kevent_sensor_drop; |
|||
event.val.sensor_drop.drop0 = drop0; |
|||
event.val.sensor_drop.drop1 = drop1; |
|||
AppEvent_pushEvent(&event); |
|||
} |
|||
|
|||
static void ads1293_spi_tx_rx_0(uint8_t* tx, uint8_t* rx, uint8_t len) { |
|||
if (!m_ads1293_driver_is_inited) { |
|||
return; |
|||
} |
|||
|
|||
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 void ads1293_spi_writereg_and_check(ads1293_t* ads, uint8_t addr, uint8_t data) { |
|||
uint8_t readbak = 0; |
|||
// readonly add |
|||
readbak = data; |
|||
if (addr >= 0x18 && addr <= 0x1E) { |
|||
return; |
|||
} |
|||
if (addr >= 0x30 && addr <= 0x3f) { |
|||
return; |
|||
} |
|||
if (addr == 0x40) { |
|||
return; |
|||
} |
|||
if (addr == 0x50) { |
|||
return; |
|||
} |
|||
ads1293_spi_writereg_and_readbak(ads, addr, data, &readbak); |
|||
if (readbak != data) { |
|||
ZLOGE("ads_%d write %x failed,w:%x readbak:%x\n", ads->id, addr, data, readbak); |
|||
} |
|||
} |
|||
|
|||
static void tryloadcfg_from_fatfs(const char* file, adscfg_t* cfg, uint16_t cfgsize, uint16_t* cfg_ret_size) { |
|||
// |
|||
*cfg_ret_size = 0; |
|||
|
|||
static FIL fd; |
|||
FRESULT ff_result = f_open(&fd, (const TCHAR*)file, FA_READ); |
|||
if (ff_result != FR_OK) { |
|||
ZLOGE("open %s failed\n", file); |
|||
return; |
|||
} |
|||
|
|||
char line[128]; |
|||
int niterm = 0; |
|||
f_gets(line, 128, &fd); |
|||
|
|||
while (f_gets(line, 128, &fd)) { |
|||
uint32_t addr; |
|||
uint32_t value; |
|||
sscanf(line, "%x,%x", &addr, &value); |
|||
cfg[niterm].add = addr; |
|||
cfg[niterm].data = value; |
|||
niterm++; |
|||
|
|||
if (niterm >= cfgsize) { |
|||
break; |
|||
} |
|||
} |
|||
*cfg_ret_size = niterm; |
|||
ZLOGI("load %s cfg size:%d\n", file, niterm); |
|||
f_close(&fd); |
|||
} |
|||
|
|||
static void ads1293_init() { |
|||
/******************************************************************************* |
|||
* SPI初始化 * |
|||
*******************************************************************************/ |
|||
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)); |
|||
|
|||
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); |
|||
|
|||
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); |
|||
|
|||
m_ads1293_driver_is_inited = true; |
|||
|
|||
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); |
|||
|
|||
ads1293_spi_writereg(&m_ads1293_0, TI_ADS1293_CONFIG_REG, 0); |
|||
|
|||
uint16_t cfgsize = 0; |
|||
tryloadcfg_from_fatfs("0.cfg", m_prvads0cfg_cache, ZARRAY_SIZE(m_prvads0cfg_cache), &cfgsize); |
|||
if (cfgsize > 0) { |
|||
ZLOGI("load 0.cfg from fatfs\n"); |
|||
|
|||
if (memcmp(m_prvads0cfg_cache, m_prvads0cfg, sizeof(m_prvads0cfg)) != 0) { |
|||
ZLOGI("0.cfg is different from default\n"); |
|||
} else { |
|||
ZLOGI("0.cfg is same as default\n"); |
|||
} |
|||
|
|||
for (uint16_t i = 0; i < cfgsize; i++) { |
|||
ads1293_spi_writereg_and_check(&m_ads1293_0, m_prvads0cfg_cache[i].add, m_prvads0cfg_cache[i].data); |
|||
} |
|||
} else { |
|||
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); |
|||
} |
|||
} |
|||
|
|||
tryloadcfg_from_fatfs("1.cfg", m_prvads1cfg_cache, ZARRAY_SIZE(m_prvads1cfg_cache), &cfgsize); |
|||
if (cfgsize > 0) { |
|||
ZLOGI("load 1.cfg from fatfs\n"); |
|||
|
|||
if (memcmp(m_prvads1cfg_cache, m_prvads1cfg, sizeof(m_prvads1cfg)) != 0) { |
|||
ZLOGI("1.cfg is different from default\n"); |
|||
} else { |
|||
ZLOGI("1.cfg is same as default\n"); |
|||
} |
|||
|
|||
for (uint16_t i = 0; i < cfgsize; i++) { |
|||
ads1293_spi_writereg_and_check(&m_ads1293_1, m_prvads1cfg_cache[i].add, m_prvads1cfg_cache[i].data); |
|||
} |
|||
} else { |
|||
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); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* @brief READY引脚中断初始化 |
|||
*/ |
|||
{ |
|||
// 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 ads1293_sample_one_frame(); |
|||
void nrfx_timer_event_handler(nrf_timer_event_t event_type, void* p_context) { // |
|||
ads1293_sample_one_frame(); |
|||
} |
|||
// static void ads1293_ready_pin_irq(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action) { ads1293_sample_one_frame(); } |
|||
static void ads1293_sample_one_frame() { |
|||
if (!m_work_flag) { |
|||
return; |
|||
} |
|||
if (m_frame_filter_index < FRAME_FILTER_INDEX_NUM) { |
|||
m_frame_filter_index++; |
|||
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]); |
|||
|
|||
m_lodstate0 = ads1293_read_error_lod(&m_ads1293_0); |
|||
m_lodstate1 = ads1293_read_error_lod(&m_ads1293_1); |
|||
|
|||
if (!m_drop_state_triggered) { |
|||
if (m_lodstate0 || m_lodstate1) { |
|||
m_drop_state_triggered = true; |
|||
prvf_trigger_sensor_drop_event(m_lodstate0, m_lodstate1); |
|||
} |
|||
} else { |
|||
if (!(m_lodstate0 || m_lodstate1)) { |
|||
m_drop_state_triggered = false; |
|||
} |
|||
} |
|||
|
|||
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 缓存数据,并触发数据块事件 |
|||
*/ |
|||
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]); |
|||
} |
|||
|
|||
/** |
|||
* @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(); |
|||
} |
|||
} |
|||
|
|||
static void ads1293_uninit() { |
|||
hwss_stop_capture(); |
|||
m_ads1293_driver_is_inited = false; |
|||
nrf_drv_spi_uninit(&spi); |
|||
} |
|||
|
|||
void hwss_init(void) { |
|||
/** |
|||
* @brief 初始化定时器 |
|||
*/ |
|||
nrfx_err_t err; |
|||
nrfx_timer_config_t timer_cfg = { |
|||
.frequency = NRF_TIMER_FREQ_250kHz, |
|||
.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); |
|||
} |
|||
|
|||
ZASSERT(SAMPLE_RATE == 400); |
|||
uint32_t timer_ticks = nrfx_timer_ms_to_ticks(&m_timer, 5); // 200HZ |
|||
ZLOGI("timer_ticks:%d\n", timer_ticks); |
|||
ZASSERT(timer_ticks % 2 == 0); // |
|||
timer_ticks = timer_ticks / 2; // 400HZ |
|||
nrfx_timer_extended_compare(&m_timer, NRF_TIMER_CC_CHANNEL0, timer_ticks, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, true); |
|||
} |
|||
|
|||
void hwss_load(void) { ads1293_init(); } |
|||
void hwss_unload(void) { |
|||
nrfx_timer_disable(&m_timer); |
|||
ads1293_uninit(); |
|||
} |
|||
|
|||
void hwss_start_capture(void) { |
|||
m_drop_state_triggered = false; |
|||
m_work_flag = true; |
|||
m_frame_index = 0; |
|||
m_frame_filter_index = 0; |
|||
prvf_light_block_cache_clear(); |
|||
ads1293_start_conversion(&m_ads1293_0); |
|||
ads1293_start_conversion(&m_ads1293_1); |
|||
nrfx_timer_enable(&m_timer); |
|||
} |
|||
void hwss_stop_capture(void) { |
|||
nrfx_timer_disable(&m_timer); |
|||
m_work_flag = false; |
|||
m_frame_index = 0; |
|||
m_frame_filter_index = 0; |
|||
prvf_light_block_cache_clear(); |
|||
ads1293_stop_conversion(&m_ads1293_0); |
|||
ads1293_stop_conversion(&m_ads1293_1); |
|||
} |
|||
|
|||
bool hwss_is_capturing(void) { return m_work_flag; } |
|||
|
|||
uint8_t hwss_get_drop_state0() { return m_lodstate0; } |
|||
uint8_t hwss_get_drop_state1() { return m_lodstate1; } |
@ -0,0 +1,35 @@ |
|||
/** |
|||
* @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 "app_event.h" |
|||
#include "board/board.h" |
|||
|
|||
/** |
|||
* @brief ³õʼ»¯ |
|||
*/ |
|||
void hwss_init(void); |
|||
|
|||
void hwss_load(void); |
|||
void hwss_unload(void); |
|||
|
|||
/** |
|||
* @brief ¿ªÊ¼²É¼¯ |
|||
*/ |
|||
void hwss_start_capture(void); |
|||
/** |
|||
* @brief Í£Ö¹²É¼¯ |
|||
*/ |
|||
void hwss_stop_capture(void); |
|||
|
|||
bool hwss_is_capturing(void); |
|||
|
|||
uint8_t hwss_get_drop_state0(); |
|||
uint8_t hwss_get_drop_state1(); |
@ -0,0 +1,43 @@ |
|||
#if 1 |
|||
#include "znordic.h" |
|||
// |
|||
#include <stdarg.h> |
|||
#include <stdio.h> |
|||
#include <stdlib.h> |
|||
#include <string.h> |
|||
// |
|||
#include "app_ble_service.h" |
|||
#include "app_event_distribute.h" |
|||
#include "basic/ads1293/ads1293.h" |
|||
#include "board/board.h" |
|||
#include "device_ctrl_service.h" |
|||
#include "zble_module.h" |
|||
#include "zdatachannel_service.h" |
|||
#include "znordic_device_info_mgr.h" |
|||
// |
|||
|
|||
int main() { |
|||
APP_SCHED_INIT(APP_MAX_EVEN_SIZE, APP_EVENT_QUEUE_SIZE); |
|||
znordic_init(); |
|||
NRF_LOG_INFO("compile time :%s", __TIME__); |
|||
ZLOGI("CUSTOMER :%d", NRF_UICR->CUSTOMER[0]); |
|||
/******************************************************************************* |
|||
* 蓝牙服务初始化 * |
|||
*******************************************************************************/ |
|||
static zble_module_cfg_t cfg; |
|||
cfg.deviceName = device_info_read_sn_str(); |
|||
cfg.on_service_init = AppBleService_onServiceInitCB; |
|||
zble_module_init(&cfg); |
|||
AppBleService_init(); |
|||
/******************************************************************************* |
|||
* 设备控制服务初始化 * |
|||
*******************************************************************************/ |
|||
DeviceCtrl_init(); |
|||
/******************************************************************************* |
|||
* LOOP * |
|||
*******************************************************************************/ |
|||
znordic_loop(); |
|||
} |
|||
#else |
|||
#include "ads1293_simple_tester.c" |
|||
#endif |
@ -0,0 +1,171 @@ |
|||
#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; |
|||
memcpy(m_sample_fileinfo_list.fileinfo[0]->filename, &_filename, sizeof(sample_data_filename_t)); |
|||
m_sample_fileinfo_list.fileinfo[0]->size = fno.fsize; |
|||
m_sample_fileinfo_list.count = 1; |
|||
|
|||
ZLOGI("filelist:"); |
|||
ZLOGI(" name:%s", "0.bin"); |
|||
ZLOGI(" size:%d", fno.fsize); |
|||
|
|||
} else { |
|||
m_sample_fileinfo_list.fileinfo[0]->size = 0; |
|||
m_sample_fileinfo_list.count = 0; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* @brief 文件驱动管理 |
|||
*/ |
|||
void SampleDataMgr_init() { |
|||
Board_sdcardInit(); |
|||
// 先连接到单片机,读取下文件状态信息 |
|||
SampleDataMgr_changeToLocalMode(); |
|||
SampleDataMgr_changeToExtMode(); |
|||
} |
|||
void SampleDataMgr_loadDriver() { |
|||
// donothing |
|||
} |
|||
void SampleDataMgr_unloadDriver() { |
|||
// donothin |
|||
} |
|||
typedef struct { |
|||
uint8_t filename[8]; |
|||
uint32_t filesize; |
|||
|
|||
} disk_state_t; |
|||
|
|||
/** |
|||
* @brief 存储器连接单片机 |
|||
*/ |
|||
void SampleDataMgr_changeToLocalMode() { |
|||
ZLOGI("change to local mode"); |
|||
Board_sdcardConnectToInternal(); |
|||
read_file_info(); |
|||
} |
|||
/** |
|||
* @brief 存储器连接外部typec |
|||
*/ |
|||
void SampleDataMgr_changeToExtMode() { |
|||
ZLOGI("change to ext mode"); |
|||
if (Board_sdcardGetConnectTo() == kConnectToInternal) { |
|||
read_file_info(); |
|||
} |
|||
Board_sdcardConnectToExt(); |
|||
} |
|||
|
|||
/** |
|||
* @brief 打开文件 |
|||
* |
|||
* @param filename |
|||
* @param flag |
|||
* @return int32_t |
|||
*/ |
|||
|
|||
static FIL m_default_file_handler; |
|||
static bool m_is_open; |
|||
|
|||
int32_t SampleDataMgr_open(sample_data_filename_t* filename, wrflag_t flag) { |
|||
if (flag == kwrflag_write_only) { |
|||
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; |
|||
} else { |
|||
FRESULT ff_result = f_open(&m_default_file_handler, (const TCHAR*)"0.bin", FA_READ); |
|||
if (ff_result != FR_OK) { |
|||
return -1; |
|||
} |
|||
m_is_open = true; |
|||
return 1; |
|||
} |
|||
} |
|||
int32_t SampleDataMgr_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 SampleDataMgr_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 SampleDataMgr_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; |
|||
} |
|||
uint32_t SampleDataMgr_getFileSizeByFd(int32_t fd) { |
|||
ZASSERT(m_is_open); |
|||
return f_size(&m_default_file_handler); |
|||
} |
|||
|
|||
int32_t SampleDataMgr_deleteFile(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* SampleDataMgr_getFileinfoList() { // |
|||
return &m_sample_fileinfo_list; |
|||
} |
|||
bool SampleDataMgr_storageIsFull() { return m_sample_fileinfo_list.count >= FILE_MAX_COUNT; } |
|||
int32_t SampleDataMgr_getFileNum() { return m_sample_fileinfo_list.count; } |
@ -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 <stdbool.h> |
|||
#include <stdint.h> |
|||
|
|||
#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 SampleDataMgr_init(); |
|||
void SampleDataMgr_loadDriver(); |
|||
void SampleDataMgr_unloadDriver(); |
|||
/******************************************************************************* |
|||
* 模式切换操作 * |
|||
*******************************************************************************/ |
|||
|
|||
/** |
|||
* @brief 存储器连接单片机 |
|||
*/ |
|||
void SampleDataMgr_changeToLocalMode(); |
|||
/** |
|||
* @brief 存储器连接外部typec |
|||
*/ |
|||
void SampleDataMgr_changeToExtMode(); |
|||
|
|||
/******************************************************************************* |
|||
* FILE_OPERATION * |
|||
*******************************************************************************/ |
|||
int32_t SampleDataMgr_open(sample_data_filename_t* filename, wrflag_t flag); |
|||
int32_t SampleDataMgr_close(int32_t fd); |
|||
int32_t SampleDataMgr_write(int32_t fd, const uint8_t* data, int32_t size); |
|||
int32_t SampleDataMgr_read(int32_t fd, uint8_t* data, int32_t size); |
|||
uint32_t SampleDataMgr_getFileSizeByFd(int32_t fd); |
|||
|
|||
/******************************************************************************* |
|||
* 文件管理操作 * |
|||
*******************************************************************************/ |
|||
int32_t SampleDataMgr_deleteFile(sample_data_filename_t* filename); |
|||
sample_data_fileinfo_list_t* SampleDataMgr_getFileinfoList(); |
|||
bool SampleDataMgr_storageIsFull(); |
|||
int32_t SampleDataMgr_getFileNum(); |
@ -0,0 +1 @@ |
|||
Subproject commit ae9a76be52669663d773370339d6a0608df4a9d4 |
Write
Preview
Loading…
Cancel
Save
Reference in new issue