개발 목표
이번 프로젝트의 단기 목표는 MQTT 메시지를 수신하여 라즈베리파이의 내부 설정을 변경하는 기능을 구현하는 것이다.
장기적으로는 여러 명령어가 추가될 것이므로, 확장 가능한 구조를 갖춘 컨트롤러 프로그램을 만들 예정이다.
개발 환경
- 개발 PC: Windows 10
- MQTT 메시지 테스트: MQTT Explorer
- 타겟 디바이스: Raspberry Pi Zero 2W
- OS: Debian 11 (bullseye), 32bit
- GCC: 10.2.1 (Raspbian)
- Mosquitto: 2.0.11
시스템 정보 확인 명령어
getconf LONG_BIT # 32비트 확인
cat /etc/*release* # OS 정보 확인
dpkg -l | grep mosquitto # Mosquitto 버전 확인
디렉토리 구조
컨트롤러 프로젝트의 구조는 다음과 같다:
/project
│
├── /build # 컴파일된 .o 파일 저장
├── /include # 헤더 파일
├── /logs # 로그 파일 저장
├── /src # C 소스 파일
├── main.c # 메인 엔트리 포인트
└── Makefile # 컴파일 자동화
로그 라이브러리 개발
개발 중에는 printf만으로는 한계가 있다.
초기에 로그 시스템을 도입하면 디버깅과 유지보수가 훨씬 수월해진다.
이번 포스팅에서는 다음과 같이 log_util 라이브러리를 직접 만들어 사용해 보았다:
- log_util.h
- log_util.c
로그 레벨은 INFO, DEBUG, WARN, ERROR로 구성하였고, 로그 파일은 /logs 디렉토리에 저장된다.
추가적으로, 로그 파일 크기가 50KB를 넘으면 자동으로 파일을 분할 저장하도록 설계하였다.
로직에 대한 정보는 아래 링크를 참고하자.
https://kksp12y.tistory.com/155
log_util.c & log_util.h
/** * @brief 로그 디렉토리가 존재하는지 확인하고 없으면 생성한다. * @return 0 성공, -1 실패 */static int ensure_log_dir() { struct stat st; // stat 함수 / LOG_DIR = logs라는 폴더가 없을 때 -1 반환 if (stat(LOG_DIR, &s
kksp12y.tistory.com
로그 테스트용 main.c 예제
#include <stdio.h>
#include "./include/log_util.h"
#define VERSION "v999.000"
int main() {
log_print(LOG_LEVEL_INFO, "프로그램 시작 - 버전: %s", VERSION);
log_print(LOG_LEVEL_DEBUG, "디버그 메시지 테스트");
log_print(LOG_LEVEL_WARN, "경고 메시지 테스트");
log_print(LOG_LEVEL_ERROR, "에러 메시지 테스트");
// 반복 로그 출력으로 로그 파일 분할 테스트
for (int i = 1; i <= 1000; i++) {
log_print(LOG_LEVEL_INFO, "반복 로그 테스트 %d회차", i);
}
return 0;
}
Makefile 구성
컴파일 자동화를 위해 다음과 같은 Makefile을 작성하였다:
# 컴파일러 지정 (기본 gcc 사용)
CC = gcc
# 컴파일 옵션
# -Iinclude : 헤더 파일을 include 디렉토리에서 찾도록 지정
# -Wall : 모든 경고 메시지 출력
# -g : 디버깅 정보 포함 (gdb 등 디버거 사용 가능)
CFLAGS = -Iinclude -Wall -g
# 소스 파일 목록
# main.c 와 src/ 디렉토리 하위의 모든 파일 포함
SRCS = main.c src/*
# 목적 파일(.o) 저장 경로
OBJDIR = build
# 목적 파일 목록
# src/hello.c → build/src/hello.o 형태로 빌드 경로 유지
OBJS = $(patsubst %.c,$(OBJDIR)/%.o,$(SRCS))
# 최종 생성할 실행 파일 이름
TARGET = main
# ======================== #
# [기본 타겟] 실행 파일 생성 #
# ======================== #
all: $(TARGET)
# 실행 파일 생성 규칙
# $@ → 목표 파일(main)
# $^ → 모든 의존 파일(.o들)
# $(LDLIBS) 는 외부 라이브러리 링크할 때 사용 가능
$(TARGET): $(OBJS)
$(CC) $(CFLAGS) -o $@ $^ $(LDLIBS)
# ======================================== #
# 소스 파일 → 목적 파일(.o) 빌드 규칙 정의 #
# - 자동으로 중간 디렉토리 생성 포함 #
# - $< : 현재 컴파일 대상 .c 파일 #
# - $@ : 생성될 목적 파일 경로 #
# ======================================== #
$(OBJDIR)/%.o: %.c
@mkdir -p $(dir $@) # 해당 디렉토리가 없으면 생성
$(CC) $(CFLAGS) -c $< -o $@ # 컴파일하여 목적 파일 생성
# 빌드 디렉토리 수동 생성용 타겟 (선택적으로 사용)
$(OBJDIR):
mkdir -p $(OBJDIR)
# ========================= #
# 정리(clean) 타겟 정의 #
# 빌드된 파일 및 실행 파일 삭제 #
# ========================= #
clean:
rm -rf $(OBJDIR) $(TARGET)
결과 확인
컴파일 후 main을 실행하면 다음과 같이 로그 파일이 생성된다:
각 로그 파일에는 다음과 같은 메시지가 기록된다:
마무리
이번 포스팅에서는 로그 시스템을 먼저 구축하여 향후 개발의 기반을 마련했다.
처음에는 단순한 기능처럼 보였지만, 로그 관리를 위한 구조 설계와 구현에는 생각보다 많은 고려가 필요했다.
이후 포스팅에서는 MQTT 수신 기능 및 명령어별 분기 처리 등을 개발해나갈 예정이다.
꾸준히 업데이트하며 진행 과정을 공유해보겠다.
'통신 > MQTT' 카테고리의 다른 글
[controller] using MQTT (들어가기 앞서) (0) | 2025.05.26 |
---|---|
raspberry pi zero 2 W에 mosquitto 설치 (0) | 2025.04.27 |
mqtt - bin파일 전송 -2 (0) | 2025.04.18 |
mqtt - bin파일 전송 (0) | 2025.04.17 |
MQTT Explorer (0) | 2025.03.24 |