Skip to content
Snippets Groups Projects
Select Git revision
  • b707a0b0f0aad4ba53d15f5c7e07126b8eab40b0
  • main default protected
2 results

flame.c

Blame
  • 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);
    }