diff --git a/pir_sensor.c b/pir_sensor.c new file mode 100644 index 0000000000000000000000000000000000000000..3f734650c22188df5a1b66967c2d767b37c191dc --- /dev/null +++ b/pir_sensor.c @@ -0,0 +1,135 @@ +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/socket.h> +#include <arpa/inet.h> +#include <string.h> + +int sock; + +#define PIR_PIN 17 // PIR 센서가 연결된 GPIO 핀 번호 + +// GPIO 핀 초기화 함수 +void init_gpio() { + int fd; + + // GPIO 핀을 export + fd = open("/sys/class/gpio/export", O_WRONLY); // /sys/class/gpio/export 파일을 쓰기 전용으로 연다. + if (fd == -1) { + perror("Error exporting GPIO"); + exit(1); + } + //파일 디스크립터(fd)가 정상적으로 열렸다면, + write(fd, "17", 2); //write(fd, "17", 2);는 17 문자열을 파일에 쓰되, 문자열의 길이가 2이므로 2바이트만큼 쓰라는 의미 + close(fd); + + // 방향 설정 (in으로 설정) + fd = open("/sys/class/gpio/gpio17/direction", O_WRONLY); ///sys/class/gpio/gpio17/direction 파일을 쓰기 전용으로 연다. 이 파일 GPIO핀의 방향을 설정하는 사용된다. + if (fd == -1) { + perror("Error setting direction GPIO"); + exit(1); + } + write(fd, "in", 2); + //in"으로 설정하기 위해 "in" 문자열을 파일에 쓰기 위해 write 함수를 사용 + // write(fd, "in", 2);는 "in" 문자열을 파일에 쓰되, 문자열의 길이가 2이므로 2바이트만큼 쓰라는 의미 + close(fd); +} + +// GPIO 핀 읽기 함수 +int read_gpio() { + int fd; + char buffer[2]; + + // 값 읽기 + fd = open("/sys/class/gpio/gpio17/value", O_RDONLY); ///sys/class/gpio/gpio17/value 경로에 위치한 파일을 읽기 전용(O_RDONLY)으로 연다. + //GPIO핀 현재상태를 나타내며 값이 1또는0이다. + if (fd == -1) { + perror("Error reading GPIO value"); + exit(1); + } + read(fd, buffer, sizeof(buffer)); //read(fd, buffer, sizeof(buffer));를 사용하여 파일에서 데이터를 읽어와서 buffer에 저장 + close(fd); + + return atoi(buffer);//atoi(buffer)를 통해 GPIO 현재값(1또는0)을 저장 +} + +int main(int argc, char *argv[]) { + printf("PIR Sensor Test\n"); + + + // GPIO 핀 초기화 + init_gpio(); + struct sockaddr_in server_addr; + + if (argc != 3) + { + printf("Please deliver IP & Port num as arguments correctly!\n"); + exit(1); + } + + sock = socket(PF_INET, SOCK_STREAM, 0); + //PF_INET은 소켓의 프로토콜패밀리이고 IPv4 프로토콜을 사욘한다. + //SOCK_STEAM은 소켓의 타입이고 이것은 TCP소켓을 생성한다. + //매배변수 0은 주로 0을 사용하면 시스템이 적절한 프로토콜을 선택한다. + if (sock == -1) + { + perror("socket() error"); + exit(1); + } + + memset(&server_addr, 0, sizeof(server_addr)); + //memset 함수는 메모리를 특정한 값으로 초기화하는 데 사용되며, + //server_addr라는 구조체 변수에 대해 0으로 초기화하는 용도로 사용 + // + server_addr.sin_family = AF_INET; + server_addr.sin_addr.s_addr = inet_addr(argv[1]); + server_addr.sin_port = htons(atoi(argv[2])); + /* + server_addr는 struct sockaddr_in 타입의 구조체로, 서버의 주소 정보를 담고 있다. + struct sockaddr_in 구조체는 IPv4 주소를 나타내는 데 사용됨. + inet_addr 함수는 문자열 형태로 주어진 IPv4 주소를 32비트의 이진 형태로 변환 + argv[1]은 프로그램 실행 시 전달된 첫 번째 명령행 인수로, 서버의 IP 주소를 나타냄 + inet_addr로 변환된 IP 주소가 server_addr 구조체의 sin_addr.s_addr에 저장. + + */ + + + if (connect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) + /* + connect 함수는 소켓을 특정 주소에 연결한다. 이때 첫 번째 매개변수 sock은 연결하려는 소켓을 의미. + 두 번째 매개변수는 서버의 주소 정보를 담고 있는 server_addr 구조체의 포인터. + 세 번째 매개변수는 server_addr 구조체의 크기 + 로서 서버와의 연결을 확인한다. + */ + { + perror("connect() error"); + exit(1); + } + printf("join success!\n"); + + FILE* fp = fopen("/sys/class/gpio/gpio17/value","r"); + sleep(1); + + while(1){ + int motion_check = read_gpio(); + + if (motion_check) { + printf("Motion detected!\n"); + if(write(sock, "1", 1)==-1){ + perror("Client sending data error"); + return -1; + } + + } else { + printf("No motion.\n"); + if(write(sock, "0", 1)==-1){ + perror("Client sending data error"); + return -1; + } + } + sleep(1); // 1초 간격으로 센서 상태를 확인 + + + } +}