Merge pull request #7 from Genaker/minor_optizations

Minor optizations
This commit is contained in:
Ion Surdu
2024-08-08 18:59:20 +03:00
committed by GitHub
9 changed files with 1044 additions and 838 deletions
+12
View File
@@ -0,0 +1,12 @@
{
"files.associations": {
"images.h": "c",
"*.tcc": "cpp",
"deque": "cpp",
"string": "cpp",
"unordered_map": "cpp",
"unordered_set": "cpp",
"vector": "cpp",
"system_error": "cpp"
}
}
+119 -96
View File
@@ -1,5 +1,6 @@
# Lora SA(Spectrum Analyzer)
RF Spectrum Analyzer using Lora Radio
## RF Spectrum Analyzer using Lora Radio
<img src="https://github.com/user-attachments/assets/4caeb467-1964-4184-ab20-ba68b97144aa" alt="LORA hardware" width="200"/>
@@ -10,46 +11,48 @@ The output is in the form of scan lines; each line has 33 power bins.
The first power bin corresponds to -11 dBm, the second to -15 dBm, and so on.
The higher number of samples in a bin corresponds to more power received
at that level.
```
```text
N in Bin / dBm
1 -11
2 -15
3 -19
4 -23
5 -27
6 -31
7 -35
8 -39
9 -43
10 -47
11 -51
12 -55
13 -59
14 -63
15 -67
16 -71
17 -75
18 -79
19 -83
20 -87
21 -91
22 -95
23 -99
24 -103
25 -107
26 -111
27 -115
28 -119
29 -123
30 -127
31 -131
32 -135
33 -139
1 -11
2 -15
3 -19
4 -23
5 -27
6 -31
7 -35
8 -39
9 -43
10 -47
11 -51
12 -55
13 -59
14 -63
15 -67
16 -71
17 -75
18 -79
19 -83
20 -87
21 -91
22 -95
23 -99
24 -103
25 -107
26 -111
27 -115
28 -119
29 -123
30 -127
31 -131
32 -135
33 -139
```
Example:
```
step-13 Frequancy:816.25
```text
step-13 Frequency:816.25
Power Bins: 0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0400, 0000,0000,0000,0000,0000,0000,0006,001B,000E,0005,0006,0002,0000
```
@@ -57,47 +60,58 @@ The spectrum analyzer performs power measurements in the configured bandwidth.
The X-axis represents frequency in MHz, and the Y-axis displays actually received power.
In the example above, the frequency span goes from 850 MHz to 950 MHz (that is a 100MHz range), and
the visual amplitude goes from -11 dBm to -110(-139) according to the datasheet(High sensitivity: down to -148dBm) dBm.
the visual amplitude goes from -11 dBm to -110(-139) according to the datasheet (High sensitivity: down to -148dBm) dBm.
To show the results in a plot, run the Python script
RadioLib/extras/SX126x_Spectrum_Scan/SpectrumScan.py
# Features
## Multiple Ranges Scan
## Features
### Multiple Ranges Scan
Disabled By Default
```
```c
// Feature to scan diapazones. Other frequency settings will be ignored.
int SCAN_DIAPAZONES[] = {};
//int SCAN_DIAPAZONES[] = {850890, 920950};
```
To Enable Add/ uncomment an array of the frequencies
```
To Enable Add/ uncomment an array of the frequencies
```c
int SCAN_DIAPAZONES[] = {850890, 920950};
```
where 850890 stands for 950-890Mhz range
920950 - 920-890Mhz
Other settings will be ignored if **Multiple Ranges Scan** is enabled.
## Waterfall
Waterfall showed only on One Page Scan
to disable - uncomment this line
```
where 850890 stands for 950-890Mhz range
920950 - 920-890Mhz
Other settings will be ignored if **Multiple Ranges Scan** is enabled.
### Waterfall
Waterfall showed only on One Page Scan
to disable - uncomment this line
```c
#define WATERFALL_ENABLED true
```
Waterfall shows the last **N** = SCREAN_HEIGHT (64) - WATERFALL_START(37) - 8 (part of the STATUS_TEXT_TOP) = **19** signal detection that excited set signal level
## RSSI Method of scan
By default, we are using the spectralScan method of the RadioLib Library: https://jgromes.github.io/RadioLib/class_s_x126x.html#a8a3ad4e12df862ab18b326d9dba26d66
This method works only with Sx1262 modules.
We implemented a scan using the **getRSSI** method, which has more flexibility and supports sx1276 and other modules.
Using this method, we also receive the signal's **dB** values, not just the O-33 number.
To enable this method, set the value of the **RSSI_METHOD** to true.
Waterfall shows the last **N** = SCREEN_HEIGHT (64) - WATERFALL_START(37) - 8 (part of the ROW_STATUS_TEXT) = **19** signal detection that excited set signal level
### RSSI Method of scan
By default, we are using the spectralScan method of the RadioLib Library: <https://jgromes.github.io/RadioLib/class_s_x126x.html#a8a3ad4e12df862ab18b326d9dba26d66>
This method works only with Sx1262 modules.
We implemented a scan using the **getRSSI** method, which has more flexibility and supports sx1276 and other modules.
Using this method, we also receive the signal's **dB** values, not just the O-33 number.
To enable this method, set the value of the **RSSI_METHOD** to true.
### Multi Screen Scan
## Multi Screen Scan
Single screen scan for now has **RANGE / 128** resolution.
Multi-page scan can be adjusted to how many MHz per page you wanna scan
Multi-page scan can be adjusted to how many MHz per page you wanna scan
```
```c
// frequency range in MHz to scan
#define FREQ_BEGIN 850
// TODO: if % RANGE_PER_PAGE != 0
@@ -108,72 +122,81 @@ int SCAN_DIAPAZONES[] = {};
// int SCAN_DIAPAZONES[] = {850890, 920950};
// MHZ per page
//To put everething into one page set RANGE_PER_PAGE = FREQ_END - 800
//To put everything into one page set RANGE_PER_PAGE = FREQ_END - 800
unsigned int RANGE_PER_PAGE = FREQ_END - FREQ_BEGIN; // FREQ_END - FREQ_BEGIN
//To Enable Multi Screen scan
// unsigned int RANGE_PER_PAGE = 50;
// Default Range on Menu Button Switch
#define DEFAULT_RANGE_PER_PAGE = 50;
```
To enable Multi-page by default set **RANGE_PER_PAGE** less than **FREQ_END - FREQ_BEGIN**;
Switch to multi-page during regular One Screen application run. Restart the ESP32 on screen after the logo press the P button.
Switch to multi-page during regular One Screen application run. Restart the ESP32 on screen after the logo press the P button.
## Mute Autio Notifications
Restart ESP32, and on the logo display, press the P button.
### Mute Audio Notifications
## Pause Execution
Press P for more than 2 seconds. Execution will pause, and the scan's current Mhz position will be shown on the display.
If less, ESP32 will turn off. Fast pressing(less than 0.5 second) P button changes the notification level
Restart ESP32, and on the logo display, press the P button.
### Pause Execution
Press P for more than 2 seconds. Execution will pause, and the scan's current Mhz position will be shown on the display.
If less, ESP32 will turn off. Fast pressing(less than 0.5 second) P button changes the notification level
## VSCode Platform.IO development env installation
# VSCode Platform.IO development env installation
1. Install VSCode
2. install Platfor.IO extension
2. install Platform.IO extension
![image](https://github.com/user-attachments/assets/00547068-6153-4c78-9f12-54981b013b06)
3. Connect ESP32 to USB. Install USB drivers for Windows
4. Clone this Git Repo or download zip of the sources
![image](https://github.com/user-attachments/assets/971b6592-3b71-414c-971c-2ecd20f0f0b7)
```
git clone https://github.com/Genaker/LoraSA.git
```
NOTE: in you case name will be Just LoraSA. I have LoraSA2 because I already have LoraSA folder
6. Open the Project with the VS code Platform.IO
```bash
git clone https://github.com/Genaker/LoraSA.git
```
NOTE: in you case name will be Just LoraSA. I have LoraSA2 because I already have LoraSA folder
5. Open the Project with the VS code Platform.IO
![image](https://github.com/user-attachments/assets/5066836b-32ac-4a24-ac03-b5f739a6a658)
![image](https://github.com/user-attachments/assets/da14488d-7a4a-410e-b754-59598578016d)
7. Select Proper Environment
6. Select Proper Environment
![image](https://github.com/user-attachments/assets/a9c6557b-a387-4457-b59b-b3d7242d2826)
8. Select ESP32 USB Device to program
7. Select ESP32 USB Device to program
![image](https://github.com/user-attachments/assets/af76c4b1-7122-45e1-b26b-08b59e03ca3b)
Note: It is theoretically possible to program via WiFi and BTH.
9. Programm your ESP32
8. Program your ESP32
![image](https://github.com/user-attachments/assets/9e67afd8-0522-4a96-82dc-8e1cdb32add5)
10. Wait until you are done with the compilation and upload.
Usually takes 1 minute. The first run is slower. It needs to compile all libraries.
9. Wait until you are done with the compilation and upload.
Usually takes 1 minute. The first run is slower. It needs to compile all libraries.
![image](https://github.com/user-attachments/assets/6796eb5d-6e3f-45bc-b88c-251499f1ad47)
You will have the UCOG SA logo and spectrum analyzing scanning screen when done.
![image](https://github.com/user-attachments/assets/f86ab32a-cab1-461e-ade9-7021136a0af7)
# Hardware
## Hardware
Heltec ESP32 Lora V3:
https://www.amazon.com/Heltec-Development-863-870MHz-ESP32-S3FN8-902-928MHz/dp/B0D1H1FN9Y/
https://heltec.org/project/wifi-lora-32-v3/
https://www.aliexpress.us/item/3256807037422978.html
<https://www.amazon.com/Heltec-Development-863-870MHz-ESP32-S3FN8-902-928MHz/dp/B0D1H1FN9Y/>
<https://heltec.org/project/wifi-lora-32-v3/>
<https://www.aliexpress.us/item/3256807037422978.html>
Battery with Wire JT connector :
https://www.amazon.com/EEMB-2000mAh-Battery-Rechargeable-Connector/dp/B08214DJLJ
Battery with Wire JT connector :
<https://www.amazon.com/EEMB-2000mAh-Battery-Rechargeable-Connector/dp/B08214DJLJ>
## 3D printed case
# 3D printed case
![image](https://github.com/user-attachments/assets/52ae4e90-5f25-4d72-888e-7586bef9df69)
https://www.printables.com/model/118750-heltec-lora-32-case-for-meshtastic
https://www.thingiverse.com/thing:3125854
https://thangs.com/designer/Snake0017/3d-model/Heltec%20LoRa%2032%20Desktop%20%26%20Vehicle%20Enclosure-40844
or buy :
https://www.amazon.com/DIYmalls-ESP32-OLED-WiFi-Type-C/dp/B0BR3MQ9BG
<https://www.printables.com/model/118750-heltec-lora-32-case-for-meshtastic>
<https://www.thingiverse.com/thing:3125854>
<https://thangs.com/designer/Snake0017/3d-model/Heltec%20LoRa%2032%20Desktop%20%26%20Vehicle%20Enclosure-40844>
or buy :
<https://www.amazon.com/DIYmalls-ESP32-OLED-WiFi-Type-C/dp/B0BR3MQ9BG>
https://www.thingiverse.com/thing:6522462
<https://www.thingiverse.com/thing:6522462>
## Heltec ESP32 Lora v3 Pin Map
# Heltec ESP32 Lora v3 Pin Map
![image](https://github.com/user-attachments/assets/a1e00b51-5566-4ff5-98fe-67eaeb5bc81f)
We are using pin 41 as a Buzzer trigger. Connect buzzer + leg with pin 41 and - leg with the ground (GND). You can change the buzzer pin in the code.
We are using pin 41 as a Buzzer trigger. Connect buzzer + leg with pin 41 and - leg with the ground (GND). You can change the buzzer pin in the code.
+25
View File
@@ -0,0 +1,25 @@
#ifndef __GLOBAL_CONFIG_H__
#define __GLOBAL_CONFIG_H__
// frequency range in MHz to scan
#define FREQ_BEGIN 850
// TODO: if % RANGE_PER_PAGE != 0
#define FREQ_END 950
// Measurement bandwidth. Allowed bandwidth values (in kHz) are:
// 4.8, 5.8, 7.3, 9.7, 11.7, 14.6, 19.5, 23.4, 29.3, 39.0, 46.9, 58.6,
// 78.2, 93.8, 117.3, 156.2, 187.2, 234.3, 312.0, 373.6 and 467.0
#define BANDWIDTH 467.0
// Detection level from the 33 levels. The higher number is more sensitive
#define DEFAULT_DRONE_DETECTION_LEVEL 21
#define BUZZER_PIN 41
// REB trigger PIN
#define REB_PIN 42
#define WATERFALL_ENABLED true
#define WATERFALL_START 37
#endif
+10
View File
@@ -0,0 +1,10 @@
#ifndef __IMAGES_H__
#define __IMAGES_H__
// Array of all bitmaps for convenience. (Total bytes used to store images in PROGMEM = 1040)
extern const unsigned char epd_bitmap_ucog [];
#endif // __IMAGES_H__
+41
View File
@@ -0,0 +1,41 @@
#ifndef __UI_H__
#define __UI_H__
#include <Arduino.h>
#include "SSD1306Wire.h"
#include "OLEDDisplayUi.h"
// #include <heltec_unofficial.h>
// (optional) major and minor tick-marks at x MHz
#define MAJOR_TICKS 10
#define MINOR_TICKS 5
#define ONE_MILLISEC 1
// Prints debug information and the scan measurement bins from the SX1262 in hex
// Change spectrum plot values at once or by line
#define ANIMATED_RELOAD false
#define MAJOR_TICK_LENGTH 2
#define MINOR_TICK_LENGTH 1
// WEIGHT of the x-axis line
#define X_AXIS_WEIGHT 1
#define ROW_STATUS_TEXT (64 - 10)
// The number of the spectrum screen lines = width of screen
// Resolution of the scan is limited by 128-pixel screen
#define STEPS 128
#define SCREEN_HEIGHT 64 // ???? not used
// publish functions
extern void UI_Init(SSD1306Wire *);
extern void UI_displayDecorate(int, int, bool);
extern void UI_setLedFlag(bool);
extern void UI_clearPlotter(void);
extern void UI_drawCursor(int16_t);
#endif // __UI_H__
+2 -2
View File
@@ -15,5 +15,5 @@ framework = arduino
upload_speed = 115200
monitor_speed = 115200
board_build.f_cpu = 240000000
lib_deps =
ropg/Heltec_ESP32_LoRa_v3@^0.9.1
lib_deps = ropg/Heltec_ESP32_LoRa_v3@^0.9.1
build_flags = -DHELTEC_POWER_BUTTON
+6 -5
View File
@@ -1,11 +1,12 @@
#include "images.h"
//'Logo_UCOG', 128x64px
//https://www.online-utility.org/image/convert/to/XBM
//https://javl.github.io/image2cpp/
//#define 1721604660673_width 128
//#define 1721604660673_height 64
const unsigned char epd_bitmap_ucog [] PROGMEM = {
const unsigned char epd_bitmap_ucog[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -95,7 +96,7 @@ const unsigned char epd_bitmap_ucog [] PROGMEM = {
};
// Array of all bitmaps for convenience. (Total bytes used to store images in PROGMEM = 1040)
const int epd_bitmap_allArray_LEN = 1;
const unsigned char* epd_bitmap_allArray[1] = {
epd_bitmap_ucog
};
// const int epd_bitmap_allArray_LEN = 1;
// const unsigned char* epd_bitmap_allArray[1] = {
// epd_bitmap_ucog
// };
+540 -735
View File
File diff suppressed because it is too large Load Diff
+289
View File
@@ -0,0 +1,289 @@
#include "ui.h"
#include "images.h"
#include "global_config.h"
#include "RadioLib.h"
// -------------------------------------------------
// LOCAL DEFINES
// Height of the plotter area
// -------------------------------------------------
#define HEIGHT RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE
//
#define SCALE_TEXT_TOP (HEIGHT + X_AXIS_WEIGHT + MAJOR_TICK_LENGTH)
static unsigned int start_scan_text = (128 / 2) - 3;
// initialized flag
static bool ui_initialized = false;
static bool led_flag = false;
static unsigned short int scan_progress_count = 0;
//(0x3c, SDA_OLED, SCL_OLED, DISPLAY_GEOMETRY);
static SSD1306Wire *display_instance;
// temporary dirty import ... to be solved durring upcoming refactoring
extern unsigned int drone_detection_level;
extern unsigned int RANGE_PER_PAGE;
extern unsigned int median_frequency;
extern unsigned int detection_count;
extern bool SOUND_ON;
extern unsigned int drone_detected_frequency_start;
extern unsigned int drone_detected_frequency_end;
extern unsigned int ranges_count;
extern int SCAN_RANGES[];
extern unsigned int ranges_count;
extern unsigned int iterations;
extern unsigned int range_item;
extern uint64_t loop_time;
void UI_Init(SSD1306Wire *display_ptr)
{
// init pointer to display instance.
display_instance = display_ptr;
// check for null ???
display_instance->clear();
// draw the UCOG welcome logo
display_instance->drawXbm(0, 2, 128, 64, epd_bitmap_ucog);
display_instance->display();
}
void UI_setLedFlag(bool new_status)
{
led_flag = new_status;
}
void clearStatus(void)
{
// clear status line
display_instance->setColor(BLACK);
display_instance->fillRect(0, ROW_STATUS_TEXT + 2, 128, 13);
display_instance->setColor(WHITE);
}
void UI_clearPlotter(void)
{
// clear the scan plot rectangle (top part)
display_instance->setColor(BLACK);
display_instance->fillRect(0, 0, STEPS, HEIGHT);
display_instance->setColor(WHITE);
}
/**
* @brief Draws ticks on the display at regular whole intervals.
*
* @param every The interval between ticks in MHz.
* @param length The length of each tick in pixels.
*/
void drawTicks(float every, int length)
{
int first_tick;
bool correction;
int pixels_per_step;
int correction_number;
int tick;
int tick_minor;
int median;
first_tick = 0;
//+ (every - (fr_begin - (int)(fr_begin / every) * every));
/*if (first_tick < fr_begin)
{
first_tick += every;
}*/
correction = false;
pixels_per_step = STEPS / (RANGE_PER_PAGE / every);
if (STEPS / RANGE_PER_PAGE != 0)
{
correction = true;
}
correction_number = STEPS - (int)(pixels_per_step * (RANGE_PER_PAGE / every));
tick = 0;
tick_minor = 0;
median = (RANGE_PER_PAGE / every) / 2;
// TODO: (RANGE_PER_PAGE / every)
// * 2 has twice extra steps we need to figureout correct logic or minor ticks is not showing to the end
for (int t = 0; t <= (RANGE_PER_PAGE / every) * 2; t++)
{
// fix if pixels per step is not int and we have shift
if (correction && t % 2 != 0 && correction_number > 1)
{
// pixels_per_step++;
correction_number--;
}
tick += pixels_per_step;
tick_minor = tick / 2;
if (tick <= 128 - 3)
{
display_instance->drawLine(tick, HEIGHT + X_AXIS_WEIGHT, tick,
HEIGHT + X_AXIS_WEIGHT + length);
// Central tick
if (tick > (128 / 2) - 3 && tick < (128 / 2) + 3)
{
display_instance->drawLine(tick + 1, HEIGHT + X_AXIS_WEIGHT,
tick + 1, HEIGHT + X_AXIS_WEIGHT + length);
}
}
#ifdef MINOR_TICKS
// Fix two ticks together
if ((tick_minor + 1 != tick) && (tick_minor - 1 != tick) && (tick_minor + 2 != tick) && (tick_minor - 2 != tick))
{
display_instance->drawLine(tick_minor, HEIGHT + X_AXIS_WEIGHT,
tick_minor, HEIGHT + X_AXIS_WEIGHT + MINOR_TICK_LENGTH);
}
// Central tick
if (tick_minor > (128 / 2) - 3 && tick_minor < (128 / 2) + 3)
{
display_instance->drawLine(tick_minor + 1, HEIGHT + X_AXIS_WEIGHT,
tick_minor + 1, HEIGHT + X_AXIS_WEIGHT + MINOR_TICK_LENGTH);
}
#endif
}
}
void UI_drawCursor(int16_t possition)
{
// Draw animated cursor on reload process
display_instance->setColor(BLACK);
display_instance->drawVerticalLine(possition, 0, HEIGHT);
display_instance->drawVerticalLine(possition + 1, 0, HEIGHT);
display_instance->setColor(WHITE);
}
/**
* @brief Decorates the display: everything but the plot itself.
*/
void UI_displayDecorate(int begin = 0, int end = 0, bool redraw = false)
{
if (!ui_initialized)
{
// Start and end ticks
display_instance->fillRect(0, HEIGHT + X_AXIS_WEIGHT, 2,
MAJOR_TICK_LENGTH + 1);
display_instance->fillRect(126, HEIGHT + X_AXIS_WEIGHT, 2,
MAJOR_TICK_LENGTH + 1);
// Drone detection level
display_instance->setTextAlignment(TEXT_ALIGN_RIGHT);
display_instance->drawString(128, 0, String(drone_detection_level));
}
if (!ui_initialized || redraw)
{
// Clear something
display_instance->setColor(BLACK);
display_instance->fillRect(0, SCALE_TEXT_TOP + 1, 128, 12);
display_instance->setColor(WHITE);
// Drone detection level
display_instance->setTextAlignment(TEXT_ALIGN_RIGHT);
display_instance->drawString(128, 0, String(drone_detection_level));
// Frequency start
display_instance->setTextAlignment(TEXT_ALIGN_LEFT);
display_instance->drawString(0, ROW_STATUS_TEXT,
(begin == 0) ? String(FREQ_BEGIN) : String(begin));
// Frequency detected
display_instance->setTextAlignment(TEXT_ALIGN_CENTER);
display_instance->drawString(128 / 2, ROW_STATUS_TEXT,
(begin == 0) ? String(median_frequency) : String(begin + ((end - begin) / 2)));
// Frequency end
display_instance->setTextAlignment(TEXT_ALIGN_RIGHT);
display_instance->drawString(128, ROW_STATUS_TEXT,
(end == 0) ? String(FREQ_END) : String(end));
}
// Status text block
if (led_flag) // 'drone' detected
{
display_instance->setTextAlignment(TEXT_ALIGN_CENTER);
// clear status line
clearStatus();
display_instance->drawString(start_scan_text, ROW_STATUS_TEXT,
String(drone_detected_frequency_start) + ">RF<" + String(drone_detected_frequency_end));
} else
{
// "Scanning"
display_instance->setTextAlignment(TEXT_ALIGN_CENTER);
// clear status line
clearStatus();
if (scan_progress_count == 0)
{
display_instance->drawString(start_scan_text, ROW_STATUS_TEXT,
"Scan \\");
}
else if (scan_progress_count == 1)
{
display_instance->drawString(start_scan_text, ROW_STATUS_TEXT,
"Scan |");
}
else if (scan_progress_count == 2)
{
display_instance->drawString(start_scan_text, ROW_STATUS_TEXT,
"Scan /");
}
else if (scan_progress_count == 3)
{
display_instance->drawString(start_scan_text, ROW_STATUS_TEXT,
"Scan -");
}
scan_progress_count++;
if (scan_progress_count >= 4)
{
scan_progress_count = 0;
}
}
if (led_flag == true && detection_count >= 5)
{
digitalWrite(LED, HIGH);
if (SOUND_ON)
{
tone(BUZZER_PIN, 104, 100);
}
digitalWrite(REB_PIN, HIGH);
led_flag = false;
}
else if (!redraw)
{
digitalWrite(LED, LOW);
}
if (ranges_count == 0)
{
#ifdef DEBUG
display_instance->setTextAlignment(TEXT_ALIGN_LEFT);
display_instance->drawString(0, ROW_STATUS_TEXT,String(loop_time));
#else
display_instance->setTextAlignment(TEXT_ALIGN_LEFT);
display_instance->drawString(0, ROW_STATUS_TEXT, String(FREQ_BEGIN));
#endif
display_instance->setTextAlignment(TEXT_ALIGN_RIGHT);
display_instance->drawString(128, ROW_STATUS_TEXT, String(FREQ_END));
}
else if (ranges_count > 0)
{
display_instance->setTextAlignment(TEXT_ALIGN_LEFT);
display_instance->drawString(0, ROW_STATUS_TEXT,
String(SCAN_RANGES[range_item] / 1000) + "-" + String(SCAN_RANGES[range_item] % 1000));
if (range_item + 1 < iterations)
{
display_instance->setTextAlignment(TEXT_ALIGN_RIGHT);
display_instance->drawString(128, ROW_STATUS_TEXT,
String(SCAN_RANGES[range_item + 1] / 1000) + "-" + String(SCAN_RANGES[range_item + 1] % 1000));
}
}
if (ui_initialized == false)
{
// X-axis
display_instance->fillRect(0, HEIGHT, STEPS, X_AXIS_WEIGHT);
// ticks
#ifdef MAJOR_TICKS
drawTicks(MAJOR_TICKS, MAJOR_TICK_LENGTH);
#endif
}
ui_initialized = true;
}