zhaohe 1 year ago
parent
commit
15e538f722
  1. 11
      .gitignore
  2. 18
      .gitmodules
  3. 245
      .vscode/c_cpp_properties.json
  4. 114
      .vscode/settings.json
  5. 379
      app/RTE/Device/nRF52833_xxAA/arm_startup_nrf52833.s
  6. 329
      app/RTE/Device/nRF52833_xxAA/system_nrf52.c
  7. 1660
      app/app.uvoptx
  8. 7882
      app/app.uvprojx
  9. 12168
      app/config/sdk_config.h
  10. 369
      app/src/ads1293_simple_tester.c
  11. 537
      app/src/app_ble_service.c
  12. 15
      app/src/app_ble_service.h
  13. 52
      app/src/app_event.h
  14. 23
      app/src/app_event_distribute.c
  15. 15
      app/src/app_event_distribute.h
  16. 129
      app/src/basic/ads1293/ads1293.c
  17. 142
      app/src/basic/ads1293/ads1293.h
  18. 3
      app/src/basic/version.h
  19. 0
      app/src/board/board.c
  20. 72
      app/src/board/board.h
  21. 36
      app/src/board/board_battery_state.c
  22. 14
      app/src/board/board_battery_state.h
  23. 102
      app/src/board/board_beep_ctrl.c
  24. 24
      app/src/board/board_beep_ctrl.h
  25. 34
      app/src/board/board_button.c
  26. 23
      app/src/board/board_button.h
  27. 79
      app/src/board/board_light_ctrl.c
  28. 23
      app/src/board/board_light_ctrl.h
  29. 172
      app/src/board/board_sdcard_driver.c
  30. 19
      app/src/board/board_sdcard_driver.h
  31. 357
      app/src/device_ctrl_service.c
  32. 44
      app/src/device_ctrl_service.h
  33. 455
      app/src/heart_wave_sample_service.c
  34. 35
      app/src/heart_wave_sample_service.h
  35. 43
      app/src/main.c
  36. 171
      app/src/sample_data_manager_service.c
  37. 78
      app/src/sample_data_manager_service.h
  38. 1
      bootloader
  39. 1
      dynamic_electrocardiograph_ble_server
  40. 1
      ify_hrs_protocol
  41. 1
      libznordic
  42. 1
      pemkey
  43. 1
      sdk

11
.gitignore

@ -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

18
.gitmodules

@ -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

245
.vscode/c_cpp_properties.json

@ -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
}

114
.vscode/settings.json

@ -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"
}

379
app/RTE/Device/nRF52833_xxAA/arm_startup_nrf52833.s

@ -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

329
app/RTE/Device/nRF52833_xxAA/system_nrf52.c

@ -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

7882
app/app.uvprojx
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

369
app/src/ads1293_simple_tester.c

@ -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;
}
}
}

537
app/src/app_ble_service.c

@ -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;
}

15
app/src/app_ble_service.h

@ -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();

52
app/src/app_event.h

@ -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);

23
app/src/app_event_distribute.c

@ -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);
}

15
app/src/app_event_distribute.h

@ -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);

129
app/src/basic/ads1293/ads1293.c

@ -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); }

142
app/src/basic/ads1293/ads1293.h

@ -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

3
app/src/basic/version.h

@ -0,0 +1,3 @@
#pragma once
#define VERSION 1
#define MANUFACTURER_NAME "iflytop"

0
app/src/board/board.c

72
app/src/board/board.h

@ -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

36
app/src/board/board_battery_state.c

@ -0,0 +1,36 @@
#include "board_battery_state.h"
void BoardBattery_init() {}
void BoardBattery_load() {
nrf_drv_saadc_config_t adccfg = NRFX_SAADC_DEFAULT_CONFIG;
adccfg.resolution = NRF_SAADC_RESOLUTION_12BIT; // 4096
ZERROR_CHECK(nrf_drv_saadc_init(&adccfg, NULL));
nrf_saadc_channel_config_t channel_config = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(BATTERY_ADC_PIN);
channel_config.acq_time = NRF_SAADC_ACQTIME_20US;
ZERROR_CHECK(nrfx_saadc_channel_init(BATTERY_ADC_CHANNEL, &channel_config));
}
void BoardBattery_unload() { nrf_drv_saadc_uninit(); }
int16_t BoardBattery_get_adc_val() {
int16_t val = znrf_adc_channel_read_val(BATTERY_ADC_CHANNEL);
return val;
}
int16_t BoardBattery_get_battery_level() {
static const float maxv = 4.0;
static const float minv = 3.3;
float voltage = BoardBattery_get_adc_val() / 4096.0 * 3.3 / 2.0 * 3;
if (voltage > maxv) voltage = maxv;
if (voltage < minv) voltage = minv;
float percent = (voltage - minv) / (maxv - minv) * 100 + (float)0.1 /*加0.1是为了避免999.999时显示电量为90*/;
int16_t percent_int = (int16_t)percent;
if (percent_int < 10 && percent_int != 0) {
percent_int = 3;
} else {
percent_int = percent_int / 10 * 10;
}
return percent_int;
}

14
app/src/board/board_battery_state.h

@ -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

102
app/src/board/board_beep_ctrl.c

@ -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);
}
}

24
app/src/board/board_beep_ctrl.h

@ -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);

34
app/src/board/board_button.c

@ -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);
}

23
app/src/board/board_button.h

@ -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(); //

79
app/src/board/board_light_ctrl.c

@ -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;
}

23
app/src/board/board_light_ctrl.h

@ -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);

172
app/src/board/board_sdcard_driver.c

@ -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_PIN0: 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; }

19
app/src/board/board_sdcard_driver.h

@ -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();

357
app/src/device_ctrl_service.c

@ -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

44
app/src/device_ctrl_service.h

@ -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() ;

455
app/src/heart_wave_sample_service.c

@ -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; }

35
app/src/heart_wave_sample_service.h

@ -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();

43
app/src/main.c

@ -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

171
app/src/sample_data_manager_service.c

@ -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; }

78
app/src/sample_data_manager_service.h

@ -0,0 +1,78 @@
/**
* @file sample_data_manager_service.h
* @author zhaohe (h_zhaohe@domain.com)
* @brief
* @version 0.1
* @date 2024-02-01
*
* @copyright Copyright (c) 2024
*
*/
#pragma once
#include <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();

1
bootloader

@ -0,0 +1 @@
Subproject commit 29de383110b3c97b15f62f3b59fd2aa228b5c974

1
dynamic_electrocardiograph_ble_server

@ -0,0 +1 @@
Subproject commit ae9a76be52669663d773370339d6a0608df4a9d4

1
ify_hrs_protocol

@ -0,0 +1 @@
Subproject commit b93a5139c4e230def8bed2ea23675267ca1f4b1c

1
libznordic

@ -0,0 +1 @@
Subproject commit 867c66a76c1c27033173350cce6507bd1b9d4006

1
pemkey

@ -0,0 +1 @@
Subproject commit d9e7fcf86d738efff466a8fc87252c01d0df0832

1
sdk

@ -0,0 +1 @@
Subproject commit 80adec4d07ebd578ef632efb8a4145dce0eb4adb
Loading…
Cancel
Save