코드 정리
- 주석 영문으로 변경 - Allman 스타일로 통일
This commit is contained in:
@@ -1,39 +1,21 @@
|
||||
/*******************************************************************************
|
||||
TEST medi50 Dec 23
|
||||
******************************************************************************/
|
||||
|
||||
/**
|
||||
* @file fstorage.c
|
||||
* @brief FDS(Flash Data Storage) 기반 설정 저장 모듈
|
||||
/*==============================================================================
|
||||
* fstorage.c - FDS (Flash Data Storage) configuration module
|
||||
*
|
||||
* 외부 EEPROM을 대체하여 nRF52840 내장 플래시에 장치 설정을 저장/로드한다.
|
||||
* Stores and loads device configuration to/from nRF52840 internal flash,
|
||||
* replacing external EEPROM. Coexists safely with the SoftDevice.
|
||||
*
|
||||
* [레코드 관리]
|
||||
* - CONFIG_FILE = 0x8010, CONFIG_REC_KEY = 0x7010 으로 단일 레코드를 관리한다.
|
||||
* Record management:
|
||||
* CONFIG_FILE = 0x8010, CONFIG_REC_KEY = 0x7010 (single record)
|
||||
*
|
||||
* [config_data_t 구조체 필드]
|
||||
* - magic(4B) : 포맷 확인용 매직 넘버 (0x20231226 -> 0x20260318(기본값 재생성을 위해 매직넘버 변경))
|
||||
* - hw_no(12B) : 하드웨어 버전 (기본값: "")
|
||||
* - serial_no(12B) : 시리얼 번호 (기본값: "VB026030000")
|
||||
* - passkey(6B) : BLE 페어링용 정적 패스키(기본값: "123456")
|
||||
* - bond_data_delete(1B) : 본딩 데이터 삭제 플래그(기본값: 1)
|
||||
* - reset_status(1B) : 리셋 상태 값(기본값: 99)
|
||||
* - life_cycle(4B) : 장치 사용 횟수(기본값: 0)
|
||||
* - piezo_freq_option : Piezo 송신 펄스 주파수(기본값: 1=2.1MHz)
|
||||
* - piezo_cycles : Piezo 송신 펄스 사이클 수 (기본값: 7)
|
||||
* - piezo_averaging : Piezo 채널당 반복 측정 횟수 (기본값: 5)
|
||||
* - piezo_delay_us : Piezo 송신 펄스 출력 후 ADC 시작 시까지 대기시간(us) (기본값: 10)
|
||||
* - piezo_num_samples : Piezo 측정 ADC 샘플 개수 (기본값: 100)
|
||||
* Magic number validation:
|
||||
* Data loaded from flash is checked against CONFIG_MAGIC_NUMBER_VALUE.
|
||||
* Mismatch -> reinitialise with factory defaults.
|
||||
*
|
||||
* [매직 넘버 검증]
|
||||
* - 플래시에서 로드한 데이터의 magic 값이 0x20231226과 일치하는지 확인하여
|
||||
* 유효한 설정인지 판별한다. 불일치 시 기본값으로 초기화한다.
|
||||
*
|
||||
* [FDS 이벤트 후처리]
|
||||
* - FDS 쓰기/업데이트 완료 이벤트 수신 후, 대기 중인 후처리를 수행한다:
|
||||
* 전원 OFF (go_device_power_off), 슬립 진입 (go_sleep_mode_enter),
|
||||
* 시스템 리셋 (go_NVIC_SystemReset)
|
||||
*/
|
||||
* FDS event post-processing:
|
||||
* After a write/update completes, pending actions are executed:
|
||||
* power-off (go_device_power_off), sleep (go_sleep_mode_enter),
|
||||
* system reset (go_NVIC_SystemReset).
|
||||
*============================================================================*/
|
||||
|
||||
#include "sdk_config.h"
|
||||
|
||||
@@ -60,29 +42,28 @@
|
||||
#include "debug_print.h"
|
||||
|
||||
|
||||
/* FDS 레코드 식별자: 파일 ID와 레코드 키로 단일 설정 레코드를 관리 */
|
||||
|
||||
/* FDS record identifiers */
|
||||
#define CONFIG_FILE (0x8010)
|
||||
#define CONFIG_REC_KEY (0x7010)
|
||||
|
||||
/* 매직 넘버: 플래시에 저장된 데이터가 유효한 설정인지 판별하는 데 사용 */
|
||||
/* Magic number used to validate stored data */
|
||||
#define CONFIG_MAGIC_NUMBER_VALUE (0x20260319)
|
||||
|
||||
/* 전역 설정 데이터 구조체 인스턴스 */
|
||||
/* Global configuration instance */
|
||||
config_data_t m_config;
|
||||
|
||||
/* FDS 쓰기 완료 후 수행할 후처리 플래그 (main.c에서 선언) */
|
||||
extern bool go_device_power_off; /* 전원 OFF 요청 */
|
||||
extern bool go_sleep_mode_enter; /* 슬립 모드 진입 요청 */
|
||||
extern bool go_NVIC_SystemReset; /* 시스템 리셋 요청 */
|
||||
/* Post-processing flags (declared in main.c) */
|
||||
extern bool go_device_power_off;
|
||||
extern bool go_sleep_mode_enter;
|
||||
extern bool go_NVIC_SystemReset;
|
||||
|
||||
/* FDS 초기화 완료 여부 플래그 (fds_evt_handler에서 true로 설정) */
|
||||
/* FDS initialisation complete flag (set in fds_evt_handler) */
|
||||
static bool volatile m_fds_initialized;
|
||||
|
||||
/* FDS 쓰기 진행 중 플래그: true이면 쓰기 완료 대기 중 */
|
||||
/* FDS write-in-progress flag */
|
||||
bool fds_flag_write = false;
|
||||
|
||||
/* FDS에 기록할 레코드 템플릿 (m_config 데이터를 가리킴) */
|
||||
/* FDS record template pointing to m_config */
|
||||
static fds_record_t const m_dummy_record =
|
||||
{
|
||||
.file_id = CONFIG_FILE,
|
||||
@@ -93,60 +74,58 @@ static fds_record_t const m_dummy_record =
|
||||
};
|
||||
|
||||
|
||||
/* 기본 설정값 상수 */
|
||||
int8_t reset_status_dflt = 99; /* 리셋 상태 기본값 */
|
||||
uint8_t static_passkey_dflt[6] = DEFAULT_PASSKEY; /* BLE 패스키 기본값 */
|
||||
/* Default values */
|
||||
int8_t reset_status_dflt = 99;
|
||||
uint8_t static_passkey_dflt[6] = DEFAULT_PASSKEY;
|
||||
|
||||
/**
|
||||
* @brief 기본 설정값 초기화
|
||||
/*==============================================================================
|
||||
* fds_default_value_set - Initialise m_config with factory defaults
|
||||
*
|
||||
* m_config 구조체의 각 필드를 공장 초기값으로 설정한다.
|
||||
* 플래시에 유효한 설정이 없거나 매직 넘버가 불일치할 때 호출된다.VB0HW0000
|
||||
*/
|
||||
* Called when flash contains no valid configuration or the magic number
|
||||
* does not match.
|
||||
*============================================================================*/
|
||||
void fds_default_value_set(void)
|
||||
{
|
||||
/* HW Number - default from HARDWARE_VERSION */
|
||||
memset(m_config.hw_no, 0, 12);
|
||||
memcpy(m_config.hw_no, HARDWARE_VERSION, strlen(HARDWARE_VERSION));
|
||||
/* HW number */
|
||||
memset(m_config.hw_no, 0, 12);
|
||||
memcpy(m_config.hw_no, HARDWARE_VERSION, strlen(HARDWARE_VERSION));
|
||||
|
||||
/* Serial Number - default from SERIAL_NUMBER */
|
||||
memset(m_config.serial_no, 0, 12);
|
||||
memcpy(m_config.serial_no, SERIAL_NUMBER, strlen(SERIAL_NUMBER));
|
||||
/* Serial number */
|
||||
memset(m_config.serial_no, 0, 12);
|
||||
memcpy(m_config.serial_no, SERIAL_NUMBER, strlen(SERIAL_NUMBER));
|
||||
|
||||
/* Static Passkey */
|
||||
memcpy(m_config.static_passkey, static_passkey_dflt, 6);
|
||||
/* Static passkey */
|
||||
memcpy(m_config.static_passkey, static_passkey_dflt, 6);
|
||||
|
||||
/* Bond data delete — 기본값: 삭제 요청 없음 (공장 초기화 경로에서만 1로 세팅) */
|
||||
m_config.bond_data_delete = 0;
|
||||
/* Bond delete — default: no pending delete */
|
||||
m_config.bond_data_delete = 0;
|
||||
|
||||
/* Reset status */
|
||||
m_config.reset_status = reset_status_dflt;
|
||||
/* Reset status */
|
||||
m_config.reset_status = reset_status_dflt;
|
||||
|
||||
/* Device usage count */
|
||||
m_config.life_cycle = 0;
|
||||
/* 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 = 3; /* 3회 평균화 */
|
||||
/* Piezo measurement parameter defaults */
|
||||
m_config.piezo_freq_option = 1; /* 2.1 MHz */
|
||||
m_config.piezo_delay_us = 10; /* 10 us after burst */
|
||||
m_config.piezo_num_samples = 100; /* 100 samples */
|
||||
m_config.piezo_cycles = 7; /* 7 cycles */
|
||||
m_config.piezo_averaging = 3; /* 3x averaging */
|
||||
}
|
||||
|
||||
|
||||
/* 마지막 FDS 이벤트 ID 저장 (디버깅용) */
|
||||
/* Last FDS event ID (for debugging) */
|
||||
static volatile uint8_t fds_last_evt = 0xFF;
|
||||
|
||||
/**
|
||||
* @brief FDS 이벤트 콜백 핸들러
|
||||
/*==============================================================================
|
||||
* fds_evt_handler - FDS event callback
|
||||
*
|
||||
* FDS 내부에서 비동기 작업이 완료될 때 호출된다.
|
||||
* - FDS_EVT_INIT : FDS 초기화 완료 → m_fds_initialized 플래그 설정
|
||||
* - FDS_EVT_WRITE : 새 레코드 쓰기 완료 → fds_flag_write 해제
|
||||
* - FDS_EVT_UPDATE : 레코드 업데이트 완료 → fds_flag_write 해제 후
|
||||
* 대기 중인 전원 OFF / 슬립 진입 / 시스템 리셋 수행
|
||||
* - FDS_EVT_DEL_RECORD / FDS_EVT_DEL_FILE / FDS_EVT_GC : 현재 미사용
|
||||
*/
|
||||
* FDS_EVT_INIT : initialisation complete -> set m_fds_initialized
|
||||
* FDS_EVT_WRITE : new record written -> clear fds_flag_write
|
||||
* FDS_EVT_UPDATE : record updated -> clear flag, then execute any
|
||||
* pending power-off / sleep / system reset
|
||||
*============================================================================*/
|
||||
static void fds_evt_handler( fds_evt_t const *p_evt )
|
||||
{
|
||||
fds_last_evt = p_evt->id;
|
||||
@@ -166,48 +145,46 @@ static void fds_evt_handler( fds_evt_t const *p_evt )
|
||||
}
|
||||
break;
|
||||
|
||||
case FDS_EVT_UPDATE:
|
||||
{
|
||||
fds_flag_write = false;
|
||||
case FDS_EVT_UPDATE:
|
||||
{
|
||||
fds_flag_write = false;
|
||||
|
||||
if(go_device_power_off == true) {
|
||||
/* After flash writing completed, System Power Off */
|
||||
if(go_device_power_off == true)
|
||||
{
|
||||
device_power_off();
|
||||
}
|
||||
if(go_sleep_mode_enter == true) {
|
||||
/* After flash writing completed, System go to Sleep Mode */
|
||||
if(go_sleep_mode_enter == true)
|
||||
{
|
||||
sleep_mode_enter();
|
||||
}
|
||||
if(go_NVIC_SystemReset == true) {
|
||||
/* After flash writing completed, System Reset */
|
||||
if(go_NVIC_SystemReset == true)
|
||||
{
|
||||
DBG_PRINTF("Off FDS_EVENT\r\n");
|
||||
NVIC_SystemReset();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case FDS_EVT_DEL_RECORD:
|
||||
break;
|
||||
case FDS_EVT_DEL_RECORD:
|
||||
break;
|
||||
|
||||
case FDS_EVT_DEL_FILE:
|
||||
break;
|
||||
case FDS_EVT_DEL_FILE:
|
||||
break;
|
||||
|
||||
case FDS_EVT_GC:
|
||||
break;
|
||||
case FDS_EVT_GC:
|
||||
break;
|
||||
|
||||
default:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief FDS 초기화 완료 대기
|
||||
/*==============================================================================
|
||||
* wait_for_fds_ready - Block until FDS initialisation completes
|
||||
*
|
||||
* m_fds_initialized 플래그가 true가 될 때까지 대기한다.
|
||||
* 최대 3초(3000ms) 타임아웃이 설정되어 있으며,
|
||||
* 타임아웃 시 에러 로그를 출력하고 반환한다.
|
||||
*/
|
||||
* Times out after 3 seconds with an error log.
|
||||
*============================================================================*/
|
||||
static void wait_for_fds_ready( void )
|
||||
{
|
||||
uint32_t timeout = 0;
|
||||
@@ -216,7 +193,7 @@ 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)
|
||||
{
|
||||
DBG_PRINTF("[FDS] TIMEOUT!\r\n");
|
||||
break;
|
||||
@@ -225,27 +202,25 @@ static void wait_for_fds_ready( void )
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief FDS에서 설정 로드
|
||||
/*==============================================================================
|
||||
* config_load - Load configuration from FDS
|
||||
*
|
||||
* 플래시에서 CONFIG_FILE/CONFIG_REC_KEY 레코드를 검색하여 m_config에 로드한다.
|
||||
*
|
||||
* 동작 흐름:
|
||||
* 1. fds_record_find()로 레코드 검색 (실패 시 최대 10회 재시도, 100ms 간격)
|
||||
* 2. 레코드 발견 시:
|
||||
* - fds_record_open()으로 열기 (CRC 에러 시 삭제 후 기본값으로 재생성)
|
||||
* - 데이터를 m_config로 복사
|
||||
* - 매직 넘버 불일치 시 기존 레코드 삭제 → 기본값 설정 → 재기록
|
||||
* 3. 레코드 미발견 시:
|
||||
* - 기본값으로 새 레코드 생성 후 다시 로드
|
||||
*/
|
||||
* Flow:
|
||||
* 1. Search for CONFIG_FILE / CONFIG_REC_KEY (retry up to 10x, 100 ms apart)
|
||||
* 2. If found:
|
||||
* - Open the record (on CRC error: delete and regenerate defaults)
|
||||
* - Copy into m_config
|
||||
* - Validate magic number; on mismatch: delete -> defaults -> rewrite
|
||||
* 3. If not found:
|
||||
* - Write factory defaults as a new record, then reload
|
||||
*============================================================================*/
|
||||
void config_load( void )
|
||||
{
|
||||
ret_code_t rc;
|
||||
fds_record_desc_t desc = { 0 };
|
||||
fds_find_token_t tok = { 0 };
|
||||
uint8_t cfg_retry = 0;
|
||||
uint32_t fds_wait_cnt = 0; // FDS write 대기 카운터
|
||||
uint32_t fds_wait_cnt = 0;
|
||||
|
||||
cfg_load_start:
|
||||
memset((char *)&desc, 0, sizeof(desc));
|
||||
@@ -264,10 +239,8 @@ void config_load( void )
|
||||
|
||||
if( rc == NRF_SUCCESS )
|
||||
{
|
||||
/* A config file is in flash. Let's update it. */
|
||||
fds_flash_record_t config = { 0 };
|
||||
|
||||
/* Open the record and read its contents. */
|
||||
rc = fds_record_open(&desc, &config);
|
||||
if (rc != NRF_SUCCESS)
|
||||
{
|
||||
@@ -279,26 +252,22 @@ void config_load( void )
|
||||
goto cfg_load_write_new;
|
||||
}
|
||||
|
||||
/* Copy the configuration from flash into m_config. */
|
||||
memcpy(&m_config, config.p_data, sizeof(config_data_t));
|
||||
|
||||
/* Close the record when done reading. */
|
||||
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);
|
||||
|
||||
if( m_config.magic_number != (uint32_t)CONFIG_MAGIC_NUMBER_VALUE )
|
||||
{ // first init
|
||||
{
|
||||
DBG_PRINTF("[FDS] FORMAT! overwriting with defaults\r\n");
|
||||
rc = fds_record_delete(&desc);
|
||||
APP_ERROR_CHECK(rc);
|
||||
m_config.magic_number = CONFIG_MAGIC_NUMBER_VALUE;
|
||||
|
||||
// default....
|
||||
fds_default_value_set();
|
||||
fds_default_value_set();
|
||||
|
||||
/* Write the updated record to flash. */
|
||||
rc = fds_record_update(&desc, &m_dummy_record);
|
||||
if( (rc != NRF_SUCCESS) && (rc == FDS_ERR_NO_SPACE_IN_FLASH) )
|
||||
{
|
||||
@@ -317,36 +286,34 @@ void config_load( void )
|
||||
{
|
||||
cfg_load_write_new:
|
||||
DBG_PRINTF("[FDS] New - writing defaults\r\n");
|
||||
/* System config not found (or corrupt); write a new one. */
|
||||
m_config.magic_number = CONFIG_MAGIC_NUMBER_VALUE;
|
||||
|
||||
// default....
|
||||
fds_default_value_set();
|
||||
fds_default_value_set();
|
||||
|
||||
fds_flag_write = true;
|
||||
rc = fds_record_write(&desc, &m_dummy_record);
|
||||
|
||||
|
||||
if (rc != NRF_SUCCESS)
|
||||
{
|
||||
DBG_PRINTF("[FDS] Write ERR=%u\r\n", rc);
|
||||
fds_flag_write = false;
|
||||
}
|
||||
|
||||
fds_wait_cnt = 0; //
|
||||
fds_wait_cnt = 0;
|
||||
|
||||
while(fds_flag_write && fds_wait_cnt < 3000) // FDS write 최대 3초 타임아웃
|
||||
while(fds_flag_write && fds_wait_cnt < 3000) /* 3 second timeout */
|
||||
{
|
||||
nrf_pwr_mgmt_run();
|
||||
nrf_delay_ms(1);
|
||||
fds_wait_cnt++;
|
||||
}
|
||||
|
||||
if(fds_flag_write) // FDS write 타임아웃 시 플래그 강제 해제
|
||||
if(fds_flag_write)
|
||||
{
|
||||
DBG_PRINTF("[FDS] write TIMEOUT! forcing flag clear\r\n");
|
||||
fds_flag_write = false;
|
||||
}
|
||||
|
||||
|
||||
if( (rc != NRF_SUCCESS) && (rc == FDS_ERR_NO_SPACE_IN_FLASH) )
|
||||
{
|
||||
rc = fds_gc();
|
||||
@@ -363,21 +330,19 @@ void config_load( void )
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 현재 설정을 FDS에 저장
|
||||
/*==============================================================================
|
||||
* config_save - Persist current configuration to FDS
|
||||
*
|
||||
* m_config의 내용을 플래시에 기록한다.
|
||||
* Flow:
|
||||
* 1. If a previous FDS write is in progress, wait up to 3 seconds
|
||||
* 2. Fix magic number if needed
|
||||
* 3. If existing record found: fds_record_update()
|
||||
* - On no-space: GC then retry
|
||||
* 4. If not found: fds_record_write() (new record)
|
||||
*
|
||||
* 동작 흐름:
|
||||
* 1. 이전 FDS 쓰기 작업이 진행 중이면 최대 3초 대기
|
||||
* 2. 매직 넘버가 올바르지 않으면 보정
|
||||
* 3. 기존 레코드가 있으면 fds_record_update()로 갱신
|
||||
* - 플래시 공간 부족 시 GC(가비지 컬렉션) 수행 후 재시도
|
||||
* 4. 기존 레코드가 없으면 fds_record_write()로 새로 생성
|
||||
*
|
||||
* 참고: 쓰기 완료는 fds_evt_handler()에서 비동기로 처리되며,
|
||||
* 완료 후 전원 OFF/슬립/리셋 등의 후처리가 수행될 수 있다.
|
||||
*/
|
||||
* Write completion is asynchronous (fds_evt_handler). Post-processing
|
||||
* (power-off / sleep / reset) may follow.
|
||||
*============================================================================*/
|
||||
void config_save( void )
|
||||
{
|
||||
ret_code_t rc;
|
||||
@@ -443,7 +408,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);
|
||||
@@ -455,37 +420,33 @@ void config_save( void )
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief config_load()의 래퍼 함수
|
||||
*
|
||||
* 외부 모듈에서 설정 로드를 요청할 때 사용한다.
|
||||
*/
|
||||
/*==============================================================================
|
||||
* fs_set_value - Wrapper for config_load()
|
||||
*============================================================================*/
|
||||
void fs_set_value(void)
|
||||
{
|
||||
config_load();
|
||||
config_load();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief FDS 초기화
|
||||
/*==============================================================================
|
||||
* fs_storage_init - Initialise FDS
|
||||
*
|
||||
* 부팅 시 호출되어 FDS 모듈을 초기화한다.
|
||||
* 1. fds_register()로 이벤트 핸들러 등록
|
||||
* 2. fds_init()로 FDS 초기화 시작
|
||||
* 3. wait_for_fds_ready()로 초기화 완료 대기 (최대 3초)
|
||||
* 4. fds_stat()로 플래시 상태 확인
|
||||
*/
|
||||
* Called once at boot:
|
||||
* 1. Register event handler
|
||||
* 2. Start FDS initialisation
|
||||
* 3. Wait for completion (up to 3 seconds)
|
||||
* 4. Verify flash stats
|
||||
*============================================================================*/
|
||||
void fs_storage_init(void)
|
||||
{
|
||||
ret_code_t rc;
|
||||
|
||||
/* Register first to receive an event when initialization is complete. */
|
||||
rc = fds_register(fds_evt_handler);
|
||||
APP_ERROR_CHECK(rc);
|
||||
|
||||
rc = fds_init();
|
||||
APP_ERROR_CHECK(rc);
|
||||
|
||||
/* Wait for fds to initialize. */
|
||||
wait_for_fds_ready();
|
||||
|
||||
fds_stat_t stat = { 0 };
|
||||
|
||||
@@ -1,32 +1,25 @@
|
||||
/*******************************************************************************
|
||||
* @file fstorage.h
|
||||
* @author CandyPops Co.
|
||||
* @version V1.0.0
|
||||
* @date 2022-09-05
|
||||
* @brief FDS(Flash Data Storage) 기반 설정 저장 모듈 인터페이스
|
||||
*******************************************************************************
|
||||
/*==============================================================================
|
||||
* fstorage.h - FDS (Flash Data Storage) configuration module interface
|
||||
*
|
||||
* [헤더 개요]
|
||||
* nRF52840 내장 플래시에 디바이스 설정을 저장/로드하는 FDS 모듈의 공용 API.
|
||||
* 외부 EEPROM을 대체하며, SoftDevice와 공존하여 플래시를 안전하게 관리한다.
|
||||
* Stores and loads device configuration to/from the nRF52840 internal flash
|
||||
* via the Nordic FDS library. Replaces external EEPROM and coexists safely
|
||||
* with the SoftDevice.
|
||||
*
|
||||
* [config_data_t 구조체] (45바이트, 패킹됨)
|
||||
* magic_number(4B): 포맷 확인용 (0x20231226)
|
||||
* hw_no(12B): 하드웨어 번호
|
||||
* serial_no(12B): 시리얼 번호 (BLE 디바이스 이름으로도 사용)
|
||||
* static_passkey(6B): BLE 페어링 패스키 (숫자 6자리)
|
||||
* bond_data_delete(1B): 본딩 삭제 플래그
|
||||
* reset_status(1B): 리셋 상태 코드
|
||||
* pd_adc_cnt(1B): ADC 샘플링 횟수
|
||||
* pd_delay_us(2B): PD 안정화 딜레이 (마이크로초)
|
||||
* life_cycle(4B): 디바이스 사용 횟수
|
||||
* config_data_t (48 bytes, packed):
|
||||
* magic_number (4B) : format validation (0x20231226)
|
||||
* hw_no (12B): hardware version string
|
||||
* serial_no (12B): serial number (also used as BLE device name)
|
||||
* static_passkey(6B) : BLE pairing passkey (6-digit numeric)
|
||||
* bond_data_delete(1B): bond-delete flag
|
||||
* reset_status (1B) : reset cause code
|
||||
* life_cycle (4B) : device usage count
|
||||
* piezo_* (8B) : piezo measurement parameters
|
||||
*
|
||||
* [주요 API]
|
||||
* fs_storage_init(): FDS 초기화 (부트 시 1회)
|
||||
* config_load(): FDS에서 설정 로드 (없으면 기본값 생성)
|
||||
* config_save(): 현재 설정을 FDS에 저장
|
||||
*
|
||||
******************************************************************************/
|
||||
* API:
|
||||
* fs_storage_init() : initialise FDS (once at boot)
|
||||
* config_load() : load config from FDS (creates defaults if absent)
|
||||
* config_save() : persist current config to FDS
|
||||
*============================================================================*/
|
||||
|
||||
#ifndef IHP_FSTORAGE_H_
|
||||
#define IHP_FSTORAGE_H_
|
||||
@@ -36,21 +29,21 @@
|
||||
#include "nordic_common.h"
|
||||
#include <stdint.h>
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* 기본 버전 정보 (FDS 기본값 및 빈 필드 복구 시 사용)
|
||||
*
|
||||
* 하드웨어 식별 코드
|
||||
* - VBTHW0100 = 개발(시험)용 Ver 1.00
|
||||
* - VB0HW0100 = 양산용 Ver 1.00
|
||||
*
|
||||
* Firmware 식별 코드
|
||||
* - VBTFW0100 = 개발(시험)용 Ver 1.00
|
||||
* - VB0FW0100 = 양산용 Ver 1.00
|
||||
*
|
||||
* 시리얼 넘버 식별 코드
|
||||
* - VBT26030001 = 개발(시험)용 26년 3월 생산 1번
|
||||
* - VB026030001 = 양산용 26년 3월 생산 1번
|
||||
------------------------------------------------------------------------- */
|
||||
/*------------------------------------------------------------------------------
|
||||
* Default version identifiers (used for FDS defaults / empty field recovery)
|
||||
*
|
||||
* Hardware ID:
|
||||
* VBTHW0100 = development / test Ver 1.00
|
||||
* VB0HW0100 = production Ver 1.00
|
||||
*
|
||||
* Firmware ID:
|
||||
* VBTFW0100 = development / test Ver 1.00
|
||||
* VB0FW0100 = production Ver 1.00
|
||||
*
|
||||
* Serial number:
|
||||
* VBT26030001 = dev/test, manufactured Mar 2026, unit #1
|
||||
* VB026030001 = production, Mar 2026, unit #1
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define HARDWARE_VERSION "VBTHW0100"
|
||||
#define SERIAL_NUMBER "VBT26030001"
|
||||
#define DEFAULT_PASSKEY "123456"
|
||||
@@ -58,21 +51,21 @@
|
||||
#pragma pack(1)
|
||||
typedef struct
|
||||
{
|
||||
uint32_t magic_number; /* 4B - 포맷 확인용 매직 넘버 */
|
||||
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 */
|
||||
uint32_t life_cycle; /* 4B - Device usage count */
|
||||
uint32_t magic_number; /* 4B - format validation magic */
|
||||
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 */
|
||||
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 - 평균화 수 : 채널당 반복 측정 횟수 (1~10) */
|
||||
uint16_t piezo_delay_us; /* 2B - 대기 시간(Delay) : 송신 펄스 출력 후 ADC 시작 시까지 대기시간 (us) (0~30) */
|
||||
uint16_t piezo_num_samples; /* 2B - 측정 ADC 샘플 개수 (80~140) */
|
||||
} config_data_t; /* Total: 48 bytes - FDS에 저장하는 디바이스 설정 */
|
||||
/* Piezo measurement parameters - 8B */
|
||||
uint8_t piezo_freq_option; /* 1B - TX pulse frequency (0=1.8M, 1=2.1M, 2=2.0M, 3=1.7M) */
|
||||
uint8_t piezo_cycles; /* 1B - burst pulse cycle count (3..7) */
|
||||
uint16_t piezo_averaging; /* 2B - averages per channel (1..10) */
|
||||
uint16_t piezo_delay_us; /* 2B - delay from TX pulse to ADC start (us) (0..30) */
|
||||
uint16_t piezo_num_samples; /* 2B - ADC sample count (80..140) */
|
||||
} config_data_t; /* Total: 48 bytes */
|
||||
|
||||
extern config_data_t m_config;
|
||||
|
||||
@@ -84,4 +77,3 @@ void fs_set_value(void);
|
||||
void fs_storage_init(void);
|
||||
|
||||
#endif /* IHP_FSTORAGE_H_ */
|
||||
|
||||
|
||||
@@ -1,29 +1,18 @@
|
||||
/*******************************************************************************
|
||||
* @file i2c_manager.c
|
||||
* @brief Reliable HW↔SW I2C Switching Logic (with Mode Set Logging)
|
||||
*******************************************************************************
|
||||
/*==============================================================================
|
||||
* i2c_manager.c - HW / SW I2C mutex switching logic
|
||||
*
|
||||
* [모듈 개요]
|
||||
* I2C 버스의 HW(하드웨어 TWI) / SW(소프트웨어 비트뱅) 모드 전환을 관리하는 모듈.
|
||||
* Manages mutually-exclusive HW (TWI peripheral) and SW (bit-bang) I2C modes.
|
||||
*
|
||||
* - HW I2C: nRF52840 내장 TWI 하드웨어 주변장치를 사용 (ICM42670P IMU 센서 통신용, 400kHz)
|
||||
* - SW I2C: GPIO 비트뱅 방식의 소프트웨어 I2C (현재 사용하지 않는 레거시 코드)
|
||||
* HW I2C : nRF52840 TWI hardware, 400 kHz Fast Mode (ICM42670P IMU)
|
||||
* SW I2C : GPIO bit-bang (legacy, currently unused)
|
||||
*
|
||||
* [핀 설정]
|
||||
* Pins:
|
||||
* SCL = P1.14 (ICM42670_I2C_SCL_PIN)
|
||||
* SDA = P1.15 (ICM42670_I2C_SDA_PIN)
|
||||
*
|
||||
* [주요 함수]
|
||||
* hw_i2c_init_once() : SW→HW 전환 또는 HW 초기화 (이미 HW 모드면 중복 초기화 방지)
|
||||
* sw_i2c_init_once() : HW→SW 전환 (TWI 해제 후 SW 모드 진입, 레거시)
|
||||
* i2c_reset_state() : 모든 I2C 모드 플래그를 초기화 (HW/SW 모두 false)
|
||||
*
|
||||
* [동작 원리]
|
||||
* HW_I2C_FRQ, SW_I2C_FRQ 두 개의 bool 플래그로 현재 모드를 추적하며,
|
||||
* 한 번에 하나의 모드만 활성화되도록 상호 배제(mutex) 방식으로 관리한다.
|
||||
* 모드 전환 시 기존 모드의 리소스를 먼저 해제한 후 새 모드를 초기화한다.
|
||||
*
|
||||
******************************************************************************/
|
||||
* The two bool flags HW_I2C_FRQ and SW_I2C_FRQ track the current mode.
|
||||
* Switching releases the old mode's resources before initialising the new one.
|
||||
*============================================================================*/
|
||||
|
||||
#include "i2c_manager.h"
|
||||
#include "debug_print.h"
|
||||
@@ -34,137 +23,101 @@
|
||||
#include "boards.h"
|
||||
#include "system_interface.h"
|
||||
|
||||
/* 현재 I2C 모드 상태 플래그 (true = 해당 모드 활성화) */
|
||||
bool HW_I2C_FRQ = true; /* HW TWI 모드 활성 여부 (기본값: true, 초기 상태는 HW) */
|
||||
bool SW_I2C_FRQ = false; /* SW 비트뱅 모드 활성 여부 */
|
||||
/* Current I2C mode flags */
|
||||
bool HW_I2C_FRQ = true;
|
||||
bool SW_I2C_FRQ = false;
|
||||
|
||||
/* TWI 인스턴스 번호 (nRF52840은 TWI0, TWI1 두 개 지원) */
|
||||
/* TWI instance (nRF52840 supports TWI0 and TWI1) */
|
||||
#define TWI_INSTANCE 0
|
||||
|
||||
/* TWI (I2C) 하드웨어 인스턴스 : IMU 드라이버에서 사용 - jhChun 26.03.16 */
|
||||
const nrfx_twi_t m_twi = NRFX_TWI_INSTANCE(TWI_INSTANCE);
|
||||
|
||||
/* TWI (I2C) 해제 - jhChun 26.03.16 */
|
||||
/* TWI 하드웨어를 비활성화하고 초기화 해제하여 GPIO 핀을 반환한다 */
|
||||
static void twi_uninitialize(void){
|
||||
nrfx_twi_disable(&m_twi); /* TWI 주변장치 비활성화 */
|
||||
nrfx_twi_uninit(&m_twi); /* TWI 초기화 해제 (핀 리소스 반환) */
|
||||
/* Disable and uninitialise the TWI peripheral, releasing GPIO pins. */
|
||||
static void twi_uninitialize(void)
|
||||
{
|
||||
nrfx_twi_disable(&m_twi);
|
||||
nrfx_twi_uninit(&m_twi);
|
||||
}
|
||||
|
||||
/* TWI (I2C) 하드웨어 초기화 (SCL/SDA핀, 400kHz) - jhChun 26.03.16 */
|
||||
/* SCL, SDA 핀을 설정하고 400kHz Fast Mode로 TWI를 초기화 및 활성화한다 */
|
||||
/* Initialise the TWI peripheral (SCL/SDA pins, 400 kHz, blocking mode). */
|
||||
static void twi_initialize(void){
|
||||
ret_code_t err_code;
|
||||
|
||||
/* TWI 설정 구조체: 핀 번호, 클럭 속도, 인터럽트 우선순위 지정 */
|
||||
const nrfx_twi_config_t twi_config = {
|
||||
.scl = ICM42670_I2C_SCL_PIN, /* SCL 핀 (P1.14) */
|
||||
.sda = ICM42670_I2C_SDA_PIN, /* SDA 핀 (P1.15) */
|
||||
.frequency = NRF_TWI_FREQ_400K, /* 400kHz Fast Mode */
|
||||
.interrupt_priority = APP_IRQ_PRIORITY_HIGH, /* 높은 인터럽트 우선순위 */
|
||||
.scl = ICM42670_I2C_SCL_PIN,
|
||||
.sda = ICM42670_I2C_SDA_PIN,
|
||||
.frequency = NRF_TWI_FREQ_400K,
|
||||
.interrupt_priority = APP_IRQ_PRIORITY_HIGH,
|
||||
};
|
||||
|
||||
/* TWI 초기화 (이벤트 핸들러 NULL = 블로킹 모드) */
|
||||
err_code = nrfx_twi_init(&m_twi, &twi_config, NULL, NULL);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
nrfx_twi_enable(&m_twi); /* TWI 주변장치 활성화 → I2C 통신 가능 */
|
||||
nrfx_twi_enable(&m_twi);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* HW (TWI) 초기화 */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/*
|
||||
* HW I2C 모드로 전환하거나 초기화하는 함수.
|
||||
* - SW 모드가 활성화되어 있으면 SW 플래그를 해제하고 HW로 전환
|
||||
* - 이미 HW 모드이면 중복 초기화를 방지하여 바로 리턴
|
||||
* - 최초 HW 초기화 시 twi_initialize()를 호출하여 TWI 하드웨어 설정
|
||||
*/
|
||||
/*==============================================================================
|
||||
* hw_i2c_init_once - Switch to or initialise HW TWI mode
|
||||
*
|
||||
* If SW mode is active, its flag is cleared first.
|
||||
* If HW mode is already active, returns immediately (no re-init).
|
||||
*============================================================================*/
|
||||
void hw_i2c_init_once(void)
|
||||
{
|
||||
// SW 모드일 경우 강제 해제 후 HW 전환
|
||||
if (SW_I2C_FRQ)
|
||||
{
|
||||
//DBG_PRINTF("[I2C]SW→HW\r\n");
|
||||
|
||||
// SW 리소스 해제 (필요 시 추가)
|
||||
SW_I2C_FRQ = false;
|
||||
nrf_delay_ms(2); /* 모드 전환 안정화 대기 (2ms) */
|
||||
nrf_delay_ms(2); /* mode-switch settling */
|
||||
}
|
||||
|
||||
/* 이미 HW 모드가 활성화되어 있으면 중복 초기화 방지를 위해 즉시 리턴 */
|
||||
// 이미 HW면 스킵
|
||||
if (HW_I2C_FRQ)
|
||||
{
|
||||
// DBG_PRINTF("[I2C] HW I2C set\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* HW TWI 하드웨어 초기화 수행 (SCL/SDA 핀 설정, 400kHz, 활성화) */
|
||||
// 실제 HW 초기화
|
||||
twi_initialize();
|
||||
nrf_delay_ms(2); /* 초기화 후 안정화 대기 (2ms) */
|
||||
nrf_delay_ms(2);
|
||||
|
||||
/* 모드 플래그 갱신: HW 활성, SW 비활성 */
|
||||
HW_I2C_FRQ = true;
|
||||
SW_I2C_FRQ = false;
|
||||
|
||||
// DBG_PRINTF("[I2C] HW I2C Mode set!\r\n");
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* SW (Port Bang-Bang) 초기화 */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/*
|
||||
* SW I2C(비트뱅) 모드로 전환하는 함수. (현재 레거시, 사용하지 않음)
|
||||
* - HW 모드가 활성화되어 있으면 TWI를 해제하고 SW로 전환
|
||||
* - 이미 SW 모드이면 중복 초기화를 방지하여 바로 리턴
|
||||
* - power_control.c의 power_loop()에서 Step 0에서 호출됨
|
||||
*/
|
||||
/*==============================================================================
|
||||
* sw_i2c_init_once - Switch to SW bit-bang mode (legacy, unused)
|
||||
*
|
||||
* If HW mode is active, TWI is released first.
|
||||
* If SW mode is already active, returns immediately.
|
||||
*============================================================================*/
|
||||
void sw_i2c_init_once(void)
|
||||
{
|
||||
// HW 모드일 경우 강제 해제 후 SW 전환
|
||||
if (HW_I2C_FRQ)
|
||||
{
|
||||
//DBG_PRINTF("[I2C]HW→SW\r\n");
|
||||
|
||||
nrfx_twi_disable(&m_twi); /* TWI 비활성화 */
|
||||
nrfx_twi_uninit(&m_twi); /* TWI 초기화 해제 */
|
||||
nrf_delay_ms(2); /* 모드 전환 안정화 대기 (2ms) */
|
||||
|
||||
nrfx_twi_disable(&m_twi);
|
||||
nrfx_twi_uninit(&m_twi);
|
||||
nrf_delay_ms(2);
|
||||
HW_I2C_FRQ = false;
|
||||
}
|
||||
|
||||
// 이미 SW 모드면 재실행 금지
|
||||
if (SW_I2C_FRQ)
|
||||
{
|
||||
// DBG_PRINTF("[I2C] SWI2C already initialized\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* TWI 라인 완전 해제 후 SW 비트뱅 모드 진입 */
|
||||
// 실제 SW 초기화
|
||||
twi_uninitialize(); // TWI 라인 해제
|
||||
nrf_delay_ms(1); /* 해제 후 안정화 대기 (1ms) */
|
||||
twi_uninitialize();
|
||||
nrf_delay_ms(1);
|
||||
|
||||
/* 모드 플래그 갱신: SW 활성, HW 비활성 */
|
||||
SW_I2C_FRQ = true;
|
||||
HW_I2C_FRQ = false;
|
||||
|
||||
// DBG_PRINTF("[I2C] SW I2C Mode set!\r\n");
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* 전체 리셋 */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/*
|
||||
* 모든 I2C 모드 플래그를 초기화하는 함수.
|
||||
* HW/SW 모두 비활성 상태로 만들어, 다음 init 호출 시 강제로 재초기화되도록 한다.
|
||||
* 주로 시스템 리셋이나 에러 복구 시 사용.
|
||||
*/
|
||||
/*==============================================================================
|
||||
* i2c_reset_state - Clear all mode flags
|
||||
*
|
||||
* Forces re-initialisation on the next init call. Used for system reset
|
||||
* or error recovery.
|
||||
*============================================================================*/
|
||||
void i2c_reset_state(void)
|
||||
{
|
||||
HW_I2C_FRQ = false; /* HW 모드 플래그 초기화 */
|
||||
SW_I2C_FRQ = false; /* SW 모드 플래그 초기화 */
|
||||
HW_I2C_FRQ = false;
|
||||
SW_I2C_FRQ = false;
|
||||
DBG_PRINTF("Flags reset\r\n");
|
||||
}
|
||||
|
||||
@@ -1,50 +1,31 @@
|
||||
/*******************************************************************************
|
||||
* @file i2c_manager.h
|
||||
* @brief Common header for HW/SW I2C mutex control
|
||||
*******************************************************************************
|
||||
/*==============================================================================
|
||||
* i2c_manager.h - HW / SW I2C mutex control
|
||||
*
|
||||
* [헤더 개요]
|
||||
* I2C 버스 HW/SW 모드 전환 관리자의 공용 인터페이스 헤더.
|
||||
* Manages the mutually-exclusive HW TWI and SW bit-bang I2C modes.
|
||||
* Only one mode may be active at a time.
|
||||
*
|
||||
* - HW_I2C_FRQ: HW TWI 모드 활성 여부 (true = HW I2C 사용 중)
|
||||
* - SW_I2C_FRQ: SW 비트뱅 모드 활성 여부 (true = SW I2C 사용 중)
|
||||
*
|
||||
* 두 플래그는 상호 배제적으로 동작하며, 동시에 true가 되지 않도록 관리된다.
|
||||
*
|
||||
******************************************************************************/
|
||||
* Flags:
|
||||
* HW_I2C_FRQ : true when HW TWI mode is active
|
||||
* SW_I2C_FRQ : true when SW bit-bang mode is active
|
||||
*============================================================================*/
|
||||
#ifndef __I2C_MANAGER_H__
|
||||
#define __I2C_MANAGER_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "app_error.h"
|
||||
|
||||
/* I2C 모드 상태 플래그 (외부 참조용) */
|
||||
extern bool HW_I2C_FRQ; /* HW TWI 모드 활성 여부 */
|
||||
extern bool SW_I2C_FRQ; /* SW 비트뱅 모드 활성 여부 */
|
||||
extern bool HW_I2C_FRQ;
|
||||
extern bool SW_I2C_FRQ;
|
||||
|
||||
/**
|
||||
* @brief HW I2C(TWI) 모드 초기화 (중복 초기화 방지)
|
||||
*
|
||||
* SW 모드가 활성화되어 있으면 해제 후 HW로 전환한다.
|
||||
* 이미 HW 모드이면 아무 동작 없이 리턴한다.
|
||||
* ICM42670P IMU 센서 통신 전에 호출하여 HW I2C를 준비한다.
|
||||
*/
|
||||
/* Initialise HW I2C (TWI) mode. If SW mode is active it is released first.
|
||||
* No-op if HW mode is already active. Call before ICM42670P IMU access. */
|
||||
void hw_i2c_init_once(void);
|
||||
|
||||
/**
|
||||
* @brief SW I2C(비트뱅) 모드 초기화 (레거시, 현재 미사용)
|
||||
*
|
||||
* HW 모드가 활성화되어 있으면 TWI를 해제한 후 SW로 전환한다.
|
||||
* 이미 SW 모드이면 아무 동작 없이 리턴한다.
|
||||
*/
|
||||
/* Initialise SW I2C (bit-bang) mode (legacy, currently unused).
|
||||
* If HW mode is active it is released first. */
|
||||
void sw_i2c_init_once(void);
|
||||
|
||||
/**
|
||||
* @brief I2C 모드 플래그 전체 초기화
|
||||
*
|
||||
* HW_I2C_FRQ, SW_I2C_FRQ를 모두 false로 리셋한다.
|
||||
* 다음 init 호출 시 강제로 재초기화가 수행된다.
|
||||
*/
|
||||
/* Reset both mode flags to false, forcing re-initialisation on next call. */
|
||||
void i2c_reset_state(void);
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user