Select Git revision
flame.c 11.89 KiB
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <time.h>
#include <signal.h>
// 상수 정의
#define BUFFER_MAX 3 // 버퍼 크기
#define DIRECTION_MAX 256 // 방향 경로 최대 길이
#define VALUE_MAX 256 // 값 경로 최대 길이
#define IN 0 // GPIO 입력 모드
#define OUT 1 // GPIO 출력 모드
#define LOW 0 // GPIO LOW 상태
#define HIGH 1 // GPIO HIGH 상태
#define BUFFER_SIZE 1024 // 소켓 버퍼 크기
#define POUT 23 // 초음파 트리거 핀
#define PIN 24 // 초음파 에코 핀
#define FLAME 21 // 불꽃 센서 핀
#define GREEN 17 // 초록색 LED 핀
#define RED 22 // 적색 LED 핀
#define BUZZER 27 // 부저 핀
// 부저 알림용 음계 배열
int fireAlarmNotes[] = { 880, 880, 0, 880, 880, 0, 988, 988, 0, 880, 880, 0 };
// 전역 변수
struct sockaddr_in server_addr; // 서버 주소 구조체
int park = 0; // 주차 상태: 0 = 비어있음, 1 = 주차됨
int setFire = 1; // 화재 상태: 1 = 정상, 0 = 화재 발생
int sock; // 소켓 디스크립터
int redLed = 2; // 초기 LED 상태
int CLEAR = 1; // 초기 화재 진압상태 1 = 화재 진압 상태 0 = 화재 미진압 상태
/* 스레드 변수 */
pthread_t ultra_thread, flame_thread, receive_thread;
// GPIO 핀 제어 함수 선언
int GPIOExport(int pin);
int GPIOUnexport(int pin);
int GPIODirection(int pin, int dir);
int GPIORead(int pin);
int GPIOWrite(int pin, int value);
/* 인터럽트 신호 처리 함수 */
void signal_handler(int no);
/*부저 알림음 생성 함수*/
/* PWM 방식으로 핀을 토글하며 특정 주파수로 소리를 발생시킴 */
void buzzerTone(int pin, int frequency, int duration) {
int period = 1000000 / frequency; // 주기 (마이크로초 단위)
int halfPeriod = period / 2;
for (int i = 0; i < (duration * 1000 / period); i++) {
GPIOWrite(pin, HIGH);
usleep(halfPeriod);
GPIOWrite(pin, LOW);
usleep(halfPeriod);
}
}
/* 초음파 센서를 통한 거리 측정 및 주차 상태 관리 스레드 함수 */
void *ultrasonic_sensor(void *arg) {
clock_t start_t, end_t; // 에코 신호 시간을 측정하기 위한 변수
double time;
while (1) {
GPIOWrite(POUT, HIGH); // 트리거 신호 발생
usleep(10); // 10마이크로초 유지
GPIOWrite(POUT, LOW); // 트리거 신호 종료
/* 에코 신호 수신 시작 */
while (GPIORead(PIN) == LOW)
start_t = clock();
while (GPIORead(PIN) == HIGH)
end_t = clock();
time = (double)(end_t - start_t) / CLOCKS_PER_SEC; // 에코 시간 계산
double distance = time / 2 * 34000; // 거리 계산 (cm 단위)
/* 상태에 따른 LED 제어 및 서버 메시지 전송 */
if (redLed == 2) {
GPIOWrite(RED, HIGH);
redLed = 1;
}
if (park == 0 && distance <= 10 && redLed == 1) {
GPIOWrite(GREEN, HIGH); // 초록색 LED 켜기
GPIOWrite(RED, LOW); // 적색 LED 끄기
park = 1; // 주차 상태 변경
redLed = 0;
printf("0-PARK\n");
send(sock, "0-PARK", strlen("0-PARK"), 0); // 서버로 주차 메시지 전송
} else if (park == 1 && distance > 10 && redLed == 0) {
GPIOWrite(GREEN, LOW);
GPIOWrite(RED, HIGH);
park = 0; // 주차 해제
redLed = 1;
printf("0-EXIT\n");
send(sock, "0-EXIT", strlen("0-EXIT"), 0); // 서버로 주차 해제 메시지 전송
}
usleep(500000);
}
return NULL;
}
/* 불꽃 센서를 통한 화재 감지 및 부저 알림 스레드 함수 */
void *flame_sensor(void *arg) {
printf("초기 FLAME 값: %d\n", GPIORead(FLAME));
while (1) {
if (GPIORead(FLAME) == 0 && setFire == 1) { // 화재 발생 감지
printf("0-FIRE\n");
send(sock, "0-FIRE", strlen("0-FIRE"), 0); // 서버로 화재 메시지 전송
setFire = 0; // 화재 상태 변경
CLEAR = 0; // 화재 진압 상태 변경
printf("FLAME 값: %d\n", GPIORead(FLAME));
}
/* CLEAR 상태가 0일 때 화재 경고음 발생 */
while (CLEAR == 0) {
for (int i = 0; i < sizeof(fireAlarmNotes) / sizeof(int); i++) {
if (CLEAR != 0) {
break;
}
if (fireAlarmNotes[i] > 0) {
buzzerTone(BUZZER, fireAlarmNotes[i], 200); // 알림음 발생
} else {
usleep(200000); // 음 사이 간격
}
}
if (CLEAR != 0) {
break;
}
}
GPIOWrite(BUZZER, LOW);
usleep(200000);
}
return NULL;
}
/* 서버와 메시지를 주고받는 스레드 함수 */
void *receive_message(void *arg) {
char buffer[BUFFER_SIZE];
int valread;
while (1) {
valread = read(sock, buffer, BUFFER_SIZE - 1); // 서버로부터 메시지 읽기
if (valread <= 0) { // 서버 연결 끊김 감지
printf("서버와의 연결이 종료되었습니다. 재연결을 시도합니다...\n");
close(sock);
/* 서버 재연결 시도 */
while (1) {
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
perror("Socket creation error");
sleep(5);
continue;
}
if (connect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
perror("Connection failed. 재연결 시도 중...");
close(sock);
sleep(5);
continue;
}
printf("서버에 재연결되었습니다.\n");
break;
}
} else {
buffer[valread] = '\0';
printf("서버로부터 받은 메시지: %s\n", buffer);
buffer[strcspn(buffer, "\r\n")] = '\0';
if (strcmp(buffer, "CLEAR") == 0) { // CLEAR 명령어 처리
setFire = 1;
CLEAR = 1;
printf("setFire 및 CLEAR가 %d, %d로 설정되었습니다.\n", setFire, CLEAR);
}
}
}
return NULL;
}
int main() {
/* SIGINT 신호 (Ctrl + C) 처리 핸들러 등록 */
signal(SIGINT, (void *)signal_handler);
/* 소켓 생성 */
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("Socket creation error");
return -1;
}
/* 서버 주소 설정 */
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(12345); // 서버 포트 설정
/* 서버 IP 주소 설정 (127.0.0.1: localhost) */
if (inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr) <= 0) {
perror("Invalid address / Address not supported");
return -1;
}
/* 서버 연결 시도 */
if (connect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
perror("Connection failed");
return -1;
}
printf("서버에 연결되었습니다.\n");
/* GPIO 핀 초기화 */
if (GPIOExport(POUT) == -1 || GPIOExport(PIN) == -1 || GPIOExport(FLAME) == -1 ||
GPIOExport(GREEN) == -1 || GPIOExport(RED) == -1 || GPIOExport(BUZZER) == -1) {
fprintf(stderr, "GPIO Export Error\n");
return 1;
}
usleep(100000); // GPIO 설정 대기
/* GPIO 핀 방향 설정 */
if (GPIODirection(POUT, OUT) == -1 || GPIODirection(PIN, IN) == -1 ||
GPIODirection(FLAME, IN) == -1 || GPIODirection(GREEN, OUT) == -1 ||
GPIODirection(RED, OUT) == -1 || GPIODirection(BUZZER, OUT) == -1) {
fprintf(stderr, "GPIO Direction Error\n");
return 2;
}
/* 초음파 센서, 불꽃 센서, 서버 메시지 처리 스레드 생성 */
pthread_create(&ultra_thread, NULL, ultrasonic_sensor, NULL);
pthread_create(&flame_thread, NULL, flame_sensor, NULL);
pthread_create(&receive_thread, NULL, receive_message, NULL);
/* 스레드 종료 대기 */
pthread_join(ultra_thread, NULL);
pthread_join(flame_thread, NULL);
pthread_join(receive_thread, NULL);
/* 종료 시 소켓 및 GPIO 정리 */
close(sock);
GPIOUnexport(POUT);
GPIOUnexport(PIN);
GPIOUnexport(FLAME);
GPIOUnexport(GREEN);
GPIOUnexport(RED);
GPIOUnexport(BUZZER);
return 0;
}
/* SIGINT 신호 처리 함수 */
/* 시스템 종료 시 GPIO 상태 정리 및 프로그램 종료 */
void signal_handler(int no) {
printf("System Interrupt.\n");
GPIOWrite(GREEN, LOW);
GPIOWrite(RED, LOW);
GPIOWrite(BUZZER, LOW);
GPIOUnexport(POUT);
GPIOUnexport(PIN);
GPIOUnexport(FLAME);
GPIOUnexport(GREEN);
GPIOUnexport(RED);
GPIOUnexport(BUZZER);
close(sock);
exit(0);
}
/* GPIO 핀 활성화 함수 */
/* 핀 번호를 "/sys/class/gpio/export"에 기록하여 활성화 */
int GPIOExport(int pin) {
char buffer[BUFFER_MAX];
ssize_t bytes_written;
int fd;
fd = open("/sys/class/gpio/export", O_WRONLY);
if (-1 == fd) {
fprintf(stderr, "Failed to open export for writing!\n");
return (-1);
}
bytes_written = snprintf(buffer, BUFFER_MAX, "%d", pin);
write(fd, buffer, bytes_written);
close(fd);
return (0);
}
/* GPIO 핀 비활성화 함수 */
/* 핀 번호를 "/sys/class/gpio/unexport"에 기록하여 비활성화 */
int GPIOUnexport(int pin) {
char buffer[BUFFER_MAX];
ssize_t bytes_written;
int fd;
fd = open("/sys/class/gpio/unexport", O_WRONLY);
if (-1 == fd) {
fprintf(stderr, "Failed to open unexport for writing!\n");
return (-1);
}
bytes_written = snprintf(buffer, BUFFER_MAX, "%d", pin);
write(fd, buffer, bytes_written);
close(fd);
return (0);
}
/* GPIO 핀 방향 설정 함수 */
/* 핀의 입력(IN) 또는 출력(OUT) 방향을 설정 */
int GPIODirection(int pin, int dir) {
static const char s_directions_str[] = "in\0out";
char path[DIRECTION_MAX];
int fd;
snprintf(path, DIRECTION_MAX, "/sys/class/gpio/gpio%d/direction", pin);
fd = open(path, O_WRONLY);
if (-1 == fd) {
fprintf(stderr, "Failed to open gpio direction for writing!\n");
return (-1);
}
if (-1 == write(fd, &s_directions_str[IN == dir ? 0 : 3], IN == dir ? 2 : 3)) {
fprintf(stderr, "Failed to set direction!\n");
return (-1);
}
close(fd);
return (0);
}
/* GPIO 핀 값 읽기 함수 */
/* 핀의 현재 상태(0 또는 1)를 읽어 반환 */
int GPIORead(int pin) {
char path[VALUE_MAX];
char value_str[3];
int fd;
snprintf(path, VALUE_MAX, "/sys/class/gpio/gpio%d/value", pin);
fd = open(path, O_RDONLY);
if (-1 == fd) {
fprintf(stderr, "Failed to open gpio value for reading!\n");
return (-1);
}
if (-1 == read(fd, value_str, 3)) {
fprintf(stderr, "Failed to read value!\n");
return (-1);
}
close(fd);
return (atoi(value_str)); // 읽은 값을 정수로 변환 후 반환
}
/* GPIO 핀 값 쓰기 함수 */
/* 핀에 0(LOW) 또는 1(HIGH) 값을 기록 */
int GPIOWrite(int pin, int value) {
static const char s_values_str[] = "01";
char path[VALUE_MAX];
int fd;
snprintf(path, VALUE_MAX, "/sys/class/gpio/gpio%d/value", pin);
fd = open(path, O_WRONLY);
if (-1 == fd) {
fprintf(stderr, "Failed to open gpio value for writing!\n");
return (-1);
}
if (1 != write(fd, &s_values_str[LOW == value ? 0 : 1], 1)) {
fprintf(stderr, "Failed to write value!\n");
return (-1);
}
close(fd);
return (0);
}