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;
}