mirror of
https://github.com/Genaker/LoraSA.git
synced 2026-03-28 17:42:59 +01:00
UI Spectrum + BT and Compass Fixes
This commit is contained in:
@@ -111,7 +111,7 @@ HardwareSerial SerialGPS(GPS_RX_PIN, GPS_TX_PIN);
|
||||
#include "driver/gpio.h"
|
||||
#endif // ARDUINO_ARCH_ESP32
|
||||
|
||||
DISPLAY_MODEL *u8g2 = NULL;
|
||||
// DISPLAY_MODEL *u8g2 = NULL;
|
||||
static DevInfo_t devInfo;
|
||||
|
||||
#ifdef HAS_GPS
|
||||
@@ -530,6 +530,7 @@ void loopPMU()
|
||||
|
||||
bool beginDisplay()
|
||||
{
|
||||
/**
|
||||
Wire.beginTransmission(DISPLAY_ADDR);
|
||||
if (Wire.endTransmission() == 0)
|
||||
{
|
||||
@@ -552,7 +553,7 @@ bool beginDisplay()
|
||||
}
|
||||
|
||||
Serial.printf("Warning: Failed to find Display at 0x%0X address\n", DISPLAY_ADDR);
|
||||
return false;
|
||||
return false;*/
|
||||
}
|
||||
|
||||
bool beginSDCard()
|
||||
@@ -847,7 +848,7 @@ void printResult(bool radio_online)
|
||||
Serial.println((psramFound()) ? "+" : "-");
|
||||
|
||||
Serial.print("Display : ");
|
||||
Serial.println((u8g2) ? "+" : "-");
|
||||
// Serial.println((u8g2) ? "+" : "-");
|
||||
|
||||
#ifdef HAS_SDCARD
|
||||
Serial.print("Sd Card : ");
|
||||
@@ -866,7 +867,7 @@ void printResult(bool radio_online)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (u8g2)
|
||||
/*if (u8g2)
|
||||
{
|
||||
|
||||
u8g2->clearBuffer();
|
||||
@@ -895,6 +896,7 @@ void printResult(bool radio_online)
|
||||
|
||||
delay(2000);
|
||||
}
|
||||
*/
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -23,12 +23,12 @@
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <SPI.h>
|
||||
#include <U8g2lib.h>
|
||||
// #include <U8g2lib.h>
|
||||
#include <Wire.h>
|
||||
#include <XPowersLib.h>
|
||||
|
||||
#ifndef DISPLAY_MODEL
|
||||
#define DISPLAY_MODEL U8G2_SSD1306_128X64_NONAME_F_HW_I2C
|
||||
// #define DISPLAY_MODEL U8G2_SSD1306_128X64_NONAME_F_HW_I2C
|
||||
#endif
|
||||
|
||||
#ifndef OLED_WIRE_PORT
|
||||
@@ -57,7 +57,7 @@ typedef struct
|
||||
uint8_t flashSpeed;
|
||||
} DevInfo_t;
|
||||
|
||||
void setupBoards(bool disable_u8g2 = false);
|
||||
void setupBoards(bool disable_u8g2 = true);
|
||||
|
||||
bool beginSDCard();
|
||||
|
||||
@@ -81,7 +81,7 @@ void loopPMU();
|
||||
extern XPowersLibInterface *PMU;
|
||||
extern bool pmuInterrupt;
|
||||
#endif
|
||||
extern DISPLAY_MODEL *u8g2;
|
||||
// extern DISPLAY_MODEL *u8g2;
|
||||
|
||||
#define U8G2_HOR_ALIGN_CENTER(t) ((u8g2->getDisplayWidth() - (u8g2->getUTF8Width(t))) / 2)
|
||||
#define U8G2_HOR_ALIGN_RIGHT(t) (u8g2->getDisplayWidth() - u8g2->getUTF8Width(t))
|
||||
|
||||
@@ -413,7 +413,7 @@
|
||||
#define __HAS_SENSOR__
|
||||
|
||||
#define PMU_WIRE_PORT Wire1
|
||||
#define DISPLAY_MODEL U8G2_SH1106_128X64_NONAME_F_HW_I2C
|
||||
// #define DISPLAY_MODEL U8G2_SH1106_128X64_NONAME_F_HW_I2C
|
||||
#define BOARD_VARIANT_NAME "T-Beam S3"
|
||||
|
||||
#elif defined(T_MOTION_S76G)
|
||||
@@ -545,7 +545,7 @@
|
||||
#define __HAS_SENSOR__
|
||||
|
||||
#define PMU_WIRE_PORT Wire
|
||||
#define DISPLAY_MODEL U8G2_SH1106_128X64_NONAME_F_HW_I2C
|
||||
// #define DISPLAY_MODEL U8G2_SH1106_128X64_NONAME_F_HW_I2C
|
||||
#define BOARD_VARIANT_NAME "T-Beam BPF"
|
||||
|
||||
#else
|
||||
|
||||
@@ -13,7 +13,7 @@ struct RadioModule
|
||||
virtual float getRSSI() = 0;
|
||||
};
|
||||
|
||||
#ifdef USING_SX1262
|
||||
#ifndef USING_SX1262_no
|
||||
struct SX1262Module : RadioModule
|
||||
{
|
||||
SX1262 *_radio;
|
||||
|
||||
@@ -250,7 +250,7 @@ build_flags =
|
||||
-DARDUINO_LILYGO_T3_S3_V1_X
|
||||
-DARDUINO_USB_MODE=1
|
||||
|
||||
[env:lilygo-T3S3-v1-2-lr1121-900-compass]
|
||||
[env:lilygo-T3S3-v1-2-lr1121-900-BT]
|
||||
platform = espressif32
|
||||
board = t3_s3_v1_x
|
||||
framework = arduino
|
||||
@@ -264,16 +264,48 @@ lib_deps =
|
||||
U8g2
|
||||
XPowersLib
|
||||
h2zero/NimBLE-Arduino
|
||||
https://github.com/Genaker/Adafruit_HMC5883_Unified
|
||||
build_flags =
|
||||
-lbt
|
||||
build_flags =
|
||||
-DLILYGO
|
||||
-DT3_S3_V1_2_LR1121
|
||||
-DARDUINO_LILYGO_T3S3_LR1121
|
||||
-DESP32
|
||||
-DSAMPLES_RSSI=5
|
||||
-DUSING_LR1121
|
||||
-DSCAN_RBW_FACTOR=2
|
||||
-DINIT_FREQ=900
|
||||
-DFREQ_BEGIN=830
|
||||
-DFREQ_END=945
|
||||
-DFREQ_RX=2440
|
||||
-DARDUINO_ARCH_ESP32
|
||||
-DARDUINO_USB_CDC_ON_BOOT=1
|
||||
-DARDUINO_LILYGO_T3_S3_V1_X
|
||||
-DARDUINO_USB_MODE=1
|
||||
-DBT_MOBILE
|
||||
|
||||
[env:lilygo-T3S3-v1-2-lr1121-900-compass]
|
||||
platform = espressif32
|
||||
board = t3_s3_v1_x
|
||||
framework = arduino
|
||||
upload_speed = 1500000
|
||||
monitor_speed = 115200
|
||||
board_build.f_cpu = 240000000
|
||||
board_build.partitions = min_spiffs.csv
|
||||
board_build.filesystem = littlefs
|
||||
lib_deps =
|
||||
ropg/Heltec_ESP32_LoRa_v3@^0.9.1
|
||||
RadioLib
|
||||
XPowersLib
|
||||
h2zero/NimBLE-Arduino
|
||||
https://github.com/Genaker/Adafruit_HMC5883_Unified
|
||||
build_flags =
|
||||
-lbt
|
||||
-Og -ggdb3
|
||||
-DLILYGO
|
||||
-DT3_S3_V1_2_LR1121
|
||||
-DARDUINO_LILYGO_T3S3_LR1121
|
||||
-DESP32
|
||||
-DSAMPLES_RSSI=2
|
||||
-DUSING_LR1121
|
||||
-DSCAN_RBW_FACTOR=1
|
||||
-DINIT_FREQ=900
|
||||
-DFREQ_BEGIN=800
|
||||
-DFREQ_END=950
|
||||
@@ -284,9 +316,11 @@ build_flags =
|
||||
-DARDUINO_USB_MODE=1
|
||||
-DCOMPASS_ENABLED
|
||||
-DCOMPASS_FREQ=915
|
||||
-DCOMPASS_DEBUG
|
||||
-DCOMPASS_DEBUG2
|
||||
-DCOMPASS_RSSI
|
||||
-DBT_MOBILE
|
||||
-DBT_RSSI
|
||||
-DBT_NM
|
||||
|
||||
[env:lilygo-T3S3-v1-2-sx1280]
|
||||
platform = espressif32
|
||||
|
||||
170
src/main.cpp
170
src/main.cpp
@@ -63,19 +63,38 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef BT_MOBILE
|
||||
#include "esp_task_wdt.h"
|
||||
#include <NimBLEDevice.h>
|
||||
|
||||
#define LOG_LOCAL_LEVEL ESP_LOG_VERBOSE
|
||||
#include "esp_log.h"
|
||||
bool deviceConnected = false;
|
||||
#define SERVICE_UUID "00001234-0000-1000-8000-00805f9b34fb"
|
||||
#define CHARACTERISTIC_UUID "00001234-0000-1000-8000-00805f9b34ac"
|
||||
|
||||
#ifndef BT_NM
|
||||
#include <BLE2902.h>
|
||||
#include <BLEDevice.h>
|
||||
#include <BLEServer.h>
|
||||
#include <BLEUtils.h>
|
||||
|
||||
BLEServer *pServer = NULL;
|
||||
BLECharacteristic *pCharacteristic = NULL;
|
||||
BLEAdvertising *pAdvertising = NULL;
|
||||
|
||||
class MyServerCallbacks : public BLEServerCallbacks
|
||||
{
|
||||
void onConnect(BLEServer *pServer) { deviceConnected = true; };
|
||||
|
||||
void onDisconnect(BLEServer *pServer)
|
||||
{
|
||||
deviceConnected = false;
|
||||
BLEDevice::startAdvertising(); // Restart advertising after disconnect
|
||||
}
|
||||
};
|
||||
|
||||
#else
|
||||
#include <NimBLEDevice.h>
|
||||
|
||||
NimBLEServer *pServer = nullptr;
|
||||
NimBLECharacteristic *pCharacteristic = nullptr;
|
||||
NimBLEAdvertising *pAdvertising = nullptr;
|
||||
bool deviceConnected = false;
|
||||
|
||||
#define SERVICE_UUID "00001234-0000-1000-8000-00805f9b34fb"
|
||||
#define CHARACTERISTIC_UUID "00001234-0000-1000-8000-00805f9b34ac"
|
||||
|
||||
class BTServerCallbacks : public NimBLEServerCallbacks
|
||||
{
|
||||
@@ -86,13 +105,7 @@ class BTServerCallbacks : public NimBLEServerCallbacks
|
||||
Serial.printf("Device Connected | Free Heap: %d kByte\n",
|
||||
ESP.getFreeHeap() / 1000);
|
||||
Serial.printf("Client address: %s\n", connInfo.getAddress().toString().c_str());
|
||||
/**
|
||||
* We can use the connection handle here to ask for different connection
|
||||
* parameters. Args: connection handle, min connection interval, max connection
|
||||
* interval latency, supervision timeout. Units; Min/Max Intervals: 1.25
|
||||
* millisecond increments. Latency: number of intervals allowed to skip. Timeout:
|
||||
* 10 millisecond increments.
|
||||
*/
|
||||
|
||||
pServer->updateConnParams(connInfo.getConnHandle(), 24, 48, 0, 180);
|
||||
}
|
||||
|
||||
@@ -111,7 +124,6 @@ class BTServerCallbacks : public NimBLEServerCallbacks
|
||||
}
|
||||
} BTServerCallbacks;
|
||||
|
||||
/** Handler class for characteristic actions */
|
||||
class CharacteristicCallbacks : public NimBLECharacteristicCallbacks
|
||||
{
|
||||
void onRead(NimBLECharacteristic *pCharacteristic, NimBLEConnInfo &connInfo) override
|
||||
@@ -128,16 +140,14 @@ class CharacteristicCallbacks : public NimBLECharacteristicCallbacks
|
||||
pCharacteristic->getValue().c_str());
|
||||
}
|
||||
|
||||
/**
|
||||
* The value returned in code is the NimBLE host return code.
|
||||
*/
|
||||
void onStatus(NimBLECharacteristic *pCharacteristic, int code) override
|
||||
{
|
||||
#ifdef COMPASS_DEBUG
|
||||
Serial.printf("Notification/Indication return code: %d, %s\n", code,
|
||||
NimBLEUtils::returnCodeToString(code));
|
||||
#endif
|
||||
}
|
||||
|
||||
/** Peer subscribed to notifications/indications */
|
||||
void onSubscribe(NimBLECharacteristic *pCharacteristic, NimBLEConnInfo &connInfo,
|
||||
uint16_t subValue) override
|
||||
{
|
||||
@@ -167,7 +177,6 @@ class CharacteristicCallbacks : public NimBLECharacteristicCallbacks
|
||||
}
|
||||
} chrCallbacks;
|
||||
|
||||
/** Handler class for descriptor actions */
|
||||
class DescriptorCallbacks : public NimBLEDescriptorCallbacks
|
||||
{
|
||||
void onWrite(NimBLEDescriptor *pDescriptor, NimBLEConnInfo &connInfo) override
|
||||
@@ -182,11 +191,11 @@ class DescriptorCallbacks : public NimBLEDescriptorCallbacks
|
||||
}
|
||||
} dscCallbacks;
|
||||
|
||||
#endif
|
||||
|
||||
void initBT()
|
||||
{
|
||||
esp_log_level_set("*", ESP_LOG_VERBOSE);
|
||||
ESP_LOGI("DEBUG", "Starting ESP32 Debugging...");
|
||||
|
||||
#ifdef BT_NM
|
||||
// Initialize BLE device
|
||||
NimBLEDevice::init("RSSI_Radar");
|
||||
|
||||
@@ -230,6 +239,30 @@ void initBT()
|
||||
pAdvertising->start();
|
||||
|
||||
Serial.println("BLE server started.");
|
||||
#else
|
||||
BLEDevice::init("ESP32_RADAR");
|
||||
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);
|
||||
|
||||
pCharacteristic->setValue("Hello from ESP32");
|
||||
pService->start();
|
||||
|
||||
pAdvertising = BLEDevice::getAdvertising();
|
||||
pAdvertising->addServiceUUID(SERVICE_UUID);
|
||||
pAdvertising->setScanResponse(true);
|
||||
pAdvertising->setMinInterval(300);
|
||||
pAdvertising->setMaxInterval(350);
|
||||
BLEDevice::startAdvertising();
|
||||
|
||||
Serial.println("BLE server is ready!");
|
||||
#endif
|
||||
}
|
||||
|
||||
// Function to send RSSI and Heading Data
|
||||
@@ -237,7 +270,10 @@ void sendBTData(float heading, float rssi)
|
||||
{
|
||||
String data =
|
||||
"RSSI_HEADING: '{H:" + String(heading) + ",RSSI:-" + String(rssi) + "}'";
|
||||
|
||||
#ifdef COMPASS_DEBUG
|
||||
Serial.println("Sending data: " + data);
|
||||
#endif
|
||||
pCharacteristic->setValue(data.c_str()); // Set BLE characteristic value
|
||||
pCharacteristic->notify(); // Notify connected client
|
||||
}
|
||||
@@ -381,7 +417,7 @@ void displaySensorDetails(void)
|
||||
Serial.println(" uT");
|
||||
Serial.println("------------------------------------");
|
||||
Serial.println("");
|
||||
delay(500);
|
||||
heltec_delay(500);
|
||||
}
|
||||
|
||||
// Variables for dynamic calibration
|
||||
@@ -925,7 +961,7 @@ int16_t initForScan(float freq)
|
||||
|
||||
// LR1121 TCXO Voltage 2.85~3.15V
|
||||
radio.setTCXO(3.0);
|
||||
delay(1000);
|
||||
heltec_delay(1000);
|
||||
#else
|
||||
state = radio.beginFSK(freq);
|
||||
#endif
|
||||
@@ -947,7 +983,7 @@ A:
|
||||
Serial.print(F("Failed to start receive mode, error code: "));
|
||||
display.drawString(0, 64 - 10, "E:startReceive");
|
||||
display.display();
|
||||
delay(2000);
|
||||
heltec_delay(2000);
|
||||
Serial.println(state);
|
||||
gotoAcounter++;
|
||||
if (gotoAcounter < 5)
|
||||
@@ -1071,6 +1107,7 @@ void init_radio()
|
||||
|
||||
if (config.radio2.enabled && config.radio2.module.equalsIgnoreCase("SX1262"))
|
||||
{
|
||||
|
||||
radio2 = new SX1262Module(config.radio2);
|
||||
state = radio2->beginScan(CONF_FREQ_BEGIN, BANDWIDTH, RADIOLIB_SHAPING_NONE);
|
||||
if (state == RADIOLIB_ERR_NONE)
|
||||
@@ -1286,7 +1323,6 @@ void draw360Scale(int start = 0, int end = 360, int width = 128, int height = 64
|
||||
for (int x = 0; x <= width; x += stepPixel)
|
||||
{
|
||||
// int x = map(i, start, end, 0, scaleLength);
|
||||
Serial.println("Tick: " + String(x));
|
||||
if (x == 128)
|
||||
{
|
||||
x = x - 1;
|
||||
@@ -2353,11 +2389,12 @@ float getCompassHeading()
|
||||
{
|
||||
calStart = millis();
|
||||
}
|
||||
#ifdef COMPASS_ENABLED
|
||||
|
||||
/* Get a new sensor event */
|
||||
sensors_event_t event2;
|
||||
mag.getEvent(&event2);
|
||||
sensors_event_t event3;
|
||||
mag.getEvent(&event3);
|
||||
|
||||
#ifdef COMPASS_DEBUG
|
||||
/* Display the results (magnetic vector values are in micro-Tesla (uT)) */
|
||||
@@ -2389,9 +2426,9 @@ float getCompassHeading()
|
||||
// Dynamicly Calibrated out
|
||||
|
||||
// Read raw magnetometer data
|
||||
float x = event2.magnetic.x;
|
||||
float y = event2.magnetic.y;
|
||||
float z = event2.magnetic.z;
|
||||
float x = (event2.magnetic.x + event3.magnetic.x) / 2;
|
||||
float y = (event2.magnetic.y + event3.magnetic.y) / 2;
|
||||
float z = (event2.magnetic.z + event3.magnetic.z) / 2;
|
||||
|
||||
// Doing calibration first 1 minute
|
||||
if (millis() - calStart < 60000)
|
||||
@@ -2446,7 +2483,6 @@ float getCompassHeading()
|
||||
// Convert radians to degrees for readability.
|
||||
float headingDegrees = heading * 180 / M_PI;
|
||||
return headingDegrees;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -2483,6 +2519,51 @@ void loop(void)
|
||||
doScan();
|
||||
reportScan();
|
||||
}
|
||||
|
||||
#ifdef BT_MOBILE
|
||||
#ifdef BT_RSSI
|
||||
while (true)
|
||||
{
|
||||
float startFreq = FREQ_BEGIN - 0.5; // Start 2 MHz left
|
||||
float endFreq = FREQ_END + 0.5; // End 2 MHz right
|
||||
float step = 0.5; // Step size in MHz
|
||||
float rssi = -122;
|
||||
float rssiMax = -999;
|
||||
|
||||
for (float freq = startFreq; freq <= endFreq; freq += step)
|
||||
{
|
||||
setFrequency(freq);
|
||||
// Serial.println("COMPASS FREQ SET: " + String(freq));
|
||||
|
||||
// heltec_delay(5);
|
||||
#ifdef USING_LR1121
|
||||
radio.getRssiInst(&rssi);
|
||||
#else
|
||||
rssi = getRssi(false);
|
||||
#endif
|
||||
if (rssi > rssiMax)
|
||||
{
|
||||
rssiMax = rssi;
|
||||
}
|
||||
Serial.println("RSSI: " + String(freq) + ":" + String(rssiMax));
|
||||
// String p = _scan_result_str(m.payload.dump, 10);
|
||||
|
||||
if (pServer && pServer->getConnectedCount())
|
||||
{
|
||||
String str = "RSSI:TEST";
|
||||
if (pCharacteristic)
|
||||
{
|
||||
pCharacteristic->setValue(
|
||||
str.c_str()); // Set BLE characteristic value
|
||||
pCharacteristic->notify(); // Notify connected client
|
||||
}
|
||||
delay(50);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef COMPASS_ENABLED
|
||||
#if defined(COMPASS_FREQ)
|
||||
// delay(1000);
|
||||
@@ -2516,15 +2597,15 @@ void loop(void)
|
||||
draw360Scale(0, 360, 128, 64);
|
||||
}
|
||||
|
||||
float rssi = -122;
|
||||
float rssiMax = -999;
|
||||
if (headingDegrees >= 0 && headingDegrees <= 360)
|
||||
{
|
||||
float startFreq = COMPASS_FREQ - 1.0; // Start 2 MHz left
|
||||
float endFreq = COMPASS_FREQ + 1.0; // End 2 MHz right
|
||||
float startFreq = COMPASS_FREQ - 0.5; // Start 2 MHz left
|
||||
float endFreq = COMPASS_FREQ + 0.5; // End 2 MHz right
|
||||
float step = 0.5; // Step size in MHz
|
||||
#ifdef COMPASS_RSSI
|
||||
draw360Scale(0, 360, 128, 64);
|
||||
float rssi = -122;
|
||||
float rssiMax = -999;
|
||||
for (int i = 0; i < SAMPLES_RSSI; i++)
|
||||
{
|
||||
for (float freq = startFreq; freq <= endFreq; freq += step)
|
||||
@@ -2540,7 +2621,7 @@ void loop(void)
|
||||
#endif
|
||||
float headingDegreesAfter = getCompassHeading();
|
||||
float compassDiff = abs(headingDegreesAfter - headingDegrees);
|
||||
if (compassDiff >= 2)
|
||||
if (compassDiff >= 3)
|
||||
{
|
||||
goto compass;
|
||||
}
|
||||
@@ -2963,6 +3044,7 @@ void doScan()
|
||||
max_x_rssi[display_x] = max_rssi;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // SCAN_METHOD == METHOD_RSSI
|
||||
|
||||
// if this code is not executed LORA radio doesn't work
|
||||
@@ -3316,17 +3398,7 @@ void loraSendMessage(Message &msg)
|
||||
|
||||
void reportScan()
|
||||
{
|
||||
#ifdef BT_MOBILE
|
||||
#ifndef COMPASS_ENABLED
|
||||
// String p = _scan_result_str(m.payload.dump, 10);
|
||||
if (pServer->getConnectedCount())
|
||||
{
|
||||
pCharacteristic->setValue("Test"); // Set BLE characteristic value
|
||||
pCharacteristic->notify(); // Notify connected client
|
||||
}
|
||||
delay(1000);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (!config.lora_enabled)
|
||||
return;
|
||||
|
||||
|
||||
@@ -171,11 +171,16 @@
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
let lineCoef = 2.5;
|
||||
// Draw data points
|
||||
dataPoints.forEach(({ angle, rssi }) => {
|
||||
const rad = (angle * Math.PI) / 180;
|
||||
const length = ((120 + rssi) / (radius / 2)) * radius; // Scale RSSI to fit within radar
|
||||
|
||||
//const length = (120 + rssi) / (radius / 2) * radius;
|
||||
const length = ((120 - 90) + (rssi + 90)) * lineCoef; // Scale RSSI to fit within radar
|
||||
if (length > radius) {
|
||||
length = radius;
|
||||
}
|
||||
console.log("Length: " + length);
|
||||
const x = centerX + length * Math.cos(rad);
|
||||
const y = centerY + length * Math.sin(rad);
|
||||
|
||||
@@ -224,7 +229,7 @@
|
||||
|
||||
// Draw current RSSI line in yellow
|
||||
const currentRad = (currentPoint.angle * Math.PI) / 180;
|
||||
const currentLength = ((120 + currentPoint.rssi) / (radius / 2)) * radius;
|
||||
const currentLength = ((120 + currentPoint.rssi) / (radius / 2)) * radius * 1.2;
|
||||
|
||||
const currentX = centerX + currentLength * Math.cos(currentRad);
|
||||
const currentY = centerY + currentLength * Math.sin(currentRad);
|
||||
@@ -420,7 +425,7 @@
|
||||
console.log(`Reconnecting to device: ${bluetoothDevice.name}`);
|
||||
const server = await bluetoothDevice.gatt.connect();
|
||||
console.log(`Reconnected to device: ${bluetoothDevice.name}`);
|
||||
deviceNameElem.textContent = bluetoothDevice.name;
|
||||
//deviceNameElem.textContent = bluetoothDevice.name;
|
||||
statusElem.textContent = "Reconnected";
|
||||
} catch (error) {
|
||||
console.error("Error reconnecting to Bluetooth device:", error);
|
||||
|
||||
303
web_app/spectr/index.html
Normal file
303
web_app/spectr/index.html
Normal file
@@ -0,0 +1,303 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Spectrum Analyzer</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
text-align: center;
|
||||
background-color: black;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 80%;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.chart-container {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.chart {
|
||||
height: 40vh;
|
||||
border: 1px solid white;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.waterfall {
|
||||
height: 40vh;
|
||||
border: 1px solid white;
|
||||
}
|
||||
|
||||
.console {
|
||||
height: 20vh;
|
||||
width: 100%;
|
||||
background-color: black;
|
||||
color: white;
|
||||
overflow-y: auto;
|
||||
padding: 10px;
|
||||
text-align: left;
|
||||
border: 1px solid white;
|
||||
}
|
||||
|
||||
.labels {
|
||||
position: absolute;
|
||||
left: -50px;
|
||||
top: 0;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.freq-labels {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
position: absolute;
|
||||
bottom: -20px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
canvas {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: block;
|
||||
image-rendering: crisp-edges;
|
||||
}
|
||||
|
||||
button {
|
||||
margin: 10px;
|
||||
padding: 10px;
|
||||
font-size: 16px;
|
||||
background-color: white;
|
||||
color: black;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
background-color: gray;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Spectrum Analyzer</h1>
|
||||
<button id="simulationButton" onclick="toggleSimulation()">Start Simulation</button>
|
||||
<button onclick="connectBluetooth()">Connect Bluetooth</button>
|
||||
<div class="container">
|
||||
<div class="chart-container">
|
||||
<div class="labels" id="dbLabels"></div>
|
||||
<canvas id="chartCanvas" class="chart"></canvas>
|
||||
<div class="freq-labels" id="freqLabels"></div>
|
||||
</div>
|
||||
<canvas id="waterfallCanvas" class="waterfall"></canvas>
|
||||
<div class="console" id="consoleOutput"></div>
|
||||
</div>
|
||||
<script>
|
||||
const chartCanvas = document.getElementById('chartCanvas');
|
||||
const chartCtx = chartCanvas.getContext('2d');
|
||||
const waterfallCanvas = document.getElementById('waterfallCanvas');
|
||||
const waterfallCtx = waterfallCanvas.getContext('2d');
|
||||
const dbLabels = document.getElementById('dbLabels');
|
||||
const freqLabels = document.getElementById('freqLabels');
|
||||
const simulationButton = document.getElementById('simulationButton');
|
||||
|
||||
const scaleFactor = 1; //window.devicePixelRatio || 2;
|
||||
chartCanvas.width = chartCanvas.clientWidth * scaleFactor;
|
||||
chartCanvas.height = chartCanvas.clientHeight * scaleFactor;
|
||||
chartCtx.scale(scaleFactor, scaleFactor);
|
||||
|
||||
waterfallCanvas.width = waterfallCanvas.clientWidth * scaleFactor;
|
||||
waterfallCanvas.height = waterfallCanvas.clientHeight * scaleFactor;
|
||||
waterfallCtx.scale(scaleFactor, scaleFactor);
|
||||
|
||||
let RSSI = {};
|
||||
let spectrumData = Array.from({ length: 80 }, () => new Array(900).fill(0));
|
||||
let waterfallHistory = Array.from({ length: 80 }, () => new Array(900).fill("black"));
|
||||
let simulationInterval;
|
||||
let isSimulationRunning = false;
|
||||
let bluetoothDevice;
|
||||
let bluetoothCharacteristic;
|
||||
|
||||
async function connectBluetooth() {
|
||||
try {
|
||||
const bluetoothDevice = await navigator.bluetooth.requestDevice({
|
||||
acceptAllDevices: true,
|
||||
optionalServices: ['00001234-0000-1000-8000-00805f9b34fb']
|
||||
});
|
||||
|
||||
const server = await bluetoothDevice.gatt.connect();
|
||||
const service = await server.getPrimaryService('00001234-0000-1000-8000-00805f9b34fb');
|
||||
const bluetoothCharacteristic = await service.getCharacteristic('00001234-0000-1000-8000-00805f9b34ac');
|
||||
|
||||
// Save the device's ID to localStorage
|
||||
localStorage.setItem("bluetoothDeviceId", bluetoothDevice.id);
|
||||
|
||||
bluetoothCharacteristic.addEventListener('characteristicvaluechanged', handleBluetoothData)
|
||||
|
||||
await bluetoothCharacteristic.startNotifications();
|
||||
|
||||
//statusElem.textContent = "Connected";
|
||||
} catch (error) {
|
||||
console.error("Error scanning for devices:", error);
|
||||
alert("Could not connect to device.");
|
||||
// statusElem.textContent = "Connection Error";
|
||||
}
|
||||
}
|
||||
|
||||
function handleBluetoothData(event) {
|
||||
const decoder = new TextDecoder("utf-8");
|
||||
const value = decoder.decode(event.target.value);
|
||||
console.log("Received data:", value); // For debugging
|
||||
console.log(value);
|
||||
parseBluetoothData(value);
|
||||
}
|
||||
|
||||
function parseBluetoothData(data) {
|
||||
let matches = data.match(/\((\d+),\s*(-?\d+)\)/g);
|
||||
if (!matches) return;
|
||||
|
||||
RSSI = {};
|
||||
matches.forEach(match => {
|
||||
let [_, freq, rssi] = match.match(/\((\d+),\s*(-?\d+)\)/);
|
||||
RSSI[freq] = { freq: parseInt(freq), rssi: parseInt(rssi) };
|
||||
});
|
||||
|
||||
spectrumData.pop();
|
||||
spectrumData.unshift(Object.values(RSSI).map(d => d.rssi));
|
||||
updateConsole();
|
||||
drawChart();
|
||||
drawWaterfall();
|
||||
}
|
||||
|
||||
function generateRSSI() {
|
||||
for (let freq = 100; freq < 1000; freq++) {
|
||||
RSSI[freq] = { freq, rssi: Math.random() * -120 - 30 };
|
||||
}
|
||||
spectrumData.pop();
|
||||
spectrumData.unshift(Object.values(RSSI).map(d => d.rssi));
|
||||
updateConsole();
|
||||
}
|
||||
|
||||
function getColor(rssi) {
|
||||
if (rssi > -40) return "red";
|
||||
if (rssi > -50) return "magenta";
|
||||
if (rssi > -60) return "yellow";
|
||||
if (rssi > -70) return "green";
|
||||
return "blue";
|
||||
}
|
||||
|
||||
function drawChart() {
|
||||
chartCtx.clearRect(0, 0, chartCanvas.width, chartCanvas.height);
|
||||
let keys = Object.keys(RSSI).map(Number);
|
||||
console.log("chartCanvas.height: " + chartCanvas.height);
|
||||
keys.forEach((freq, index) => {
|
||||
let rssi = RSSI[freq].rssi;
|
||||
let color = getColor(rssi);
|
||||
chartCtx.fillStyle = color;
|
||||
const x = ((freq - 100) / 900) * chartCanvas.width;
|
||||
let minRssi = -90;
|
||||
let maxRssi = -30;
|
||||
let rssiDiapason = Math.abs(minRssi) - Math.abs(maxRssi);
|
||||
let yCoef = (chartCanvas.height / rssiDiapason);
|
||||
|
||||
let y = 0;
|
||||
if (rssi < minRssi) {
|
||||
y = chartCanvas.height;
|
||||
} else {
|
||||
y = (rssiDiapason - (rssiDiapason - Math.abs(Math.abs(rssi) - Math.abs(maxRssi)))) * yCoef;
|
||||
// y = chartCanvas.height * 0.1;
|
||||
}
|
||||
console.log(freq + ":" + rssi + " Y height: " + y);
|
||||
console.log("Y height: " + chartCanvas.height + "Coef: " + yCoef);
|
||||
/* x - The x-axis coordinate of the rectangle's starting point.
|
||||
y - The y-axis coordinate of the rectangle's starting point.
|
||||
width - The rectangle's width. Positive values are to the right, and negative to the left.
|
||||
height - The rectangle's height. Positive values are down, and negative are up.
|
||||
*/
|
||||
|
||||
chartCtx.fillRect(x, chartCanvas.height, chartCanvas.width / keys.length, -chartCanvas.height + y);
|
||||
waterfallHistory[0][index] = color;
|
||||
});
|
||||
}
|
||||
|
||||
function drawWaterfall() {
|
||||
waterfallCtx.clearRect(0, 0, waterfallCanvas.width, waterfallCanvas.height);
|
||||
waterfallHistory.pop();
|
||||
waterfallHistory.unshift([...waterfallHistory[0]]);
|
||||
for (let y = 0; y < waterfallHistory.length; y++) {
|
||||
for (let x = 0; x < waterfallHistory[y].length; x++) {
|
||||
waterfallCtx.fillStyle = waterfallHistory[y][x];
|
||||
waterfallCtx.fillRect(
|
||||
(x / waterfallHistory[y].length) * waterfallCanvas.width,
|
||||
(y / waterfallHistory.length) * waterfallCanvas.height,
|
||||
waterfallCanvas.width / waterfallHistory[y].length,
|
||||
waterfallCanvas.height / waterfallHistory.length
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function updateScales() {
|
||||
dbLabels.innerHTML = "";
|
||||
for (let db = 30; db <= 80; db += 10) {
|
||||
let div = document.createElement("div");
|
||||
div.textContent = "-" + db + " dB";
|
||||
div.style.flexGrow = "1";
|
||||
dbLabels.appendChild(div);
|
||||
}
|
||||
|
||||
freqLabels.innerHTML = "";
|
||||
for (let freq = 100; freq <= 1000; freq += 100) {
|
||||
let div = document.createElement("div");
|
||||
div.textContent = freq + " MHz";
|
||||
freqLabels.appendChild(div);
|
||||
}
|
||||
}
|
||||
|
||||
function updateConsole() {
|
||||
const consoleOutput = document.getElementById('consoleOutput');
|
||||
consoleOutput.innerHTML = Object.values(RSSI)
|
||||
.map(entry => `Freq: ${entry.freq} MHz | RSSI: ${entry.rssi.toFixed(2)} dB`)
|
||||
.join('<br>');
|
||||
}
|
||||
|
||||
function startSimulation() {
|
||||
updateScales();
|
||||
simulationInterval = setInterval(() => {
|
||||
generateRSSI();
|
||||
drawChart();
|
||||
drawWaterfall();
|
||||
}, 100);
|
||||
}
|
||||
|
||||
function stopSimulation() {
|
||||
clearInterval(simulationInterval);
|
||||
simulationInterval = null;
|
||||
}
|
||||
|
||||
function toggleSimulation() {
|
||||
if (isSimulationRunning) {
|
||||
stopSimulation();
|
||||
simulationButton.textContent = "Start Simulation";
|
||||
} else {
|
||||
startSimulation();
|
||||
simulationButton.textContent = "Stop Simulation";
|
||||
}
|
||||
isSimulationRunning = !isSimulationRunning;
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Reference in New Issue
Block a user