Compare commits
7
Commits
eeb2aac75c
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
47f2766bb8 | ||
|
|
839ea1490a | ||
|
|
831501ea41 | ||
|
|
abf1226b47 | ||
|
|
6ac93f0a5b | ||
|
|
66bdf9327a | ||
|
|
95225a5811 |
@@ -9,3 +9,4 @@ compile_commands.json
|
|||||||
include/
|
include/
|
||||||
!scripts/include/
|
!scripts/include/
|
||||||
*.o
|
*.o
|
||||||
|
test
|
||||||
+29
-50
@@ -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()
|
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -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
|
||||||
|
)
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
set(PROJECT_LANGUAGES CXX)
|
||||||
@@ -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)
|
||||||
@@ -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
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-2
@@ -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
|
||||||
@@ -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
@@ -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 {
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
+168
-87
@@ -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
|
||||||
|
font::puts(
|
||||||
|
std::format("Tracking {} aircraft", aircraft["aircraft"].size()),
|
||||||
|
0, 0, {0xff, 0xff, 0xff});
|
||||||
|
#endif
|
||||||
|
for (nlohmann::json &craft : aircraft["aircraft"]) {
|
||||||
|
|
||||||
uint32_t altitude;
|
uint32_t altitude;
|
||||||
try {
|
try {
|
||||||
if(craft["alt_baro"].is_string()) {
|
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 {
|
|
||||||
speed = knot_to_km(craft["gs"].get<float>());
|
|
||||||
track = craft["track"].get<float>();
|
|
||||||
} catch(...) {
|
|
||||||
std::clog << YELLOW"[WARNING]" RESET " aircraft with no ground speed or track data detected!\n";
|
|
||||||
speed = 0;
|
|
||||||
}
|
|
||||||
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";
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
#ifdef CONFIG_AUTOSCALE
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} 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();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user