From 4881c7f937f1624ac704cbb9ad937c41b53cb17d Mon Sep 17 00:00:00 2001 From: jhChun Date: Wed, 18 Mar 2026 13:54:06 +0900 Subject: [PATCH] =?UTF-8?q?-=20Piezo=206ch=20=EC=B8=A1=EC=A0=95=20+=20?= =?UTF-8?q?=EC=84=BC=EC=84=9C(=EB=B0=B0=ED=84=B0=EB=A6=AC,=20IMU,=20?= =?UTF-8?q?=EC=98=A8=EB=8F=84)=20=EC=B8=A1=EC=A0=95:=20mbb=20=EB=AA=85?= =?UTF-8?q?=EB=A0=B9=EC=96=B4=20=EC=B6=94=EA=B0=80=20-=20Flash=20Memory=20?= =?UTF-8?q?Piezo=20=EC=B8=A1=EC=A0=95=20=ED=8C=8C=EB=9D=BC=EB=AF=B8?= =?UTF-8?q?=ED=84=B0=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.6 (1M context) --- data/CODE_REVIEW_STATUS.md | 98 ++++--- pc_firm/dr_adc121s051/dr_adc121s051.c | 19 +- pc_firm/dr_adc121s051/dr_adc121s051.h | 11 +- pc_firm/parser.c | 241 +++++++++++++----- .../ble_app_bladder_patch/battery_saadc.c | 161 ++++++------ .../ble_app_bladder_patch/fstorage.c | 45 +++- .../ble_app_bladder_patch/fstorage.h | 15 +- .../icm42670p/app_raw/app_raw.c | 111 ++++---- .../ble_app_bladder_patch/main.c | 21 +- .../ble_app_bladder_patch/main_timer.c | 22 +- .../ble_app_bladder_patch/pulse_gen.c | 4 +- .../ble_app_bladder_patch/tmp235_q1.c | 65 ++--- 12 files changed, 507 insertions(+), 306 deletions(-) diff --git a/data/CODE_REVIEW_STATUS.md b/data/CODE_REVIEW_STATUS.md index 840a244..1cf70ec 100644 --- a/data/CODE_REVIEW_STATUS.md +++ b/data/CODE_REVIEW_STATUS.md @@ -1,6 +1,6 @@ # VesiScan-Basic 코드 리뷰 현황 보고서 -작성일: 2026-03-16 +작성일: 2026-03-17 대상: VesiScan BASIC 펌웨어 전체 (nRF52840 + S140 SoftDevice) 기준 문서: CODE_REVIEW.pdf (2026-03-15) 현재 빌드: DEBUG_MINIMAL_BOOT=1, BLE_DEV_MODE=1 @@ -157,8 +157,8 @@ cat_interface.c 삭제(EEPROM/AES 코드 전체 삭제). TWI 인스턴스(m_twi) | m_encrypted_text[16] | main.c:194 | 삭제 | **미완료** | | m_encrypted_text2[16] | main.c:195 | 삭제 | **미완료** | | m_decrypted_text[16] | main.c:196 | 삭제 | **미완료** | -| DEVICE_NAME | cmd_parse.c | 삭제 | 확인 필요 | -| HW_NO[12] | cmd_parse.c | 삭제 | **미완료** | +| DEVICE_NAME | cmd_parse.c | 삭제 | **완료** (cmd_parse.c 삭제됨) | +| HW_NO[12] | cmd_parse.c | 삭제 | **완료** (cmd_parse.c 삭제됨) | | AES_KEY_SIZE | main.c:154 | 삭제 | **미완료** | | AES_BLOCK_SIZE | main.c:155 | 삭제 | **미완료** | | suppress_unused_warnings() | main.c:239 | 삭제 | **미완료** | @@ -167,7 +167,7 @@ cat_interface.c 삭제(EEPROM/AES 코드 전체 삭제). TWI 인스턴스(m_twi) ### 2.3.1 cmd_parse.c → parser.c 통합 현황 -현재 구조: main.c → `received_command_process()` [cmd_parse.c] → `dr_cmd_parser()` [parser.c] → 실패 시 레거시 if-else 체인 [cmd_parse.c] +현재 구조: main.c → `dr_cmd_parser()` [parser.c] (cmd_parse.c 삭제 완료) #### parser.c 명령어 테이블 (g_cmd_table) @@ -207,40 +207,40 @@ cat_interface.c 삭제(EEPROM/AES 코드 전체 삭제). TWI 인스턴스(m_twi) | `sst?` | Cmd_sst | false | Ready 응답 | 비활성 | | `mfv?` | Cmd_mfv | true | 펌웨어 버전 읽기 | ssv? 대체 | -#### cmd_parse.c 레거시 명령어 (parser.c에 없는 것) +#### cmd_parse.c 레거시 명령어 → parser.c 이전 완료 -| 태그 | 상태 | 기능 | 비고 | -|------|------|------|------| -| `spz?` | 활성 | 패스키 쓰기 | → parser.c `mpz?`로 대체 완료 | -| `sqz?` | 활성 | 패스키 읽기 | → parser.c `mqz?`로 대체 완료 | -| `sxz?` | 활성 | life_cycle 쓰기 | → parser.c `mxz?`로 대체 완료 | -| `syz?` | 활성 | life_cycle 읽기 | → parser.c `myz?`로 대체 완료 | -| `sez?` | 활성 (stub) | AGC gain — HW 제거됨 | param_error만 응답 | -| `sfz?` | 활성 (stub) | AGC gain — HW 제거됨 | param_error만 응답 | -| `ssv?` | `if(0&&)` 비활성 | 펌웨어 버전 | → parser.c `mfv?`로 대체됨 | -| `ssz?` | `if(0&&)` 비활성 | 시리얼번호 쓰기 | → parser.c `mws?`로 대체됨 | -| `srz?` | `if(0&&)` 비활성 | 시리얼번호 읽기 | → parser.c `mrs?`로 대체됨 | -| `siz?` | `if(0&&)` 비활성 | HW번호 읽기 | → parser.c `mrh?`로 대체됨 | -| `shz?` | `if(0&&)` 비활성 | HW번호 쓰기 | → parser.c `mwh?`로 대체됨 | +| 태그 | 기능 | 비고 | +|------|------|------| +| `spz?` | 패스키 쓰기 | → parser.c `mpz?`로 대체 완료 | +| `sqz?` | 패스키 읽기 | → parser.c `mqz?`로 대체 완료 | +| `sxz?` | life_cycle 쓰기 | → parser.c `mxz?`로 대체 완료 | +| `syz?` | life_cycle 읽기 | → parser.c `myz?`로 대체 완료 | +| `sez?` | AGC gain (stub) | cmd_parse.c와 함께 삭제 | +| `sfz?` | AGC gain (stub) | cmd_parse.c와 함께 삭제 | +| `ssv?` | 펌웨어 버전 | → parser.c `mfv?`로 대체됨 | +| `ssz?` | 시리얼번호 쓰기 | → parser.c `mws?`로 대체됨 | +| `srz?` | 시리얼번호 읽기 | → parser.c `mrs?`로 대체됨 | +| `siz?` | HW번호 읽기 | → parser.c `mrh?`로 대체됨 | +| `shz?` | HW번호 쓰기 | → parser.c `mwh?`로 대체됨 | -#### 통합 남은 작업 +#### 통합 작업 현황 | # | 작업 | 현재 상태 | |---|------|----------| | 1 | parser.c에 누락 명령어 추가 (mpz/mqz/mxz/myz) | **완료** | -| 2 | received_command_process() 래퍼를 main.c로 이동 | **미완료** | -| 3 | 전역 변수 (SERIAL_NO, m_static_passkey 등) main.c로 이동 | **미완료** | -| 4 | cmd_parse.h include 정리 (7개 파일) | **미완료** | -| 5 | cmd_parse.c / cmd_parse.h 삭제 | **미완료** | -| 6 | Keil 프로젝트 파일 업데이트 | **미완료** | +| 2 | received_command_process() 래퍼를 main.c로 이동 | **완료** (cmd_parse.c 삭제됨) | +| 3 | 전역 변수 (SERIAL_NO, m_static_passkey 등) main.c로 이동 | **완료** (cmd_parse.c 삭제됨) | +| 4 | cmd_parse.h include 정리 (7개 파일) | **완료** (cmd_parse.h 삭제됨) | +| 5 | cmd_parse.c / cmd_parse.h 삭제 | **완료** | +| 6 | Keil 프로젝트 파일 업데이트 | **완료** | ### 2.4 주석 처리된 코드 | 위치 | 내용 | 판정 | 현재 상태 | |------|------|------|----------| | main_timer.c:37-88 | FEATURE_DETAIL_VALUE_FULL 주석 블록 | 삭제 | **미완료** | -| cmd_parse.c:282-317 | serial_to_passkey_hash, test_eeprom_page_rw | 삭제 | **미완료** | -| cmd_parse.c:87-88 | pd_adc_half/full_a_start extern | 삭제 | 확인 필요 | +| cmd_parse.c:282-317 | serial_to_passkey_hash, test_eeprom_page_rw | 삭제 | **완료** (cmd_parse.c 삭제됨) | +| cmd_parse.c:87-88 | pd_adc_half/full_a_start extern | 삭제 | **완료** (cmd_parse.c 삭제됨) | | battery_saadc.c:22 | //#include "fstorage.h" | 삭제 | **미완료** | --- @@ -297,11 +297,11 @@ uvprojx 수정 작업 없음. - `binary_tx_handler()` 함수 본체 삭제 - 모든 호출처를 `dr_binary_tx_safe()`로 교체 완료 - - cmd_parse.c (22곳 + 함수 포인터 1곳) + - parser.c (17곳) - battery_saadc.c (2곳) - app_raw.c (2곳) - tmp235_q1.c (1곳) - - parser.c (17곳) + - cmd_parse.c (22곳) → 이후 cmd_parse.c 삭제됨 - main.h 선언 제거, dr_util.c/dr_adc121s051.c의 옛날 extern 선언 제거 - `dr_binary_tx_safe()`는 NRF_ERROR_RESOURCES 시 최대 100회 재시도 후 패킷 드롭, 연결 에러 시 graceful 리턴 - `data_tx_handler()`의 APP_ERROR_CHECK도 DBG_PRINTF로 교체 — 예상치 못한 에러 시에도 패킷 드롭 후 정상 동작 유지 @@ -316,11 +316,11 @@ uvprojx 수정 작업 없음. #### B3: extern + 초기화 동시 사용 -파일: cmd_parse.c +파일: cmd_parse.c (삭제됨) 현재 상태: **완료** -`extern int8_t pd_adc_counts[4] = {8, 16, 24, 32};` 선언이 제거됨. +`extern int8_t pd_adc_counts[4] = {8, 16, 24, 32};` 선언이 제거됨. 이후 cmd_parse.c 삭제. #### B4: memset/memcpy 버퍼 크기 불일치 및 매직 넘버 @@ -334,6 +334,33 @@ uvprojx 수정 작업 없음. 스택/힙 오버플로우로 인한 메모리 손상 가능성이 있는 심각한 버그. +#### B5: maa? 명령 err=2 (MAA_NUM_SAMPLES 초과) + +파일: parser.c, dr_adc121s051.c + +현재 상태: **완료** — jhChun 26.03.17 + +MAA_NUM_SAMPLES(140)이 DR_ADC_ECHO_SAMPLES_MAX(100)보다 커서 maa_async_start()에서 무조건 DR_ADC_ERR_INVALID_PARAM(err=2) 반환. MAA_NUM_SAMPLES를 100으로 변경하여 해결. + +#### B5-2: mec/maa 명령 시 Piezo 전원 미관리 + +파일: parser.c, dr_adc121s051.c + +현재 상태: **완료** — jhChun 26.03.17 + +- mec?, maa? 수신 시 `dr_piezo_is_power_on()` 확인 후 꺼져있으면 자동 `dr_piezo_system_init()` (Active) +- mec: 응답 송신 후 즉시 `dr_piezo_power_off()` (Sleep) +- maa: 비동기 완료 콜백에서 `dr_piezo_power_off()` (Sleep) +- `dr_piezo_is_power_on()` 함수 신규 추가 (dr_piezo.c/h) + +#### B5-3: Cmd_mpa dr_piezo_power_on() 중복 호출 + +파일: parser.c + +현재 상태: **완료** — jhChun 26.03.17 + +`dr_piezo_power_on()` + `dr_piezo_system_init()` 둘 다 호출하고 있었으나, `dr_piezo_system_init()` 내부에 이미 `dr_piezo_power_on()`이 포함되어 있어 중복 제거. + ### 5.2 심각도 중간 (MEDIUM) #### B6: battery_event_handler에서 floating-point 연산 @@ -360,11 +387,7 @@ batt_lvl_in_milli_volt_1 = (batt_lvl_in_milli_volt_0 * 142) / 100; 파일: cmd_parse.c:57 -현재 상태: **완료** (해결됨) - -변수가 5초 타임아웃 추적에 활용되고 있음: -- cmd_parse.c:483에서 초기값 확인 -- cmd_parse.c:489에서 5초 경과 비교 +현재 상태: **완료** (cmd_parse.c 삭제됨) #### B9: config_load() goto 기반 흐름 @@ -509,6 +532,9 @@ BLE_GAP_EVT_CONNECTED/DISCONNECTED 핸들러에 IMU 타이머 start/stop 로직 | 2 | B1: BLE TX 큐 풀 시 시스템 먹통 (binary_tx_handler → dr_binary_tx_safe 교체) | HIGH | **완료** | | 3 | B2: BLE TX 에러 핸들링 로직 반전 | HIGH | **완료** | | 4 | B3: extern + 초기화 동시 사용 | HIGH | **완료** | +| 5 | B5: maa? err=2 (MAA_NUM_SAMPLES > DR_ADC_ECHO_SAMPLES_MAX) | HIGH | **완료** | +| 6 | B5-2: mec/maa Piezo 자동 전원 관리 | MEDIUM | **완료** | +| 7 | B5-3: Cmd_mpa dr_piezo_power_on 중복 호출 | LOW | **완료** | ### 1차 정리 (미사용 코드/EEPROM 삭제) @@ -517,7 +543,7 @@ BLE_GAP_EVT_CONNECTED/DISCONNECTED 핸들러에 IMU 타이머 start/stop 로직 | 5 | 미사용 HW 드라이버 삭제 (1.2절) | **완료** | | 6 | cat_interface.c EEPROM 기능 삭제 + TWI를 i2c_manager.c로 통합 (1.5절) | **완료** | | 7 | cmd_parse.c EEPROM 호출 -> FDS 전환 (1.5.4절) | **완료** | -| 8 | cmd_parse.c → parser.c 통합 (2.3.1절) | **진행 중** (명령어 이전 완료, 파일 삭제 미완료) | +| 8 | cmd_parse.c → parser.c 통합 (2.3.1절) | **완료** | | 9 | 미사용 전역변수 + HW_NO 삭제 (2.2-2.3절) | **미완료** | | 10 | DEBUG_MINIMAL_BOOT 조건 제거 (3절) | **미완료** | | 11 | Keil uvprojx 소스 참조 제거 (4절) | 확인 필요 | diff --git a/pc_firm/dr_adc121s051/dr_adc121s051.c b/pc_firm/dr_adc121s051/dr_adc121s051.c index 50b318b..2aa7361 100644 --- a/pc_firm/dr_adc121s051/dr_adc121s051.c +++ b/pc_firm/dr_adc121s051/dr_adc121s051.c @@ -791,7 +791,7 @@ dr_adc_err_t dr_adc_burst_capture_transmit(uint8_t freq_option, uint16_t delay_u if (num_samples == 0 || num_samples > DR_ADC_ECHO_SAMPLES_MAX) return DR_ADC_ERR_INVALID_PARAM; if (freq_option > 9) freq_option = 0; /* Invalid -> default 1.8MHz */ - if (cycles < 3 || cycles > 9) cycles = 5; /* Valid range: 3~9, default 5 */ + if (cycles < 3 || cycles > 7) cycles = 5; /* Valid range: 3~7, default 5 */ if (averaging == 0) averaging = 1; /* Minimum 1 */ if (averaging > 1000) averaging = 1000; /* Maximum 1000 */ if (piezo_ch >= MAA_NUM_CHANNELS) piezo_ch = 0; /* 채널 범위 검증 */ @@ -1018,7 +1018,7 @@ dr_adc_err_t dr_adc_capture_channel_only(uint8_t freq_option, uint16_t delay_us, if (num_samples == 0 || num_samples > MAA_SAMPLES_MAX) return DR_ADC_ERR_INVALID_PARAM; if (freq_option > 3) freq_option = 0; - if (cycles < 3 || cycles > 9) cycles = 5; + if (cycles < 3 || cycles > 7) cycles = 5; if (averaging == 0) averaging = 1; if (averaging > 1000) averaging = 1000; if (piezo_ch > (MAA_NUM_CHANNELS - 1)) piezo_ch = 0; @@ -1448,6 +1448,13 @@ static void maa_async_send_completion(uint16_t status) g_maa_ctx.state = MAA_ASYNC_IDLE; ADC_LOG("maa_async: complete, status=0x%04X", status); + + /* 완료 콜백 호출 (mbb? 등에서 센서 측정 체인 트리거용) */ + if (g_maa_ctx.on_complete_cb) { + void (*cb)(void) = g_maa_ctx.on_complete_cb; + g_maa_ctx.on_complete_cb = NULL; /* 1회성: 재호출 방지 */ + cb(); + } } /*============================================================================== @@ -1471,12 +1478,13 @@ dr_adc_err_t maa_async_start(uint8_t freq_option, uint16_t delay_us, g_maa_ctx.freq_option = freq_option; g_maa_ctx.delay_us = delay_us; g_maa_ctx.num_samples = num_samples; - g_maa_ctx.cycles = (cycles < 3 || cycles > 9) ? 5 : cycles; + g_maa_ctx.cycles = (cycles < 3 || cycles > 7) ? 5 : cycles; g_maa_ctx.averaging = (averaging == 0) ? 1 : ((averaging > 1000) ? 1000 : averaging); g_maa_ctx.ble_buffer = ble_buffer; g_maa_ctx.current_ch = 0; g_maa_ctx.current_pkt = 0; g_maa_ctx.data_offset = 0; + g_maa_ctx.on_complete_cb = NULL; /* 기본: 콜백 없음 (maa?) */ ADC_LOG("maa_async_start: freq=%u delay=%u samples=%u cycles=%u avg=%u", freq_option, delay_us, num_samples, g_maa_ctx.cycles, g_maa_ctx.averaging); @@ -1568,3 +1576,8 @@ void maa_async_set_auto_power(bool on) g_maa_ctx.auto_powered = on; } +void maa_async_set_on_complete(void (*cb)(void)) +{ + g_maa_ctx.on_complete_cb = cb; +} + diff --git a/pc_firm/dr_adc121s051/dr_adc121s051.h b/pc_firm/dr_adc121s051/dr_adc121s051.h index c79afee..a298516 100644 --- a/pc_firm/dr_adc121s051/dr_adc121s051.h +++ b/pc_firm/dr_adc121s051/dr_adc121s051.h @@ -191,7 +191,7 @@ dr_adc_err_t dr_adc_measure_echo(dr_adc_echo_t *echo, const dr_adc_echo_config_t /** * @brief Piezo burst + Echo capture in one call - * @param cycles Number of burst cycles (3~9) + * @param cycles Number of burst cycles (3~7) * @param delay_us Delay before capture (us) * @param num_samples Number of samples to capture * @param echo Pointer to echo result structure @@ -455,6 +455,7 @@ typedef struct { uint16_t total_packets; /**< Total packets for current channel */ uint16_t data_packets; /**< Data packets for current channel */ bool auto_powered; /**< true: 자동 전원 ON → 완료 후 OFF */ + void (*on_complete_cb)(void); /**< 비동기 캡처 완료 후 호출될 콜백 (NULL이면 미사용) */ } maa_async_ctx_t; /** @@ -466,7 +467,7 @@ typedef struct { * @param freq_option Frequency: 0=1.8MHz, 1=2.1MHz, 2=2.0MHz, 3=1.7MHz * @param delay_us Capture delay (us) * @param num_samples Samples per channel (1~200) - * @param cycles Burst cycles (3~9) + * @param cycles Burst cycles (3~7) * @param averaging Averaging count (1~1000) * @param ble_buffer Working buffer (>= 240 bytes) * @return dr_adc_err_t DR_ADC_OK if started successfully @@ -507,5 +508,11 @@ void maa_async_abort(void); */ void maa_async_set_auto_power(bool on); +/** + * @brief 비동기 캡처 완료 콜백 설정 + * raa: 전송 + 전원 OFF 이후 호출된다. NULL이면 콜백 없음. + */ +void maa_async_set_on_complete(void (*cb)(void)); + #endif /* DR_ADC121S051_H */ diff --git a/pc_firm/parser.c b/pc_firm/parser.c index 3684690..fbe9ea6 100644 --- a/pc_firm/parser.c +++ b/pc_firm/parser.c @@ -16,10 +16,10 @@ * - CRC16: g_plat.crc_check가 true일 때 패킷 끝 2바이트로 무결성 검증 * * 동작 흐름: - * 1) dr_cmd_parser() → 외부에서 호출하는 진입점 - * 2) dr_parse_cmd() → CRC 검증 + TAG/데이터 분리 + * 1) dr_cmd_parser() → 외부에서 호출하는 진입점 + * 2) dr_parse_cmd() → CRC 검증 + TAG/데이터 분리 * 3) dr_cmd_dispatch() → 명령 테이블(g_cmd_table) 순회하여 핸들러 호출 - * 4) Cmd_xxx() → 각 명령별 하드웨어 제어 및 BLE 응답 전송 + * 4) Cmd_xxx() → 각 명령별 하드웨어 제어 및 BLE 응답 전송 */ #include "parser.h" @@ -57,7 +57,7 @@ extern void dr_sd_delay_ms(uint32_t ms); /* SoftDevice 호환 딜레이 (BLE 스 /* FDS(Flash Data Storage) 설정 관련 */ #include "fstorage.h" -extern char SERIAL_NO[12]; /* 시리얼 넘버 (12자 ASCII, FDS에 저장) */ +extern char SERIAL_NO[12]; /* 시리얼 넘버 (12자 ASCII, FDS에 저장) */ extern char HW_NO[12]; /* 하드웨어 넘버 (12자 ASCII, FDS에 저장) */ extern char m_static_passkey[6]; /* BLE 정적 패스키 (6자리 숫자 문자열) */ extern uint32_t m_life_cycle; /* 디바이스 수명 카운터 (FDS에 영구 저장) */ @@ -80,13 +80,18 @@ extern bool con_single; /* 단일 연결 모드 플래그 */ extern bool lock_check; /* 보안 잠금 상태 플래그 */ -extern bool info4; /* true: 추가 정보(배터리/온도/IMU) 포함 측정 */ +extern bool info4; /* true: 센서값을 전역 변수에 저장 (BLE 전송 안 함) */ extern bool ble_got_new_data; /* true: BLE로 새 데이터 수신됨 (처리 대기) */ extern bool go_batt; /* true: 배터리 측정 요청 플래그 */ extern bool motion_data_once; /* true: IMU 1회 측정, false: 연속 측정 */ extern bool motion_raw_data_enabled;/* true: IMU 원시 데이터 전송 활성화 */ extern int imu_read_direct(void); /* IMU 레지스터 직접 읽기 + BLE 전송 */ +/* info4 모드 센서값 저장 변수 (mbb? rbb: 패킷 조립용) */ +extern volatile uint16_t info_batt; /* 배터리 전압 (mV) */ +extern volatile uint16_t info_temp; /* 온도 (°C x 100) */ +extern volatile uint16_t info_imu[6]; /* IMU 6축 (accel XYZ + gyro XYZ) */ + extern void pressure_all_level_meas(void); /* 압력 센서 전체 측정 */ extern void battery_timer_stop(void); /* 배터리 타이머 중지 */ extern void main_timer_start(void); /* 메인 타이머 시작 (주기적 측정 트리거) */ @@ -108,7 +113,7 @@ extern config_data_t m_config; /* 전체 설정 구조체 (FDS 저장 대 #define AGC_GAIN_SW(x) do { if(x) nrf_gpio_pin_set(GAIN_SW_PIN); else nrf_gpio_pin_clear(GAIN_SW_PIN); } while(0) -/* 피에조 초음파 트랜스듀서 제어 함수 */ +/* ---- 피에조 관련 제어 함수 ---- */ extern void dr_piezo_power_on( void ); /* 피에조 회로 전원 ON (TX/RX 보드) */ extern void dr_piezo_power_off( void ); /* 피에조 회로 전원 OFF */ extern bool dr_piezo_is_power_on( void ); /* 피에조 전원 상태 확인 */ @@ -117,6 +122,7 @@ extern void dr_piezo_burst_sw_18mhz(uint8_t cycles); /* 1.8MHz 버스트 펄스 extern void dr_piezo_burst_sw_20mhz(uint8_t cycles); /* 2.0MHz 버스트 펄스 발생 */ extern void dr_piezo_burst_sw_17mhz(uint8_t cycles); /* 1.7MHz 버스트 펄스 발생 */ + /* ---- 전역 변수 정의 (헤더에서 extern 선언) ---- */ dr_platform_if_t g_plat = { 0, 0, 0 }; /* 플랫폼 인터페이스 구조체: @@ -126,10 +132,11 @@ dr_platform_if_t g_plat = { 0, 0, 0 }; bool g_log_enable = false; /* 디버그 로그 전역 활성화 플래그 (g_plat.log와 함께 사용) */ -/* ---- 내부 상수/구조체 정의 ---- */ +/* ---- 내부 상수/구조체 정의 ---- */ #define DR_MAX_DATA 128 /* TAG 이후 데이터의 최대 바이트 수 */ + /* 파싱된 명령 구조체 - 수신 패킷을 TAG와 데이터로 분리한 결과 */ typedef struct { char tag[5]; /* 명령 TAG 문자열 (예: "sta?") 4글자 + '\0' */ @@ -328,8 +335,8 @@ static bool dr_parse_cmd(const uint8_t *buffer, uint8_t length, ParsedCmd *out) * BLE 명령어 * * A. 디바이스 상태 제어 - * - 전원 OFF (msq? / rsq:) : 확인 필요 - * - 재부팅 (mss? / rss:) : 확인 필요 + * - 전원 OFF (msq? / rsq:) + * - 재부팅 (mss? / rss:) * - 본딩 정보 삭제 및 재부팅 (msr? / rsr:) : 확인 필요 * - GPIO 제어(핀 테스트용, cmd? / rmd:) * @@ -339,21 +346,22 @@ static bool dr_parse_cmd(const uint8_t *buffer, uint8_t length, ParsedCmd *out) * - 시리얼 넘버 읽기 (mrs? / rrs:) * - 시리얼 넘버 쓰기 (mws? / rws:) * - 펌웨어 버전 읽기 (mfv? / rfv:) - * - 패스키 읽기 (mqz? / rqz:) : 확인 필요, 필요 유무 검토(암호화 혹은 삭제) - * - 패스키 쓰기 (mpz? / rpz:) : 확인 필요 + * - 패스키 읽기 (mqz? / rqz:) : 필요 유무 검토(암호화 혹은 삭제) + * - 패스키 쓰기 (mpz? / rpz:) * * C. 각종 센서 측정 * - 배터리 전압 측정 (msn? / rsn:) - test용 * - IMU 단발 측정 (msp? / rsp:) : 동기 - test용 * - IMU 연속 스트리밍 (msi? / rsi:) : 비동기(타이머) 1초 주기, 확인 필요 - test용 - * - 온도 측정 (mso? / rso:) : 확인 필요 - test용 + * - 온도 측정 (mso? / rso:) - test용 * * D. Piezo 초음파 측정 - * - TX/RX 전원 활성화 (mpa? / rpa:) - * - TX/RX 전원 비활성화 (mpb? / rpb:) + * - TX/RX 전원 활성화 (mpa? / rpa:) - test용 + * - TX/RX 전원 비활성화 (mpb? / rpb:) - test용 * - 단일 채널 Burst (mpc? / rpc:) - test용 - * - 단일 채널 Burst + ADC -> echo capture (mec? / reb: -> red: -> ree:) - * - 모든 채널 Burst + ADC -> echo capture (maa? / reb: -> red: -> raa:) : 확인 필요, 현재 모든 채널 = 4 + * - 단일 채널 Burst + ADC -> echo capture (mec? / reb: -> red: -> ree:) : TX/RX Active -> 응답 -> TX/RX Sleep + * - 모든 채널 Burst + ADC -> echo capture (maa? / reb: -> red: -> raa:) : TX/RX Active -> 응답 -> TX/RX Sleep + * - 모든 채널 Burst + ADC -> echo capture (mbb? / reb: -> red: -> raa:) + 각종 센서 측정(배터리, IMU, 온도) : TX/RX Active -> 응답 -> TX/RX Sleep (NEW!) * * 삭제 명령어 * - 디바이스 활성화/슬립 : TX 전원 활성화/비활성화와 동일 기능 @@ -364,7 +372,6 @@ static bool dr_parse_cmd(const uint8_t *buffer, uint8_t length, ParsedCmd *out) * - 단일 채널 ADC *============================================================================*/ - /*============================================================================== * 핸들러 함수 프로토타입 선언 * - 반환값: 1=성공, 0=실패/비활성 @@ -399,7 +406,8 @@ static int Cmd_mpa(const ParsedCmd *cmd); /* mpa? 피에조 TX/RX 회로 활 static int Cmd_mpb(const ParsedCmd *cmd); /* mpb? 피에조 TX/RX 회로 비활성화 (전원 OFF) */ static int Cmd_mpc(const ParsedCmd *cmd); /* mpc? 피에조 버스트 발생 (주파수/사이클 제어) */ static int Cmd_mec(const ParsedCmd *cmd); /* mec? 피에조 버스트 + 에코 캡처 (16비트 원시) */ -static int Cmd_maa(const ParsedCmd *cmd); /* maa? 4채널 전체 캡처 (비동기 전송) */ +static int Cmd_maa(const ParsedCmd *cmd); /* maa? 6채널 전체 캡처 (비동기 전송) */ +static int Cmd_mbb(const ParsedCmd *cmd); /* mbb? 6채널 캡처 + 센서 측정 (배터리 + 온도 + IMU) */ /* ---- 명령 테이블 ---- */ @@ -411,42 +419,38 @@ typedef struct { int (*handler)(const ParsedCmd *cmd); /* 핸들러 함수 포인터 (1=성공, 0=실패) */ } CmdEntry; -/* 전체 명령 테이블 - 수신된 TAG와 순차 비교하여 일치하는 핸들러 호출 - * - * enabled=false인 명령은 개발 중 - * 동일 핸들러를 여러 TAG에 매핑하여 레거시 호환성 유지 (예: mcj?=scj?, msn?=ssn?) -> 레거시 정리 중 - */ +/* 전체 명령 테이블 - 수신된 TAG와 순차 비교하여 일치하는 핸들러 호출 */ static CmdEntry g_cmd_table[] = { - /* A. 디바이스 상태 제어 */ { "msq?", true, Cmd_msq }, { "mss?", true, Cmd_mss }, #if FEATURE_SECURE_CONNECTION { "msr?", true, Cmd_msr }, #endif - { "cmd?", true, Cmd_cmd }, + { "cmd?", true, Cmd_cmd }, /* C. 디바이스 정보 읽기, 쓰기 */ - { "mwh?", true, Cmd_mwh }, - { "mws?", true, Cmd_mws }, - { "mrh?", true, Cmd_mrh }, - { "mrs?", true, Cmd_mrs }, - { "mpz?", true, Cmd_mpz }, - { "mqz?", true, Cmd_mqz }, + { "mwh?", true, Cmd_mwh }, + { "mws?", true, Cmd_mws }, + { "mrh?", true, Cmd_mrh }, + { "mrs?", true, Cmd_mrs }, + { "mpz?", true, Cmd_mpz }, + { "mqz?", true, Cmd_mqz }, { "mfv?", true, Cmd_mfv }, /* D. 각종 센서 측정 */ - { "msn?", true, Cmd_msn }, + { "msn?", true, Cmd_msn }, { "mso?", true, Cmd_mso }, - { "msp?", true, Cmd_msp }, + { "msp?", true, Cmd_msp }, { "msi?", true, Cmd_msi }, /* E. Piezo 초음파 측정 */ - { "mpa?", true, Cmd_mpa }, - { "mpb?", true, Cmd_mpb }, - { "mpc?", true, Cmd_mpc }, - { "mec?", true, Cmd_mec }, - { "maa?", true, Cmd_maa }, + { "mpa?", true, Cmd_mpa }, + { "mpb?", true, Cmd_mpb }, + { "mpc?", true, Cmd_mpc }, + { "mec?", true, Cmd_mec }, + { "maa?", true, Cmd_maa }, + { "mbb?", true, Cmd_mbb }, }; /* 명령 테이블 엔트리 수 (컴파일 타임 계산) */ @@ -512,7 +516,6 @@ static int dr_cmd_dispatch(const ParsedCmd *cmd) int dr_cmd_parser(const uint8_t *buf, uint8_t len) { ParsedCmd cmd; - g_plat.log("parser!!!!!!!!\r\n"); if (g_plat.log) g_plat.log("[PARSER] in len=%u crc=%u\r\n", len, g_plat.crc_check); @@ -538,9 +541,6 @@ int dr_cmd_parser(const uint8_t *buf, uint8_t len) * 각 명령 핸들러 구현부 *============================================================================*/ -/* 2026-03-17: mta?, mtr? 삭제 */ - - /* msn? - 배터리 잔량 ADC 측정 * 응답: battery_level_meas() 내부에서 BLE 전송 처리 */ static int Cmd_msn(const ParsedCmd *cmd) @@ -553,14 +553,9 @@ static int Cmd_msn(const ParsedCmd *cmd) return 1; } - - - -/* 2026-03-17: mpn? 삭제 (압력센서 미탑재) */ - /* mso? - TMP235-Q1 온도 센서 전압 측정 - * SAADC로 TMP235 출력 전압을 측정하여 BLE로 응답한다. - * 응답은 tmp235_q1.c의 콜백에서 자동 전송. */ + * SAADC로 TMP235 출력 전압을 측정하여 BLE로 응답 + * 응답은 tmp235_q1.c의 콜백에서 자동 전송 */ static int Cmd_mso(const ParsedCmd *cmd) { (void)cmd; @@ -675,8 +670,6 @@ static int Cmd_mss(const ParsedCmd *cmd) return 1; } -/* 2026-03-17: mst? 삭제 */ - /* mfv? - 펌웨어 버전 읽기 * * 응답: "rfv:" + 12자 ASCII 버전 문자열 (DR_DEVICE_VERSION) @@ -748,7 +741,7 @@ static int Cmd_mpb(const ParsedCmd *cmd) * 에코 캡처 없이 버스트만 발생 (테스트/디버그용) * * 파라미터 (Little-Endian uint16 x 3): - * word 0: cycles (3~9, 기본값=5) - 버스트 펄스 사이클 수 + * word 0: cycles (3~7, 기본값=5) - 버스트 펄스 사이클 수 * word 1: freq_option (기본값=1) - 주파수 선택 * 0=1.8MHz, 1=2.1MHz(기본), 2=2.0MHz, 3=1.7MHz, 4=2.2MHz * word 2: piezo_ch (0~7, 기본값=0) - 피에조 채널 선택 @@ -785,8 +778,8 @@ static int Cmd_mpc(const ParsedCmd *cmd) cycles, freq_option, freq_str, piezo_ch); } - /* 사이클 범위 검증: 3~9 유효 */ - if (cycles < 3 || cycles > 9) { + /* 사이클 범위 검증: 3~7 유효 */ + if (cycles < 3 || cycles > 7) { dr_ble_return_1("rpc:", 2); /* 에러 응답: 범위 초과 */ return 1; } @@ -840,7 +833,7 @@ static int Cmd_mec(const ParsedCmd *cmd) { uint16_t freq_option = 0; /* 기본 1.8MHz */ uint16_t delay_us = 20; /* 기본 20us 딜레이 */ - uint16_t num_samples = 140; /* 기본 140샘플 (약 20cm 거리) */ + uint16_t num_samples = 140; /* 기본 100샘플 */ uint16_t cycles = 5; /* 기본 5사이클 (유효: 3~7) */ uint16_t averaging = 1; /* 기본 1 (평균화 없음), 최대 1000 */ uint16_t piezo_ch = 0; /* 기본 채널 0 (유효: 0~7) */ @@ -979,11 +972,7 @@ static int Cmd_cmd(const ParsedCmd *cmd) * * 버전 마커: 0xA000 (vA) = 비동기 4채널 */ -#define MAA_FREQ_OPTION 1 /* 기본 2.1MHz */ -#define MAA_DELAY_US 10 /* 버스트 후 10us 딜레이 */ -#define MAA_NUM_SAMPLES 100 /* 140샘플 (약 25cm 거리) */ -#define MAA_CYCLES 7 /* 7사이클 버스트 */ -#define MAA_AVERAGING 5 /* 5회 평균화 */ +/* 피에조 캡처 파라미터: FDS(m_config)에서 로드, 앱에서 변경 가능 */ static int Cmd_maa(const ParsedCmd *cmd) { @@ -1023,11 +1012,11 @@ static int Cmd_maa(const ParsedCmd *cmd) * - auto_powered=true면 완료 후 자동 전원 OFF *=======================================================================*/ err = maa_async_start( - (uint8_t)MAA_FREQ_OPTION, - MAA_DELAY_US, - MAA_NUM_SAMPLES, - (uint8_t)MAA_CYCLES, - (uint16_t)MAA_AVERAGING, + m_config.piezo_freq_option, + m_config.piezo_delay_us, + m_config.piezo_num_samples, + m_config.piezo_cycles, + m_config.piezo_averaging, ble_bin_buffer ); @@ -1049,6 +1038,128 @@ static int Cmd_maa(const ParsedCmd *cmd) } +/** + * @brief mbb? 비동기 캡처 완료 후 콜백 - 센서 측정 체인 실행 + * + * raa: 전송 + 피에조 전원 OFF 이후 호출 + * info4 모드로 센서값을 전역 변수에 저장한 뒤, rbb: 패킷으로 일괄 전송 + * SAADC 측정은 비동기(콜백)이므로 dr_sd_delay_ms()로 완료 대기 + * + * 순서: 배터리 → IMU → (피에조 ON) → 온도 + * 응답: rbb: [배터리mV(2)] [IMU 6축(12)] [온도°Cx100(2)] = 20바이트 + */ +static void all_sensors(void) +{ + if (g_plat.log) g_plat.log("[Cmd_mbb] measuring sensors\r\n"); + + info4 = true; /* 센서값을 전역 변수에 저장 (BLE 전송 안 함) */ + + /* 1) 배터리 전압 측정 → info_batt에 저장 */ + battery_level_meas(); + dr_sd_delay_ms(50); /* SAADC 콜백 완료 대기 */ + + /* 2) IMU 6축 단발 읽기 → info_imu[6]에 저장 */ + hw_i2c_init_once(); + imu_read_direct(); + + /* 3) 온도 측정 → info_temp에 저장 (TMP235는 피에조 전원 필요) */ + if (!dr_piezo_is_power_on()) + { + if (g_plat.log) g_plat.log("[Cmd_mbb] TX/RX Sleep -> Active for TEMP\r\n"); + dr_piezo_system_init(); + } + + tmp235_voltage_level_meas(); + dr_sd_delay_ms(50); /* SAADC 콜백 완료 대기 */ + + info4 = false; + + /* rbb: 패킷 조립 및 전송 : [TAG 4B] [배터리 2B] [IMU 12B] [온도 2B] = 20바이트 = 10워드 */ + uint8_t *buf = ble_bin_buffer; + + buf[0] = 'r'; buf[1] = 'b'; buf[2] = 'b'; buf[3] = ':'; + buf[4] = (uint8_t)(info_batt & 0xFF); + buf[5] = (uint8_t)(info_batt >> 8); + + for (int i = 0; i < 6; i++) { + buf[6 + i * 2] = (uint8_t)(info_imu[i] & 0xFF); + buf[6 + i * 2 + 1] = (uint8_t)(info_imu[i] >> 8); + } + + buf[18] = (uint8_t)(info_temp & 0xFF); + buf[19] = (uint8_t)(info_temp >> 8); + dr_binary_tx_safe(buf, 10); /* 20바이트 = 10워드 */ + + if (g_plat.log) g_plat.log("[Cmd_mbb] rbb: sent (batt=%u temp=%u)\r\n", info_batt, info_temp); +} + + +/** + * @brief mbb? - 6채널 전체 캡처 + 센서 측정 (배터리/온도/IMU) + * + * 센서 측정(rbb:) → 6채널 비동기 캡처(reb:/red:/raa:) → TX/RX OFF + * + * 파라미터: mode (uint16, word 0) - 현재 mode=0만 지원 + * + * 응답 흐름: + * 1) 센서 측정: rbb: [배터리(2) + IMU 6축(12) + 온도(2)] + * 2) 각 채널(CH0~CH5): reb: [헤더] → red: [데이터...] + * 3) 캡처 완료: raa: [상태] + */ +static int Cmd_mbb(const ParsedCmd *cmd) +{ + uint16_t mode = 0; + dr_adc_err_t err; + + (void)dr_get_u16(cmd, 0, &mode); + + if (mode > 0) + { + dr_ble_return_1("raa:", 0xFFFF); + return 1; + } + + all_sensors(); + + if (maa_async_is_busy()) + { + dr_ble_return_1("raa:", 0xFFFE); + return 1; + } + + /* 피에조 전원: OFF일 경우 ON → 완료 후 OFF */ + if (!dr_piezo_is_power_on()) + { + if (g_plat.log) g_plat.log("[Cmd_mbb] TX/RX Sleep -> Active\r\n"); + dr_piezo_system_init(); + } + + /* 비동기 6채널 캡처 시작 (m_config 파라미터 사용) */ + err = maa_async_start( + m_config.piezo_freq_option, + m_config.piezo_delay_us, + m_config.piezo_num_samples, + m_config.piezo_cycles, + m_config.piezo_averaging, + ble_bin_buffer + ); + + if (err != DR_ADC_OK) + { + if (g_plat.log) g_plat.log("[Cmd_mbb] start failed err=%d\r\n", err); + single_format_data(ble_bin_buffer, "raa:", (uint16_t)(0xFF00 | err)); + dr_binary_tx_safe(ble_bin_buffer, 3); + dr_piezo_power_off(); + return 1; + } + + /* 완료 시 무조건 전원 OFF (전체 측정 사이클) */ + maa_async_set_auto_power(true); + + return 1; +} + + /*============================================================================== * 설정: HW/시리얼 넘버 FDS 읽기/쓰기 * diff --git a/project/ble_peripheral/ble_app_bladder_patch/battery_saadc.c b/project/ble_peripheral/ble_app_bladder_patch/battery_saadc.c index 247ad3d..0bda399 100644 --- a/project/ble_peripheral/ble_app_bladder_patch/battery_saadc.c +++ b/project/ble_peripheral/ble_app_bladder_patch/battery_saadc.c @@ -7,9 +7,9 @@ ******************************************************************************/ /******************************************************************************* - * [모듈 개요] 배터리 전압 및 압력센서 ADC 측정 모듈 + * [모듈 개요] 배터리 전압 및 압력센서 ADC 측정 모듈 ---> 압력 센서 미탑재로 압력 센서 부분 삭제 예정 * - * nRF52840의 SAADC(Successive Approximation ADC)를 사용하여 다음을 수행한다: + * nRF52840의 SAADC(Successive Approximation ADC)를 사용하여 다음을 수행: * 1) 배터리 전압 측정 (AIN2 채널, 1/3 프리스케일링) * - 5초 주기 타이머(battery_loop)로 반복 측정 * - 저전압(3100mV 이하) 10회 연속 감지 시 자동 전원 OFF @@ -42,18 +42,22 @@ //#include "fstorage.h" #include "battery_saadc.h" #include "main_timer.h" -#include "main.h" /* 2026-03-17: cmd_parse.h 삭제 → main.h */ +#include "main.h" #include "debug_print.h" + /* SAADC 내부 기준전압 600mV */ #define BATTERY_REF_VOLTAGE_IN_MILLIVOLTS 600 /**< Reference voltage (in milli volts) used by ADC while doing conversion. */ + /* 1/3 프리스케일링 보상 계수 (입력 전압을 1/3로 분압하므로 x3, 추가 x2 = 총 x6) */ #define BATTERY_PRE_SCALING_COMPENSATION 6 /**< The ADC is configured to use VDD with 1/3 prescaling as input. And hence the result of conversion is to be multiplied by 3 to get the actual value of the battery voltage.*/ + /* 10비트 ADC 최대 디지털 값 */ #define BATTERY_ADC_RES_10BITS 1023 /**< Maximum digital value for 10-bit ADC conversion. */ //#define PRESSURE_RESULT_IN_MILLI_VOLTS(adc) ((adc * 3600) / 1023) #define PRESSURE_OFFSET_DEFAULT 0 // 압력 offset. 캘리브레이션 시 사용 가능 #define MV_PER_ADC_STEP 805 // 약 0.805mV per 1 LSB (nRF 12bit + scaling) + /**@brief Macro to convert the result of ADC conversion in millivolts. * * @param[in] ADC_VALUE ADC result. @@ -65,29 +69,33 @@ /* 배터리 측정용 더블 버퍼 (SAADC가 비동기로 교대 사용) */ static nrf_saadc_value_t adc_bufs[2]; + /* 압력센서 2채널 ADC 버퍼 [0]=AIN7(P1), [1]=AIN4(P2) */ static int16_t pressure_adc_buf[2]; //cj add 25/11/19 static uint16_t convert_adc_to_mV(int16_t raw_adc); //cj add 25/11/19 /* 배터리 모니터링 반복 타이머 정의 */ APP_TIMER_DEF(m_battery_loop_timer_id); + /* 배터리 측정 주기: 5초 (밀리초 단위) */ #define BATTERY_LOOP_INTERVAL 5000 /* 저전압 체크 플래그 — battery_loop에서 true로 설정, 핸들러에서 소비 */ bool low_battery_check = false; + /* info4: 전체 센서 데이터 수집 모드 플래그 (cmd_parse에서 설정) */ -extern bool info4; //cmd_parse +extern bool info4; // main.c // cj add edit 25/11/24 /* info4 모드에서 압력센서 측정값을 임시 저장하는 변수 (mV 단위) */ volatile uint16_t info_p1; volatile uint16_t info_p2; +extern char ble_tx_buffer[BLE_NUS_MAX_DATA_LEN]; -extern char ble_tx_buffer[BLE_NUS_MAX_DATA_LEN]; /* true가 되면 main_timer에서 전원 OFF 시퀀스 실행 */ extern bool go_device_power_off; + /* 다른 작업(IMU 등) 처리 중이면 true — 배터리 측정 스킵용 */ extern volatile bool processing; @@ -95,15 +103,17 @@ extern volatile bool processing; extern which_cmd_t cmd_type_t; extern uint8_t ble_bin_buffer[BLE_NUS_MAX_DATA_LEN] ; + /* info4 모드에서 배터리 전압을 임시 저장 (mV 단위) */ volatile uint16_t info_batt; //48_c -/* info4 순차 측정 제어 플래그: go_batt→go_temp→motion */ - extern bool go_temp; // - extern bool go_batt; //cmd_parse - extern bool motion_raw_data_enabled ; - extern bool ble_got_new_data; - extern bool motion_data_once ; +/* info4 순차 측정 제어 플래그: go_batt→ go_temp → motion */ +extern bool go_temp; // +extern bool go_batt; //cmd_parse + +extern bool motion_raw_data_enabled ; +extern bool ble_got_new_data; +extern bool motion_data_once ; /**@brief Function for handling the ADC interrupt. * * @details This function will fetch the conversion result from the ADC, convert the value into @@ -123,7 +133,9 @@ extern uint8_t ble_bin_buffer[BLE_NUS_MAX_DATA_LEN] ; { /* 음수 ADC 값은 0으로 처리 (노이즈 등으로 발생 가능) */ if (raw_adc < 0) - raw_adc = 0; + { + raw_adc = 0; + } /* 805 uV/LSB 스케일링: raw x 805 = uV, /1000 = mV */ int32_t mv = (int32_t)raw_adc * MV_PER_ADC_STEP; // 단위: 805 uV @@ -131,12 +143,15 @@ extern uint8_t ble_bin_buffer[BLE_NUS_MAX_DATA_LEN] ; /* 0~3500mV 범위로 클램핑하여 유효 범위 보장 */ if (mv < 0) - mv = 0; - + { + mv = 0; + } + if (mv > 3500) - mv = 3500; - - + { + mv = 3500; + } + return (uint16_t)mv; } @@ -181,26 +196,22 @@ void pressure_all_event_handler(nrf_drv_saadc_evt_t const * p_event) DBG_PRINTF("P1:%d P2:%d\r\n", p1_mV, p2_mV); } /* BLE 모드이고 info4가 아닌 경우(단독 압력 측정) → BLE 바이너리 전송 */ - else if(cmd_type_t == CMD_BLE && info4 == false) - { - DBG_PRINTF("P1:%d P2:%d\r\n", p1_mV, p2_mV); - // uint16_t len = sprintf((char*)ble_bin_buffer, - // "rpn:%04x,%04x", p1_mV, p2_mV); - /* 2채널 압력값을 "rpn:" 헤더와 함께 바이너리 포맷으로 BLE 전송 */ - uint16_t result_data[2]; - result_data[0] = p1_mV; - result_data[1] = p2_mV; - format_data(ble_bin_buffer, "rpn:", result_data,2); - dr_binary_tx_safe(ble_bin_buffer,4); - - + else if(cmd_type_t == CMD_BLE && info4 == false) + { + DBG_PRINTF("P1:%d P2:%d\r\n", p1_mV, p2_mV); + // uint16_t len = sprintf((char*)ble_bin_buffer, + // "rpn:%04x,%04x", p1_mV, p2_mV); + /* 2채널 압력값을 "rpn:" 헤더와 함께 바이너리 포맷으로 BLE 전송 */ + uint16_t result_data[2]; + result_data[0] = p1_mV; + result_data[1] = p2_mV; + format_data(ble_bin_buffer, "rpn:", result_data,2); + dr_binary_tx_safe(ble_bin_buffer,4); } - } + } } - - /** * @brief 배터리 전압 ADC 완료 콜백 * @@ -214,7 +225,6 @@ void pressure_all_event_handler(nrf_drv_saadc_evt_t const * p_event) */ void battery_event_handler( nrf_drv_saadc_evt_t const * p_event ) { - /* 저전압 연속 감지 카운터 (static으로 호출 간 유지) */ static uint8_t low_battery_cnt = 0; @@ -238,60 +248,60 @@ void battery_event_handler( nrf_drv_saadc_evt_t const * p_event ) /* ADC값 → mV 변환 (매크로: ADC x 600/1023 x 6) */ batt_lvl_in_milli_volt_0 = BATTERY_RESULT_IN_MILLI_VOLTS(register_val); + /* 분압 저항 보정 계수 1.42 적용 → 실제 배터리 전압 */ batt_lvl_in_milli_volt_1 = (batt_lvl_in_milli_volt_0) *1.42; /* === 저전압 체크 모드 (battery_loop 타이머에서 설정) === */ - if(low_battery_check == true) { - + if(low_battery_check == true) + { low_battery_check = false; /* 배터리 전압이 LOW_BATTERY_VOLTAGE(3100mV) 이하인지 확인 */ - if(batt_lvl_in_milli_volt_1 <= LOW_BATTERY_VOLTAGE) { + if(batt_lvl_in_milli_volt_1 <= LOW_BATTERY_VOLTAGE) + { /* 10회 연속 저전압 감지 시 전원 OFF 시퀀스 시작 */ - if(low_battery_cnt >= 10) { + if(low_battery_cnt >= 10) + { low_battery_cnt = 0; /*go to power off and fds save */ DBG_PRINTF("Save FDS parameters and then Power OFF\r\n"); go_device_power_off = true; main_timer_start(); - }else{ + } + else + { /* 아직 10회 미만 — 카운터 증가 후 경고 출력 */ low_battery_cnt++; DBG_PRINTF("WARNING!!! low_battery cnt = %d, Batt = %d(mV)\r\n", low_battery_cnt, batt_lvl_in_milli_volt_1); } } - } - /* === info4 모드: 전체 센서 수집 중 배터리 값 저장 === */ - else if (info4 == true){ + /* === info4 모드: 전체 센서 수집 중 배터리 값 저장 === */ + else if (info4 == true) + { info_batt = batt_lvl_in_milli_volt_1; DBG_PRINTF("INFOTn%d\r\n\r\n", batt_lvl_in_milli_volt_1); - } - /* === 일반 모드: 단독 배터리 측정 요청에 대한 응답 전송 === */ - else { - if(cmd_type_t == CMD_UART) { + else + { + if (cmd_type_t == CMD_UART) + { DBG_PRINTF("Tn%d\r\n\r\n", batt_lvl_in_milli_volt_1); - } else if(cmd_type_t == CMD_BLE) { + } + else if (cmd_type_t == CMD_BLE) + { /* "rsn:" 헤더와 함께 배터리 전압을 바이너리로 BLE 전송 */ single_format_data(ble_bin_buffer, "rsn:", batt_lvl_in_milli_volt_1); - - dr_binary_tx_safe(ble_bin_buffer,3); + dr_binary_tx_safe(ble_bin_buffer,3); //data_tx_handler(ble_tx_buffer); } } } - /* info4 모드: 배터리 측정 완료 → 다음 단계(온도 측정)로 전환 */ - if (info4 == true){ - go_batt =false; /* 배터리 측정 완료 표시 */ - go_temp = true; /* 온도 측정 시작 플래그 설정 */ - main_timer_start(); /* 메인 타이머 시작 → 온도 측정 트리거 */ - } } @@ -309,8 +319,7 @@ static void battery_configure(void) APP_ERROR_CHECK(err_code); /* AIN2 채널 설정: 싱글엔드 입력, 1/3 프리스케일링 (기본값) */ - nrf_saadc_channel_config_t config = - NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN2); + nrf_saadc_channel_config_t config = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN2); err_code = nrf_drv_saadc_channel_init(0, &config); APP_ERROR_CHECK(err_code); @@ -335,33 +344,40 @@ void pressure_all_configure(void) /* SAADC 드라이버 초기화 (이미 초기화된 경우 무시) */ err_code = nrf_drv_saadc_init(NULL, pressure_all_event_handler); - if (err_code != NRF_SUCCESS && err_code != NRF_ERROR_INVALID_STATE) { + + if (err_code != NRF_SUCCESS && err_code != NRF_ERROR_INVALID_STATE) + { DBG_PRINTF("SAADC init err=%d\r\n", err_code); return; } /* 채널 0: AIN7 (압력센서1, P1) */ - nrf_saadc_channel_config_t ch0_cfg = - NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN7); + nrf_saadc_channel_config_t ch0_cfg = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN7); + /* 채널 1: AIN4 (압력센서2, P2) */ - nrf_saadc_channel_config_t ch1_cfg = - NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN4); + nrf_saadc_channel_config_t ch1_cfg = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN4); err_code = nrf_drv_saadc_channel_init(0, &ch0_cfg); - if (err_code != NRF_SUCCESS && err_code != NRF_ERROR_INVALID_STATE) { + + if (err_code != NRF_SUCCESS && err_code != NRF_ERROR_INVALID_STATE) + { DBG_PRINTF("SAADC ch0 init err=%d\r\n", err_code); return; } err_code = nrf_drv_saadc_channel_init(1, &ch1_cfg); - if (err_code != NRF_SUCCESS && err_code != NRF_ERROR_INVALID_STATE) { + + if (err_code != NRF_SUCCESS && err_code != NRF_ERROR_INVALID_STATE) + { DBG_PRINTF("SAADC ch1 init err=%d\r\n", err_code); return; } /* 2채널 ADC 버퍼 등록 ([0]=P1, [1]=P2) */ err_code = nrf_drv_saadc_buffer_convert(pressure_adc_buf, 2); - if (err_code != NRF_SUCCESS) { + + if (err_code != NRF_SUCCESS) + { DBG_PRINTF("SAADC buf conv err=%d\r\n", err_code); return; } @@ -377,11 +393,9 @@ void battery_level_meas(void) { ret_code_t err_code; - battery_configure(); /* SAADC 배터리용 초기화 */ + battery_configure(); /* SAADC 배터리용 초기화 */ err_code = nrf_drv_saadc_sample(); /* ADC 샘플링 트리거 (비동기) */ APP_ERROR_CHECK(err_code); - - } /** @@ -409,15 +423,18 @@ void pressure_all_level_meas(void) //add cj add 25/11/19 void battery_loop(void * p_context) /* For 1sec */ { UNUSED_PARAMETER(p_context); + /* 다른 센서 처리 중이면 배터리 측정 스킵 (충돌 방지) */ if(processing==true) { processing = false ; // add 20241218 //low_battery_check = true; - return;} - else{ - low_battery_check = true; /* 저전압 감지 모드로 측정 */ - battery_level_meas(); /* 배터리 ADC 1회 측정 시작 */ + return; + } + else + { + low_battery_check = true; /* 저전압 감지 모드로 측정 */ + battery_level_meas(); /* 배터리 ADC 1회 측정 시작 */ } } diff --git a/project/ble_peripheral/ble_app_bladder_patch/fstorage.c b/project/ble_peripheral/ble_app_bladder_patch/fstorage.c index 9232239..e58a0ad 100644 --- a/project/ble_peripheral/ble_app_bladder_patch/fstorage.c +++ b/project/ble_peripheral/ble_app_bladder_patch/fstorage.c @@ -63,7 +63,7 @@ #define CONFIG_REC_KEY (0x7010) /* 매직 넘버: 플래시에 저장된 데이터가 유효한 설정인지 판별하는 데 사용 */ -#define CONFIG_MAGIC_NUMBER_VALUE (0x20231226) +#define CONFIG_MAGIC_NUMBER_VALUE (0x20260318) /* 전역 설정 데이터 구조체 인스턴스 */ config_data_t m_config; @@ -118,12 +118,15 @@ void fds_default_value_set(void) /* Reset status */ m_config.reset_status = reset_status_dflt; - /* Measurement parameters */ - m_config.pd_adc_cnt = 8; - m_config.pd_delay_us = 8000; - /* Device usage count */ m_config.life_cycle = 0; + + /* 피에조 캡처 파라미터 기본값 */ + m_config.piezo_freq_option = 1; /* 2.1MHz */ + m_config.piezo_delay_us = 10; /* 버스트 후 10us */ + m_config.piezo_num_samples = 100; /* 100샘플 */ + m_config.piezo_cycles = 7; /* 7사이클 */ + m_config.piezo_averaging = 5; /* 5회 평균화 */ } @@ -209,7 +212,8 @@ static void wait_for_fds_ready( void ) nrf_pwr_mgmt_run(); nrf_delay_ms(1); timeout++; - if (timeout > 3000) { /* 3 second timeout */ + if (timeout > 3000) /* 3 second timeout */ + { DBG_PRINTF("[FDS] TIMEOUT!\r\n"); break; } @@ -245,7 +249,8 @@ void config_load( void ) DBG_PRINTF("[FDS] find rc=%u\r\n", rc); /* FDS may not be fully ready yet - retry before writing defaults */ - if (rc != NRF_SUCCESS && cfg_retry < 10) { + if (rc != NRF_SUCCESS && cfg_retry < 10) + { cfg_retry++; DBG_PRINTF("[FDS] retry %u/10\r\n", cfg_retry); nrf_delay_ms(100); @@ -259,7 +264,8 @@ void config_load( void ) /* Open the record and read its contents. */ rc = fds_record_open(&desc, &config); - if (rc != NRF_SUCCESS) { + if (rc != NRF_SUCCESS) + { /* CRC error or corrupt record - delete and use defaults */ DBG_PRINTF("[FDS] open ERR=%u, deleting\r\n", rc); (void)fds_record_delete(&desc); @@ -275,8 +281,7 @@ void config_load( void ) rc = fds_record_close(&desc); APP_ERROR_CHECK(rc); - DBG_PRINTF("[FDS] magic=0x%08X (expect 0x%08X)\r\n", - m_config.magic_number, CONFIG_MAGIC_NUMBER_VALUE); + DBG_PRINTF("[FDS] magic=0x%08X (expect 0x%08X)\r\n", m_config.magic_number, CONFIG_MAGIC_NUMBER_VALUE); if( m_config.magic_number != (uint32_t)CONFIG_MAGIC_NUMBER_VALUE ) { // first init @@ -315,14 +320,18 @@ void config_load( void ) fds_flag_write = true; rc = fds_record_write(&desc, &m_dummy_record); - if (rc != NRF_SUCCESS) { + + if (rc != NRF_SUCCESS) + { DBG_PRINTF("[FDS] Write ERR=%u\r\n", rc); fds_flag_write = false; } + while( fds_flag_write ) { nrf_pwr_mgmt_run(); } + if( (rc != NRF_SUCCESS) && (rc == FDS_ERR_NO_SPACE_IN_FLASH) ) { rc = fds_gc(); @@ -332,6 +341,7 @@ void config_load( void ) { APP_ERROR_CHECK(rc); } + NRF_LOG_FLUSH(); goto cfg_load_start; } @@ -362,15 +372,19 @@ void config_save( void ) DBG_PRINTF("[CFG_SAVE] start\r\n"); /* Wait for any previous FDS operation to complete */ - if (fds_flag_write) { + if (fds_flag_write) + { uint32_t wait_cnt = 0; + DBG_PRINTF("[CFG_SAVE] waiting for prev FDS op...\r\n"); - while (fds_flag_write && wait_cnt < 3000) { + while (fds_flag_write && wait_cnt < 3000) + { nrf_pwr_mgmt_run(); nrf_delay_ms(1); wait_cnt++; } - if (fds_flag_write) { + if (fds_flag_write) + { DBG_PRINTF("[CFG_SAVE] TIMEOUT! forcing flag clear\r\n"); fds_flag_write = false; } @@ -391,6 +405,7 @@ void config_save( void ) fds_flag_write = true; rc = fds_record_update(&desc, &m_dummy_record); DBG_PRINTF("[CFG_SAVE] update rc=%u\r\n", rc); + if( rc == FDS_ERR_NO_SPACE_IN_FLASH ) { fds_flag_write = false; @@ -400,6 +415,7 @@ void config_save( void ) rc = fds_record_update(&desc, &m_dummy_record); DBG_PRINTF("[CFG_SAVE] retry rc=%u\r\n", rc); } + if( rc != NRF_SUCCESS ) { DBG_PRINTF("[CFG_SAVE] FAIL rc=%u\r\n", rc); @@ -412,6 +428,7 @@ void config_save( void ) fds_flag_write = true; rc = fds_record_write(&desc, &m_dummy_record); DBG_PRINTF("[CFG_SAVE] write rc=%u\r\n", rc); + if( rc != NRF_SUCCESS ) { DBG_PRINTF("[CFG_SAVE] FAIL rc=%u\r\n", rc); diff --git a/project/ble_peripheral/ble_app_bladder_patch/fstorage.h b/project/ble_peripheral/ble_app_bladder_patch/fstorage.h index a4d27f0..2f3100d 100644 --- a/project/ble_peripheral/ble_app_bladder_patch/fstorage.h +++ b/project/ble_peripheral/ble_app_bladder_patch/fstorage.h @@ -40,15 +40,20 @@ typedef struct { uint32_t magic_number; /* 4B - 0x20231226 */ - char hw_no[12]; /* 12B - HW Number */ + char hw_no[12]; /* 12B - HW Version */ char serial_no[12]; /* 12B - Serial Number */ uint8_t static_passkey[6]; /* 6B - BLE Passkey */ uint8_t bond_data_delete; /* 1B - Bond delete flag */ int8_t reset_status; /* 1B - Reset status */ - uint8_t pd_adc_cnt; /* 1B - ADC sample count */ - uint16_t pd_delay_us; /* 2B - PD delay (us) */ - uint32_t life_cycle; /* 4B - Device usage count (sxz/syz command) */ -} config_data_t; /* Total: 45 bytes - FDS에 저장하는 디바이스 설정 */ + uint32_t life_cycle; /* 4B - Device usage count */ + + /* Piezo 측정 파라미터 - 8B */ + uint8_t piezo_freq_option; /* 1B - Frequency : 송신 펄스 주파수 (0=1.8M, 1=2.1M, 2=2.0M, 3=1.7M) */ + uint8_t piezo_cycles; /* 1B - Burst Cycle : 송신 펄스 사이클 수 (3~7) */ + uint16_t piezo_averaging; /* 2B - 채널당 반복 측정 횟수 */ + uint16_t piezo_delay_us; /* 2B - 송신 펄스 출력 후 ADC 시작 시까지 대기시간(us) */ + uint16_t piezo_num_samples; /* 2B - 측정 ADC 샘플 개수(80~140) */ +} config_data_t; /* Total: 48 bytes - FDS에 저장하는 디바이스 설정 */ extern config_data_t m_config; diff --git a/project/ble_peripheral/ble_app_bladder_patch/icm42670p/app_raw/app_raw.c b/project/ble_peripheral/ble_app_bladder_patch/icm42670p/app_raw/app_raw.c index 45cdd44..eca9e15 100644 --- a/project/ble_peripheral/ble_app_bladder_patch/icm42670p/app_raw/app_raw.c +++ b/project/ble_peripheral/ble_app_bladder_patch/icm42670p/app_raw/app_raw.c @@ -9,8 +9,8 @@ /******************************************************************************* * [모듈 개요] ICM42670P IMU 드라이버 상위 레이어 * - * ICM42670P IMU 센서의 초기화, 설정, 데이터 읽기를 담당하는 애플리케이션 - * 레이어 모듈이다. InvenSense 드라이버 API를 래핑하여 사용한다. + * ICM42670P IMU 센서의 초기화, 설정, 데이터 읽기를 담당하는 애플리케이션 레이어 모듈 + * InvenSense 드라이버 API를 래핑하여 사용 * * 주요 기능: * 1) setup_imu_device() - IMU 초기화 및 WHOAMI 확인 (0x67 = ICM42670P) @@ -28,8 +28,7 @@ * - 센서 설정 → 전원 ON → 80ms 대기 → 12바이트 읽기 → 슬립 * * 마운팅 매트릭스: - * Q30 고정소수점 형식의 3x3 회전 매트릭스로, 보드에 장착된 센서의 - * 물리적 방향을 소프트웨어 좌표계에 맞춰 보정한다. + * Q30 고정소수점 형식의 3x3 회전 매트릭스로, 보드에 장착된 센서의물리적 방향을 소프트웨어 좌표계에 맞춰 보정 ******************************************************************************/ #include "sdk_config.h" @@ -43,7 +42,6 @@ #include "app_util_platform.h" #include "main.h" -/* 2026-03-17: cmd_parse.h 삭제 — main.h는 이미 포함됨 */ #include "debug_print.h" #include "nrf_delay.h" @@ -60,7 +58,7 @@ * Static and extern variables * -------------------------------------------------------------------------------------- */ -/* IMU 드라이버 객체 — 드라이버 API 호출 시 항상 이 구조체를 전달 */ +/* IMU 드라이버 객체 — 드라이버 API 호출 시 항상 이 구조체 전달 */ static struct inv_imu_device icm_driver; /* BLE 전송용 바이너리 버퍼 */ @@ -69,11 +67,11 @@ static struct inv_imu_device icm_driver; /* * ICM42670P 마운팅 매트릭스 (Q30 고정소수점) * - * 센서가 보드에 장착된 물리적 방향에 따라 좌표 변환을 수행한다. + * 센서가 보드에 장착된 물리적 방향에 따라 좌표 변환 * Q30 형식: 1.0 = (1 << 30) = 0x40000000 * * SM_REVB_DB (개발보드): X→-Y, Y→X 변환 (90도 회전) - * 기본 (SmartMotion): 단위 행렬 (변환 없음) + * 기본 (SmartMotion): 단위 행렬 (변환 없음) */ #if (SM_BOARD_REV == SM_REVB_DB) /* when DB or EVB are used */ static int32_t icm_mounting_matrix[9] = { 0, -(1<<30), 0, @@ -85,13 +83,13 @@ static int32_t icm_mounting_matrix[9] = {(1<<30), 0, 0, 0, 0, (1<<30)}; #endif -bool custom_add_data; /* 커스텀 데이터 추가 플래그 (BLE 전송 제어) */ -extern bool motion_raw_data_enabled; /* 외부에서 원시 데이터 읽기를 요청하는 플래그 */ -extern char ble_tx_buffer[BLE_NUS_MAX_DATA_LEN]; /* BLE 텍스트 전송 버퍼 */ -extern which_cmd_t cmd_type_t; /* 현재 명령 소스 (BLE 또는 UART) */ -uint16_t ssp_data[6]={0,}; /* BLE 전송용 6축 데이터 배열 (accel XYZ + gyro XYZ) */ -extern bool info4; /* info4 모드 플래그 (cmd_parse에서 설정) */ - volatile uint16_t info_imu[6]; /* info4 모드에서 IMU 데이터를 저장하는 전역 배열 */ +bool custom_add_data; /* 커스텀 데이터 추가 플래그 (BLE 전송 제어) */ +extern bool motion_raw_data_enabled; /* 외부에서 원시 데이터 읽기를 요청하는 플래그 */ +extern char ble_tx_buffer[BLE_NUS_MAX_DATA_LEN]; /* BLE 텍스트 전송 버퍼 */ +extern which_cmd_t cmd_type_t; /* 현재 명령 소스 (BLE 또는 UART) */ +uint16_t ssp_data[6]={0,}; /* BLE 전송용 6축 데이터 배열 (accel XYZ + gyro XYZ) */ +extern bool info4; /* info4 모드 플래그 (cmd_parse에서 설정) */ + volatile uint16_t info_imu[6]; /* info4 모드에서 IMU 데이터를 저장하는 전역 배열 */ /* -------------------------------------------------------------------------------------- * static function declaration @@ -143,7 +141,7 @@ int setup_imu_device(struct inv_imu_serif *icm_serif) /* * configure_imu_device() - * IMU 센서 동작 파라미터를 설정한다. + * IMU 센서 동작 파라미터 설정 * * 설정 항목: * - FIFO: 비활성화 (USE_FIFO=0일 때, 레지스터 직접 읽기 모드) @@ -161,7 +159,7 @@ int configure_imu_device(void) { int rc = 0; - /* FIFO 비활성화 — 레지스터에서 직접 데이터를 읽는다 */ + /* FIFO 비활성화 — 레지스터에서 직접 데이터를 읽기 */ if (!USE_FIFO) rc |= inv_imu_configure_fifo(&icm_driver, INV_IMU_FIFO_DISABLED); @@ -199,9 +197,9 @@ int configure_imu_device(void) /* * get_imu_data() - * IMU에서 센서 데이터를 읽는다. - * USE_FIFO 설정에 따라 FIFO 또는 레지스터에서 데이터를 가져온다. - * 읽은 데이터는 imu_callback()을 통해 처리된다. + * IMU에서 센서 데이터 읽기 + * USE_FIFO 설정에 따라 FIFO 또는 레지스터에서 데이터를 가져옴 + * 읽은 데이터는 imu_callback()을 통해 처리 */ int get_imu_data(void) { @@ -255,7 +253,7 @@ static void get_accel_and_gyr_fsr(int16_t * accel_fsr_g, int16_t * gyro_fsr_dps) /* * imu_callback() - * IMU 드라이버가 새 센서 데이터를 읽을 때마다 호출되는 콜백 함수. + * IMU 드라이버가 새 센서 데이터를 읽을 때마다 호출되는 콜백 함수 * * 처리 흐름: * 1) 이벤트에서 가속도/자이로 원시 데이터 추출 @@ -370,45 +368,45 @@ void imu_callback(inv_imu_sensor_event_t *event) { motion_raw_data_enabled = false; + /* info4 모드: 전역 배열 info_imu[6]에 데이터 저장, 외부 모듈에서 이 배열을 폴링하여 데이터 사용 */ if (info4 == true) { - /* - * info4 모드: 전역 배열 info_imu[6]에 데이터를 저장한다. - * 외부 모듈에서 이 배열을 폴링하여 데이터를 사용한다. - */ - info_imu[0] = (uint16_t)accel[0]; + info_imu[0] = (uint16_t)accel[0]; info_imu[1] = (uint16_t)accel[1]; - info_imu[2] = (uint16_t) accel[2]; + info_imu[2] = (uint16_t)accel[2]; info_imu[3] = (uint16_t)gyro[0]; - info_imu[4] = (uint16_t) gyro[1]; - info_imu[5] = (uint16_t)gyro[2]; + info_imu[4] = (uint16_t)gyro[1]; + info_imu[5] = (uint16_t)gyro[2]; } + /* UART 모드: "Tp" 접두사로 6축 데이터를 텍스트 형식으로 출력 */ else if(cmd_type_t == CMD_UART) { - /* UART 모드: "Tp" 접두사로 6축 데이터를 텍스트 형식으로 출력 */ printf("Tp%d,%d,%d,%d,%d,%d\r\n\r\n", accel[0], accel[1], accel[2], gyro[0], gyro[1], gyro[2]); - } else if(cmd_type_t == CMD_BLE) { - /* - * BLE 모드: 6축 데이터를 바이너리 패킷으로 BLE 전송 - * ssp_data[0~2] = 가속도 XYZ, ssp_data[3~5] = 자이로 XYZ - * format_data()로 "rsp:" 태그 + 12바이트 데이터를 패킷화 - * dr_binary_tx_safe()로 8바이트 BLE 전송 - */ - ssp_data[0] = (uint16_t)accel[0]; - ssp_data[1] = (uint16_t)accel[1]; - ssp_data[2] = (uint16_t)accel[2]; - ssp_data[3] = (uint16_t)gyro[0]; - ssp_data[4] = (uint16_t)gyro[1]; - ssp_data[5] = (uint16_t)gyro[2]; - format_data(imu_bin_buffer, "rsp:", ssp_data,12); + } + + /* + * BLE 모드: 6축 데이터를 바이너리 패킷으로 BLE 전송 + * ssp_data[0~2] = 가속도 XYZ, ssp_data[3~5] = 자이로 XYZ + * format_data()로 "rsp:" 태그 + 12바이트 데이터를 패킷화 + * dr_binary_tx_safe()로 8바이트 BLE 전송 + */ + else if(cmd_type_t == CMD_BLE) { + ssp_data[0] = (uint16_t)accel[0]; + ssp_data[1] = (uint16_t)accel[1]; + ssp_data[2] = (uint16_t)accel[2]; + ssp_data[3] = (uint16_t)gyro[0]; + ssp_data[4] = (uint16_t)gyro[1]; + ssp_data[5] = (uint16_t)gyro[2]; + + format_data(imu_bin_buffer, "rsp:", ssp_data,12); printf("Tp%d,%d,%d,%d,%d,%d\r\n\r\n", accel[0], accel[1], accel[2], gyro[0], gyro[1], gyro[2]); dr_binary_tx_safe(imu_bin_buffer,8); - if(custom_add_data==true) - { + + if(custom_add_data==true) { custom_add_data = false; } - else{ - //data_tx_handler(ble_tx_buffer); + else { + //data_tx_handler(ble_tx_buffer); } } } @@ -544,7 +542,7 @@ int imu_read_direct(void) DBG_PRINTF("[IMU] A:%d,%d,%d G:%d,%d,%d\r\n", accel[0], accel[1], accel[2], gyro[0], gyro[1], gyro[2]); - /* BLE 전송용 데이터 패킹: "rsp:" 태그 + 6축 데이터(12바이트) */ + /* 데이터 패킹 */ ssp_data[0] = (uint16_t)accel[0]; ssp_data[1] = (uint16_t)accel[1]; ssp_data[2] = (uint16_t)accel[2]; @@ -552,8 +550,19 @@ int imu_read_direct(void) ssp_data[4] = (uint16_t)gyro[1]; ssp_data[5] = (uint16_t)gyro[2]; - format_data(imu_bin_buffer, "rsp:", ssp_data, 12); - dr_binary_tx_safe(imu_bin_buffer, 8); + if (info4 == true) { + /* info4 모드: 전역 배열에 저장 (mbb?에서 rbb: 패킷으로 일괄 전송) */ + info_imu[0] = ssp_data[0]; + info_imu[1] = ssp_data[1]; + info_imu[2] = ssp_data[2]; + info_imu[3] = ssp_data[3]; + info_imu[4] = ssp_data[4]; + info_imu[5] = ssp_data[5]; + } else { + /* 일반 모드: "rsp:" 태그로 BLE 즉시 전송 */ + format_data(imu_bin_buffer, "rsp:", ssp_data, 12); + dr_binary_tx_safe(imu_bin_buffer, 8); + } /* IMU 슬립 모드: PWR_MGMT0 = 0x00 → 가속도/자이로 모두 OFF (전력 절감) */ { diff --git a/project/ble_peripheral/ble_app_bladder_patch/main.c b/project/ble_peripheral/ble_app_bladder_patch/main.c index 365b110..e022181 100644 --- a/project/ble_peripheral/ble_app_bladder_patch/main.c +++ b/project/ble_peripheral/ble_app_bladder_patch/main.c @@ -278,7 +278,7 @@ char HW_NO[HW_NO_LENGTH]; /* 하드웨어 번호 (FDS bool bond_data_delete; /* 본딩 데이터 삭제 요청 플래그 */ uint32_t m_life_cycle; /* 디바이스 수명 사이클 카운터 */ uint8_t resetCount = 0; /* 통신 타임아웃 카운터 (리셋 감지용) */ -bool info4; /* 추가 정보(배터리/온도/IMU) 포함 측정 플래그 */ +bool info4; /* 센서 측정 정보(배터리/IMU/온도) 포함 측정 플래그 */ uint8_t m_reset_status; /* 리셋 상태 코드 (1=정상, 2=SW리셋, 5=보안리셋, 10=본딩완료) */ /*============================================================================== @@ -318,10 +318,13 @@ static void power_hold_init(void) */ static void power_control_handler(on_off_cont_t device_power_st) { - if (device_power_st == OFF) { + if (device_power_st == OFF) + { nrf_gpio_pin_clear(POWER_HOLD); /* P0.8 LOW → 전원 래치 해제 → 전원 차단 */ DBG_PRINTF("[PWR] OFF\r\n"); - } else if (device_power_st == ON) { + } + else if (device_power_st == ON) + { nrf_gpio_pin_set(POWER_HOLD); /* P0.8 HIGH → 전원 유지 */ DBG_PRINTF("[PWR] ON\r\n"); } @@ -404,7 +407,8 @@ static void load_flash_config(void) m_need_save_defaults = false; /* 하드웨어 번호 — 비어있으면 기본값 채움 */ - if (m_config.hw_no[0] == 0 || m_config.hw_no[0] == (char)0xFF) { + if (m_config.hw_no[0] == 0 || m_config.hw_no[0] == (char)0xFF) + { memset(m_config.hw_no, 0, HW_NO_LENGTH); memcpy(m_config.hw_no, HARDWARE_VERSION, strlen(HARDWARE_VERSION)); DBG_PRINTF("[CFG] HW empty, set default: %s\r\n", HARDWARE_VERSION); @@ -412,7 +416,8 @@ static void load_flash_config(void) } /* 시리얼 번호 — 비어있으면 기본값 채움 */ - if (m_config.serial_no[0] == 0 || m_config.serial_no[0] == (char)0xFF) { + if (m_config.serial_no[0] == 0 || m_config.serial_no[0] == (char)0xFF) + { memset(m_config.serial_no, 0, SERIAL_NO_LENGTH); memcpy(m_config.serial_no, FIRMWARE_SERIAL_NO, strlen(FIRMWARE_SERIAL_NO)); DBG_PRINTF("[CFG] S/N empty, set default: %s\r\n", FIRMWARE_SERIAL_NO); @@ -472,7 +477,8 @@ static void PM_s(void * p_context) UNUSED_PARAMETER(p_context); APP_ERROR_CHECK(app_timer_stop(m_PM_timer_id)); - if (m_reset_status == 5) { + if (m_reset_status == 5) + { DBG_PRINTF("[PM] Kill\r\n"); sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION); } @@ -628,7 +634,8 @@ static void nus_data_handler(ble_nus_evt_t * p_evt) DBG_PRINTF("[NUS] RX len=%d\r\n", p_evt->params.rx_data.length); /* 콜백에서는 복사만 하고, 메인 루프에서 처리 */ - if (p_evt->params.rx_data.length <= BLE_NUS_MAX_DATA_LEN) { + if (p_evt->params.rx_data.length <= BLE_NUS_MAX_DATA_LEN) + { memcpy((void *)pending_cmd_buf, p_evt->params.rx_data.p_data, p_evt->params.rx_data.length); pending_cmd_len = p_evt->params.rx_data.length; } diff --git a/project/ble_peripheral/ble_app_bladder_patch/main_timer.c b/project/ble_peripheral/ble_app_bladder_patch/main_timer.c index 8a43b3a..fbf1e92 100644 --- a/project/ble_peripheral/ble_app_bladder_patch/main_timer.c +++ b/project/ble_peripheral/ble_app_bladder_patch/main_timer.c @@ -215,16 +215,11 @@ void main_loop(void * p_context) /* For x ms */ } - - - /* For System Control */ /* ---- 시스템 제어 이벤트 처리 ---- */ - /* 디바이스 전원 OFF 처리 */ if(go_device_power_off == true){ main_timer_stop(); /* 타이머 정지 */ - DBG_PRINTF("Off main_timer\r\n"); device_power_off(); /* 디바이스 전원 OFF 실행 */ } @@ -232,21 +227,14 @@ void main_loop(void * p_context) /* For x ms */ /* 슬립 모드 진입 처리 */ if(go_sleep_mode_enter == true){ main_timer_stop(); /* 타이머 정지 */ - DBG_PRINTF("sleep main timer\r\n"); - - sleep_mode_enter(); /* 슬립 모드 진입 실행 */ } /* NVIC 시스템 리셋 처리 */ if(go_NVIC_SystemReset == true) { - - - main_timer_stop(); /* 타이머 정지 */ - - NVIC_SystemReset(); /* ARM Cortex-M4 시스템 리셋 */ + NVIC_SystemReset(); /* ARM Cortex-M4 시스템 리셋 */ } } @@ -254,7 +242,7 @@ void main_loop(void * p_context) /* For x ms */ /** * @brief 메인 루프 타이머 시작 * - * 싱글샷 모드로 MAIN_LOOP_INTERVAL(10ms 또는 80ms) 후 main_loop()를 호출한다. + * 싱글샷 모드로 MAIN_LOOP_INTERVAL(10ms 또는 80ms) 후 main_loop()를 호출 */ void main_timer_start(void) { @@ -264,7 +252,7 @@ void main_timer_start(void) /** * @brief 지정된 간격(ms)으로 메인 루프 타이머 시작 * - * IMU 연속 스트리밍 등 기본 간격과 다른 주기가 필요할 때 사용. + * IMU 연속 스트리밍 등 기본 간격과 다른 주기가 필요할 때 사용 */ void main_timer_start_ms(uint32_t interval_ms) { @@ -282,8 +270,8 @@ void main_timer_stop(void) /** * @brief 메인 루프 타이머 초기화 (앱 시작 시 1회 호출) * - * 싱글샷 모드 타이머를 생성하고, 콜백으로 main_loop()를 등록한다. - * 싱글샷이므로 매 호출마다 main_timer_start()로 수동 재시작해야 한다. + * 싱글샷 모드 타이머를 생성하고, 콜백으로 main_loop()를 등록 + * 싱글샷이므로 매 호출마다 main_timer_start()로 수동 재시작해야 함 */ void main_timer_init(void) { diff --git a/project/ble_peripheral/ble_app_bladder_patch/pulse_gen.c b/project/ble_peripheral/ble_app_bladder_patch/pulse_gen.c index 40f3fb3..f5bd98b 100644 --- a/project/ble_peripheral/ble_app_bladder_patch/pulse_gen.c +++ b/project/ble_peripheral/ble_app_bladder_patch/pulse_gen.c @@ -7,11 +7,11 @@ ******************************************************************************/ /******************************************************************************* - * [한국어 설명] PWM 펄스 생성기 + * PWM 펄스 생성기 * * === 현재 상태 === * SKIP_PWM 매크로가 정의되어 있어 PWM 기능이 비활성화됨. - * init/start/stop 함수는 모두 Stub(빈 껍데기) 구현으로, + * init/start/stop 함수는 모두 Stub으로, * 로그만 출력하고 실제 PWM 동작은 하지 않는다. * 빌드 호환성을 위해 함수 인터페이스만 유지. * diff --git a/project/ble_peripheral/ble_app_bladder_patch/tmp235_q1.c b/project/ble_peripheral/ble_app_bladder_patch/tmp235_q1.c index 1692aee..54010a5 100644 --- a/project/ble_peripheral/ble_app_bladder_patch/tmp235_q1.c +++ b/project/ble_peripheral/ble_app_bladder_patch/tmp235_q1.c @@ -9,9 +9,8 @@ /******************************************************************************* * [모듈 개요] TMP235-Q1 아날로그 온도센서 드라이버 * - * TMP235-Q1은 온도에 비례하는 아날로그 전압(Vout)을 출력하는 센서이다. - * nRF52840 SAADC의 AIN3 채널로 Vout을 읽고, mV로 변환한 뒤 - * 온도(°C)로 계산한다. + * TMP235-Q1은 온도에 비례하는 아날로그 전압(Vout)을 출력하는 센서 + * nRF52840 SAADC의 AIN3 채널로 Vout을 읽고, mV로 변환한 뒤 온도(°C)로 계산 * * 온도 계산 공식 (구간별 선형 보간): * - Vout <= 1500mV (0~100°C): Ta = (Vout - 500) / 10.0 @@ -61,13 +60,17 @@ static nrf_saadc_value_t adc_buf; extern char ble_tx_buffer[BLE_NUS_MAX_DATA_LEN]; extern uint8_t ble_bin_buffer[BLE_NUS_MAX_DATA_LEN] ; + /* 현재 명령 소스: CMD_UART 또는 CMD_BLE */ extern which_cmd_t cmd_type_t; + /* info4: 전체 센서 데이터 수집 모드 플래그 */ -extern bool info4; //cmd_parse +extern bool info4; // main.c + /* 온도 측정 순서 제어 플래그 */ -extern bool go_temp; //cmd_parse -/* info4 모드에서 온도값을 임시 저장 (°C x 100, 정수 표현) */ +extern bool go_temp; // main_timer.c + +/* info4 모드에서 온도값 임시 저장 (°C x 100, 정수 표현) */ volatile uint16_t info_temp; //48_C extern bool motion_raw_data_enabled; @@ -87,9 +90,9 @@ extern bool motion_raw_data_enabled; */ void tmp235_voltage_handler(nrf_drv_saadc_evt_t const * p_event) /* TMP325 Vout reading */ { - float led_temp; /* 계산된 온도 (°C, 부동소수점) */ uint16_t led_temp_16; /* BLE 전송용 온도 (°C x 100, 정수) */ + if (p_event->type == NRF_DRV_SAADC_EVT_DONE) { nrf_saadc_value_t adc_result; @@ -113,50 +116,50 @@ void tmp235_voltage_handler(nrf_drv_saadc_evt_t const * p_event) /* TMP325 Vout * 100~125°C 구간: 기울기 10.1 mV/°C * 125~150°C 구간: 기울기 10.6 mV/°C */ - if(tmp235_voltage_in_milli_volts <= 1500) { + if(tmp235_voltage_in_milli_volts <= 1500) + { /* 0~100°C: Ta = (Vout - 500mV) / 10.0 mV/°C */ led_temp = (tmp235_voltage_in_milli_volts - 500.0f) / 10.0f + 0.0f; - }else if(tmp235_voltage_in_milli_volts <= 1750) { + } + else if(tmp235_voltage_in_milli_volts <= 1750) + { /* 100~125°C: 기울기가 10.1로 약간 증가 */ led_temp = (tmp235_voltage_in_milli_volts - 1500.0f) / 10.1f + 100.0f; - }else if(tmp235_voltage_in_milli_volts <= 2000) { + } + else if(tmp235_voltage_in_milli_volts <= 2000) + { /* 125~150°C: 기울기가 10.6으로 더 증가 */ led_temp = (tmp235_voltage_in_milli_volts - 1752.5f) / 10.6f + 125.0f; - }else { + } + else + { /* 150°C 초과 — 센서 측정 범위 벗어남 */ DBG_PRINTF("ERR!!! Temprature is over 150c\r\n"); } /* info4 모드: 온도값을 정수(°C x 100)로 저장 (예: 36.50°C → 3650) */ - if (info4 == true){ - + if (info4 == true) + { info_temp =(uint16_t)(led_temp*100); - } /* UART 모드: 소수점 2자리까지 텍스트로 출력 */ - else if(cmd_type_t == CMD_UART) { + else if(cmd_type_t == CMD_UART) + { DBG_PRINTF("To%.2f\r\n\r\n",led_temp); + } /* BLE 모드: °C x 100 정수를 "rso:" 헤더로 바이너리 전송 */ - } else if(cmd_type_t == CMD_BLE) { - led_temp_16 = (uint16_t)(led_temp*100); - single_format_data(ble_bin_buffer, "rso:", led_temp_16); + else if(cmd_type_t == CMD_BLE) + { + led_temp_16 = (uint16_t)(led_temp*100); + single_format_data(ble_bin_buffer, "rso:", led_temp_16); - dr_binary_tx_safe(ble_bin_buffer,3); + dr_binary_tx_safe(ble_bin_buffer,3); // sprintf(ble_tx_buffer, "To%.2f\r\n",led_temp); // data_tx_handler(ble_tx_buffer); } } - /* info4 모드: 온도 측정 완료 → 다음 단계(IMU 측정)로 전환 */ - if (info4 == true){ - - go_temp = false; /* 온도 측정 완료 표시 */ - - - motion_raw_data_enabled = true; /* IMU 데이터 수집 시작 플래그 */ - main_timer_start(); /* 메인 타이머 시작 → IMU 측정 트리거 */ - } } @@ -173,8 +176,7 @@ void tmp235_init(void) APP_ERROR_CHECK(err_code); /* AIN3 채널 설정: TMP235-Q1 Vout 핀 (싱글엔드 입력) */ - nrf_saadc_channel_config_t config = - NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN3); /* TMP235_Q1 Voltage Output Measurement */ + nrf_saadc_channel_config_t config = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN3); /* TMP235_Q1 Voltage Output Measurement */ err_code = nrf_drv_saadc_channel_init(0, &config); APP_ERROR_CHECK(err_code); @@ -197,8 +199,7 @@ void tmp235_init(void) */ void tmp235_voltage_level_meas(void) { - tmp235_init(); + tmp235_init(); // init 함수에 있는 걸 그냥 여기 넣어도 //tmp235_uninit(); - }