Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
S
Sys
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package registry
Container registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Terms and privacy
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
GIHO KOH
Sys
Merge requests
!1
Add new file (센싱보드 코드)
Code
Review changes
Check out branch
Download
Patches
Plain diff
Merged
Add new file (센싱보드 코드)
son4216/sys:son4216-main-patch-11807
into
main
Overview
0
Commits
1
Pipelines
0
Changes
1
Merged
영현 손
requested to merge
son4216/sys:son4216-main-patch-11807
into
main
11 months ago
Overview
0
Commits
1
Pipelines
0
Changes
1
Expand
0
0
Merge request reports
Viewing commit
005ac1b5
Show latest version
1 file
+
430
−
0
Side-by-side
Compare changes
Side-by-side
Inline
Show whitespace changes
Show one file at a time
005ac1b5
Add new file (센싱보드 코드)
· 005ac1b5
영현 손
authored
11 months ago
yeonghyeon.c
0 → 100644
+
430
−
0
Options
#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
\0
out"
;
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