Răsfoiți Sursa

adding Docs

Aldino Arya Pramana 7 luni în urmă
părinte
comite
ae1f16d6aa

+ 0 - 0
DOCUMENT LOG SHEET - PROJECT TASK TIMELINE - Bluetooth LE.pdf → docs/DOCUMENT LOG SHEET - PROJECT TASK TIMELINE - Bluetooth LE.pdf


BIN
docs/Project Docs.docx


BIN
src/LC3_Codec_Python/audio.mp3


BIN
src/LC3_Codec_Python/audio.wav


+ 22 - 41
src/LC3_Codec_Python/testlc3.py

@@ -1,44 +1,25 @@
-import sounddevice as sd
+import serial
+import wave
 import numpy as np
 import time
-import struct
 
-FS = 16000
-FRAME_MS = 7.5
-SAMPLES_PER_FRAME = int(FS * FRAME_MS / 1000)
-sequence_number = 0
-
-def lc3_encode(pcm_frame):
-    return bytes((pcm_frame >> 8).astype(np.uint8))
-
-def make_lc3_packet(sequence_number, lc3_payload):
-    timestamp = int(time.time() * 1000) & 0xFFFFFFFF
-    packet = struct.pack('<HI', sequence_number, timestamp) + lc3_payload
-    return packet
-
-# ------------------------
-# Stream input + output
-# ------------------------
-def audio_callback(indata, outdata, frames, time_info, status):
-    global sequence_number
-    pcm_frame = (indata[:,0] * 32767).astype(np.int16)
-
-    # Encode LC3 (simulasi)
-    lc3_frame = lc3_encode(pcm_frame)
-    pkt = make_lc3_packet(sequence_number, lc3_frame)
-    sequence_number = (sequence_number + 1) % 65536
-
-    # Kirim PCM asli ke outdata (realtime)
-    outdata[:,0] = pcm_frame / 32768.0  # normalisasi float -1..1
-
-    print(f"SN={sequence_number}, Paket size={len(pkt)} bytes")
-
-with sd.Stream(samplerate=FS, blocksize=SAMPLES_PER_FRAME,
-               dtype='float32',
-               channels=1, callback=audio_callback):
-    print("Recording from mic... Speak now! Press Ctrl+C to stop")
-    try:
-        while True:
-            time.sleep(1)
-    except KeyboardInterrupt:
-        print("Stopped")
+# Serial ke ESP32
+ser = serial.Serial("COM8", 115200)
+
+# Load WAV mono 16-bit
+wav_file = wave.open("audio.wav", "rb")
+frames_per_packet = 30
+
+while True:
+    raw = wav_file.readframes(frames_per_packet)
+    if len(raw) == 0:
+        break
+    # Convert ke int16
+    pcm = np.frombuffer(raw, dtype=np.int16)
+    # Dummy LC3 encode: 60 byte
+    lc3_frame = bytearray(60)
+    for i in range(60):
+        lc3_frame[i] = pcm[i % len(pcm)] & 0xFF
+    # Kirim ke ESP32
+    ser.write(b'\x55' + lc3_frame)
+    time.sleep(0.01)  # 10ms per frame

+ 103 - 62
src/main/main.ino

@@ -1,21 +1,35 @@
 #include <BLEDevice.h>
 #include <BLEServer.h>
 #include <BLEUtils.h>
+#include <BLEScan.h>
+#include <BLEAdvertisedDevice.h>
 #include <BLE2902.h>
 #include <ArduinoJson.h>
 #include <map>
 
-std::map<int, int> connIdToIndex;  // mapping connId → index di array Devices
+#define AUDIO_FRAME_SIZE 60
+uint8_t audioBuffer[AUDIO_FRAME_SIZE];
+int bufferIndex = 0;
+bool readingAudio = false;
+
+// Simpan data scan: MAC -> RSSI/TX/Name
+struct DeviceInfo {
+  int RSSI;
+  int TXPower;
+  String name;
+};
+std::map<String, DeviceInfo> scannedDevices;
+
+// Simpan device yang connect: connId -> JSON index
+std::map<int, int> connIdToIndex;
+
+BLEServer *pServer = nullptr;
+BLECharacteristic *pCharacteristic = nullptr;
 
-BLEServer *pServer = NULL;
-BLECharacteristic *pCharacteristic = NULL;
 int connectedClients = 0;
-bool deviceConnected = false;
-uint32_t value = 0;
-unsigned int lastTime = 0;
 
-StaticJsonDocument<512> doc;                           // dokumen utama
-JsonArray devices = doc.createNestedArray("Devices");  // array untuk semua device
+StaticJsonDocument<2048> doc;
+JsonArray devices;
 
 #define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
 #define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
@@ -24,18 +38,33 @@ class MyServerCallbacks : public BLEServerCallbacks {
   void onConnect(BLEServer *pServer, ble_gap_conn_desc *desc) override {
     connectedClients++;
 
-    // Buat object untuk device baru
+    if (devices.isNull()) devices = doc.createNestedArray("Devices");
+
     JsonObject device = devices.createNestedObject();
-    device["mac"] = BLEAddress(desc->peer_ota_addr).toString().c_str();
-    device["connectedID"] = pServer->getConnId();
+    int connId = pServer->getConnId();
+    device["connectedID"] = connId;
     device["connInterval"] = desc->conn_itvl;
     device["latency"] = desc->conn_latency;
     device["timeout"] = desc->supervision_timeout;
 
-    // Simpan mapping connId → index device
-    connIdToIndex[pServer->getConnId()] = devices.size() - 1;
+    // Gunakan MAC dari scannedDevices jika ada RSSI terakhir
+    // Biasanya kita tidak punya MAC real connect, bisa pakai RSSI terkuat
+    if (!scannedDevices.empty()) {
+      auto strongest = scannedDevices.begin();
+      for (auto it = scannedDevices.begin(); it != scannedDevices.end(); ++it) {
+        if (it->second.RSSI > strongest->second.RSSI) strongest = it;
+      }
+      device["mac"] = strongest->first;
+      device["name"] = strongest->second.name;
+      device["RSSI"] = strongest->second.RSSI;
+      device["TXPower"] = strongest->second.TXPower;
+    } else {
+      device["mac"] = "Unknown";
+      device["name"] = "Unknown";
+    }
+
+    connIdToIndex[connId] = devices.size() - 1;
 
-    // Update status umum
     doc["Status"] = "NEW_CONNECT";
     doc["connectedClients"] = connectedClients;
 
@@ -51,20 +80,22 @@ class MyServerCallbacks : public BLEServerCallbacks {
     int connId = pServer->getConnId();
     if (connIdToIndex.count(connId)) {
       int index = connIdToIndex[connId];
-      // Hapus device dari array (buat ulang array)
       JsonArray newDevices = doc.createNestedArray("Devices");
       for (int i = 0; i < devices.size(); i++) {
-        if (i == index) continue;  // skip device yang disconnect
+        if (i == index) continue;
         JsonObject oldDevice = devices[i];
         JsonObject newDevice = newDevices.createNestedObject();
-        newDevice["mac"] = oldDevice["mac"];
         newDevice["connectedID"] = oldDevice["connectedID"];
         newDevice["connInterval"] = oldDevice["connInterval"];
         newDevice["latency"] = oldDevice["latency"];
         newDevice["timeout"] = oldDevice["timeout"];
+        if (oldDevice.containsKey("RSSI")) newDevice["RSSI"] = oldDevice["RSSI"];
+        if (oldDevice.containsKey("TXPower")) newDevice["TXPower"] = oldDevice["TXPower"];
+        if (oldDevice.containsKey("mac")) newDevice["mac"] = oldDevice["mac"];
+        if (oldDevice.containsKey("name")) newDevice["name"] = oldDevice["name"];
       }
-      devices = newDevices;         // update devices
-      connIdToIndex.erase(connId);  // hapus mapping
+      devices = newDevices;
+      connIdToIndex.erase(connId);
     }
 
     serializeJson(doc, Serial);
@@ -72,22 +103,56 @@ class MyServerCallbacks : public BLEServerCallbacks {
   }
 };
 
+class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks {
+  void onResult(BLEAdvertisedDevice advertisedDevice) override {
+    Serial.printf("Advertised Device: %s \n", advertisedDevice.toString().c_str());
+    String mac = advertisedDevice.getAddress().toString();
+    // String name = advertisedDevice.getName();
+    String name = advertisedDevice.haveName() ? advertisedDevice.getName() : "Unknown";
+    int rssi = advertisedDevice.getRSSI();
+    int txPower = advertisedDevice.getTXPower();
+
+    // Simpan ke scannedDevices
+    scannedDevices[mac] = { rssi, txPower, name };
+
+    for (auto &pair : connIdToIndex) {
+      int index = pair.second;
+      JsonObject device = devices[index];
+      // Di sini kita tidak bisa cocokkan MAC karena connect MAC random,
+      // tapi bisa update semua RSSI terakhir dari scannedDevices
+      if (scannedDevices.count(mac)) {
+        device["Name"] = scannedDevices[mac].name;
+        device["RSSI"] = scannedDevices[mac].RSSI;
+        device["TXPower"] = scannedDevices[mac].TXPower;
+      }
+    }
+  }
+};
+
+BLEScan *pBLEScan;
+
 void setup() {
   Serial.begin(115200);
   pinMode(LED_BUILTIN, OUTPUT);
 
   BLEDevice::init("ESP32");
 
+  // Setup scan
+  pBLEScan = BLEDevice::getScan();
+  pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
+  pBLEScan->setActiveScan(true);
+  pBLEScan->setInterval(100);
+  pBLEScan->setWindow(99);
+
+  // Setup server
   pServer = BLEDevice::createServer();
   pServer->setCallbacks(new MyServerCallbacks());
 
   BLEService *pService = pServer->createService(SERVICE_UUID);
-
   pCharacteristic = pService->createCharacteristic(
     CHARACTERISTIC_UUID,
     BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_NOTIFY | BLECharacteristic::PROPERTY_INDICATE);
   pCharacteristic->addDescriptor(new BLE2902());
-
   pService->start();
 
   BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
@@ -95,51 +160,27 @@ void setup() {
   pAdvertising->setScanResponse(false);
   pAdvertising->setMinPreferred(0x0);
   BLEDevice::startAdvertising();
-
-  // Serial.println("Waiting for client connections to notify...");
-  // Serial.println("Type 'disconnect <connId>' to disconnect a client.");
 }
 
-void loop() {
-
-  if (connectedClients > 0) {
-    pCharacteristic->setValue((uint8_t *)&value, 4);
-    pCharacteristic->notify();
-    value++;
-    delay(100);
-    
+unsigned long lastScanTime = 0;
+const unsigned long scanInterval = 1000;  // 1 detik
 
-  }
-
-  if (Serial.available()) {
-    String cmd = Serial.readStringUntil('\n');
-    cmd.trim();
-    digitalWrite(LED_BUILTIN, HIGH); 
-    if (cmd.startsWith("DISCONNECT:")) {
-      
-      int connId = cmd.substring(11).toInt();
-      // Serial.println("Arduino will disconnect connID: " + String(connId));
-      // panggil fungsi BLE untuk disconnect
-      pServer->disconnect(connId);  // sesuai API ESP32 BLE
-    }
-  }
-  digitalWrite(LED_BUILTIN, LOW); 
+void loop() {
+  digitalWrite(LED_BUILTIN, connectedClients > 0 ? HIGH : LOW);
 
-  if (connectedClients == 0 && deviceConnected) {
-    delay(500);
-    pServer->startAdvertising();
-    // Serial.println("No clients connected, restarting advertising");
-    deviceConnected = false;
-  }
+  // Scan BLE setiap 1 detik
+  // if (millis() - lastScanTime > scanInterval) {
+  //   lastScanTime = millis();
+  //   pBLEScan->start(0, nullptr, false);  // non-blocking scan
+  // }
 
-  if (connectedClients > 0 && !deviceConnected) {
-    deviceConnected = true;
+  pBLEScan->start(2, false);  // non-blocking scan
+  // Kirim JSON update ke Serial
+  static unsigned long lastJsonTime = 0;
+  if (millis() - lastJsonTime > scanInterval) {
+    lastJsonTime = millis();
+    doc["connectedClients"] = connectedClients;
+    serializeJson(doc, Serial);
+    Serial.println();
   }
-
-  // if (millis() - lastTime >= 1000) {
-  //   // Serial.println(json);
-  //   serializeJson(doc, Serial);
-  //   Serial.println();
-  //   lastTime = millis();
-  // }
 }