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:
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user