Files
esp32/BLE_Uart1_CSC_Notify.ino
dj99k 6ae01a0809 2026-07-22
BLE
UART1(GPIO20(TX), GPIO21(RX)) ---> CSC Check ---> SEND BLE ---> Adroid BLE 수신.
2026-07-22 23:42:16 +09:00

217 lines
6.3 KiB
Arduino

/*--------------------------------------
2026-07-22 PAYLOAD
----------------------------------------*/
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
#define LED_PIN1 8 // 수신 데이터에 따라 제어할 LED ESP32-C3
#define LED_PIN2 7 // BLE 연결 상태 표시 LED
BLEServer *pServer = NULL;
BLECharacteristic *pTxCharacteristic; // ESP32 -> Central (Notify)
BLECharacteristic *pRxCharacteristic; // Central -> ESP32 (Write)
bool deviceConnected = false;
bool oldDeviceConnected = false;
// Nordic UART UUID 세트
#define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"
// UART1 객체 생성 (USB CDC 대신 GPIO20/21 사용)
HardwareSerial MySerial(1);
// --- CSC 계산 관련 함수 ---
char nibbleToAscii(uint8_t nibble) {
return (nibble < 10) ? ('0' + nibble) : ('A' + (nibble - 10));
}
String calcChecksum(String data) {
uint32_t sum = 0;
for (int i = 0; i < data.length(); i++) {
sum += (uint8_t)data[i];
}
uint8_t oneByte = sum & 0xFF;
char csc[3];
csc[0] = nibbleToAscii((oneByte >> 4) & 0x0F);
csc[1] = nibbleToAscii(oneByte & 0x0F);
csc[2] = '\0';
return String(csc);
}
String verifyPacket(String cmd, String len, String payload, String recvCsc) {
String body = cmd + len + payload;
String calcCsc = calcChecksum(body);
return (calcCsc == recvCsc) ? "True" : "Fault";
}
// --- BLE 서버 콜백 ---
class MyServerCallbacks : public BLEServerCallbacks {
void onConnect(BLEServer* pServer) {
deviceConnected = true;
};
void onDisconnect(BLEServer* pServer) {
deviceConnected = false;
}
};
// --- BLE RX 콜백 ---
class MyCallbacks : public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pCharacteristic) {
String rxValue = pCharacteristic->getValue();
if (rxValue.length() > 0) {
Serial.print("BLE Rx: ");
Serial.println(rxValue);
// UART1로 에코
MySerial.print("Echo to UART: ");
MySerial.println(rxValue);
digitalWrite(LED_PIN1, HIGH); // test LED
delay(500);
digitalWrite(LED_PIN1, LOW);
}
}
};
void setup() {
Serial.begin(115200); //USB to Serial Port
// while (!Serial) { ; }
// UART1 초기화 (GPIO20=RX, GPIO21=TX)
MySerial.begin(115200, SERIAL_8N1, 20, 21);
// LED 핀 설정
pinMode(LED_PIN1, OUTPUT);
pinMode(LED_PIN2, OUTPUT);
digitalWrite(LED_PIN1, HIGH);
digitalWrite(LED_PIN2, HIGH);
// BLE 초기화
BLEDevice::init("MMS UART");
pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyServerCallbacks());
BLEService *pService = pServer->createService(SERVICE_UUID);
pTxCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID_TX,
BLECharacteristic::PROPERTY_NOTIFY
);
pTxCharacteristic->addDescriptor(new BLE2902());
pRxCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID_RX,
BLECharacteristic::PROPERTY_WRITE
);
pRxCharacteristic->setCallbacks(new MyCallbacks());
pService->start();
pServer->getAdvertising()->start();
Serial.println("Waiting a client connection to notify...");
}
void loop() {
if (deviceConnected) {
digitalWrite(LED_PIN2, LOW);
// UART1에서 들어온 데이터를 BLE로 전송
if (MySerial.available() > 0) {
String uartData = MySerial.readStringUntil('\n');
uartData.trim();
if (uartData.length() > 7) {
Serial.print("UART Rx(BLE SEND): ");
Serial.println(uartData);
// 파싱: CMD(1) + LEN(4) + PAYLOAD + CSC(2)
String cmd = uartData.substring(0, 1);
String len = uartData.substring(1, 5);
String payload = uartData.substring(5, uartData.length() - 2);
String recvCsc = uartData.substring(uartData.length() - 2);
Serial.print("CMD: "); Serial.println(cmd);
Serial.print("LEN: "); Serial.println(len);
Serial.print("PAYLOAD: "); Serial.println(payload);
Serial.print("Recv CSC: "); Serial.println(recvCsc);
String result = verifyPacket(cmd, len, payload, recvCsc);
Serial.print("CSC Verify Result: ");
Serial.println(result);
if (result == "True") {
// LED ON
digitalWrite(LED_PIN1, HIGH);
// BLE Notify 전송 (True일 때만)
pTxCharacteristic->setValue(uartData.c_str());
pTxCharacteristic->notify();
Serial.println("Sent to BLE (Notify).");
delay(500);
digitalWrite(LED_PIN1, LOW);
} else {
// Fault일 경우 데이터 버림, LED OFF
Serial.println("Fault detected, data discarded.");
digitalWrite(LED_PIN1, HIGH);
delay(100);
digitalWrite(LED_PIN1, LOW);
delay(100);
digitalWrite(LED_PIN1, HIGH);
delay(100);
digitalWrite(LED_PIN1, LOW);
}
}
}
} else {
digitalWrite(LED_PIN2, HIGH);
}
if (!deviceConnected && oldDeviceConnected) {
delay(500);
pServer->startAdvertising();
Serial.println("start advertising");
oldDeviceConnected = deviceConnected;
}
if (deviceConnected && !oldDeviceConnected) {
digitalWrite(LED_PIN1, HIGH);
delay(500);
digitalWrite(LED_PIN1, LOW);
delay(500);
digitalWrite(LED_PIN1, HIGH);
delay(500);
digitalWrite(LED_PIN1, LOW);
oldDeviceConnected = deviceConnected;
}
delay(10);
}
/*
방금 올려주신 BLE/UART 브리지 코드에 UART 수신 데이터 CSC 검증을 그대로 적용한 버전을 준비했습니다.
이제 시리얼로 입력된 패킷을 <CMD><LEN><PAYLOAD><CSC> 구조로 파싱하고, CSC가 맞으면 "True", 틀리면 "Fault"를 출력하며 LED1 상태도 반영합니다.
CSC 계산 함수(calcChecksum)와 검증 함수(verifyPacket) 추가.
loop()에서 UART 수신 시 패킷을 파싱하고 CSC 검증 수행.
결과 "True"/"Fault"를 시리얼 출력.
LED1은 "True"일 때 ON, "Fault"일 때 OFF.
BLE Notify는 원본 UART 데이터를 그대로 전송.
Fault 일떄는 데이터를 버리고, 다음 데이터 수신하여 true이면 ble로 전송하도록 할 것
-> CSC 검증 후 "Fault"일 경우:
BLE 전송 하지 않음.
데이터 버림.
LED1 OFF.
"True"일 경우:
BLE Notify 전송.
LED1 ON.
*/