diff --git a/Kconfig b/Kconfig index 4eab853..d093434 100644 --- a/Kconfig +++ b/Kconfig @@ -55,6 +55,14 @@ config TIME_BASED_VECTOR_LENGHT For example if set to 2 minutes the line will end where the plane be in 2 minutes, if direction and speed does not change. +config VECTOR_FOLLOW_TRACK_RATE + bool "Time based vector follows change of track" + default 1 + help + Make Time based vector follows change of track of aircraft. + This option will turn the vector from line into curve. + This is of course be more computationaly expensive. + comment "Receiver configuration" config FALLBACK_LAT @@ -76,3 +84,70 @@ config METRIC default y help Show altitudes in meters instead of feet. + +comment "Platform dependent options" + +choice + prompt "Build target" + default BUILD_LINUX + help + Select platform you want p-rad to be compiled for. + +config BUILD_LINUX + bool "Linux" + +config BUILD_PICO + bool "PI pico W" + +config BUILD_OTHER_UNIX + bool "Other Unix/Posix compatable system (NOT IMPLEMENTED)" +endchoice + + + +if BUILD_LINUX + + +choice + prompt "SDL render target" + default SDL_TARGET_WINDOW + help + Select where you want SDL3 to render to. + +config SDL_TARGET_WINDOW + bool "Full-Screen Window" + help + Render to Full-Screen Window using window system like X11 or wayland. + +config SDL_TARGET_KMSDRM + bool "Direct to DRM" + help + Render directly to GPU using kmsdrm +endchoice + + + +endif + +if BUILD_LINUX || BUILD_OTHER_UNIX + +config SDL_DRIVERS + string "Enabled SDL3 render drivers" + default "gpu,vulkan,opengl" + help + Comma-speparated list of drivers, + SDL will try each name, in the order listed, until one succeeds or all of them fail. + leave empty and SDL will attempt to choose the best option for you, + based on what is available on the your system. + (I dont recommend leaving this option empty.) + Available drivers can be listed by running this code: + #include + int main() { + SDL_Init(SDL_INIT_VIDEO); + SDL_Log("Available renderer drivers:"); + for (int i = 0; i < SDL_GetNumRenderDrivers(); i++) { + SDL_Log("%d. %s", i + 1, SDL_GetRenderDriver(i)); + } + } + +endif diff --git a/src/core/units.hpp b/src/core/units.hpp index f3982d8..221a513 100644 --- a/src/core/units.hpp +++ b/src/core/units.hpp @@ -2,4 +2,8 @@ template static inline T feet_to_meters(T ft) { return static_cast(ft * 0.3048); +} +template +static inline T knot_to_km(T kn) { + return static_cast(kn * 0.5399568); } \ No newline at end of file diff --git a/src/hal/draw.hpp b/src/hal/draw.hpp index d80132a..5ee7369 100644 --- a/src/hal/draw.hpp +++ b/src/hal/draw.hpp @@ -19,4 +19,5 @@ struct rect_t { void filled_rect(const rect_t* rect, 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 line(const uint16_t x1,const uint16_t y1,const uint16_t x2,const uint16_t y2, const color_t color); } \ No newline at end of file diff --git a/src/hal/hal_linux.cpp b/src/hal/hal_linux.cpp index 9dab85a..dd9de00 100644 --- a/src/hal/hal_linux.cpp +++ b/src/hal/hal_linux.cpp @@ -1,6 +1,8 @@ #include "../core/const.hpp" #include #include +#include +#include #include #include #include @@ -14,6 +16,8 @@ #include #include +#include "../core/color.h" +#include "core/config.hpp" #include "draw.hpp" #include "hal/hal.hpp" #include @@ -22,7 +26,7 @@ #include #include #include -#include "../core/color.h" + struct sdl_session { SDL_Window *window; SDL_Renderer *renderer; @@ -34,16 +38,53 @@ CURL *curl; namespace hal { int init() { - SDL_Init(SDL_INIT_VIDEO); +#ifdef CONFIG_SDL_TARGET_KMSDRM + if (!SDL_SetHint(SDL_HINT_KMSDRM_DEVICE_INDEX, "-1")) { + SDL_Log("hint failed: %s", SDL_GetError()); + } + + if (!SDL_SetHint(SDL_HINT_KMSDRM_REQUIRE_DRM_MASTER, "1")) { + SDL_Log("hint failed: %s", SDL_GetError()); + } + if (!SDL_SetHint(SDL_HINT_VIDEO_DRIVER, "kmsdrm")) { + SDL_Log("hint failed: %s", SDL_GetError()); + } + if (!SDL_SetHint(SDL_HINT_RENDER_DRIVER, CONFIG_SDL_DRIVERS)) { + SDL_Log("hint failed: %s", SDL_GetError()); + } +#endif + if (!SDL_Init(SDL_INIT_VIDEO)) { + SDL_Log("init failed: %s", SDL_GetError()); + return 1; + } + // DEBUG + std::clog << "active driver: " << SDL_GetCurrentVideoDriver() << "\n"; + mode = SDL_GetCurrentDisplayMode(SDL_GetPrimaryDisplay()); + if (!mode) { + SDL_Log("failed to get display mode: %s", SDL_GetError()); + return 1; + } main_sdl_session.window = SDL_CreateWindow(program_name, mode->w, mode->h, SDL_WINDOW_FULLSCREEN); - main_sdl_session.renderer = - SDL_CreateRenderer(main_sdl_session.window, "gpu,vulcan"); - + if (!main_sdl_session.window) { + SDL_Log("window failed: %s", SDL_GetError()); + return 1; + } + main_sdl_session.renderer = SDL_CreateRenderer(main_sdl_session.window, +#ifndef CONFIG_SDL_TARGET_KMSDRM + CONFIG_SDL_DRIVERS +#else + NULL +#endif + ); + if (!main_sdl_session.renderer) { + SDL_Log("renderer failed: %s", SDL_GetError()); + return 1; + } + curl = curl_easy_init(); return 0; - } std::tuple get_screen_size() { return {mode->w, mode->h}; } @@ -56,6 +97,26 @@ void start_frame() { const Uint64 frame_delay_ns = 1000000000ULL / 1; void end_frame() { + SDL_Event event; + while (SDL_PollEvent(&event)) { + switch (event.type) { + // Handles Window close (the 'X' button), Alt+F4, or SIGINT (Ctrl+C) + + // Handles keyboard key presses + case SDL_EVENT_KEY_DOWN: + // Check if the pressed key is 'Q' + if (event.key.key != SDLK_Q) { + break; + } + + case SDL_EVENT_QUIT: + SDL_Quit(); + std::exit(0); + break; + default: + break; + } + } SDL_RenderPresent(main_sdl_session.renderer); @@ -83,72 +144,83 @@ void filled_rect(const rect_t *rect, const color_t color) { SDL_RenderFillRect(main_sdl_session.renderer, &frect); } -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) { SDL_SetRenderDrawColor(main_sdl_session.renderer, color.r, color.g, color.b, 0xff); - // based on https://www.geeksforgeeks.org/dsa/mid-point-circle-drawing-algorithm/ + // based on + // https://www.geeksforgeeks.org/dsa/mid-point-circle-drawing-algorithm/ int x = radius, y = 0; - // Printing the initial point on the axes - // after translation + // Printing the initial point on the axes + // after translation + SDL_RenderPoint(main_sdl_session.renderer, x + x_center, y + y_center); + + // When radius is zero only a single + // point will be printed + if (radius > 0) { + 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); + std::cout << "\n"; + } + + // Initialising the value of P + int P = 1 - radius; + while (x > y) { + y++; + + // Mid-point is inside or on the perimeter + if (P <= 0) + P = P + 2 * y + 1; + // Mid-point is outside the perimeter + else { + x--; + P = P + 2 * y - 2 * x + 1; + } + + // All the perimeter points have already been printed + if (x < y) + break; + + // Printing the generated point and its reflection + // in the other octants after translation 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, x + x_center, -y + y_center); + SDL_RenderPoint(main_sdl_session.renderer, -x + x_center, -y + y_center); - // When radius is zero only a single - // point will be printed - if (radius > 0) - { - 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); - std::cout << "\n"; - } - - // Initialising the value of P - int P = 1 - radius; - while (x > y) - { - y++; - - // Mid-point is inside or on the perimeter - if (P <= 0) - P = P + 2*y + 1; - // Mid-point is outside the perimeter - else - { - x--; - P = P + 2*y - 2*x + 1; - } - - // All the perimeter points have already been printed - if (x < y) - break; - - // Printing the generated point and its reflection - // in the other octants after translation - 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, x + x_center, -y + y_center); - SDL_RenderPoint(main_sdl_session.renderer, -x + x_center, -y + y_center); - - // If the generated point is on the line x = y then - // the perimeter points have already been printed - if (x != y) - { - 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); - } + // If the generated point is on the line x = y then + // the perimeter points have already been printed + if (x != y) { + 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); } + } } -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) { SDL_SetRenderDrawColor(main_sdl_session.renderer, color.r, color.g, color.b, 0xff); - const SDL_FPoint points[] = {{static_cast(x_center+radius),static_cast(y_center)},{static_cast(x_center),static_cast(y_center+radius)},{static_cast(x_center-radius),static_cast(y_center)},{static_cast(x_center),static_cast(y_center-radius)},{static_cast(x_center+radius),static_cast(y_center)}}; + const SDL_FPoint points[] = { + {static_cast(x_center + radius), static_cast(y_center)}, + {static_cast(x_center), static_cast(y_center + radius)}, + {static_cast(x_center - radius), static_cast(y_center)}, + {static_cast(x_center), static_cast(y_center - radius)}, + {static_cast(x_center + radius), static_cast(y_center)}}; SDL_RenderLines(main_sdl_session.renderer, points, ARRAY_LENGHT(points)); } + +void line(const uint16_t x1, const uint16_t y1, const uint16_t x2, + const uint16_t y2, const color_t color) { + SDL_SetRenderDrawColor(main_sdl_session.renderer, color.r, color.g, color.b, + 0xff); + SDL_RenderLine(main_sdl_session.renderer, x1, y1, x2, y2); +} } // namespace draw namespace net { @@ -190,4 +262,4 @@ nlohmann::json http_get_json(const std::string &url) { } return nullptr; } -} // namespace net \ No newline at end of file +} // namespace net diff --git a/src/hal/hal_pico.cpp b/src/hal/hal_pico.cpp index c5de636..27b85b4 100644 --- a/src/hal/hal_pico.cpp +++ b/src/hal/hal_pico.cpp @@ -52,6 +52,8 @@ void filled_rect(const rect_t *rect, 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 line(const uint16_t x1, const uint16_t y1, const uint16_t x2, const uint16_t y2, const color_t color) {} } // namespace draw namespace net { diff --git a/src/main.cpp b/src/main.cpp index 8115dae..f8df885 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -8,8 +8,10 @@ #include "nlohmann/json_fwd.hpp" #include #include +#include #include #include +#include #include "core/global.hpp" #include "core/geo.hpp" #include "core/gfx.hpp" @@ -106,6 +108,18 @@ int main() { std::clog << YELLOW"[WARNING]" RESET " aircraft with no alt data detected!\n"; altitude = 0; } + + // aircraft gorund speed in km/h + float speed; + // aircraft track in degreees + float track; + try { + speed = knot_to_km(craft["gs"].get()); + track = craft["track"].get(); + } 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(), craft["lon"].get()); @@ -119,7 +133,18 @@ int main() { #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); + // 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(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); } catch(...) { std::clog << YELLOW"[WARNING]" RESET " aircraft with no lat/lon data detected!\n";