fix: BLE TX 먹통 해결 및 메모리 안전성 개선

- binary_tx_handler를 dr_binary_tx_safe로 전체 교체 (APP_ERROR_CHECK 제거)
- data_tx_handler APP_ERROR_CHECK → DBG_PRINTF 교체
- memset/memcpy 하드코딩 크기를 define 상수로 교체 (버퍼 오버런 수정)
- SERIAL_NO_LENGTH, HW_NO_LENGTH, PASSKEY_LENGTH를 main.h로 통합
- 미사용 HW 드라이버/EEPROM 코드 삭제, TWI를 i2c_manager.c로 통합
- EEPROM → FDS 전환, 코드 리뷰 현황 문서 추가

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-16 16:39:26 +09:00
parent a77919b4d3
commit 831dbc2844
76 changed files with 43253 additions and 16370 deletions

View File

@@ -64,29 +64,16 @@
#include "main.h"
#include "app_raw_main.h"
#include "main_timer.h"
#include "ad5272_i2c.h"
#include "ada2200_spi.h"
#include "power_control.h"
#include "tmp235_q1.h"
#include "mcp4725_i2c.h"
#include "measurements.h"
#include "fds.h"
#include "battery_saadc.h"
#include "mcp4725_adc.h"
#include "meas_pd_voltage_simple.h"
#include "meas_pd_voltage_half.h"
#include "meas_pd_voltage_full.h"
#include "full_agc.h"
#include "meas_pd_voltage_custom.h"
#include "meas_pd_imm.h"
#if FEATURE_SECURE_CONNECTION
#include "peer_manager.h"
#include "peer_manager_handler.h"
#include "nrf_ble_lesc.h"
#include "ble_quick_security.h"
#include "cat_interface.h"
#include "ir_i2c.h"
#include "i2c_manager.h"
#endif
@@ -150,7 +137,6 @@
#define SEC_PARAM_MIN_KEY_SIZE 7
#define SEC_PARAM_MAX_KEY_SIZE 16
#define PASSKEY_TXT_LENGTH 8
#define PASSKEY_LENGTH 6
#endif
/*==============================================================================
@@ -217,18 +203,8 @@ extern bool go_sleep_mode_enter;
extern bool go_NVIC_SystemReset;
extern bool ble_got_new_data;
extern bool motion_data_once;
extern bool adc_enabled;
extern bool con_single;
extern bool info4;
extern uint16_t led_pd_dac_v[LED_NUM];
extern uint8_t pd_adc_count;
extern int8_t c_max;
extern uint8_t simple_samples_in_buffer;
extern uint8_t full_samples_in_buffer;
extern uint8_t custom_samples_in_buffer;
extern bool pd_adc_custom_a_start;
extern bool pd_adc_custom_start;
extern bool full_agc_a_start;
extern uint8_t add_cycle;
extern bool motion_raw_data_enabled;
@@ -247,13 +223,11 @@ bool erase_bonds;
volatile bool ble_connection_st;
volatile bool data_tx_in_progress = false;
extern char m_static_passkey[6];
extern char SERIAL_NO[12];
extern char m_static_passkey[PASSKEY_LENGTH];
extern char SERIAL_NO[SERIAL_NO_LENGTH];
extern bool bond_data_delete;
uint8_t m_reset_status;
extern uint8_t m_pd_adc_cnt;
extern uint16_t m_pd_delay_us;
extern uint32_t m_life_cycle;
/*==============================================================================
@@ -306,14 +280,6 @@ static void full_gpio_init(void)
{
minimal_gpio_init();
LED_CONFIG();
LED_ALLOFF();
PD_CONFIG();
PD_ALLOFF();
trig_r_CONFIG();
trig_SW(false);
GAIN_SW_CONFIG();
AGC_GAIN_SW(false);
eeprom_control(OFF);
DBG_PRINTF("[GPIO] Full OK\r\n");
@@ -325,14 +291,12 @@ static void full_gpio_init(void)
*============================================================================*/
static void load_default_config(void)
{
memset(SERIAL_NO, 0, 16);
memset(SERIAL_NO, 0, SERIAL_NO_LENGTH);
memcpy(SERIAL_NO, FIRMWARE_SERIAL_NO, strlen(FIRMWARE_SERIAL_NO));
memset(m_static_passkey, 0, 16);
memcpy(m_static_passkey, "123456", 6);
memset(m_static_passkey, 0, PASSKEY_LENGTH);
memcpy(m_static_passkey, "123456", PASSKEY_LENGTH);
m_pd_delay_us = 8000;
m_pd_adc_cnt = 8;
m_reset_status = 1;
bond_data_delete = 1;
@@ -352,7 +316,7 @@ static void load_flash_config(void)
/* Hardware Number — fill default if empty */
if (m_config.hw_no[0] == 0 || m_config.hw_no[0] == (char)0xFF) {
memset(m_config.hw_no, 0, 12);
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);
m_need_save_defaults = true;
@@ -360,19 +324,19 @@ static void load_flash_config(void)
/* Serial Number — fill default if empty */
if (m_config.serial_no[0] == 0 || m_config.serial_no[0] == (char)0xFF) {
memset(m_config.serial_no, 0, 12);
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);
m_need_save_defaults = true;
}
/* Serial Number → BLE device name */
memset(SERIAL_NO, 0, 16);
memcpy(SERIAL_NO, m_config.serial_no, 12);
memset(SERIAL_NO, 0, SERIAL_NO_LENGTH);
memcpy(SERIAL_NO, m_config.serial_no, SERIAL_NO_LENGTH);
/* Passkey */
memset(m_static_passkey, 0, 16);
memcpy(m_static_passkey, m_config.static_passkey, 6);
memset(m_static_passkey, 0, PASSKEY_LENGTH);
memcpy(m_static_passkey, m_config.static_passkey, PASSKEY_LENGTH);
/* Bond data delete flag */
bond_data_delete = m_config.bond_data_delete;
@@ -380,52 +344,12 @@ static void load_flash_config(void)
/* Reset status */
m_reset_status = m_config.reset_status;
/* Measurement parameters (with validation) */
m_pd_adc_cnt = (m_config.pd_adc_cnt > 0 && m_config.pd_adc_cnt <= 32)
? m_config.pd_adc_cnt : 8;
m_pd_delay_us = (m_config.pd_delay_us > 0)
? m_config.pd_delay_us : 8000;
DBG_PRINTF("[CFG] HW=%.12s S/N=%s passkey=%.6s bond=%d rst=%d adc=%d delay=%u\r\n",
DBG_PRINTF("[CFG] HW=%.12s S/N=%s passkey=%.6s bond=%d rst=%d\r\n",
m_config.hw_no, SERIAL_NO, m_static_passkey, bond_data_delete,
m_reset_status, m_pd_adc_cnt, m_pd_delay_us);
m_reset_status);
}
#if !DEBUG_MINIMAL_BOOT
static void load_eeprom_config(void)
{
DBG_PRINTF("[CFG] EEPROM loading...\r\n");
eeprom_initialize();
nrf_delay_us(10);
eeprom_init_values_read();
eeprom_uninitialize();
nrf_delay_us(50);
#if BLE_DEV_MODE
memset(SERIAL_NO, 0, 16);
memcpy(SERIAL_NO, FIRMWARE_SERIAL_NO, strlen(FIRMWARE_SERIAL_NO));
DBG_PRINTF("[CFG] DEV S/N=%s\r\n", SERIAL_NO);
#else
if (!is_valid_serial_no(SERIAL_NO))
{
memset(SERIAL_NO, 0, 16);
memcpy(SERIAL_NO, FIRMWARE_SERIAL_NO, strlen(FIRMWARE_SERIAL_NO));
}
char const init_pass[6] = "123456";
memset(m_static_passkey, 0, 16);
memcpy(m_static_passkey, (uint8_t *)init_pass, 6);
#endif
m_pd_delay_us = 8000;
m_pd_adc_cnt = 8;
m_reset_status = 1;
bond_data_delete = BLE_DEV_MODE ? 1 : 0;
DBG_PRINTF("[CFG] EEPROM OK\r\n");
}
#endif
/* load_eeprom_config() 삭제 — EEPROM 제거됨, FDS가 대체 - jhChun 26.03.16 */
/*==============================================================================
* TIMER CALLBACKS
@@ -468,11 +392,6 @@ static void timers_init(void)
main_timer_init();
battery_timer_init();
imm_check_timer_init();
m48_check_timer_init();
full_agc_timer_init();
full_agc_send_timer_init();
mea_send_timer_init();
power_timer_init();
#if FEATURE_PRINTF
@@ -879,8 +798,6 @@ static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)
if (device_status == true)
{
LED_ALLOFF();
PD_ALLOFF();
if (device_sleep_mode() == 0)
{
device_status = false;
@@ -1150,7 +1067,7 @@ void device_power_off(void)
/*==============================================================================
* DATA TRANSMISSION
*============================================================================*/
void data_tx_handler(char const *p_data_to_send)
void data_tx_handler(char const *p_data_to_send) // 문자열 (ASCII 텍스트) 전송 함수
{
if (m_tx_in_progress) return;
@@ -1180,8 +1097,9 @@ void data_tx_handler(char const *p_data_to_send)
m_conn_handle = BLE_CONN_HANDLE_INVALID;
m_tx_in_progress = false;
} else {
DBG_PRINTF("[BLE TX] Err:0x%X\r\n", err_code); // APP_ERROR_CHECK 대신 로그 - jhChun 26.03.16
m_tx_in_progress = false;
APP_ERROR_CHECK(err_code);
//APP_ERROR_CHECK(err_code);
}
}
}
@@ -1245,46 +1163,10 @@ void ascii_format_data(uint8_t *buffer, const char *tag, const char *data_ascii,
}
}
void binary_tx_handler(uint8_t const *ble_bin_buff, uint16_t length)
{
uint32_t err_code;
static uint8_t tx_buffer[BLE_NUS_MAX_DATA_LEN] = {0};
if (ble_connection_st == 0) return;
data_tx_in_progress = true;
if (length * sizeof(uint16_t) > (BLE_NUS_MAX_DATA_LEN - 2)) return;
if (ble_connection_st == BLE_CONNECTED_ST)
{
memcpy(tx_buffer, ble_bin_buff, length * sizeof(uint16_t));
uint16_t crc = crc16_compute(tx_buffer, length * sizeof(uint16_t), NULL);
tx_buffer[length * sizeof(uint16_t)] = (uint8_t)(crc & 0xFF);
tx_buffer[length * sizeof(uint16_t) + 1] = (uint8_t)((crc >> 8) & 0xFF);
uint16_t total_len = length * sizeof(uint16_t) + 2;
do {
err_code = ble_nus_data_send(&m_nus, tx_buffer, &total_len, m_conn_handle);
if ((err_code != NRF_ERROR_INVALID_STATE) &&
(err_code != NRF_ERROR_RESOURCES) &&
(err_code != NRF_ERROR_NOT_FOUND))
{
nrf_delay_ms(10);
}
APP_ERROR_CHECK(err_code);
} while (err_code == NRF_ERROR_RESOURCES);
data_tx_in_progress = false;
}
}
/**
* @brief Safe BLE binary transmission with proper error handling
*
* Unlike binary_tx_handler which may assert on errors,
* this function properly handles NRF_ERROR_RESOURCES by retrying
* Properly handles NRF_ERROR_RESOURCES by retrying
* and returns gracefully on connection errors.
*
* @param ble_bin_buff Data buffer to send
@@ -1309,18 +1191,19 @@ void dr_sd_delay_ms(uint32_t ms)
nrf_delay_ms(ms);
}
void dr_binary_tx_safe(uint8_t const *ble_bin_buff, uint16_t length)
/* 기존 binary_tx_handler 함수 삭제 및 호출처 교체 - jhChun 26.03.16 */
void dr_binary_tx_safe(uint8_t const *ble_bin_buff, uint16_t length) // BLE로 바이너리 데이터를 안전하게 전송하는 함수
{
uint32_t err_code;
static uint8_t tx_buffer[BLE_NUS_MAX_DATA_LEN] = {0};
uint16_t retry_count = 0;
const uint16_t MAX_RETRIES = 100; /* Max retries (~500ms at 5ms each) */
if (ble_connection_st == 0) return;
if (ble_connection_st == 0) return; // 연결 확인
data_tx_in_progress = true;
if (length * sizeof(uint16_t) > (BLE_NUS_MAX_DATA_LEN - 2)) {
if (length * sizeof(uint16_t) > (BLE_NUS_MAX_DATA_LEN - 2)) { // 길이 검증 (CRC 2바이트 공간 확보)
data_tx_in_progress = false;
return;
}
@@ -1328,9 +1211,9 @@ void dr_binary_tx_safe(uint8_t const *ble_bin_buff, uint16_t length)
if (ble_connection_st == BLE_CONNECTED_ST)
{
memcpy(tx_buffer, ble_bin_buff, length * sizeof(uint16_t));
uint16_t crc = crc16_compute(tx_buffer, length * sizeof(uint16_t), NULL);
uint16_t crc = crc16_compute(tx_buffer, length * sizeof(uint16_t), NULL); // 버퍼 복사
tx_buffer[length * sizeof(uint16_t)] = (uint8_t)(crc & 0xFF);
tx_buffer[length * sizeof(uint16_t) + 1] = (uint8_t)((crc >> 8) & 0xFF);
tx_buffer[length * sizeof(uint16_t) + 1] = (uint8_t)((crc >> 8) & 0xFF); // CRC16 2바이트 추가
uint16_t total_len = length * sizeof(uint16_t) + 2;
@@ -1339,27 +1222,26 @@ void dr_binary_tx_safe(uint8_t const *ble_bin_buff, uint16_t length)
uint16_t send_len = total_len; /* MUST reset each iteration - ble_nus_data_send modifies it! */
err_code = ble_nus_data_send(&m_nus, tx_buffer, &send_len, m_conn_handle);
if (err_code == NRF_SUCCESS) {
if (err_code == NRF_SUCCESS) { // 전송 성공 -> 루프 탈출
/* TX queued successfully */
break;
} else if (err_code == NRF_ERROR_RESOURCES) {
} else if (err_code == NRF_ERROR_RESOURCES) { // TX 큐가 가득 찬 경우 5ms 대기 후 재시도 (최대 100회, ~500ms)
/* BLE TX queue full - wait for connection event to complete TX */
/* Use small delay to allow BLE stack to process TX complete events */
nrf_delay_ms(5); /* Wait ~5ms for TX slot to free up */
retry_count++;
} else if (err_code == NRF_ERROR_INVALID_STATE ||
err_code == NRF_ERROR_NOT_FOUND) {
} else if (err_code == NRF_ERROR_INVALID_STATE || err_code == NRF_ERROR_NOT_FOUND) { // 연결 끊김, 리턴
DBG_PRINTF("[BLE TX] Disconnected\r\n");
data_tx_in_progress = false;
return;
} else {
} else { // 기타 에러 -> 로그 출력 후 리턴
DBG_PRINTF("[BLE TX] Err:0x%X\r\n", err_code);
data_tx_in_progress = false;
return;
}
} while (retry_count < MAX_RETRIES);
if (retry_count >= MAX_RETRIES) {
if (retry_count >= MAX_RETRIES) { // 최대 재시도(100회) 초과 시 해당 패킷 드롭, 연결은 유지
DBG_PRINTF("[BLE TX] FAIL %u retries\r\n", retry_count);
data_tx_in_progress = false;
/* Don't set ble_connection_st = 0 here - just drop this packet and continue */
@@ -1395,15 +1277,10 @@ static void main_s(void * p_context)
power_control_handler(ON);
nrf_delay_ms(100);
bond_data_delete = true;
eeprom_initialize();
nrf_delay_ms(10);
eeprom_write_byte(0x0060, (uint8_t)bond_data_delete);
nrf_delay_ms(20);
const char pass_init[6] = "123456";
eeprom_write_encrypted(0x0020, (uint8_t *)pass_init, 6);
nrf_delay_ms(10);
eeprom_init_values_read();
eeprom_uninitialize();
m_config.bond_data_delete = (uint8_t)bond_data_delete;
const char pass_init[PASSKEY_LENGTH] = "123456";
memcpy(m_config.static_passkey, pass_init, PASSKEY_LENGTH);
config_save();
nrf_delay_ms(1000);
go_device_power_off = true;
main_timer_start();
@@ -1435,16 +1312,10 @@ static void main_s(void * p_context)
advertising_start();
#endif
ada2200_init();
nrf_delay_ms(1);
mcp4725_init();
nrf_delay_ms(1);
ad5272_i2c_init();
m_reset_status = 1;
eeprom_write_byte(0x0065, m_reset_status);
nrf_delay_ms(10);
eeprom_init_values_read();
m_config.reset_status = m_reset_status;
config_save();
#endif
m_reset_status = 1;
DBG_PRINTF("[BOOT] Ready\r\n");