From 9b0b3820b0e31d44ac3666c78dc183b934c93c14 Mon Sep 17 00:00:00 2001
From: dayoung Lee <ekdud305@ajou.ac.kr>
Date: Thu, 21 Dec 2023 14:54:38 +0900
Subject: [PATCH] Add new file

---
 gas_client.c | 150 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 150 insertions(+)
 create mode 100644 gas_client.c

diff --git a/gas_client.c b/gas_client.c
new file mode 100644
index 0000000..5d18d7d
--- /dev/null
+++ b/gas_client.c
@@ -0,0 +1,150 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <fcntl.h>
+#include <linux/spi/spidev.h>
+#include <linux/types.h>
+#include <stdint.h>
+#include <sys/ioctl.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
+static const char *DEVICE = "/dev/spidev0.0";
+static uint8_t MODE = 0;
+static uint8_t BITS = 8;
+static uint32_t CLOCK = 1000000;
+static uint16_t DELAY = 5;
+int sock;
+
+void error_handling(char *message, int sock)
+{                    // socket error날 시 handle
+    close(sock);     // socket 닫기
+    perror(message); // error message 출력
+    fputc('\n', stderr);
+    exit(1); // 종료
+}
+
+static int prepare(int fd)
+{ // SPI 통신 설정을 하는 함수
+    if (ioctl(fd, SPI_IOC_WR_MODE, &MODE) == -1)
+    { // SPI모드를 설정
+        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)
+    { // SPI통신 속도 설정
+        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)
+{                              // 주어진 채널에 대한 SPI 제어 비트를 생성
+    return (channel & 7) << 4; // 채널의 하위 3비트를 사용해 SPI제어 비트를 생성, 반환
+}
+
+uint8_t control_bits(uint8_t channel)
+{                                                    // SPI제어 비트를 생성
+    return 0x8 | control_bits_differential(channel); // 0x8을 OR연산하여 최종 SPI제어 비트를 반환
+}
+
+int readadc(int fd, uint8_t channel)
+{ // SPI통신을 통해 ADC값을 읽어오는 함수
+    uint8_t tx[] = {1, control_bits(channel), 0};
+    uint8_t rx[3];
+
+    struct spi_ioc_transfer tr = {
+        // SPI통신 설정을 지정
+        .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)
+    { // SPI통신 수행
+        perror("IO Error");
+        abort();
+    }
+
+    return ((rx[1] << 8) & 0x300) | (rx[2] & 0xFF); // 읽어온 데이터를 조합해 ADC를 계산하고 반환
+}
+
+int main(int argc, char *argv[])
+{
+
+    char val[3] = "10";
+    struct sockaddr_in server_addr;
+
+    if (argc != 3)
+    {
+        printf("Please deliver IP & Port num as argemnts Correctly!");
+        exit(1);
+    }
+
+    sock = socket(PF_INET, SOCK_STREAM, 0);
+    if (sock == -1)
+        error_handling("socket() error", sock);
+
+    memset(&server_addr, 0, sizeof(server_addr));
+    server_addr.sin_family = AF_INET;
+    server_addr.sin_addr.s_addr = inet_addr(argv[1]);
+    server_addr.sin_port = htons(atoi(argv[2]));
+
+    if (connect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1)
+        error_handling("connect() error", sock); // 서버연결
+
+    int fd = open(DEVICE, O_RDWR); // SPI장치 열기
+    if (fd <= 0)
+    {
+        perror("Device open error");
+        return -1;
+    }
+
+    if (prepare(fd) == -1)
+    {
+        perror("Device prepare error");
+        return -1;
+    }
+
+    while (1)
+    {
+        printf("value: %d , %d\n", readadc(fd, 0), readadc(fd, 1)); // 가스센서 채널:0 일산화탄소 채널:1
+        if (readadc(fd, 0) > 300 && readadc(fd, 1) > 300)
+        { // 아날로그 신호 읽기
+            if (write(sock, &val[0], 1) == -1)
+            {
+                perror("Client sending data error"); // 가스발생하면 서버에 1보내기
+                return -1;
+            }
+        }
+        else if (write(sock, &val[1], 1) == -1)
+        {
+            perror("Client sending data error"); // 발생하지 않으면 0보내기
+            return -1;
+        }
+        sleep(1); // 1초마다 측정을 반복
+    }
+}
-- 
GitLab