Skip to content
Snippets Groups Projects
Commit f96e0148 authored by 최 민서's avatar 최 민서
Browse files

feat: 배터리 랜덤값으로 시작

parent 49aa2e7a
No related branches found
No related tags found
No related merge requests found
#include <stdio.h> #include <stdio.h> // 표준 입출력 라이브러리
#include <string.h> #include <string.h> // 문자열 처리 라이브러리
#include <fcntl.h> #include <fcntl.h> // 파일 제어 관련 라이브러리
#include <unistd.h> #include <unistd.h> // 유닉스 표준 시스템 호출 관련 라이브러리
#include <pthread.h> #include <pthread.h> // POSIX 스레드 관련 라이브러리
#include <stdlib.h> #include <stdlib.h> // 일반 유틸리티 함수 라이브러리
#include <stdint.h> #include <stdint.h> // 정수 타입 정의 라이브러리
#include <linux/i2c-dev.h> #include <linux/i2c-dev.h> // I2C 장치 드라이버 관련 헤더
#include <arpa/inet.h> #include <arpa/inet.h> // 인터넷 주소 변환 함수 관련 헤더
#include <sys/ioctl.h> #include <sys/ioctl.h> // I/O 제어 함수 관련 헤더
#include "MFRC522.h" #include "MFRC522.h" // RFID 모듈 관련 헤더 파일 (사용자 정의)
#define I2C_ADDR 0x23 #define I2C_ADDR 0x23 // I2C LCD 디바이스 주소
#define LCD_CHR 1 #define LCD_CHR 1 // LCD 데이터 모드
#define LCD_CMD 0 #define LCD_CMD 0 // LCD 명령 모드
#define LINE1 0x80 #define LINE1 0x80 // LCD 첫 번째 줄
#define LINE2 0xC0 #define LINE2 0xC0 // LCD 두 번째 줄
#define LCD_BACKLIGHT 0x08 #define LCD_BACKLIGHT 0x08 // LCD 백라이트 ON
#define ENABLE 0b00000100 #define ENABLE 0b00000100 // LCD enable 비트 설정
#define BUFFER_SIZE 1024 #define BUFFER_SIZE 1024 // 서버로부터 수신할 데이터의 버퍼 크기
#define SERVER_IP "127.0.0.1" #define SERVER_IP "127.0.0.1" // 서버 IP 주소 (localhost)
#define SERVER_PORT 12345 #define SERVER_PORT 12345 // 서버 포트 번호
int lcd_fd; // 전역 변수 선언
int client_socket; int lcd_fd; // LCD I2C 파일 디스크립터
int battery_percentage = 50; int client_socket; // 클라이언트 소켓
int charging = 0; int battery_percentage; // 배터리 충전 상태 (0 ~ 99까지 랜덤한 값으로 가정)
int fire_detected = 0; int charging = 0; // 충전 여부 (0: 충전 중 아님, 1: 충전 중)
int car_parked = 0; int fire_detected = 0; // 화재 감지 여부 (0: 감지 안 됨, 1: 감지됨)
int car_parked = 0; // 차량 주차 여부 (0: 미주차, 1: 주차)
void lcd_init(int fd);
void lcd_byte(int fd, int bits, int mode); // 함수 프로토타입 선언
void lcd_toggle_enable(int fd, int bits); void lcd_init(int fd); // LCD 초기화 함수
void lcd_loc(int fd, int line); void lcd_byte(int fd, int bits, int mode); // LCD 데이터 전송 함수
void lcd_clear(int fd); void lcd_toggle_enable(int fd, int bits); // LCD enable 토글 함수
void typeln(int fd, const char *s); void lcd_loc(int fd, int line); // LCD 줄 선택 함수
void *listen_to_server(void *arg); void lcd_clear(int fd); // LCD 화면 초기화 함수
void *update_battery_status(void *arg); void typeln(int fd, const char *s); // LCD 문자열 출력 함수
void *rfid_tag_listener(void *arg); void *listen_to_server(void *arg); // 서버 메시지 수신 스레드 함수
void *update_battery_status(void *arg); // 배터리 상태 업데이트 스레드 함수
void *rfid_tag_listener(void *arg); // RFID 태그 감지 스레드 함수
// 서버 연결을 초기화하는 함수
int connect_to_server() {
if (client_socket > 0) { // 이미 소켓이 열려 있다면 닫기
close(client_socket);
}
int main() { client_socket = socket(AF_INET, SOCK_STREAM, 0); // 새 소켓 생성
pthread_t server_thread, battery_thread, rfid_thread; if (client_socket < 0) {
perror("Socket creation failed"); // 소켓 생성 실패 처리
return -1;
}
struct sockaddr_in server_address;
server_address.sin_family = AF_INET; // IPv4 설정
server_address.sin_port = htons(SERVER_PORT); // 포트 설정
inet_pton(AF_INET, SERVER_IP, &server_address.sin_addr); // IP 주소 변환
if (connect(client_socket, (struct sockaddr *)&server_address, sizeof(server_address)) < 0) { // 서버 연결 시도
perror("Connection to server failed");
return -1;
}
// Initialize LCD printf("Connected to the server successfully.\n");
const char *i2c_device = "/dev/i2c-1"; return 0;
lcd_fd = open(i2c_device, O_RDWR); }
// LCD 초기화를 수행하는 함수
void lcd_reset() {
const char *i2c_device = "/dev/i2c-1"; // I2C 장치 파일 경로
lcd_fd = open(i2c_device, O_RDWR); // I2C 장치 열기
if (lcd_fd < 0) { if (lcd_fd < 0) {
perror("Failed to open I2C device"); perror("Failed to open I2C device"); // 실패 시 오류 출력
return 1; return;
} }
if (ioctl(lcd_fd, I2C_SLAVE, I2C_ADDR) < 0) { if (ioctl(lcd_fd, I2C_SLAVE, I2C_ADDR) < 0) { // 슬레이브 장치 설정
perror("Failed to acquire bus access or talk to slave"); perror("Failed to acquire bus access or talk to slave");
close(lcd_fd); close(lcd_fd);
return 1; return;
} }
lcd_init(lcd_fd); lcd_init(lcd_fd); // LCD 초기화
client_socket = socket(AF_INET, SOCK_STREAM, 0);
if (client_socket < 0) {
perror("Socket creation failed");
return 1;
} }
struct sockaddr_in server_address; int main() {
server_address.sin_family = AF_INET; pthread_t server_thread, battery_thread, rfid_thread; // 스레드 식별자
server_address.sin_port = htons(SERVER_PORT); srand(time(NULL)); // 랜덤 시드 설정
inet_pton(AF_INET, SERVER_IP, &server_address.sin_addr); battery_percentage = rand() % 100; // 배터리 초기값 설정
if (connect(client_socket, (struct sockaddr *)&server_address, sizeof(server_address)) < 0) { lcd_reset(); // LCD 초기화
perror("Connection to server failed");
return 1;
}
// Create threads while (1) {
pthread_create(&server_thread, NULL, listen_to_server, NULL); if (connect_to_server() == 0) { // 서버 연결 성공 시
pthread_create(&battery_thread, NULL, update_battery_status, NULL); printf("Connected to server. Starting threads...\n");
pthread_create(&rfid_thread, NULL, rfid_tag_listener, NULL);
pthread_join(server_thread, NULL); pthread_create(&server_thread, NULL, listen_to_server, NULL); // 서버 수신 스레드 생성
pthread_join(battery_thread, NULL); pthread_create(&battery_thread, NULL, update_battery_status, NULL); // 배터리 업데이트 스레드 생성
pthread_join(rfid_thread, NULL); pthread_create(&rfid_thread, NULL, rfid_tag_listener, NULL); // RFID 감지 스레드 생성
close(client_socket); pthread_join(server_thread, NULL); // 서버 스레드 종료 대기
close(lcd_fd);
pthread_cancel(battery_thread); // 배터리 스레드 종료
pthread_cancel(rfid_thread); // RFID 스레드 종료
pthread_join(battery_thread, NULL); // 배터리 스레드 자원 해제
pthread_join(rfid_thread, NULL); // RFID 스레드 자원 해제
} else {
sleep(5); // 재연결 대기
}
}
close(client_socket); // 클라이언트 소켓 닫기
close(lcd_fd); // LCD 파일 디스크립터 닫기
return 0; return 0;
} }
// LCD 초기화 함수
void lcd_init(int fd) { void lcd_init(int fd) {
lcd_byte(fd, 0x33, LCD_CMD); lcd_byte(fd, 0x33, LCD_CMD); // 초기화 명령 1
lcd_byte(fd, 0x32, LCD_CMD); lcd_byte(fd, 0x32, LCD_CMD); // 초기화 명령 2
lcd_byte(fd, 0x06, LCD_CMD); lcd_byte(fd, 0x06, LCD_CMD); // 화면 이동 설정
lcd_byte(fd, 0x0C, LCD_CMD); lcd_byte(fd, 0x0C, LCD_CMD); // 디스플레이 켜기
lcd_byte(fd, 0x28, LCD_CMD); lcd_byte(fd, 0x28, LCD_CMD); // 2라인 모드 설정
lcd_byte(fd, 0x01, LCD_CMD); lcd_byte(fd, 0x01, LCD_CMD); // 화면 지우기
usleep(5000); usleep(5000); // 초기화 대기
} }
// LCD 데이터 전송 함수
void lcd_byte(int fd, int bits, int mode) { void lcd_byte(int fd, int bits, int mode) {
int bits_high = mode | (bits & 0xF0) | LCD_BACKLIGHT; int bits_high = mode | (bits & 0xF0) | LCD_BACKLIGHT; // 상위 4비트 설정
int bits_low = mode | ((bits << 4) & 0xF0) | LCD_BACKLIGHT; int bits_low = mode | ((bits << 4) & 0xF0) | LCD_BACKLIGHT; // 하위 4비트 설정
write(fd, &bits_high, 1); write(fd, &bits_high, 1); // 상위 4비트 전송
lcd_toggle_enable(fd, bits_high); lcd_toggle_enable(fd, bits_high); // Enable 신호 토글
write(fd, &bits_low, 1); write(fd, &bits_low, 1); // 하위 4비트 전송
lcd_toggle_enable(fd, bits_low); lcd_toggle_enable(fd, bits_low); // Enable 신호 토글
} }
// LCD Enable 토글 함수
void lcd_toggle_enable(int fd, int bits) { void lcd_toggle_enable(int fd, int bits) {
usleep(500); usleep(500); // 대기
int bits_enable = bits | ENABLE; int bits_enable = bits | ENABLE; // Enable 설정
int bits_disable = bits & ~ENABLE; int bits_disable = bits & ~ENABLE; // Enable 해제
write(fd, &bits_enable, 1); write(fd, &bits_enable, 1); // Enable 활성화
write(fd, &bits_disable, 1); write(fd, &bits_disable, 1); // Enable 비활성화
usleep(500); usleep(500); // 대기
} }
// LCD 특정 줄로 커서 이동
void lcd_loc(int fd, int line) { void lcd_loc(int fd, int line) {
lcd_byte(fd, line, LCD_CMD); lcd_byte(fd, line, LCD_CMD); // 줄 위치 설정
} }
// LCD 화면 초기화
void lcd_clear(int fd) { void lcd_clear(int fd) {
lcd_byte(fd, 0x01, LCD_CMD); lcd_byte(fd, 0x01, LCD_CMD); // 화면 지우기 명령
lcd_byte(fd, 0x02, LCD_CMD); usleep(5000); // 대기
lcd_byte(fd, 0x02, LCD_CMD); // 커서 초기화
usleep(5000); // 대기
} }
// LCD 문자열 출력 함수
void typeln(int fd, const char *s) { void typeln(int fd, const char *s) {
while (*s) { while (*s) {
lcd_byte(fd, *(s++), LCD_CHR); lcd_byte(fd, *(s++), LCD_CHR); // 문자 출력
} }
} }
// 문자열 양끝 공백 제거 함수
char *trim(char *str) {
char *end;
while (isspace((unsigned char)*str)) str++; // 시작 공백 제거
if (*str == 0) return str; // 문자열이 비어 있으면 반환
end = str + strlen(str) - 1; // 끝 공백 제거
while (end > str && isspace((unsigned char)*end)) end--;
*(end + 1) = '\0'; // 문자열 종료 설정
return str;
}
// 서버 메시지 수신 및 처리 스레드
void *listen_to_server(void *arg) { void *listen_to_server(void *arg) {
char buffer[BUFFER_SIZE]; char buffer[BUFFER_SIZE];
while (1) { while (1) {
int bytes_received = recv(client_socket, buffer, BUFFER_SIZE, 0); int bytes_received = recv(client_socket, buffer, BUFFER_SIZE, 0); // 서버로부터 데이터를 수신
if (bytes_received <= 0) { if (bytes_received <= 0) { // 수신 실패 또는 연결 종료 시
perror("Server connection lost"); perror("Server connection lost. Attempting to reconnect..."); // 오류 메시지 출력
break; lcd_clear(lcd_fd); // LCD 화면 초기화
lcd_loc(lcd_fd, LINE1); // 첫 번째 줄로 커서 이동
typeln(lcd_fd, "Connection lost."); // 연결 끊김 메시지 출력
lcd_loc(lcd_fd, LINE2); // 두 번째 줄로 커서 이동
typeln(lcd_fd, "Reconnecting..."); // 재연결 시도 메시지 출력
break; // 재연결을 위해 루프 종료
} }
buffer[bytes_received] = '\0'; buffer[bytes_received] = '\0'; // 수신 데이터 끝에 null 문자 추가
printf("%s\n", buffer); printf("Received message: %s\n", buffer); // 수신된 메시지 출력
fire_detected = strstr(buffer, "-FIRE") != NULL; if (fire_detected) { // 화재 감지 상태에서
if (fire_detected) { if (strcmp(trim(buffer), "CLEAR") == 0) { // CLEAR 메시지 확인
charging = 0; lcd_reset(); // LCD 초기화
lcd_clear(lcd_fd); lcd_clear(lcd_fd); // LCD 화면 지우기
lcd_loc(lcd_fd, LINE1); lcd_loc(lcd_fd, LINE1); // 첫 번째 줄로 이동
typeln(lcd_fd, "FIRE ALERT!"); typeln(lcd_fd, "Fire cleared!"); // 화재 해제 메시지 출력
lcd_loc(lcd_fd, LINE2); lcd_loc(lcd_fd, LINE2); // 두 번째 줄로 이동
typeln(lcd_fd, "EVACUATE AREA!"); typeln(lcd_fd, "All systems OK"); // 시스템 정상 메시지 출력
} else if (strcmp(buffer, "0-PARK") == 0) { sleep(5); // 5초 대기
car_parked = 1; fire_detected = 0; // 화재 경고 해제
} else if (strcmp(buffer, "0-EXIT") == 0) { car_parked = 0; // 차량 주차 상태 초기화
car_parked = 1; } else {
car_parked = 0; printf("Fire alarm still active. Ignored message: %s\n", buffer); // 무시된 메시지 출력
battery_percentage = 50; continue; // 루프 계속 진행
charging = 0; }
lcd_clear(lcd_fd); } else if (strstr(buffer, "-FIRE") != NULL) { // 화재 경고 메시지 수신 시
} else if (strcmp(buffer, "CLEAR") == 0) { printf("FIRE ALERT RECEIVED\n"); // 경고 로그 출력
car_parked = 1; fire_detected = 1; // 화재 상태 활성화
fire_detected = 0; charging = 0; // 충전 중지
lcd_clear(lcd_fd); lcd_reset(); // LCD 초기화
lcd_clear(lcd_fd); // LCD 화면 지우기
lcd_loc(lcd_fd, LINE1); // 첫 번째 줄로 이동
typeln(lcd_fd, "FIRE ALERT!"); // 화재 경고 메시지 출력
lcd_loc(lcd_fd, LINE2); // 두 번째 줄로 이동
typeln(lcd_fd, "EVACUATE AREA!"); // 대피 메시지 출력
} else if (strcmp(trim(buffer), "0-PARK") == 0) { // 차량 주차 메시지 수신 시
printf("CAR PARKED\n"); // 주차 상태 로그 출력
car_parked = 1; // 차량 주차 상태 활성화
} else if (strcmp(trim(buffer), "0-EXIT") == 0) { // 차량 출차 메시지 수신 시
printf("CAR EXITED\n"); // 출차 상태 로그 출력
lcd_reset(); // LCD 초기화
usleep(5000);
lcd_loc(lcd_fd, LINE1); // 첫 번째 줄로 이동
typeln(lcd_fd, "Car exited."); // 출차 메시지 출력
sleep(2); // 2초 대기
car_parked = 0; // 차량 주차 상태 초기화
battery_percentage = rand() % 100; // 배터리 상태 초기화
charging = 0; // 충전 중지
} }
} }
return NULL; return NULL; // 스레드 종료
} }
// 배터리 상태 업데이트 스레드
void *update_battery_status(void *arg) { void *update_battery_status(void *arg) {
while (1) { while (1) {
if (charging && !fire_detected && car_parked) { if (charging && !fire_detected && car_parked) { // 충전 조건 확인
if (battery_percentage < 100) { if (battery_percentage < 100) { // 배터리 충전 중
battery_percentage++; battery_percentage++; // 배터리 퍼센트 증가
lcd_clear(lcd_fd); lcd_reset(); // LCD 초기화
lcd_loc(lcd_fd, LINE1); lcd_loc(lcd_fd, LINE1); // 첫 번째 줄로 이동
char msg[16]; char msg[16];
snprintf(msg, sizeof(msg), "Charging: %d%%", battery_percentage); snprintf(msg, sizeof(msg), "Charging: %d%%", battery_percentage); // 충전 상태 메시지 생성
typeln(lcd_fd, msg); typeln(lcd_fd, msg); // 충전 상태 메시지 출력
char server_msg[16]; char server_msg[16];
snprintf(server_msg, sizeof(server_msg), "0-%d", battery_percentage); snprintf(server_msg, sizeof(server_msg), "0-%d", battery_percentage); // 서버 전송 메시지 생성
send(client_socket, server_msg, strlen(server_msg), 0); send(client_socket, server_msg, strlen(server_msg), 0); // 서버로 전송
} else { } else {
lcd_loc(lcd_fd, LINE1); lcd_loc(lcd_fd, LINE1); // 첫 번째 줄로 이동
typeln(lcd_fd, "CHARGE COMPLETE"); typeln(lcd_fd, "CHARGE COMPLETE"); // 충전 완료 메시지 출력
sleep(1); sleep(1); // 1초 대기
} }
sleep(1); sleep(1); // 다음 업데이트까지 대기
} else { } else {
usleep(500000); usleep(500000); // 충전 조건 미충족 시 대기
} }
} }
return NULL; return NULL; // 스레드 종료
} }
// RFID 태그 감지 및 처리 스레드
void *rfid_tag_listener(void *arg) { void *rfid_tag_listener(void *arg) {
MFRC522 rfid(RPI_V2_GPIO_P1_24, RPI_V2_GPIO_P1_15); MFRC522 rfid(RPI_V2_GPIO_P1_24, RPI_V2_GPIO_P1_15); // RFID 모듈 초기화
rfid.PCD_Init(); rfid.PCD_Init(); // RFID 모듈 초기화 호출
uint8_t card_id[4]; uint8_t card_id[4]; // RFID 카드 ID 저장 공간
while (1) { while (1) {
if (!fire_detected) { if (!fire_detected) { // 화재 상태가 아닐 경우
if (!car_parked) { // 주차 대기 상황 if (!car_parked) { // 차량이 주차되지 않은 경우
lcd_clear(lcd_fd); lcd_reset(); // LCD 초기화
lcd_loc(lcd_fd, LINE1); lcd_loc(lcd_fd, LINE1); // 첫 번째 줄로 이동
typeln(lcd_fd, "NO CAR PARKED"); typeln(lcd_fd, "NO CAR PARKED"); // 주차 필요 메시지 출력
sleep(2); sleep(2); // 2초 대기
} else if (charging) { // 충전중 (충전 중지 감지) } else if (charging) { // 차량이 충전 중인 경우
if (rfid.PICC_IsNewCardPresent() && rfid.PICC_ReadCardSerial()) { if (rfid.PICC_IsNewCardPresent() && rfid.PICC_ReadCardSerial()) { // 새 카드 감지 및 읽기 성공
memcpy(card_id, rfid.uid.uidByte, 4); memcpy(card_id, rfid.uid.uidByte, 4); // 카드 ID 복사
charging = 0; // 충전 중지
charging = 0; lcd_reset(); // LCD 초기화
lcd_clear(lcd_fd); lcd_loc(lcd_fd, LINE1); // 첫 번째 줄로 이동
lcd_loc(lcd_fd, LINE1); typeln(lcd_fd, "Charging Stopped"); // 충전 중지 메시지 출력
typeln(lcd_fd, "Charging Stopped"); sleep(2); // 2초 대기
sleep(2); }
} } else if (!charging) { // 차량이 충전 대기 중인 경우
} else if (!charging) { // 충전 대기중 (충전 시작 감지) lcd_reset(); // LCD 초기화
lcd_clear(lcd_fd);
lcd_loc(lcd_fd, LINE1); lcd_loc(lcd_fd, LINE1); // 첫 번째 줄로 이동
typeln(lcd_fd, "Scan your card"); typeln(lcd_fd, "Scan your card"); // 카드 스캔 요청 메시지 출력
lcd_loc(lcd_fd, LINE2); // 두 번째 줄로 이동
if (rfid.PICC_IsNewCardPresent() && rfid.PICC_ReadCardSerial()) { typeln(lcd_fd, "for 1 second"); // 카드 스캔 요청 메시지 출력
memcpy(card_id, rfid.uid.uidByte, 4); sleep(1); // 1초 대기
if (rfid.PICC_IsNewCardPresent() && rfid.PICC_ReadCardSerial()) { // 새 카드 감지 및 읽기 성공
charging = 1; memcpy(card_id, rfid.uid.uidByte, 4); // 카드 ID 복사
lcd_clear(lcd_fd);
lcd_loc(lcd_fd, LINE1); charging = 1; // 충전 시작
typeln(lcd_fd, "Card Accepted"); lcd_reset(); // LCD 초기화
lcd_loc(lcd_fd, LINE1); // 첫 번째 줄로 이동
typeln(lcd_fd, "Card Accepted"); // 카드 인식 메시지 출력
char uid_message[64]; char uid_message[64];
snprintf(uid_message, sizeof(uid_message), "0-d%02X%02X%02X%02X", card_id[0], card_id[1], card_id[2], card_id[3]); snprintf(uid_message, sizeof(uid_message), "0-d%02X%02X%02X%02X", card_id[0], card_id[1], card_id[2], card_id[3]); // 카드 ID 메시지 생성
send(client_socket, uid_message, strlen(uid_message), 0); send(client_socket, uid_message, strlen(uid_message), 0); // 서버로 전송
sleep(2); sleep(2); // 2초 대기
} }
} }
usleep(100000); usleep(100000); // 루프 대기 시간
} }
} }
return NULL; return NULL; // 스레드 종료
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment