SHT30 온습도 모니터링 시스템 전체 소스(서버 PHP, STM32 펌웨어, SQL, 테스트). 전체 코드리뷰에서 도출된 보안 하드닝 10건 반영: - 요청 서명 HMAC-SHA256 전환(펌웨어 sig.c/서버 config.php/호스트 패리티 동시) - 재전송 방어 + 기본 API_KEY fail-closed + 디바이스 문자열 정제(api/sensor_data.php) - 오프라인 SMS 중복 발송 경합 제거(cron_heartbeat.php, 원자적 선점) - CSV 수식 주입 방지(monthly_report.php), 감사로그 회전 락(retention_cleanup.php) - 브루트포스 카운터 원자화(login.php), 예시 TOTP 비밀키 무효화, 마이그레이션 멱등화 _backup/(하드코딩 실 비밀값 포함)·config.local.php·런타임 상태는 .gitignore 제외.
283 lines
14 KiB
CMake
283 lines
14 KiB
CMake
# =============================================================================
|
|
# CMakeLists.txt - SHT30 온습도 모니터링 STM32F407 펌웨어
|
|
#
|
|
# 타깃:
|
|
# sht30_fw : SHT30 온습도 보드(-DBOARD_SHT30, sensor_id=2) board_sht30/*
|
|
#
|
|
# 스택: STM32CubeF4 HAL + CMSIS / FreeRTOS-Kernel(네이티브 API) / LwIP / mbedTLS.
|
|
# 전부 firmware/third_party 아래에 "벤더링"되어 있어야 한다(폐쇄망 — 빌드/런타임
|
|
# 모두 네트워크 금지). 벤더링은 networked 빌드 머신에서 scripts/vendor.{ps1,sh}
|
|
# 로 1회 수행한다.
|
|
#
|
|
# 구성(configure):
|
|
# cmake -S firmware -B firmware/build -G Ninja \
|
|
# -DCMAKE_TOOLCHAIN_FILE=firmware/cmake/arm-none-eabi-toolchain.cmake \
|
|
# -DCMAKE_BUILD_TYPE=Release
|
|
# cmake --build firmware/build
|
|
#
|
|
# 산출물(타깃별): <name>.elf / <name>.bin / <name>.hex / <name>.map + 크기 출력.
|
|
# =============================================================================
|
|
cmake_minimum_required(VERSION 3.20)
|
|
|
|
# 툴체인 파일 없이 호스트 컴파일러로 들어오는 사고 방지(친절한 에러).
|
|
if(NOT CMAKE_TOOLCHAIN_FILE AND NOT CMAKE_CROSSCOMPILING)
|
|
message(WARNING
|
|
"툴체인 파일이 지정되지 않았습니다. arm-none-eabi 크로스 빌드를 위해 "
|
|
"-DCMAKE_TOOLCHAIN_FILE=cmake/arm-none-eabi-toolchain.cmake 를 사용하세요.")
|
|
endif()
|
|
|
|
project(sht30_sensor_fw
|
|
VERSION 26.6.0
|
|
DESCRIPTION "STM32F407 SHT30 temperature/humidity sensor firmware (air-gapped)"
|
|
LANGUAGES C ASM)
|
|
|
|
set(CMAKE_C_STANDARD 11)
|
|
set(CMAKE_C_STANDARD_REQUIRED ON)
|
|
|
|
if(NOT CMAKE_BUILD_TYPE)
|
|
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Build type" FORCE)
|
|
endif()
|
|
|
|
# 크기/성능 균형: -Os(크기 최적화) + 디버그 심볼(.elf 에만, .bin 비대화 없음).
|
|
set(CMAKE_C_FLAGS_RELEASE "-Os -g")
|
|
set(CMAKE_C_FLAGS_RELWITHDEBINFO "-Os -g")
|
|
set(CMAKE_C_FLAGS_DEBUG "-Og -g3")
|
|
|
|
# =============================================================================
|
|
# 경로 변수
|
|
# =============================================================================
|
|
set(FW_ROOT "${CMAKE_CURRENT_SOURCE_DIR}")
|
|
set(FW_COMMON "${FW_ROOT}/common")
|
|
set(FW_CONFIG "${FW_ROOT}/config")
|
|
set(FW_CERTS "${FW_ROOT}/certs")
|
|
set(FW_LD "${FW_ROOT}/ld/STM32F407VGTx_FLASH.ld")
|
|
set(TP "${FW_ROOT}/third_party") # 벤더링 루트 (폐쇄망)
|
|
|
|
# 벤더 트리 (scripts/vendor.* 가 채운다). 핀 고정 버전 가정.
|
|
# TODO(vendor): 아래 하위 경로/파일명은 핀 고정 버전에 맞춰 vendor 스크립트와
|
|
# 동기화할 것. 버전이 바뀌면 GLOB 결과 및 startup/포트 경로가 달라질 수 있다.
|
|
set(CUBE "${TP}/STM32CubeF4")
|
|
set(CMSIS "${CUBE}/Drivers/CMSIS")
|
|
set(HAL "${CUBE}/Drivers/STM32F4xx_HAL_Driver")
|
|
set(FREERTOS "${TP}/FreeRTOS-Kernel")
|
|
set(LWIP "${TP}/lwip")
|
|
set(MBEDTLS "${TP}/mbedtls")
|
|
|
|
# 벤더 트리 부재/미벤더링 시 configure 단계에서 명확히 안내한다.
|
|
# third_party 디렉터리 자체가 없거나, 디렉터리는 있으나 각 의존성 트리가 아직
|
|
# 없으면(README 만 있는 미벤더링 상태) "Cannot find source file" 같은 모호한
|
|
# 에러 대신 친절한 안내를 띄운다.
|
|
set(_vendor_missing "")
|
|
foreach(_v "${CUBE}" "${FREERTOS}" "${LWIP}" "${MBEDTLS}")
|
|
if(NOT EXISTS "${_v}")
|
|
list(APPEND _vendor_missing "${_v}")
|
|
endif()
|
|
endforeach()
|
|
if(_vendor_missing)
|
|
string(REPLACE ";" "\n " _vendor_missing_str "${_vendor_missing}")
|
|
message(FATAL_ERROR
|
|
"벤더링되지 않은 의존성이 있습니다(폐쇄망 빌드 전 벤더링 필요).\n"
|
|
" 누락:\n ${_vendor_missing_str}\n"
|
|
" networked 빌드 머신에서 먼저 실행하세요:\n"
|
|
" pwsh firmware/scripts/vendor.ps1 (또는 firmware/scripts/vendor.sh)")
|
|
endif()
|
|
|
|
# =============================================================================
|
|
# 컴파일 정의 (전 타깃 공통)
|
|
# =============================================================================
|
|
# STM32F407xx : CMSIS 디바이스 선택
|
|
# USE_HAL_DRIVER : HAL 활성화
|
|
# (USE_FULL_LL_DRIVER 는 정의하지 않음 → LL 미사용)
|
|
# MBEDTLS_CONFIG_FILE: 메모리 절약형 mbedtls 설정(firmware/common 또는 config 에 위치)
|
|
set(COMMON_DEFS
|
|
STM32F407xx
|
|
USE_HAL_DRIVER
|
|
MBEDTLS_CONFIG_FILE="mbedtls_config.h"
|
|
)
|
|
|
|
# =============================================================================
|
|
# 인클루드 디렉터리 (전 타깃 공통)
|
|
# - 프로젝트 헤더: common(컨트랙트), config(FreeRTOSConfig/lwipopts/mbedtls_config),
|
|
# certs(server_ca)
|
|
# - 벤더 헤더: CMSIS, HAL Inc, FreeRTOS include + portable/GCC/ARM_CM4F,
|
|
# lwip src/include, mbedtls include
|
|
#
|
|
# 참고: mbedtls_config.h / lwipopts.h / stm32f4xx_hal_conf.h 는 프로젝트 측
|
|
# config 또는 common 에 둔다(타 서브에이전트 산출). 두 경로 모두 추가하여
|
|
# 배치 위치에 무관하게 찾도록 한다. TODO(hw): 실제 배치 확정 시 한 곳으로 정리.
|
|
# =============================================================================
|
|
set(COMMON_INCLUDES
|
|
${FW_COMMON}
|
|
${FW_CONFIG}
|
|
${FW_CERTS}
|
|
|
|
# ── CMSIS / HAL ──────────────────────────────────────────────────────────
|
|
${CMSIS}/Include
|
|
${CMSIS}/Device/ST/STM32F4xx/Include
|
|
${HAL}/Inc
|
|
${HAL}/Inc/Legacy
|
|
|
|
# ── FreeRTOS (네이티브 API) ──────────────────────────────────────────────
|
|
${FREERTOS}/include
|
|
${FREERTOS}/portable/GCC/ARM_CM4F
|
|
|
|
# ── LwIP ─────────────────────────────────────────────────────────────────
|
|
${LWIP}/src/include
|
|
${LWIP}/src/include/lwip
|
|
${LWIP}/src/include/netif
|
|
# LwIP 의 sys_arch/cc.h 포트 헤더(FreeRTOS 통합)는 프로젝트 port 에 둔다.
|
|
# TODO(hw): lwip port(sys_arch.c + arch/cc.h, sys_arch.h) 경로 확정 시 추가.
|
|
# 기본 후보: ${FW_ROOT}/net/lwip_port 또는 ${FW_CONFIG}
|
|
${LWIP}/contrib/ports/freertos/include
|
|
|
|
# ── mbedTLS ──────────────────────────────────────────────────────────────
|
|
${MBEDTLS}/include
|
|
)
|
|
|
|
# =============================================================================
|
|
# 소스 수집
|
|
# =============================================================================
|
|
|
|
# ── (A) 검증된 포터블 코어 + 모든 공통 모듈 .c ──────────────────────────────
|
|
# common/*.c 를 GLOB 한다. 검증 코어(sha256_sw/hexutil/sig/jsonbody/sht30_convert/
|
|
# httpapi)와 보드 무관 모듈(reporter/sht30/bsp 등)이 모두 포함된다.
|
|
# CONFIGURE_DEPENDS: 새 .c 추가 시 재구성 트리거(개발 편의).
|
|
file(GLOB COMMON_SOURCES CONFIGURE_DEPENDS "${FW_COMMON}/*.c")
|
|
|
|
# 임베드된 서버 CA(PEM → C 배열).
|
|
list(APPEND COMMON_SOURCES "${FW_CERTS}/server_ca.c")
|
|
|
|
# ── (B) 벤더: CMSIS startup(어셈블리) + system 초기화 ───────────────────────
|
|
# startup 은 GCC 변형(Templates/gcc) 사용. 정확한 경로는 벤더 버전에 따라 다름.
|
|
# TODO(vendor): 핀 고정 CubeF4 의 startup/system 경로를 확인하여 갱신.
|
|
set(STARTUP_S "${CMSIS}/Device/ST/STM32F4xx/Source/Templates/gcc/startup_stm32f407xx.s")
|
|
set(SYSTEM_C "${CMSIS}/Device/ST/STM32F4xx/Source/Templates/system_stm32f4xx.c")
|
|
|
|
# ── (C) 벤더: STM32F4xx HAL 드라이버 ────────────────────────────────────────
|
|
# 필요한 HAL 모듈만 컴파일하면 크기/시간이 줄지만, 의존이 많아 GLOB 후
|
|
# 템플릿(_template) 파일만 제외하는 방식이 견고하다.
|
|
# TODO(vendor): 미사용 모듈(예: ll_*, 사용 안 하는 주변장치)은 빌드 시간 절약을
|
|
# 위해 선택적으로 제외 가능. 우선 정확성 위해 전체 컴파일.
|
|
file(GLOB HAL_SOURCES CONFIGURE_DEPENDS "${HAL}/Src/*.c")
|
|
# *_template.c 는 사용자 재정의용 예제이므로 제외(중복 심볼/약한 정의 회피).
|
|
list(FILTER HAL_SOURCES EXCLUDE REGEX ".*_template\\.c$")
|
|
|
|
# ── (D) 벤더: FreeRTOS 커널 + heap_4 + Cortex-M4F 포트 ──────────────────────
|
|
# TODO(vendor): FreeRTOS-Kernel 루트의 *.c (tasks/queue/list/timers/event_groups/
|
|
# stream_buffer/croutine) 를 컴파일. heap_4 와 ARM_CM4F port 는 명시 지정.
|
|
file(GLOB FREERTOS_CORE CONFIGURE_DEPENDS "${FREERTOS}/*.c")
|
|
set(FREERTOS_SOURCES
|
|
${FREERTOS_CORE}
|
|
${FREERTOS}/portable/MemMang/heap_4.c
|
|
${FREERTOS}/portable/GCC/ARM_CM4F/port.c
|
|
)
|
|
|
|
# ── (E) 벤더: LwIP 코어 + IPv4 + netif + apps/sntp + FreeRTOS sys_arch ──────
|
|
# LwIP 는 Filelists.cmake 를 제공하지만 버전에 따라 변수명이 다르므로 GLOB 후
|
|
# 필요한 하위 트리만 포함한다.
|
|
# TODO(vendor): 핀 고정 lwip 버전의 src/Filelists.cmake 를 include 하여
|
|
# ${lwipcore_SRCS} 등 공식 목록을 쓰는 편이 더 견고함. 우선 GLOB 로 구성.
|
|
file(GLOB LWIP_CORE CONFIGURE_DEPENDS "${LWIP}/src/core/*.c")
|
|
file(GLOB LWIP_CORE_IPV4 CONFIGURE_DEPENDS "${LWIP}/src/core/ipv4/*.c")
|
|
file(GLOB LWIP_NETIF CONFIGURE_DEPENDS "${LWIP}/src/netif/*.c")
|
|
file(GLOB LWIP_API CONFIGURE_DEPENDS "${LWIP}/src/api/*.c")
|
|
# SNTP 앱(시간 동기 — timesync.c 가 사용).
|
|
set(LWIP_SNTP "${LWIP}/src/apps/sntp/sntp.c")
|
|
# FreeRTOS sys_arch 포트(LwIP ↔ FreeRTOS 통합). 위치는 벤더 contrib.
|
|
# TODO(hw): sys_arch.c 가 프로젝트 net/lwip_port 에 있다면 그쪽을 사용.
|
|
set(LWIP_SYS_ARCH "${LWIP}/contrib/ports/freertos/sys_arch.c")
|
|
set(LWIP_SOURCES
|
|
${LWIP_CORE}
|
|
${LWIP_CORE_IPV4}
|
|
${LWIP_NETIF}
|
|
${LWIP_API}
|
|
${LWIP_SNTP}
|
|
${LWIP_SYS_ARCH}
|
|
)
|
|
|
|
# ── (F) 벤더: mbedTLS 라이브러리 ────────────────────────────────────────────
|
|
# TODO(vendor): library/*.c 전체 컴파일(설정 헤더에서 미사용 기능은 컴파일
|
|
# 아웃되므로 코드 크기에는 큰 영향 없음). psa/ 하위는 사용 안 하면 제외 가능.
|
|
file(GLOB MBEDTLS_SOURCES CONFIGURE_DEPENDS "${MBEDTLS}/library/*.c")
|
|
|
|
# =============================================================================
|
|
# 공유 펌웨어 INTERFACE 라이브러리(정의/인클루드/플래그 모음)
|
|
# - 두 실행 타깃이 동일 베이스를 공유하되, 보드 매크로만 다르게 한다.
|
|
# =============================================================================
|
|
add_library(fw_base INTERFACE)
|
|
target_include_directories(fw_base INTERFACE ${COMMON_INCLUDES})
|
|
target_compile_definitions(fw_base INTERFACE ${COMMON_DEFS})
|
|
target_compile_options(fw_base INTERFACE
|
|
-Wall -Wextra
|
|
# HAL/LwIP/mbedtls 벤더 코드의 경고로 빌드가 막히지 않게 -Werror 는 미사용.
|
|
$<$<COMPILE_LANGUAGE:C>:-fno-common>
|
|
)
|
|
|
|
# 벤더 소스(타깃 무관 동일). 두 실행파일에 그대로 포함된다.
|
|
set(VENDOR_SOURCES
|
|
${STARTUP_S}
|
|
${SYSTEM_C}
|
|
${HAL_SOURCES}
|
|
${FREERTOS_SOURCES}
|
|
${LWIP_SOURCES}
|
|
${MBEDTLS_SOURCES}
|
|
)
|
|
|
|
# =============================================================================
|
|
# 실행 타깃 생성 헬퍼
|
|
# board_dir: board_sht30 (보드 전용 main/app 소스)
|
|
# board_def: BOARD_SHT30
|
|
# =============================================================================
|
|
function(add_board_firmware target_name board_dir board_def)
|
|
# 보드 전용 소스 수집(main.c + app_*.c 등). GLOB + CONFIGURE_DEPENDS.
|
|
file(GLOB BOARD_SOURCES CONFIGURE_DEPENDS "${FW_ROOT}/${board_dir}/*.c")
|
|
if(NOT BOARD_SOURCES)
|
|
message(FATAL_ERROR "${board_dir} 에 소스(.c)가 없습니다: ${target_name}")
|
|
endif()
|
|
|
|
add_executable(${target_name}
|
|
${BOARD_SOURCES}
|
|
${COMMON_SOURCES}
|
|
${VENDOR_SOURCES}
|
|
)
|
|
|
|
target_link_libraries(${target_name} PRIVATE fw_base)
|
|
target_compile_definitions(${target_name} PRIVATE ${board_def})
|
|
|
|
# 링커 스크립트 + 맵 파일. -T 로 .ld 지정, .map 으로 메모리 맵 출력.
|
|
target_link_options(${target_name} PRIVATE
|
|
-T${FW_LD}
|
|
-Wl,-Map=$<TARGET_FILE_DIR:${target_name}>/${target_name}.map,--cref
|
|
)
|
|
# .ld 변경 시 재링크 트리거.
|
|
set_target_properties(${target_name} PROPERTIES
|
|
LINK_DEPENDS "${FW_LD}"
|
|
SUFFIX ".elf")
|
|
|
|
# ── 후처리: .bin / .hex 생성 + 크기 출력 ───────────────────────────────
|
|
set(elf "$<TARGET_FILE:${target_name}>")
|
|
set(out_dir "$<TARGET_FILE_DIR:${target_name}>")
|
|
add_custom_command(TARGET ${target_name} POST_BUILD
|
|
COMMAND ${CMAKE_OBJCOPY} -O binary ${elf} ${out_dir}/${target_name}.bin
|
|
COMMAND ${CMAKE_OBJCOPY} -O ihex ${elf} ${out_dir}/${target_name}.hex
|
|
COMMAND ${CMAKE_SIZE} --format=berkeley ${elf}
|
|
COMMENT "[${target_name}] objcopy → .bin/.hex, size 출력"
|
|
VERBATIM)
|
|
endfunction()
|
|
|
|
# =============================================================================
|
|
# 펌웨어 타깃 (SHT30 단일 보드)
|
|
# =============================================================================
|
|
add_board_firmware(sht30_fw board_sht30 BOARD_SHT30)
|
|
|
|
# =============================================================================
|
|
# Configure 요약
|
|
# =============================================================================
|
|
message(STATUS "──────────────────────────────────────────────")
|
|
message(STATUS " ${PROJECT_NAME} ${PROJECT_VERSION}")
|
|
message(STATUS " toolchain : ${CMAKE_C_COMPILER}")
|
|
message(STATUS " build type: ${CMAKE_BUILD_TYPE}")
|
|
message(STATUS " ld script : ${FW_LD}")
|
|
message(STATUS " third_party: ${TP}")
|
|
message(STATUS " targets : sht30_fw (BOARD_SHT30)")
|
|
message(STATUS "──────────────────────────────────────────────")
|