Skip to content
Snippets Groups Projects

Add new file (센싱보드 코드)

Merged 영현 손 requested to merge son4216/sys:son4216-main-patch-11807 into main
1 file
+ 430
0
Compare changes
  • Side-by-side
  • Inline
yeonghyeon.c 0 → 100644
+ 430
0
 
#include <arpa/inet.h>
 
#include <fcntl.h>
 
#include <stdio.h>
 
#include <stdlib.h>
 
#include <string.h>
 
#include <sys/socket.h>
 
#include <sys/stat.h>
 
#include <sys/types.h>
 
#include <unistd.h>
 
#include <sys/select.h>
 
#include <sys/time.h>
 
#include <pthread.h>
 
#include <linux/spi/spidev.h>
 
#include <linux/types.h>
 
#include <signal.h>
 
 
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
 
#define BUFFER_MAX 3
 
#define DIRECTION_MAX 256
 
#define VALUE_MAX 256
 
 
// GPIO 핀 정의
 
#define IN 0
 
#define OUT 1
 
#define LOW 0
 
#define HIGH 1
 
 
// 우적 센서의 GPIO 핀 번호
 
#define RAIN_SENSOR_PIN 16
 
 
// 가스와 소음 센서의 임계값 설정
 
#define GAS_THRESHOLD 500
 
#define SOUND_THRESHOLD 30
 
 
// SPI 설정
 
static const char *DEVICE = "/dev/spidev0.0"; // SPI 장치 파일 경로
 
static uint8_t MODE = 0;
 
static uint8_t BITS = 8;
 
static uint32_t CLOCK = 1000000; // 1MHz
 
static uint16_t DELAY = 5;
 
static int SAMPLE_SIZE = 10; // 소음 센서 평균을 계산할 샘플 크기
 
 
// 서버 정보
 
const char* SERVER_IP = "192.168.22.4"; // 서버 IP
 
const int SERVER_PORT = 8800; // 서버 포트
 
 
// 전역 소켓 변수
 
int sock;
 
int spi_fd;
 
 
// 전역 상태 변수
 
int rain_status = 0;
 
int gas_status = 0;
 
int sound_status = 0;
 
int rain_initialized = 0; // 초기 상태 전송 플래그
 
int gas_initialized = 0; // 초기 상태 전송 플래그
 
int sound_initialized = 0; // 초기 상태 전송 플래그
 
pthread_mutex_t status_mutex = PTHREAD_MUTEX_INITIALIZER; // 상태 변수 보호용 뮤텍스
 
 
// GPIO 함수 선언
 
static int GPIOExport(int pin);
 
static int GPIOUnexport(int pin);
 
static int GPIODirection(int pin, int dir);
 
static int GPIORead(int pin);
 
 
// 센서 스레드 함수 선언
 
void* rain_sensor_routine(void* arg);
 
void* gas_sensor_routine(void* arg);
 
void* sound_sensor_routine(void* arg);
 
 
// 클라이언트 소켓 함수 선언
 
void setup_socket();
 
void send_message_to_server(int value);
 
void dispose();
 
void update_status_and_send_message();
 
 
// 인터럽트 핸들러 함수
 
void handle_interrupt(int sig) {
 
dispose();
 
exit(0);
 
}
 
 
// GPIO 핀을 시스템에 export 위한 함수
 
static int GPIOExport(int pin) {
 
char buffer[3];
 
int fd = open("/sys/class/gpio/export", O_WRONLY);
 
if (fd == -1) {
 
perror("Failed to open export for writing");
 
return -1;
 
}
 
snprintf(buffer, 3, "%d", pin);
 
if (write(fd, buffer, 3) == -1) {
 
perror("Failed to export gpio");
 
close(fd);
 
return -1;
 
}
 
close(fd);
 
return 0;
 
}
 
 
// GPIO 핀을 시스템에서 unexport 위한 함수
 
static int GPIOUnexport(int pin) {
 
char buffer[3];
 
int fd = open("/sys/class/gpio/unexport", O_WRONLY);
 
if (fd == -1) {
 
perror("Failed to open unexport for writing");
 
return -1;
 
}
 
snprintf(buffer, 3, "%d", pin);
 
if (write(fd, buffer, 3) == -1) {
 
perror("Failed to unexport gpio");
 
close(fd);
 
return -1;
 
}
 
close(fd);
 
return 0;
 
}
 
 
// GPIO 핀의 방향을 설정하는 함수
 
static int GPIODirection(int pin, int dir) {
 
const char s_directions_str[] = "in\0out";
 
char path[40];
 
int fd;
 
 
snprintf(path, 40, "/sys/class/gpio/gpio%d/direction", pin);
 
fd = open(path, O_WRONLY);
 
if (fd == -1) {
 
perror("Failed to open gpio direction for writing");
 
return -1;
 
}
 
 
if (write(fd, &s_directions_str[IN == dir ? 0 : 3], IN == dir ? 2 : 3) == -1) {
 
perror("Failed to set direction");
 
close(fd);
 
return -1;
 
}
 
close(fd);
 
return 0;
 
}
 
 
// GPIO 핀의 값을 읽어오는 함수
 
static int GPIORead(int pin) {
 
char path[40];
 
char value_str[3];
 
int fd;
 
 
snprintf(path, 40, "/sys/class/gpio/gpio%d/value", pin);
 
fd = open(path, O_RDONLY);
 
if (fd == -1) {
 
perror("Failed to open gpio value for reading");
 
return -1;
 
}
 
 
if (read(fd, value_str, 3) == -1) {
 
perror("Failed to read value");
 
close(fd);
 
return -1;
 
}
 
close(fd);
 
 
return atoi(value_str);
 
}
 
 
// 클라이언트 소켓 설정 함수
 
void setup_socket() {
 
struct sockaddr_in serv_addr;
 
 
sock = socket(PF_INET, SOCK_STREAM, 0);
 
if (sock == -1) {
 
perror("socket() error");
 
exit(1);
 
}
 
 
memset(&serv_addr, 0, sizeof(serv_addr));
 
serv_addr.sin_family = AF_INET;
 
serv_addr.sin_addr.s_addr = inet_addr(SERVER_IP);
 
serv_addr.sin_port = htons(SERVER_PORT);
 
 
if (connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) == -1) {
 
perror("connect() error");
 
close(sock);
 
exit(1);
 
}
 
 
printf("Connection established\n");
 
}
 
 
// 클라이언트 소켓으로 서버에 메시지를 보내는 함수
 
void send_message_to_server(int value) {
 
char output_str[3] = {0};
 
snprintf(output_str, sizeof(output_str), "%d", value);
 
int len = write(sock, output_str, strlen(output_str));
 
if (len == -1) {
 
perror("write() error");
 
} else {
 
printf("Sent message to server: %s\n", output_str);
 
}
 
}
 
 
// 자원 해제 함수. 강제 종료했을 때, 리소스 오류를 방지
 
void dispose() {
 
GPIOUnexport(RAIN_SENSOR_PIN);
 
close(sock);
 
close(spi_fd);
 
pthread_mutex_destroy(&status_mutex);
 
printf("Resources disposed\n");
 
}
 
 
// 상태 업데이트 및 메시지 전송 함수
 
void update_status_and_send_message() {
 
pthread_mutex_lock(&status_mutex); // 상태 변수 보호를 위해 뮤텍스 사용
 
if (rain_initialized && gas_initialized && sound_initialized) {
 
int combined_status = rain_status + gas_status + sound_status;
 
send_message_to_server(combined_status);
 
}
 
pthread_mutex_unlock(&status_mutex);
 
}
 
 
// 우적 센서 스레드 함수
 
void* rain_sensor_routine(void* arg) {
 
int previous_state = -1; // 이전 상태를 저장하기 위한 변수
 
while (1) {
 
int value = GPIORead(RAIN_SENSOR_PIN);
 
if (value == -1) {
 
printf("Failed to read from rain sensor\n");
 
break;
 
}
 
int current_state = (value == LOW) ? 1 : 0; // 비 감지 시 1, 비 없음 시 0
 
if (current_state == 1) {
 
printf("빗물 감지\n");
 
}
 
if (current_state != previous_state) {
 
pthread_mutex_lock(&status_mutex); // 상태 변수 보호를 위해 뮤텍스 사용
 
rain_status = current_state == 1 ? 1 : 0;
 
rain_initialized = 1;
 
pthread_mutex_unlock(&status_mutex);
 
update_status_and_send_message();
 
previous_state = current_state;
 
}
 
usleep(1000000); // 1초 대기
 
}
 
return NULL;
 
}
 
 
// SPI 준비 함수
 
static int prepare(int fd) {
 
if (ioctl(fd, SPI_IOC_WR_MODE, &MODE) == -1) {
 
perror("Can't set MODE");
 
return -1;
 
}
 
 
if (ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &BITS) == -1) {
 
perror("Can't set number of BITS");
 
return -1;
 
}
 
 
if (ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &CLOCK) == -1) {
 
perror("Can't set write CLOCK");
 
return -1;
 
}
 
 
if (ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &CLOCK) == -1) {
 
perror("Can't set read CLOCK");
 
return -1;
 
}
 
 
return 0;
 
}
 
 
// 차동 모드용 컨트롤 비트를 생성하는 함수
 
uint8_t control_bits_differential(uint8_t channel) {
 
return (channel & 7) << 4;
 
}
 
 
// 단일 모드용 컨트롤 비트를 생성하는 함수
 
uint8_t control_bits(uint8_t channel) {
 
return 0x8 | control_bits_differential(channel);
 
}
 
 
// ADC 값을 읽어오는 함수
 
int readadc(int fd, uint8_t channel) {
 
uint8_t tx[] = {1, control_bits(channel), 0};
 
uint8_t rx[3];
 
 
struct spi_ioc_transfer tr = {
 
.tx_buf = (unsigned long)tx,
 
.rx_buf = (unsigned long)rx,
 
.len = ARRAY_SIZE(tx),
 
.delay_usecs = DELAY,
 
.speed_hz = CLOCK,
 
.bits_per_word = BITS,
 
};
 
 
if (ioctl(fd, SPI_IOC_MESSAGE(1), &tr) == 1) {
 
perror("IO Error");
 
abort();
 
}
 
 
return ((rx[1] << 8) & 0x300) | (rx[2] & 0xFF);
 
}
 
 
// 가스 센서 스레드 함수
 
void* gas_sensor_routine(void* arg) {
 
int fd = *(int*)arg;
 
int previous_state = -1; // 이전 상태를 저장하기 위한 변수
 
 
while (1) {
 
int value = readadc(fd, 0); // 채널 0 사용
 
printf("가스 센서 값: %d\n", value);
 
 
int current_state = (value > GAS_THRESHOLD) ? 1 : 0; // 가스 감지 시 1, 가스 없음 시 0
 
if (current_state != previous_state) {
 
pthread_mutex_lock(&status_mutex); // 상태 변수 보호를 위해 뮤텍스 사용
 
gas_status = current_state == 1 ? 2 : 0;
 
gas_initialized = 1;
 
pthread_mutex_unlock(&status_mutex);
 
update_status_and_send_message();
 
previous_state = current_state;
 
}
 
 
usleep(1000000); // 1초 대기
 
}
 
 
return NULL;
 
}
 
 
// 소음 센서 스레드 함수
 
void* sound_sensor_routine(void* arg) {
 
int fd = *(int*)arg;
 
int32_t samples[SAMPLE_SIZE];
 
int sample_index = 0;
 
int previous_state = -1; // 이전 상태를 저장하기 위한 변수
 
 
while (1) {
 
int value = readadc(fd, 7); // 채널 7 사용
 
samples[sample_index] = value;
 
sample_index = (sample_index + 1) % SAMPLE_SIZE;
 
 
if (sample_index == 0) {
 
int32_t sum = 0;
 
for (int i = 0; i < SAMPLE_SIZE; i++) {
 
sum += samples[i];
 
}
 
int32_t average_value = sum / SAMPLE_SIZE;
 
printf("소음 센서 평균 값: %d\n", average_value);
 
 
int current_state = (average_value > SOUND_THRESHOLD) ? 1 : 0; // 소음 감지 시 1, 소음 없음 시 0
 
if (current_state != previous_state) {
 
pthread_mutex_lock(&status_mutex); // 상태 변수 보호를 위해 뮤텍스 사용
 
sound_status = current_state == 1 ? 4 : 0;
 
sound_initialized = 1;
 
pthread_mutex_unlock(&status_mutex);
 
update_status_and_send_message();
 
previous_state = current_state;
 
}
 
}
 
 
usleep(1000000); // 1초 대기
 
}
 
 
return NULL;
 
}
 
 
int main(int argc, char **argv) {
 
// 인터럽트 신호 처리 설정
 
signal(SIGINT, handle_interrupt);
 
signal(SIGTERM, handle_interrupt);
 
 
// SPI 장치 열기
 
spi_fd = open(DEVICE, O_RDWR);
 
if (spi_fd <= 0) {
 
perror("Device open error");
 
return -1;
 
}
 
 
// SPI 장치 준비
 
if (prepare(spi_fd) == -1) {
 
perror("Device prepare error");
 
return -1;
 
}
 
 
// 소켓 설정
 
setup_socket();
 
 
pthread_t rain_thread, gas_thread, sound_thread;
 
 
// GPIO 초기화
 
if (GPIOExport(RAIN_SENSOR_PIN) == -1) {
 
return 1;
 
}
 
if (GPIODirection(RAIN_SENSOR_PIN, IN) == -1) {
 
return 1;
 
}
 
 
printf("프로그램이 시작되었습니다. 센싱을 시작하기 전에 초기 설정을 완료합니다.\n");
 
printf("10초 후에 센싱을 시작합니다. 잠시 후에 초기 값이 출력이 됩니다.\n");
 
printf("먼저 소음 센서부터 센싱을 시작하며, 9초 후에 가스 센서와 우적 센서가 순차적으로 시작됩니다.\n");
 
printf("센서 상태 코드: 정상 상태: 0, 우적 감지: 1, 가스 감지: 2, 소음 감지: 4\n");
 
printf("복합 상태 코드: 우적 + 가스: 3, 우적 + 소음: 5, 가스 + 소음: 6, 우적 + 가스 + 소음: 7\n");
 
printf("[초기 상태]\n");
 
 
// 소음 센서 스레드 생성
 
if (pthread_create(&sound_thread, NULL,sound_sensor_routine, &spi_fd) != 0) {
 
perror("Failed to create sound sensor thread");
 
return 1;
 
}
 
 
usleep(9000000); // 9초 대기
 
// 우적 센서 스레드 생성
 
if (pthread_create(&rain_thread, NULL, rain_sensor_routine, NULL) != 0) {
 
perror("Failed to create rain sensor thread");
 
return 1;
 
}
 
 
// 가스 센서 스레드 생성
 
if (pthread_create(&gas_thread, NULL, gas_sensor_routine, &spi_fd) != 0) {
 
perror("Failed to create gas sensor thread");
 
return 1;
 
}
 
 
// 스레드 종료 대기
 
pthread_join(rain_thread, NULL);
 
pthread_join(gas_thread, NULL);
 
pthread_join(sound_thread, NULL);
 
 
// 자원 해제
 
dispose();
 
 
return 0;
 
}
Loading