LoRa 송신 및 수신 코드

By | 2025년 1월 21일
Table of Contents

LoRa 송신 및 수신 코드

이런 코드 따위는 인공지능이 작성해 주더라…

Visual C++ 에서 컴파일하는 방법

  • Developer Command Prompt for VS 관리자권한으로 실행
  • 소스코드 경로로 이동
  • cl /MT /O2 /utf-8 lora.c /link advapi32.lib
  • cl /MT /O2 /utf-8 /W4 /EHsc lora.c /link advapi32.lib user32.lib /OUT:lora.exe

소스코드

#include <windows.h>
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <conio.h>  // _kbhit(), _getch() 사용
#include <locale.h>
#include <wchar.h>

#define MAX_PORT_NAME 20
#define MAX_MESSAGE_LENGTH 256
#define BROADCAST_INTERVAL 2500  // 메시지 전송 간격 (밀리초)

// uLory 장치 구조체
typedef struct {
    HANDLE hSerial;
    bool connected;
} ULoryDevice;

// 장치 초기화 함수
void initULoryDevice(ULoryDevice* device) {
    device->hSerial = INVALID_HANDLE_VALUE;
    device->connected = false;
}

// 시리얼 포트 설정 함수
bool configureSerialPort(HANDLE hSerial) {
    DCB dcbSerialParams = { 0 };
    dcbSerialParams.DCBlength = sizeof(dcbSerialParams);

    if (!GetCommState(hSerial, &dcbSerialParams)) {
        return false;
    }

    // uLory 기본 통신 설정
    dcbSerialParams.BaudRate = CBR_9600;  // 9600 보드레이트
    dcbSerialParams.ByteSize = 8;         // 8 데이터 비트
    dcbSerialParams.StopBits = ONESTOPBIT;
    dcbSerialParams.Parity = NOPARITY;

    dcbSerialParams.fOutxCtsFlow = TRUE;
    dcbSerialParams.fRtsControl = RTS_CONTROL_HANDSHAKE;

    dcbSerialParams.fBinary = TRUE;
    dcbSerialParams.fParity = FALSE;

    if (!SetCommState(hSerial, &dcbSerialParams)) {
        return false;
    }

    // 타임아웃 설정
    COMMTIMEOUTS timeouts = { 0 };
    timeouts.ReadIntervalTimeout = 10;         // 더 짧은 인터벌
    timeouts.ReadTotalTimeoutConstant = 10;    // 더 짧은 타임아웃
    timeouts.ReadTotalTimeoutMultiplier = 1;   // 더 작은 승수
    timeouts.WriteTotalTimeoutConstant = 10;   // 더 짧은 타임아웃
    timeouts.WriteTotalTimeoutMultiplier = 1;  // 더 작은 승수

    if (!SetCommTimeouts(hSerial, &timeouts)) {
        return false;
    }

    return true;
}

// 장치 연결 함수
bool connectULory(ULoryDevice* device, wchar_t* portName) {
    char deviceName[MAX_PORT_NAME];
    wcstombs(deviceName, portName, MAX_PORT_NAME);
    device->hSerial = CreateFile(deviceName,
        GENERIC_READ | GENERIC_WRITE,
        0,
        0,
        OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL,
        0);

    if (device->hSerial == INVALID_HANDLE_VALUE) {
        DWORD error = GetLastError();
        wprintf(L"포트 열기 실패: %ls (오류 코드: %lu)\n", portName, error);
        return false;
    }

    if (!configureSerialPort(device->hSerial)) {
        CloseHandle(device->hSerial);
        wprintf(L"포트 설정 실패\n");
        return false;
    }

    device->connected = true;
    return true;
}

// 문자열 브로드캐스트 함수
bool broadcastString(ULoryDevice* device, const wchar_t* message) {
    if (!device->connected) {
        wprintf(L"장치가 연결되어 있지 않습니다.\n");
        return false;
    }

    PurgeComm(device->hSerial, PURGE_TXCLEAR | PURGE_RXCLEAR);

    unsigned bufferSize = WideCharToMultiByte(CP_UTF8, 0, message, -1, NULL, 0, NULL, NULL);
    char* utf8Buffer = (char*)malloc(bufferSize);
    WideCharToMultiByte(CP_UTF8, 0, message, -1, utf8Buffer, bufferSize, NULL, NULL);

    DWORD bytesWritten;
    bool success = WriteFile(device->hSerial, utf8Buffer, bufferSize-1, &bytesWritten, NULL);
    free(utf8Buffer);

    if (!success) {
        wprintf(L"메시지 전송 실패\n");
        return false;
    }

    FlushFileBuffers(device->hSerial);

    if (bytesWritten != (bufferSize-1)) {
        wprintf(L"일부 데이터만 전송됨: %lu / %lu bytes\n", bytesWritten, (bufferSize-1));
        return false;
    }

    return true;
}

// 장치 연결 해제 함수
void disconnectULory(ULoryDevice* device) {
    if (device->connected) {
        const char* stopCmd = "AT+STOP\r\n";
        WriteFile(device->hSerial, stopCmd, strlen(stopCmd), NULL, NULL);
        Sleep(100);

        CloseHandle(device->hSerial);
        device->connected = false;
        device->hSerial = INVALID_HANDLE_VALUE;
    }
}

// COM 포트 번호 입력 받기
void getComPort(wchar_t* portName, size_t maxLength) {
    int portNumber;
    bool validInput = false;

    while (!validInput) {
        wprintf(L"COM 포트 번호를 입력하세요 (1-256): ");
        if (scanf_s("%d", &portNumber) == 1) {
            if (portNumber > 0 && portNumber < 257) {
                swprintf(portName, maxLength, L"\\\\.\\COM%d", portNumber);
                validInput = true;
            } else {
                wprintf(L"유효하지 않은 포트 번호입니다. 1-256 사이의 숫자를 입력하세요.\n");
            }
        } else {
            wprintf(L"잘못된 입력입니다. 숫자를 입력하세요.\n");
            // 입력 버퍼 비우기
            while (getchar() != '\n');
        }
    }
    // 입력 버퍼 비우기
    while (getchar() != '\n');
}

// 메시지 입력 받기
void getMessage(wchar_t* message, size_t maxLength) {
    wprintf(L"전송할 메시지를 입력하세요: ");
    fgetws(message, maxLength, stdin);

    // 개행 문자 제거
    size_t len = wcslen(message);
    if (len > 0 && message[len-1] == L'\n') {
        message[len-1] = L'\0';
    }
}

int main() {
    ULoryDevice device;
    wchar_t portName[MAX_PORT_NAME];
    wchar_t message[MAX_MESSAGE_LENGTH];
    DWORD messageCount = 0;

    setlocale(LC_ALL, "Korean");
    // SetConsoleOutputCP(CP_UTF8);
    // SetConsoleCP(CP_UTF8);

    initULoryDevice(&device);

    // COM 포트 번호 입력 받기
    getComPort(portName, MAX_PORT_NAME);

    if (!connectULory(&device, portName)) {
        wprintf(L"uLory 장치 연결 실패\n");
        return 1;
    }

    wprintf(L"uLory 장치가 연결되었습니다. (%ls)\n", portName);

    // 전송할 메시지 입력 받기
    getMessage(message, MAX_MESSAGE_LENGTH);

    wprintf(L"\n메시지 전송을 시작합니다. 종료하려면 'q' 키를 누르세요.\n\n");

    // 무한 루프로 메시지 전송
    while (1) {
        if (broadcastString(&device, message)) {
            messageCount++;
            wprintf(L"\r메시지 전송 성공 (총 %lu회): %ls", messageCount, message);
        } else {
            wprintf(L"\n메시지 전송 실패\n");
            break;
        }

        // 키 입력 확인
        if (_kbhit()) {
            int ch = _getch();
            if (ch == 'q' || ch == 'Q') {
                wprintf(L"\n\n사용자가 종료를 요청했습니다.\n");
                break;
            }
        }

        // 전송 간격 대기
        Sleep(BROADCAST_INTERVAL);
    }

    // 장치 연결 해제
    disconnectULory(&device);
    wprintf(L"장치 연결이 해제되었습니다.\n");

    return 0;
}
#include <windows.h>
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <conio.h>
#include <locale.h>
#include <wchar.h>

#define MAX_PORT_NAME 20
#define BUFFER_SIZE 1024

typedef struct {
    HANDLE hSerial;
    bool connected;
} ULoryReceiver;

void initReceiver(ULoryReceiver* receiver) {
    receiver->hSerial = INVALID_HANDLE_VALUE;
    receiver->connected = false;
}

bool configureSerialPort(HANDLE hSerial) {
    DCB dcbSerialParams = { 0 };
    dcbSerialParams.DCBlength = sizeof(dcbSerialParams);

    if (!GetCommState(hSerial, &dcbSerialParams)) {
        return false;
    }

    dcbSerialParams.BaudRate = CBR_9600;
    dcbSerialParams.ByteSize = 8;
    dcbSerialParams.StopBits = ONESTOPBIT;
    dcbSerialParams.Parity = NOPARITY;

    dcbSerialParams.fOutxCtsFlow = TRUE;
    dcbSerialParams.fRtsControl = RTS_CONTROL_HANDSHAKE;

    dcbSerialParams.fBinary = TRUE;
    dcbSerialParams.fParity = FALSE;

    if (!SetCommState(hSerial, &dcbSerialParams)) {
        return false;
    }

    COMMTIMEOUTS timeouts = { 0 };
    timeouts.ReadIntervalTimeout = 10;
    timeouts.ReadTotalTimeoutConstant = 10;
    timeouts.ReadTotalTimeoutMultiplier = 1;
    timeouts.WriteTotalTimeoutConstant = 10;
    timeouts.WriteTotalTimeoutMultiplier = 1;

    if (!SetCommTimeouts(hSerial, &timeouts)) {
        return false;
    }

    return true;
}

bool connectReceiver(ULoryReceiver* receiver, wchar_t* portName) {
    char deviceName[MAX_PORT_NAME];
    wcstombs(deviceName, portName, MAX_PORT_NAME);

    receiver->hSerial = CreateFile(deviceName,
        GENERIC_READ | GENERIC_WRITE,
        0,
        0,
        OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL,
        0);

    if (receiver->hSerial == INVALID_HANDLE_VALUE) {
        DWORD error = GetLastError();
        wprintf(L"포트 열기 실패: %ls (오류 코드: %lu)\n", portName, error);
        return false;
    }

    if (!configureSerialPort(receiver->hSerial)) {
        CloseHandle(receiver->hSerial);
        wprintf(L"포트 설정 실패\n");
        return false;
    }

    receiver->connected = true;
    return true;
}

bool receiveData(ULoryReceiver* receiver, wchar_t* buffer, DWORD bufferSize, DWORD* bytesRead) {
    static char tempBuffer[BUFFER_SIZE];
    static DWORD remainBytes = 0;

    if (!receiver->connected) {
        wprintf(L"장치가 연결되어 있지 않습니다.\n");
        return false;
    }

    if (!ReadFile(receiver->hSerial, tempBuffer + remainBytes, 
                 BUFFER_SIZE - remainBytes - 1, bytesRead, NULL)) {
        return false;
    }

    DWORD totalBytes = remainBytes + *bytesRead;
    tempBuffer[totalBytes] = '\0';

    // UTF-8 문자열을 와이드 문자열로 변환
    unsigned wideLen = MultiByteToWideChar(CP_UTF8, 0, tempBuffer, totalBytes, NULL, 0);
    if (wideLen > 0 && wideLen < bufferSize) {
        MultiByteToWideChar(CP_UTF8, 0, tempBuffer, totalBytes, buffer, wideLen);
        buffer[wideLen] = L'\0';
        *bytesRead = wideLen;
        return true;
    }

    return false;
}

void disconnectReceiver(ULoryReceiver* receiver) {
    if (receiver->connected) {
        CloseHandle(receiver->hSerial);
        receiver->connected = false;
        receiver->hSerial = INVALID_HANDLE_VALUE;
    }
}

void getComPort(wchar_t* portName, size_t maxLength) {
    int portNumber;
    bool validInput = false;

    while (!validInput) {
        wprintf(L"COM 포트 번호를 입력하세요 (1-256): ");
        if (scanf_s("%d", &portNumber) == 1) {
            if (portNumber > 0 && portNumber < 257) {
                swprintf(portName, maxLength, L"\\\\.\\COM%d", portNumber);
                validInput = true;
            } else {
                wprintf(L"유효하지 않은 포트 번호입니다. 1-256 사이의 숫자를 입력하세요.\n");
            }
        } else {
            wprintf(L"잘못된 입력입니다. 숫자를 입력하세요.\n");
            while (getchar() != '\n');
        }
    }
    while (getchar() != '\n');
}

int main() {
    ULoryReceiver receiver;
    wchar_t portName[MAX_PORT_NAME];
    wchar_t buffer[BUFFER_SIZE];
    DWORD bytesRead;
    DWORD messageCount = 0;

    setlocale(LC_ALL, "Korean");

    initReceiver(&receiver);

    getComPort(portName, MAX_PORT_NAME);

    if (!connectReceiver(&receiver, portName)) {
        wprintf(L"수신 장치 연결 실패\n");
        return 1;
    }

    wprintf(L"수신 장치가 연결되었습니다. (%ls)\n", portName);
    wprintf(L"\n데이터 수신을 시작합니다. 종료하려면 'q' 키를 누르세요.\n\n");

    while (1) {
        wmemset(buffer, 0, BUFFER_SIZE);

        if (receiveData(&receiver, buffer, BUFFER_SIZE, &bytesRead) && bytesRead > 0) {
            messageCount++;
            wprintf(L"\r수신된 메시지 (총 %lu회): %ls", messageCount, buffer);
            Sleep(100);
        }

        if (_kbhit()) {
            int ch = _getch();
            if (ch == 'q' || ch == 'Q') {
                wprintf(L"\n\n사용자가 종료를 요청했습니다.\n");
                break;
            }
        }
    }

    disconnectReceiver(&receiver);
    wprintf(L"장치 연결이 해제되었습니다.\n");

    return 0;
}

답글 남기기