티스토리 뷰

1. [주요 내용 1] 개별 오류 상세 분석 (제목, 원인, 방지 방법)

① 데이터 전송(HTTP POST) 무한 블로킹

  • 원인: 서버로 계측 데이터를 업로드하는 sendData, sendBatchData, createTable 등의 함수에서 HTTPClient 객체의 타임아웃(http.setTimeout) 설정이 누락되었습니다. 네트워크 불안정이나 TLS 핸드셰이크 지연 발생 시 소켓 수신 대기 상태에 걸려 태스크가 영구 정지합니다.
  • 현재 코드 내 구현: 텔레그램 전송 함수(sendTelegramDirect 등)와 pingServer에는 각각 2.5초~5초의 타임아웃이 개별 설정되어 있으나, 핵심 데이터 업로드에는 누락되어 있었습니다.
  • 방지 방법 (구현 계획서 반영): NetworkManager.cpp 내의 모든 http.POST 호출 직전에 차등 타임아웃(일반 데이터 3초, 배치/OTA 10초) 설정을 일괄 추가하여 네트워크 단절 시 강제로 대기를 풀고 에러로 복귀시킵니다.

② BLE 수집 루틴(isBLETransferActive) 고착으로 인한 안전 가드 우회

  • 원인: BLETask가 슬레이브 연결 및 통신 중 알 수 없는 드라이버 고착에 빠질 경우, isBLETransferActive 플래그가 true 상태로 영구 락업됩니다. 이로 인해 NetworkTask FSM 루프 최상단에서 매번 continue로 우회하여 루프 최하단의 힙 감시 및 미복구 재부팅 로직이 동작하지 못합니다.
  • 현재 코드 내 구현: BLETask 연결 해제 시 oldDeviceConnected 감지 및 리소스 자동 해제(delete[] secureTxPayload) 로직이 들어가 있으나, 연결 실패 시 플래그 락 자체에 대한 타임아웃 가드는 부재했습니다.
  • 방지 방법 (구현 계획서 반영): NetworkTask 루프 내 플래그 감시 영역에 60초 소프트웨어 타임아웃 가드를 도입하여, 60초 이상 BLE 작업이 멈춰있으면 플래그를 강제로 false로 리셋하고 안전 감시 로직이 돌 수 있도록 구제합니다.

③ BLE 콜백 함수(notifyCallback) 실행 시 스택 오버플로우

  • 원인: 슬레이브로부터 알림을 받는 notifyCallback 내부에 uint8_t decrypted[2048] (2KB) 및 JSON 도큐먼트 등 대용량 변수가 스택 영역에 선언되어 있습니다. 이 콜백은 스택 크기가 보통 4~6KB로 매우 타이트한 Bluedroid 드라이버 호스트 태스크 상에서 구동되어 스택 오버플로우와 조용한 메모리 오염을 유발합니다.
  • 현재 코드 내 구현: 복호화 및 HMAC 매핑 검증 로직은 철저하게 구현되어 있으나, 스택 메모리 할당 제한을 고려하지 못했습니다.
  • 방지 방법 (구현 계획서 반영): 스택 영역을 보존하기 위해 해당 버퍼에 static 지시어를 추가하여 데이터(BSS) 영역으로 이전하고 사용 시 memset으로 리셋하도록 수정합니다.

④ vTaskSuspend() 호출 시 프리RTOS 힙 락(Heap Lock) 데드락

  • 원인: OTA 진입 시 또는 텔레그램 전송 실패 등의 상황에서 다른 코어의 BLETask나 InstrumentTask를 강제 정지하기 위해 vTaskSuspend를 호출합니다. 만약 해당 태스크가 동적 메모리 할당(new/delete/String) 중 힙 락(Heap Lock/Spinlock)을 획득한 순간 일시 정지되면, 다른 태스크가 메모리를 할당하려고 할 때 영구 데드락(Hard Freeze)에 걸립니다.
  • 현재 코드 내 구현: 태스크 중단 전 bleMutex를 확보하여 안전성을 지키려 했으나, 힙 락 자체는 프리RTOS 내부의 일이므로 뮤텍스로 완전 방어가 불가능했습니다.
  • 방지 방법 (구현 계획서 반영): 태스크를 강제 중지하는 대신 sysState.requestBLETaskPause = true와 같은 플래그를 두고, 대상 태스크가 메모리 할당이 없는 안전한 루프 시작부에서 스스로 일시 대기하도록 하는 협력적 일시 정지(Cooperative Pause) 방식을 전면 도입합니다.

⑤ 큐 자원(UploadDataQueue) 동시 접근으로 인한 메모리 파손

  • 원인: std::vector<cDataInfo> UploadDataQueue 객체를 아두이노 메인 loopTask와 센서 스캔 InstrumentTask가 각각 동시에 push_back 및 erase로 조작합니다. std::vector는 스레드 안전하지 않으므로 데이터 경쟁에 의해 힙 포인터가 손상되고 시스템이 불시에 다운됩니다.
  • 현재 코드 내 구현: I2C 통신 자체는 i2cMutex로 상호 배제되어 보호되고 있으나, 이 데이터 벡터 조작 시에는 락이 누락되었습니다.
  • 방지 방법 (구현 계획서 반영): 해당 벡터를 조작하는 ChangeTesterMode, GetUploadDataInfo, MakeUploadDataInfo 함수 내부에 재귀형 i2cMutex 락 획득/해제 절차를 명시적으로 둘러씌워 임계 영역을 동기화합니다.

⑥ NVS 설정 데이터 비정상 인입 시의 자가 복구 가드

  • 상황/원인: 기기가 직접 파싱되지 않는 손상된 NVS(Non-Volatile Storage) 영역에 직면하거나 오염된 IP/URL 값이 주입되어 부팅 시 HTTPClient::begin() 등에서 크래시가 발생하는 위험이 있습니다.
  • 현재 코드 내 구현: ESP32의 NVS(Preferences) 드라이버 자체에 NVS 포맷 손상 시 자동 포맷 기능이 활성화되어 있어 파티션 오염으로 인한 무한 락업은 하부 레벨에서 예방됩니다.
  • 방지 방법 (구현 계획서 반영): 무결성 확보를 위해 NetworkManager.cpp에서 설정된 URL 수신 시 프로토콜 시작 조건(startsWith("http"))을 철저히 매핑하여 잘못된 설정 주입 시에도 커널 크래시를 우회하도록 구성하였습니다.

⑦ OTA 진행 시 왓치독(TWDT) 강제 리셋으로 인한 벽돌화 (Bricking)

  • 원인: NetworkTask가 감시용 왓치독에 등록되어 있는 상태에서 OTA 펌웨어 쓰기가 실행되면, 바이너리 다운로드 및 대형 플래시 쓰기 작업으로 인해 태스크가 10~30초간 블로킹됩니다. 이로 인해 왓치독 타임아웃(8초)을 초과하게 되어 플래시 메모리 쓰기 도중 기기가 강제 리셋되는 하드웨어 벽돌화 현상이 동반됩니다.
  • 현재 코드 내 구현: OTA 수행 전 다른 두 태스크(BLETask, InstrumentTask)만 일시 정지(Suspend)시켰을 뿐, 실행 주체 태스크의 왓치독 감시 해제 조치는 존재하지 않았습니다.
  • 방지 방법 (구현 계획서 반영): OTAManager.cpp에서 협력적 일시 정지가 최종 성립된 직후 esp_task_wdt_delete(NULL)을 명시적으로 실행하여 실행 태스크를 왓치독 감시에서 제외하고, OTA 실패 복구 시 esp_task_wdt_add(NULL)로 감시망에 복귀시킵니다.

 

comprehensive_error_analysis.pdf
0.62MB

반응형
반응형
250x250
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2026/07   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함