Compare commits

..
7 Commits
Author SHA1 Message Date
PoliEcho 47f2766bb8 some housekeeping 2026-08-11 12:51:19 +02:00
PoliEcho 839ea1490a format 2026-08-11 12:14:53 +02:00
PoliEcho 831501ea41 fix possible wraparound 2026-08-11 12:06:03 +02:00
PoliEcho abf1226b47 bug fixes 2026-08-08 11:24:27 +02:00
PoliEcho 6ac93f0a5b make compilation better 2026-08-08 09:49:25 +02:00
PoliEcho 66bdf9327a add arc and alt 2026-08-07 16:36:56 +02:00
PoliEcho 95225a5811 add usage of text 2026-08-07 15:37:13 +02:00
14 changed files with 358 additions and 157 deletions
+2 -1
View File
@@ -8,4 +8,5 @@ compile_commands.json
.config.* .config.*
include/ include/
!scripts/include/ !scripts/include/
*.o *.o
test
+29 -50
View File
@@ -1,6 +1,13 @@
cmake_minimum_required(VERSION 3.13) cmake_minimum_required(VERSION 3.13)
option(BUILD_FOR_PICO "Build for Raspberry Pi Pico" ON) set(BUILD_PLATFORM "Linux" CACHE STRING "Target platform: Pico or Linux")
set_property(CACHE BUILD_PLATFORM PROPERTY STRINGS Pico Linux)
if(NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/cmake/platform_${BUILD_PLATFORM}_pre.cmake")
message(FATAL_ERROR "Unknown BUILD_PLATFORM '${BUILD_PLATFORM}' (no cmake/platform_${BUILD_PLATFORM}_pre.cmake found)")
endif()
string(TOLOWER ${BUILD_PLATFORM} BUILD_PLATFORM_LOWER)
set(GEOGRAPHICLIB_DIR ${CMAKE_CURRENT_SOURCE_DIR}/geographiclib) set(GEOGRAPHICLIB_DIR ${CMAKE_CURRENT_SOURCE_DIR}/geographiclib)
@@ -10,55 +17,27 @@ set(BUILD_DOCUMENTATION OFF CACHE BOOL "" FORCE)
set(BUILD_BOTH_LIBRARIES OFF CACHE BOOL "" FORCE) set(BUILD_BOTH_LIBRARIES OFF CACHE BOOL "" FORCE)
set(PACKAGE_DEBIAN OFF CACHE BOOL "" FORCE) set(PACKAGE_DEBIAN OFF CACHE BOOL "" FORCE)
# Automatically collect core sources and platform-specific HAL files # Pre-project platform setup (e.g. Pico's pico_sdk_import.cmake must run
# before project(), and it must set PROJECT_LANGUAGES).
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/platform_${BUILD_PLATFORM}_pre.cmake)
project(p-rad ${PROJECT_LANGUAGES})
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_compile_options(-Wall -Wextra -Wpedantic -Wno-write-strings)
# NOTE: don't use add_link_options/add_compile_options here - they apply to
# every target including pico-sdk's bs2_default, whose binary gets fully
# garbage-collected. Scope them to the p-rad target instead (see platform files).
# Automatically collect core sources and platform-specific HAL files.
# HAL files are matched by suffix convention: src/hal/*_<platform>.cpp
file(GLOB CORE_SOURCES CONFIGURE_DEPENDS "src/core/*.cpp" "src/core/*.c") file(GLOB CORE_SOURCES CONFIGURE_DEPENDS "src/core/*.cpp" "src/core/*.c")
file(GLOB HAL_PICO_SOURCES CONFIGURE_DEPENDS "src/hal/*_pico.cpp") file(GLOB HAL_SOURCES CONFIGURE_DEPENDS "src/hal/*_${BUILD_PLATFORM_LOWER}.cpp")
file(GLOB HAL_LINUX_SOURCES CONFIGURE_DEPENDS "src/hal/*_linux.cpp")
if(BUILD_FOR_PICO) add_subdirectory(${GEOGRAPHICLIB_DIR} EXCLUDE_FROM_ALL)
set(PICO_BOARD pico_w CACHE STRING "Board type")
include(pico_sdk_import.cmake)
project(p-rad C CXX ASM)
set(CMAKE_CXX_STANDARD 23) # Post-project platform setup: add_executable, link libraries, platform-specific calls.
set(CMAKE_CXX_STANDARD_REQUIRED ON) include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/platform_${BUILD_PLATFORM}.cmake)
pico_sdk_init()
add_subdirectory(${GEOGRAPHICLIB_DIR} EXCLUDE_FROM_ALL)
target_compile_options(GeographicLib INTERFACE -fexceptions -frtti)
add_executable(p-rad
src/main.cpp
${CORE_SOURCES}
${HAL_PICO_SOURCES}
)
target_compile_definitions(p-rad PRIVATE PICO_BUILD)
target_include_directories(p-rad PRIVATE src)
target_link_libraries(p-rad pico_stdlib pico_cyw43_arch_lwip_threadsafe_background hardware_rtc GeographicLib)
pico_enable_stdio_usb(p-rad 1)
pico_enable_stdio_uart(p-rad 0)
pico_add_extra_outputs(p-rad)
else()
project(p-rad CXX)
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_subdirectory(${GEOGRAPHICLIB_DIR} EXCLUDE_FROM_ALL)
add_executable(p-rad
src/main.cpp
${CORE_SOURCES}
${HAL_LINUX_SOURCES}
)
target_include_directories(p-rad PRIVATE src)
find_package(Threads REQUIRED)
find_package(SDL3 REQUIRED CONFIG)
find_package(CURL REQUIRED)
target_link_libraries(p-rad Threads::Threads SDL3::SDL3 CURL::libcurl GeographicLib)
endif()
+22 -2
View File
@@ -63,11 +63,31 @@ config VECTOR_FOLLOW_TRACK_RATE
This option will turn the vector from line into curve. This option will turn the vector from line into curve.
This is of course be more computationaly expensive. This is of course be more computationaly expensive.
config AIRCRAFT_RHOMBUS_RADIUS
int "Radius of rhombus or aircraft icon"
range 0 65535
default 8
config CHARACTER_SPACING config CHARACTER_SPACING
int "Spacing between character in pixels" int "Spacing between character in pixels"
range 1 255 range 0 255
default 1 default 1
config X_TEXT_OFFSET
int "X offset of text from aircraft"
range 0 65535
default 10
config NO_CALLSIGN_IDENTIFICATION
string "Callsign used for aircraft with unknown callsign"
default "UNK"
config EXTRA_INFO
bool "Enable extra information on top of the screen"
default 1
help
Show information like number of tracked aircraft on top of the screen
comment "Receiver configuration" comment "Receiver configuration"
config FALLBACK_LAT config FALLBACK_LAT
@@ -88,7 +108,7 @@ config METRIC
bool "Use metric units" bool "Use metric units"
default y default y
help help
Show altitudes in meters instead of feet. Show units in metric instead of aeronautical.
comment "Platform dependent options" comment "Platform dependent options"
+4 -2
View File
@@ -12,12 +12,14 @@ all: linux pico
linux: $(AUTOHEADER) linux: $(AUTOHEADER)
mkdir -p build-linux mkdir -p build-linux
(cd build-linux && cmake .. -DBUILD_FOR_PICO=OFF && make -j$(nproc)) (cd build-linux && cmake .. -DBUILD_PLATFORM=Linux && make -j$(nproc))
pico: $(AUTOHEADER) pico: $(AUTOHEADER)
mkdir -p build-pico mkdir -p build-pico
(cd build-pico && cmake .. -DBUILD_FOR_PICO=ON && make -j$(nproc)) (cd build-pico && cmake .. -DBUILD_PLATFORM=Pico && make -j$(nproc))
clean:
rm -fr build*
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# kconfig targets # kconfig targets
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
+23
View File
@@ -0,0 +1,23 @@
add_executable(p-rad
src/main.cpp
${CORE_SOURCES}
${HAL_SOURCES}
)
target_compile_options(p-rad PRIVATE -ffunction-sections -fdata-sections)
target_link_options(p-rad PRIVATE -Wl,--gc-sections)
if(CMAKE_BUILD_TYPE EQUAL Release)
add_compile_options(-O3 -s)
endif()
target_include_directories(p-rad PRIVATE src)
find_package(Threads REQUIRED)
find_package(SDL3 REQUIRED CONFIG)
find_package(CURL REQUIRED)
target_link_libraries(p-rad
Threads::Threads
SDL3::SDL3
CURL::libcurl
GeographicLib
)
+1
View File
@@ -0,0 +1 @@
set(PROJECT_LANGUAGES CXX)
+31
View File
@@ -0,0 +1,31 @@
pico_sdk_init()
target_compile_options(GeographicLib INTERFACE -fexceptions -frtti)
add_executable(p-rad
src/main.cpp
${CORE_SOURCES}
${HAL_SOURCES}
)
target_compile_options(p-rad PRIVATE -ffunction-sections -fdata-sections)
target_link_options(p-rad PRIVATE -Wl,--gc-sections)
if(CMAKE_BUILD_TYPE EQUAL Release)
add_compile_options(-Os -s)
endif()
target_compile_definitions(p-rad PRIVATE PICO_BUILD)
target_include_directories(p-rad PRIVATE src)
target_link_libraries(p-rad
pico_stdlib
pico_cyw43_arch_lwip_threadsafe_background
hardware_rtc
GeographicLib
)
pico_enable_stdio_usb(p-rad 1)
pico_enable_stdio_uart(p-rad 0)
pico_add_extra_outputs(p-rad)
+4
View File
@@ -0,0 +1,4 @@
set(PROJECT_LANGUAGES C CXX ASM)
set(PICO_BOARD pico_w CACHE STRING "Board type")
include(${CMAKE_SOURCE_DIR}/pico_sdk_import.cmake)
+6 -8
View File
@@ -42,7 +42,7 @@ draw::color_t interpolateColor(double value,
return stops.back().color; return stops.back().color;
} }
#ifdef CONFIG_METRIC
draw::color_t get_altitude_color(uint32_t value) { draw::color_t get_altitude_color(uint32_t value) {
static constexpr std::array<color_stop, 11> stops = {{ static constexpr std::array<color_stop, 11> stops = {{
#ifdef CONFIG_METRIC #ifdef CONFIG_METRIC
@@ -57,8 +57,7 @@ draw::color_t get_altitude_color(uint32_t value) {
{6000, {40, 175, 215}}, {6000, {40, 175, 215}},
{9000, {50, 110, 240}}, {9000, {50, 110, 240}},
{12000, {140, 50, 220}} {12000, {140, 50, 220}}
#endif #else
#ifndef CONFIG_METRIC
{0, {220, 90, 20}}, // Brown/Dark Orange {0, {220, 90, 20}}, // Brown/Dark Orange
{500, {245, 115, 25}}, // Orange {500, {245, 115, 25}}, // Orange
{1000, {250, 150, 30}}, // Light Orange {1000, {250, 150, 30}}, // Light Orange
@@ -74,7 +73,6 @@ draw::color_t get_altitude_color(uint32_t value) {
}}; }};
return interpolateColor(value, stops); return interpolateColor(value, stops);
} }
#endif
enum letter_id { enum letter_id {
LETTER_A, LETTER_A,
@@ -159,10 +157,10 @@ void putchar(const char c, uint16_t x, uint16_t y, const draw::color_t color) {
x = x_orig; x = x_orig;
for (uint8_t j = 0; j < FONT_WIDTH; j++) { for (uint8_t j = 0; j < FONT_WIDTH; j++) {
if (get_Nth_bit_in_grid(_5x7_dotmatrix_charset, if (get_Nth_bit_in_grid(_5x7_dotmatrix_charset,
static_cast<typeof(character_bit_offset)>( static_cast<std::remove_const_t<decltype(character_bit_offset)>>(
character_bit_offset + j), character_bit_offset + j),
static_cast<typeof(character_bit_offset)>(i), static_cast<std::remove_const_t<decltype(character_bit_offset)>>(i),
static_cast<typeof(character_bit_offset)>( static_cast<std::remove_const_t<decltype(character_bit_offset)>>(
_5X7_DOTMATRIX_CHARSET_WIDTH))) { _5X7_DOTMATRIX_CHARSET_WIDTH))) {
draw::pixel(x, y, color); draw::pixel(x, y, color);
} }
@@ -171,7 +169,7 @@ void putchar(const char c, uint16_t x, uint16_t y, const draw::color_t color) {
y++; y++;
} }
} }
void puts(const std::string &s, uint16_t x, uint16_t y, draw::color_t color) { void puts(const std::string &s, const uint16_t x, const uint16_t y, const draw::color_t color) {
for (size_t i = 0; i < s.length(); i++) { for (size_t i = 0; i < s.length(); i++) {
putchar(s[i], x+((FONT_WIDTH+CONFIG_CHARACTER_SPACING)*i), y, color); putchar(s[i], x+((FONT_WIDTH+CONFIG_CHARACTER_SPACING)*i), y, color);
} }
+16 -3
View File
@@ -1,9 +1,22 @@
#pragma once #pragma once
#include "config.hpp"
template<typename T> template<typename T>
static inline T feet_to_meters(T ft) { static inline T feet_to_meters(T ft) {
return static_cast<T>(ft * 0.3048); return static_cast<T>(ft * 0.3048);
} }
template<typename T> template<typename T>
static inline T knot_to_km(T kn) { static inline T knot_to_km(T kt) {
return static_cast<T>(kn * 0.5399568); return static_cast<T>(kt * 1.852);
} }
#ifdef CONFIG_METRIC
#define SPEED_UNIT "kmph"
#else
#define SPEED_UNIT "knot"
#endif
#ifdef CONFIG_METRIC
#define ALTITUDE_UNIT "m"
#else
#define ALTITUDE_UNIT "ft"
#endif
+1
View File
@@ -20,4 +20,5 @@ struct rect_t {
void circle(const uint16_t x_center, const uint16_t y_center,const uint16_t radius, const color_t color); void circle(const uint16_t x_center, const uint16_t y_center,const uint16_t radius, const color_t color);
void rhombus(const uint16_t x_center, const uint16_t y_center,const uint16_t radius, const color_t color); void rhombus(const uint16_t x_center, const uint16_t y_center,const uint16_t radius, const color_t color);
void line(const uint16_t x1,const uint16_t y1,const uint16_t x2,const uint16_t y2, const color_t color); void line(const uint16_t x1,const uint16_t y1,const uint16_t x2,const uint16_t y2, const color_t color);
void arc(uint16_t start_x, uint16_t start_y, float start_angle, float speed /*in pps*/,float angular_speed, uint16_t duration, color_t color);
} }
+48 -3
View File
@@ -25,6 +25,7 @@
#include <iostream> #include <iostream>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include <nlohmann/json_fwd.hpp> #include <nlohmann/json_fwd.hpp>
#include <numbers>
#include <tuple> #include <tuple>
struct sdl_session { struct sdl_session {
@@ -95,7 +96,7 @@ void start_frame() {
SDL_RenderClear(main_sdl_session.renderer); SDL_RenderClear(main_sdl_session.renderer);
} }
const Uint64 frame_delay_ns = 1000000000ULL / 1; constexpr Uint64 frame_delay_ns = 1000000000ULL / 1;
void end_frame() { void end_frame() {
SDL_Event event; SDL_Event event;
while (SDL_PollEvent(&event)) { while (SDL_PollEvent(&event)) {
@@ -108,7 +109,7 @@ void end_frame() {
if (event.key.key != SDLK_Q) { if (event.key.key != SDLK_Q) {
break; break;
} }
[[fallthrough]];
case SDL_EVENT_QUIT: case SDL_EVENT_QUIT:
SDL_Quit(); SDL_Quit();
std::exit(0); std::exit(0);
@@ -163,7 +164,6 @@ void circle(const uint16_t x_center, const uint16_t y_center,
SDL_RenderPoint(main_sdl_session.renderer, x + x_center, -y + y_center); SDL_RenderPoint(main_sdl_session.renderer, x + x_center, -y + y_center);
SDL_RenderPoint(main_sdl_session.renderer, y + x_center, x + y_center); SDL_RenderPoint(main_sdl_session.renderer, y + x_center, x + y_center);
SDL_RenderPoint(main_sdl_session.renderer, -y + x_center, x + y_center); SDL_RenderPoint(main_sdl_session.renderer, -y + x_center, x + y_center);
std::cout << "\n";
} }
// Initialising the value of P // Initialising the value of P
@@ -221,6 +221,51 @@ void line(const uint16_t x1, const uint16_t y1, const uint16_t x2,
0xff); 0xff);
SDL_RenderLine(main_sdl_session.renderer, x1, y1, x2, y2); SDL_RenderLine(main_sdl_session.renderer, x1, y1, x2, y2);
} }
#ifdef CONFIG_VECTOR_FOLLOW_TRACK_RATE
void arc(uint16_t start_x, uint16_t start_y, float start_angle_rad, float speed /*in pps*/,float angular_speed_rads, uint16_t duration, color_t color) {
SDL_SetRenderDrawColor(main_sdl_session.renderer, color.r, color.g, color.b,
0xff);
if (speed == 0) {
SDL_RenderPoint(main_sdl_session.renderer, start_x, start_y);
return;
}
// Handle straight line case
if (std::fabs(angular_speed_rads) < 1e-6f) {
uint16_t steps = static_cast<int>(speed * duration);
for (uint16_t i = 0; i <= steps; ++i) {
float t = i / speed;
float x = start_x + std::cos(start_angle_rad) * speed * t;
float y = start_y + std::sin(start_angle_rad) * speed * t;
SDL_RenderPoint(main_sdl_session.renderer,static_cast<int>(std::round(x)), static_cast<int>(std::round(y)));
}
return;
}
float r = speed / angular_speed_rads;
// Center of circle: perpendicular to heading
float center_x = start_x - r * std::sin(start_angle_rad);
float center_y = start_y + r * std::cos(start_angle_rad);
// Angle from center to start point
float radius_angle = std::atan2(start_y - center_y, start_x - center_x);
// Step size in time — approx 1 pixel arc-length per step
float dt = 1.0f / std::max(std::fabs(speed), 1.0f);
uint16_t steps = static_cast<int>(duration / dt);
for (uint16_t i = 0; i <= steps; ++i) {
float t = i * dt;
float a = radius_angle + angular_speed_rads * t;
float x = center_x + std::fabs(r) * std::cos(a);
float y = center_y + std::fabs(r) * std::sin(a);
SDL_RenderPoint(main_sdl_session.renderer,static_cast<int>(std::round(x)), static_cast<int>(std::round(y)));
}
}
#endif
} // namespace draw } // namespace draw
namespace net { namespace net {
+2
View File
@@ -54,6 +54,8 @@ void circle(const uint16_t x_center, const uint16_t y_center,const uint16_t radi
} }
void rhombus(const uint16_t x_center, const uint16_t y_center, const uint16_t radius, const color_t color) {} void rhombus(const uint16_t x_center, const uint16_t y_center, const uint16_t radius, const color_t color) {}
void line(const uint16_t x1, const uint16_t y1, const uint16_t x2, const uint16_t y2, const color_t color) {} void line(const uint16_t x1, const uint16_t y1, const uint16_t x2, const uint16_t y2, const color_t color) {}
void arc(uint16_t start_x, uint16_t start_y, float start_angle, float speed /*in pps*/,float angular_speed, uint16_t duration, color_t color) {}
} // namespace draw } // namespace draw
namespace net { namespace net {
+169 -88
View File
@@ -2,39 +2,38 @@
#include "core/color.h" #include "core/color.h"
#include "core/config.hpp" #include "core/config.hpp"
#include "core/font.hpp" #include "core/font.hpp"
#include "core/geo.hpp"
#include "core/gfx.hpp"
#include "core/global.hpp"
#include "core/units.hpp" #include "core/units.hpp"
#include "hal/draw.hpp" #include "hal/draw.hpp"
#include "hal/hal.hpp" #include "hal/hal.hpp"
#include "hal/net.hpp" #include "hal/net.hpp"
#include "nlohmann/json_fwd.hpp" #include "nlohmann/json_fwd.hpp"
#include <cmath>
#include <cstdint> #include <cstdint>
#include <cstdlib> #include <cstdlib>
#include <cmath>
#include <format> #include <format>
#include <iostream> #include <iostream>
#include <numbers> #include <numbers>
#include <string> #include <string>
#include "core/global.hpp"
#include "core/geo.hpp"
#include "core/gfx.hpp"
#ifndef CONFIG_AUTOSCALE #ifndef CONFIG_AUTOSCALE
constexpr constexpr
#endif #endif
uint16_t max_range = CONFIG_MAX_RANGE; uint16_t max_range = CONFIG_MAX_RANGE;
int main() { int main() {
if (hal::init() != 0) { if (hal::init() != 0) {
return 1; return 1;
} }
const auto [screen_w, screen_h] = hal::get_screen_size(); const auto [screen_w, screen_h] = hal::get_screen_size();
#ifndef CONFIG_AUTOSCALE #ifndef CONFIG_AUTOSCALE
const const
#endif #endif
float pixels_per_km = float pixels_per_km =
static_cast<float>(screen_h > screen_w ? screen_w : screen_h) / static_cast<float>(screen_h > screen_w ? screen_w : screen_h) /
(max_range * 2); (max_range * 2);
bool odd_even = true; bool odd_even = true;
const uint16_t middle_x = (screen_w / 2); const uint16_t middle_x = (screen_w / 2);
@@ -85,94 +84,176 @@ int main() {
} }
} }
#ifdef CONFIG_AUTOSCALE #ifdef CONFIG_AUTOSCALE
{ {
// fardest aircraft in km // fardest aircraft in km
uint16_t fardest_aircraft_distance_linear = 0; uint16_t fardest_aircraft_distance_linear = 0;
#endif #endif
{ // draw planes { // draw planes
nlohmann::json aircraft = net::http_get_json(std::format("{}/aircraft.json", CONFIG_BASE_URL)); nlohmann::json aircraft = net::http_get_json(
if (aircraft!= nullptr) { std::format("{}/aircraft.json", CONFIG_BASE_URL));
for(nlohmann::json &craft : aircraft["aircraft"]) { if (aircraft != nullptr) {
#ifdef CONFIG_EXTRA_INFO
uint32_t altitude; font::puts(
try { std::format("Tracking {} aircraft", aircraft["aircraft"].size()),
if(craft["alt_baro"].is_string()) { 0, 0, {0xff, 0xff, 0xff});
#endif
for (nlohmann::json &craft : aircraft["aircraft"]) {
uint32_t altitude;
try {
if (craft["alt_baro"].is_string()) {
altitude = 0;
} else {
altitude = craft["alt_baro"].get<uint32_t>();
#ifdef CONFIG_METRIC
altitude = feet_to_meters(altitude);
#endif
}
} catch (...) {
std::clog << YELLOW "[WARNING]" RESET
" aircraft with no alt data detected!\n";
altitude = 0; altitude = 0;
} else {
altitude =craft["alt_baro"].get<uint32_t>();
#ifdef CONFIG_METRIC
altitude = feet_to_meters(altitude);
#endif
} }
} catch(...) { #ifndef CONFIG_METRIC
std::clog << YELLOW"[WARNING]" RESET " aircraft with no alt data detected!\n"; // aircraft ground speed in knots
altitude = 0; float speed_knot;
#endif
// aircraft ground speed in km/h
float speed;
// aircraft track in degreees
float track;
try {
#ifdef CONFIG_METRIC
speed = knot_to_km(craft["gs"].get<float>());
#else
speed_knot = craft["gs"].get<float>();
speed = knot_to_km(speed_knot);
#endif
track = craft["track"].get<float>();
} catch (...) {
std::clog << YELLOW
"[WARNING]" RESET
" aircraft with no ground speed or track data detected!\n";
speed = 0;
track = 0;
#ifndef CONFIG_METRIC
speed_knot = 0;
#endif
}
draw::color_t color = get_altitude_color(altitude);
try {
const auto [x_offset, y_offset] = get_offset_from_station(
craft["lat"].get<double>(), craft["lon"].get<double>());
#ifdef CONFIG_AUTOSCALE
if (std::abs(x_offset) / 1000 >
fardest_aircraft_distance_linear) {
fardest_aircraft_distance_linear = std::abs(x_offset) / 1000;
}
if (std::abs(y_offset) / 1000 >
fardest_aircraft_distance_linear) {
fardest_aircraft_distance_linear = std::abs(y_offset) / 1000;
}
#endif
const uint16_t x_center =
middle_x + ((x_offset / 1000) * pixels_per_km);
const uint16_t y_center =
middle_y + ((y_offset / 1000) * pixels_per_km);
// draw::pixel(x_center, y_center, color);
// speed in pixels per hour
const float speed_pph = speed * pixels_per_km;
// track in radians
const float track_rad =
std::fmod((track - 90), 360.0f) *
(static_cast<float>(std::numbers::pi) / 180.0f);
#ifdef CONFIG_VECTOR_FOLLOW_TRACK_RATE
{
float track_rate_rads;
try {
track_rate_rads =
craft["track_rate"].get<float>() *
(static_cast<float>(std::numbers::pi) / 180.0f);
} catch (...) {
std::clog
<< YELLOW "[WARNING]" RESET
" aircraft with no track_rate data detected!\n";
track_rate_rads = 0;
}
draw::arc(x_center, y_center, track_rad, speed_pph / 3600,
track_rate_rads, CONFIG_TIME_BASED_VECTOR_LENGHT * 60,
color);
}
#else
// lenght of Time-Based Vector
const float vector_lenght =
(speed_pph / 60) * CONFIG_TIME_BASED_VECTOR_LENGHT;
draw::line(
x_center, y_center,
std::clamp(x_center + (vector_lenght * std::cos(track_rad)),
0.0f, static_cast<float>(UINT16_MAX)),
std::clamp(y_center + (vector_lenght * std::sin(track_rad)),
0.0f, static_cast<float>(UINT16_MAX)),
color);
#endif
draw::rhombus(x_center, y_center, CONFIG_AIRCRAFT_RHOMBUS_RADIUS,
color);
{
std::string callsign;
try {
callsign = craft["flight"].get<std::string>();
} catch (...) {
std::clog << YELLOW "[WARNING]" RESET
" aircraft with no callsign detected!\n";
callsign = CONFIG_NO_CALLSIGN_IDENTIFICATION;
}
// print some info
font::puts(callsign, x_center + CONFIG_X_TEXT_OFFSET,
y_center - (FONT_HEIGHT + CONFIG_CHARACTER_SPACING),
color);
font::puts(std::to_string(static_cast<uint16_t>(
#ifdef CONFIG_METRIC
speed
#else
speed_knot
#endif
)) +
SPEED_UNIT,
x_center + CONFIG_X_TEXT_OFFSET, y_center, color);
font::puts(std::to_string(altitude) + ALTITUDE_UNIT,
x_center + CONFIG_X_TEXT_OFFSET,
y_center + (FONT_HEIGHT + CONFIG_CHARACTER_SPACING),
color);
}
} catch (...) {
std::clog << YELLOW "[WARNING]" RESET
" aircraft with no lat/lon data detected!\n";
}
} }
} else {
// aircraft gorund speed in km/h // TODO draw visual error
float speed; std::cerr << RED "[ERROR]" RESET " failed to get aircraft\n";
// aircraft track in degreees }
float track; }
try { #ifdef CONFIG_AUTOSCALE
speed = knot_to_km(craft["gs"].get<float>()); if (fardest_aircraft_distance_linear > 0) {
track = craft["track"].get<float>(); for (uint16_t i = CONFIG_FIRST_RING_DISTANCE; i < UINT16_MAX; i *= 2) {
} catch(...) { if (i + (CONFIG_RANGE_PADDING / 2) >=
std::clog << YELLOW"[WARNING]" RESET " aircraft with no ground speed or track data detected!\n"; fardest_aircraft_distance_linear) {
speed = 0; max_range = i + CONFIG_RANGE_PADDING;
pixels_per_km =
static_cast<float>(screen_h > screen_w ? screen_w : screen_h) /
(max_range * 2);
break;
} }
draw::color_t color= get_altitude_color(altitude);
try {
const auto [x_offset,y_offset] = get_offset_from_station(craft["lat"].get<double>(), craft["lon"].get<double>());
#ifdef CONFIG_AUTOSCALE
if(std::abs(x_offset)/1000 > fardest_aircraft_distance_linear) {
fardest_aircraft_distance_linear = std::abs(x_offset)/1000;
}
if(std::abs(y_offset)/1000 > fardest_aircraft_distance_linear) {
fardest_aircraft_distance_linear = std::abs(y_offset)/1000;
}
#endif
const uint16_t x_center = middle_x+((x_offset/1000)*pixels_per_km);
const uint16_t y_center = middle_y+((y_offset/1000)*pixels_per_km);
// draw::pixel(x_center, y_center, color);
//speed in pixels per hour
const float speed_pph = speed* pixels_per_km;
// lenght of Time-Based Vector
const float vector_lenght = (speed_pph/60) * CONFIG_TIME_BASED_VECTOR_LENGHT;
// track in radians
const float track_rad = std::fmod((track-90),365.0f) * (static_cast<float>(std::numbers::pi)/180.0f);
draw::line(x_center, y_center,x_center + (vector_lenght*std::cos(track_rad)), y_center + (vector_lenght*std::sin(track_rad)), color);
draw::rhombus(x_center, y_center, 8/*TODO: remove magic*/,color);
font::puts("TEST123", x_center+10, y_center, color);
} catch(...) {
std::clog << YELLOW"[WARNING]" RESET " aircraft with no lat/lon data detected!\n";
} }
}
} else {
// TODO draw vizual error
std::cerr << RED"[ERROR]" RESET " failed to get aircraft\n";
} }
} }
#ifdef CONFIG_AUTOSCALE #endif
if (fardest_aircraft_distance_linear > 0) {
for(uint16_t i = CONFIG_FIRST_RING_DISTANCE; i < UINT16_MAX; i*=2) {
if (i+(CONFIG_RANGE_PADDING/2) >= fardest_aircraft_distance_linear) {
max_range = i+CONFIG_RANGE_PADDING;
pixels_per_km =
static_cast<float>(screen_h > screen_w ? screen_w : screen_h) /
(max_range * 2);
break;
}
}
}
}
#endif
hal::end_frame(); hal::end_frame();
} }