mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2025-10-17 17:35:18 +00:00
ADS-B TX works well enough for dump1090 and gr-air-modes
Hooked ADS-B RX to baseband instead of debug IQ file, not tested
This commit is contained in:
@@ -139,7 +139,6 @@ set(CPPSRC
|
||||
debounce.cpp
|
||||
touch.cpp
|
||||
touch_adc.cpp
|
||||
protocols/adsb.cpp
|
||||
protocols/aprs.cpp
|
||||
protocols/ax25.cpp
|
||||
protocols/bht.cpp
|
||||
@@ -217,6 +216,8 @@ set(CPPSRC
|
||||
${COMMON}/pocsag_packet.cpp
|
||||
${COMMON}/pocsag.cpp
|
||||
${COMMON}/morse.cpp
|
||||
${COMMON}/adsb_frame.cpp
|
||||
${COMMON}/adsb.cpp
|
||||
ais_app.cpp
|
||||
tpms_app.cpp
|
||||
pocsag_app.cpp
|
||||
|
@@ -24,7 +24,6 @@
|
||||
// Gimp image > indexed colors (16), then "xxd -i *.bmp"
|
||||
|
||||
//TODO: De bruijn sequence scanner for encoders
|
||||
//TODO: Waveform viewer
|
||||
//TEST: Mic tx
|
||||
//TEST: Menuview refresh, seems to blink a lot
|
||||
//TEST: Check AFSK transmit end, skips last bits ?
|
||||
|
@@ -1,198 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2016 Furrtek
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "adsb.hpp"
|
||||
|
||||
#include "portapack_persistent_memory.hpp"
|
||||
|
||||
namespace adsb {
|
||||
|
||||
uint8_t adsb_frame::get_DF() {
|
||||
return (raw_data[0] >> 3);
|
||||
}
|
||||
|
||||
uint8_t adsb_frame::get_msg_type() {
|
||||
return (raw_data[4] >> 3);
|
||||
}
|
||||
|
||||
uint32_t adsb_frame::get_ICAO_address() {
|
||||
return (raw_data[1] << 16) + (raw_data[2] << 8) + raw_data[3];
|
||||
}
|
||||
|
||||
void adsb_frame::clear() {
|
||||
index = 0;
|
||||
memset(raw_data, 0, 14);
|
||||
}
|
||||
|
||||
void adsb_frame::push_byte(uint8_t byte) {
|
||||
if (index >= 14)
|
||||
return;
|
||||
|
||||
raw_data[index++] = byte;
|
||||
}
|
||||
|
||||
uint8_t adsb_frame::get_byte(uint8_t index) {
|
||||
if (index >= 14)
|
||||
return 0;
|
||||
|
||||
return raw_data[index];
|
||||
}
|
||||
|
||||
std::string adsb_frame::get_callsign() {
|
||||
uint64_t callsign_coded = 0;
|
||||
uint32_t c;
|
||||
std::string callsign = "";
|
||||
|
||||
// Frame bytes to long
|
||||
for (c = 5; c < 11; c++) {
|
||||
callsign_coded <<= 8;
|
||||
callsign_coded |= raw_data[c];
|
||||
}
|
||||
|
||||
// Long to 6-bit characters
|
||||
for (c = 0; c < 8; c++) {
|
||||
callsign.append(1, icao_id_lut[(callsign_coded >> 42) & 0x3F]);
|
||||
callsign_coded <<= 6;
|
||||
}
|
||||
|
||||
return callsign;
|
||||
}
|
||||
|
||||
void adsb_frame::make_CRC() {
|
||||
uint8_t adsb_crc[14]; // Temp buffer
|
||||
uint8_t b, c, s, bitn;
|
||||
const uint32_t crc_poly = 0x1205FFF;
|
||||
|
||||
// Clear CRC
|
||||
raw_data[11] = 0x00;
|
||||
raw_data[12] = 0x00;
|
||||
raw_data[13] = 0x00;
|
||||
|
||||
// Compute CRC
|
||||
memcpy(adsb_crc, raw_data, 14);
|
||||
for (c = 0; c < 11; c++) {
|
||||
for (b = 0; b < 8; b++) {
|
||||
if ((adsb_crc[c] << b) & 0x80) {
|
||||
for (s = 0; s < 25; s++) {
|
||||
bitn = (c * 8) + b + s;
|
||||
if ((crc_poly >> s) & 1) adsb_crc[bitn >> 3] ^= (0x80 >> (bitn & 7));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Insert CRC in frame
|
||||
memcpy(&raw_data[11], &adsb_crc[11], 3);
|
||||
}
|
||||
|
||||
void make_frame_mode_s(adsb_frame& frame, const uint32_t ICAO_address) {
|
||||
frame.clear();
|
||||
frame.push_byte((17 << 3) | 5); // DF17 and CA
|
||||
frame.push_byte(ICAO_address >> 16);
|
||||
frame.push_byte(ICAO_address >> 8);
|
||||
frame.push_byte(ICAO_address & 0xFF);
|
||||
}
|
||||
|
||||
void generate_frame_id(adsb_frame& frame, const uint32_t ICAO_address, std::string & callsign) {
|
||||
std::string callsign_formatted(8, '_');
|
||||
uint64_t callsign_coded = 0;
|
||||
uint32_t c, s;
|
||||
char ch;
|
||||
|
||||
make_frame_mode_s(frame, ICAO_address);
|
||||
|
||||
frame.push_byte(4 << 3); // TC = 4: Aircraft ID
|
||||
|
||||
// Translate and encode callsign
|
||||
for (c = 0; c < 8; c++) {
|
||||
ch = callsign[c];
|
||||
|
||||
for (s = 0; s < 64; s++)
|
||||
if (ch == icao_id_lut[s]) break;
|
||||
|
||||
if (s >= 64) {
|
||||
ch = ' '; // Invalid character
|
||||
s = 32;
|
||||
}
|
||||
callsign_coded |= ((uint64_t)s << ((7 - c) * 6));
|
||||
callsign[c] = ch;
|
||||
}
|
||||
|
||||
// Insert callsign in frame
|
||||
for (c = 0; c < 6; c++)
|
||||
frame.push_byte((callsign_coded >> ((5 - c) * 8)) & 0xFF);
|
||||
|
||||
frame.make_CRC();
|
||||
}
|
||||
|
||||
void generate_frame_emergency(adsb_frame& frame, const uint32_t ICAO_address, const uint8_t code) {
|
||||
make_frame_mode_s(frame, ICAO_address);
|
||||
|
||||
frame.push_byte((28 << 3) + 1); // TC = 28 (Emergency), subtype = 1 (Emergency)
|
||||
frame.push_byte(code << 5);
|
||||
|
||||
frame.make_CRC();
|
||||
}
|
||||
|
||||
/*
|
||||
void generate_frame_pos(uint8_t * const adsb_frame, const uint32_t ICAO_address, const uint32_t altitude,
|
||||
const float latitude, const float longitude) {
|
||||
uint8_t c, time_parity;
|
||||
uint32_t altitude_coded;
|
||||
uint32_t LAT, LON;
|
||||
float delta_lat, yz, rlat, delta_lon, xz;
|
||||
|
||||
LAT = 0;
|
||||
|
||||
make_frame_mode_s(adsb_frame, ICAO_address);
|
||||
|
||||
adsb_frame[4] = 11 << 3; // TC = 11: Airborne position
|
||||
|
||||
altitude_coded = (altitude + 1000) / 25; // Can be coded in 100ft steps also
|
||||
|
||||
// LAT:
|
||||
// index j = floor(59*latcprE-60*latcprO+0.50)
|
||||
// latE = DlatE*(mod(j,60)+latcprE)
|
||||
// latO = DlatO*(mod(j,59)+latcprO)
|
||||
// if latE >= 270 -> latE -= 360
|
||||
// if latO >= 270 -> latO -= 360
|
||||
//time_parity = 0; // 0~1
|
||||
//delta_lat = 90.0 / (60.0 - (time_parity / 4.0));
|
||||
//yz = 524288.0 * (mod(lat, delta_lat) / delta_lat); // Round to int !
|
||||
//rlat = delta_lat * ((yz / 524288.0) + int(lat / delta_lat));
|
||||
//delta_lon = 360.0 / (NL(rlat) - time_parity);
|
||||
//xz = 524288.0 * (mod(lon, delta_lon) / delta_lon); // Round to int !
|
||||
if (time_parity) {
|
||||
A = sign(rlat0)[NL(rlat0) - NL(rlat1)];
|
||||
}
|
||||
// int xz and yz, then:
|
||||
// xz >>= 2;
|
||||
// yz >>= 2;
|
||||
// To get 17 bits
|
||||
|
||||
// aaaaaaa Q bbbb
|
||||
adsb_frame[5] = ((altitude_coded & 0x7F0) >> 3) | 1;
|
||||
adsb_frame[6] = ((altitude_coded & 0x00F) << 4) | (LAT >> 15); // Then 0, even/odd, and the 2 LAT-CPR MSBs
|
||||
}
|
||||
*/
|
||||
|
||||
} /* namespace adsb */
|
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2016 Furrtek
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
#ifndef __ADSB_H__
|
||||
#define __ADSB_H__
|
||||
|
||||
#define ADSB_PREAMBLE_LENGTH 16
|
||||
|
||||
namespace adsb {
|
||||
|
||||
struct adsb_frame {
|
||||
public:
|
||||
uint8_t get_DF();
|
||||
uint8_t get_msg_type();
|
||||
uint32_t get_ICAO_address();
|
||||
std::string get_callsign();
|
||||
|
||||
void push_byte(uint8_t byte);
|
||||
uint8_t get_byte(uint8_t index); // DEBUG
|
||||
void make_CRC();
|
||||
void clear();
|
||||
|
||||
private:
|
||||
uint8_t index { 0 };
|
||||
uint8_t raw_data[14] { }; // 112 bits at most
|
||||
};
|
||||
|
||||
const char icao_id_lut[65] = "#ABCDEFGHIJKLMNOPQRSTUVWXYZ##### ###############0123456789######";
|
||||
const uint8_t adsb_preamble[16] = { 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
void make_frame_mode_s(adsb_frame& frame, const uint32_t ICAO_address);
|
||||
void generate_frame_id(adsb_frame&, const uint32_t ICAO_address, std::string& callsign);
|
||||
//void generate_frame_pos(uint8_t * const adsb_frame, const uint32_t ICAO_address, const uint32_t altitude,
|
||||
// const float latitude, const float longitude);
|
||||
void generate_frame_emergency(adsb_frame&, const uint32_t ICAO_address, const uint8_t code);
|
||||
|
||||
} /* namespace adsb */
|
||||
|
||||
#endif/*__ADSB_H__*/
|
@@ -26,7 +26,6 @@
|
||||
|
||||
#include "adsb.hpp"
|
||||
#include "string_format.hpp"
|
||||
#include "sine_table_int8.hpp"
|
||||
#include "portapack.hpp"
|
||||
#include "baseband_api.hpp"
|
||||
#include "portapack_persistent_memory.hpp"
|
||||
@@ -39,25 +38,35 @@ using namespace portapack;
|
||||
|
||||
namespace ui {
|
||||
|
||||
template<>
|
||||
void RecentEntriesTable<ADSBRecentEntries>::draw(
|
||||
const Entry& entry,
|
||||
const Rect& target_rect,
|
||||
Painter& painter,
|
||||
const Style& style
|
||||
) {
|
||||
painter.draw_string(target_rect.location(), style, to_string_hex_array((uint8_t*)entry.raw_data, 10) + " " + entry.time);
|
||||
}
|
||||
|
||||
void ADSBRxView::focus() {
|
||||
offset_field.focus();
|
||||
offset_field.set_value(13179);
|
||||
}
|
||||
|
||||
ADSBRxView::~ADSBRxView() {
|
||||
//transmitter_model.disable();
|
||||
//baseband::shutdown();
|
||||
receiver_model.disable();
|
||||
baseband::shutdown();
|
||||
}
|
||||
|
||||
bool ADSBRxView::analyze(uint64_t offset) {
|
||||
/*bool ADSBRxView::analyze(uint64_t offset) {
|
||||
Coord lcd_x = 0, lcd_y = 0;
|
||||
int8_t re, im;
|
||||
adsb_frame frame;
|
||||
int16_t file_data[128]; // 256 bytes / 2 IQ / 16 bits = 64 samples
|
||||
complex8_t iq_data[256]; // 256 samples
|
||||
uint64_t file_offset = 0;
|
||||
uint8_t data_put = 0, data_get = 0;
|
||||
int16_t f_re, f_im;
|
||||
int8_t re, im;
|
||||
uint32_t c;
|
||||
uint8_t level, bit, byte;
|
||||
Color mark_color;
|
||||
@@ -224,42 +233,64 @@ bool ADSBRxView::analyze(uint64_t offset) {
|
||||
}
|
||||
|
||||
return false;
|
||||
}*/
|
||||
|
||||
void ADSBRxView::on_frame(const ADSBFrameMessage * message) {
|
||||
rtc::RTC datetime;
|
||||
std::string str_timestamp;
|
||||
auto frame = message->frame;
|
||||
auto& entry = ::on_packet(recent, frame.get_ICAO_address());
|
||||
|
||||
rtcGetTime(&RTCD1, &datetime);
|
||||
str_timestamp = to_string_dec_uint(datetime.hour(), 2, '0') + ":" +
|
||||
to_string_dec_uint(datetime.minute(), 2, '0') + ":" +
|
||||
to_string_dec_uint(datetime.second(), 2, '0');
|
||||
entry.set_time(str_timestamp);
|
||||
entry.set_raw(frame.get_raw_data());
|
||||
recent_entries_view.set_dirty();
|
||||
}
|
||||
|
||||
ADSBRxView::ADSBRxView(NavigationView& nav) {
|
||||
|
||||
//baseband::run_image(portapack::spi_flash::image_tag_adsb_rx);
|
||||
baseband::run_image(portapack::spi_flash::image_tag_adsb_rx);
|
||||
|
||||
add_children({
|
||||
&labels,
|
||||
//&labels,
|
||||
&offset_field,
|
||||
&button_ffw,
|
||||
//&button_ffw,
|
||||
&text_debug_a,
|
||||
&text_debug_b,
|
||||
&text_debug_c,
|
||||
&text_debug_d,
|
||||
&text_debug_e
|
||||
&recent_entries_view
|
||||
});
|
||||
|
||||
// File must be 16bit complex @ 2Msps !
|
||||
recent_entries_view.set_parent_rect({ 0, 64, 240, 224 });
|
||||
|
||||
auto result = iq_file.open("ADSB.C16");
|
||||
// File must be 16bit complex @ 2Msps !
|
||||
/*auto result = iq_file.open("ADSB.C16");
|
||||
if (result.is_valid()) {
|
||||
text_debug_a.set("Can't open file");
|
||||
}
|
||||
}*/
|
||||
|
||||
offset_field.on_change = [this, &nav](int32_t value) {
|
||||
/*offset_field.on_change = [this, &nav](int32_t value) {
|
||||
// TODO
|
||||
};
|
||||
};*/
|
||||
|
||||
button_ffw.on_select = [this, &nav](Button&) {
|
||||
auto new_view = nav.push<GeoMapView>();
|
||||
/*while (!analyze(f_offset)) {
|
||||
/*button_ffw.on_select = [this, &nav](Button&) {
|
||||
//nav.push<GeoMapView>();
|
||||
while (!analyze(f_offset)) {
|
||||
f_offset++;
|
||||
}
|
||||
offset_field.set_value(f_offset);
|
||||
f_offset++;*/
|
||||
};
|
||||
f_offset++;
|
||||
};*/
|
||||
|
||||
baseband::set_adsb();
|
||||
|
||||
receiver_model.set_tuning_frequency(1090000000);
|
||||
receiver_model.set_modulation(ReceiverModel::Mode::SpectrumAnalysis);
|
||||
receiver_model.set_sampling_rate(2000000);
|
||||
receiver_model.set_baseband_bandwidth(2500000);
|
||||
receiver_model.enable();
|
||||
}
|
||||
|
||||
} /* namespace ui */
|
||||
|
@@ -26,12 +26,48 @@
|
||||
//#include "ui_widget.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
#include "ui_font_fixed_8x16.hpp"
|
||||
#include "recent_entries.hpp"
|
||||
|
||||
#include "message.hpp"
|
||||
#include "portapack.hpp"
|
||||
|
||||
namespace ui {
|
||||
|
||||
struct ADSBRecentEntry {
|
||||
using Key = uint32_t;
|
||||
|
||||
static constexpr Key invalid_key = 0xffffffff;
|
||||
|
||||
uint32_t ICAO_address;
|
||||
uint8_t raw_data[14] { }; // 112 bits at most
|
||||
std::string time { "" };
|
||||
|
||||
ADSBRecentEntry(
|
||||
) : ADSBRecentEntry { 0 }
|
||||
{
|
||||
}
|
||||
|
||||
ADSBRecentEntry(
|
||||
const uint32_t ICAO_address
|
||||
) : ICAO_address { ICAO_address }
|
||||
{
|
||||
}
|
||||
|
||||
Key key() const {
|
||||
return ICAO_address;
|
||||
}
|
||||
|
||||
void set_time(std::string& new_time) {
|
||||
time = new_time;
|
||||
}
|
||||
|
||||
void set_raw(uint8_t * raw_ptr) {
|
||||
memcpy(raw_data, raw_ptr, 14);
|
||||
}
|
||||
};
|
||||
|
||||
using ADSBRecentEntries = RecentEntries<ADSBRecentEntry>;
|
||||
|
||||
class ADSBRxView : public View {
|
||||
public:
|
||||
ADSBRxView(NavigationView& nav);
|
||||
@@ -42,16 +78,24 @@ public:
|
||||
std::string title() const override { return "ADS-B debug"; };
|
||||
|
||||
private:
|
||||
static constexpr float k = 1.0f / 128.0f;
|
||||
//static constexpr float k = 1.0f / 128.0f;
|
||||
|
||||
File iq_file { };
|
||||
size_t f_offset { 0 };
|
||||
//File iq_file { };
|
||||
//size_t f_offset { 0 };
|
||||
|
||||
bool analyze(uint64_t offset);
|
||||
//bool analyze(uint64_t offset);
|
||||
void on_frame(const ADSBFrameMessage * message);
|
||||
|
||||
Labels labels {
|
||||
const RecentEntriesColumns columns { {
|
||||
{ "Raw", 21 },
|
||||
{ "Time", 8 },
|
||||
} };
|
||||
ADSBRecentEntries recent { };
|
||||
RecentEntriesView<RecentEntries<ADSBRecentEntry>> recent_entries_view { columns, recent };
|
||||
|
||||
/*Labels labels {
|
||||
{ { 0 * 8, 0 * 8 }, "Test", Color::light_grey() }
|
||||
};
|
||||
};*/
|
||||
|
||||
NumberField offset_field {
|
||||
{ 0, 0 },
|
||||
@@ -60,10 +104,6 @@ private:
|
||||
1,
|
||||
'0'
|
||||
};
|
||||
Text text_debug_e {
|
||||
{ 7 * 8, 0 * 16, 14 * 8, 16 },
|
||||
"-"
|
||||
};
|
||||
|
||||
Text text_debug_a {
|
||||
{ 0 * 8, 1 * 16, 30 * 8, 16 },
|
||||
@@ -77,24 +117,19 @@ private:
|
||||
{ 0 * 8, 3 * 16, 30 * 8, 16 },
|
||||
"-"
|
||||
};
|
||||
Text text_debug_d {
|
||||
{ 0 * 8, 4 * 16, 30 * 8, 16 },
|
||||
"-"
|
||||
};
|
||||
|
||||
Button button_ffw {
|
||||
/*Button button_ffw {
|
||||
{ 184, 0 * 16, 56, 16 },
|
||||
"FFW"
|
||||
};
|
||||
|
||||
/*
|
||||
MessageHandlerRegistration message_handler_tx_done {
|
||||
Message::ID::TXDone,
|
||||
[this](const Message* const p) {
|
||||
const auto message = *reinterpret_cast<const TXDoneMessage*>(p);
|
||||
this->on_txdone(message.done);
|
||||
}
|
||||
};*/
|
||||
|
||||
MessageHandlerRegistration message_handler_frame {
|
||||
Message::ID::ADSBFrame,
|
||||
[this](Message* const p) {
|
||||
const auto message = static_cast<const ADSBFrameMessage*>(p);
|
||||
this->on_frame(message);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
} /* namespace ui */
|
||||
|
@@ -26,7 +26,6 @@
|
||||
#include "string_format.hpp"
|
||||
#include "portapack.hpp"
|
||||
#include "baseband_api.hpp"
|
||||
#include "portapack_persistent_memory.hpp"
|
||||
|
||||
#include <cstring>
|
||||
#include <stdio.h>
|
||||
@@ -37,7 +36,6 @@ using namespace portapack;
|
||||
namespace ui {
|
||||
|
||||
void ADSBTxView::focus() {
|
||||
//sym_icao.focus();
|
||||
tx_view.focus();
|
||||
}
|
||||
|
||||
@@ -46,28 +44,38 @@ ADSBTxView::~ADSBTxView() {
|
||||
baseband::shutdown();
|
||||
}
|
||||
|
||||
void ADSBTxView::paint(Painter& painter) {
|
||||
(void)painter;
|
||||
void ADSBTxView::paint(Painter&) {
|
||||
button_callsign.set_text(callsign);
|
||||
}
|
||||
|
||||
void ADSBTxView::generate_frame() {
|
||||
uint32_t c;
|
||||
std::string str_debug;
|
||||
uint8_t * bin_ptr = shared_memory.bb_data.data;
|
||||
|
||||
generate_frame_id(frame, sym_icao.value_hex_u64(), callsign);
|
||||
generate_frame_id(frames[0], sym_icao.value_hex_u64(), callsign);
|
||||
generate_frame_pos(frames[1], sym_icao.value_hex_u64(), 5000, field_lat_degrees.value(), field_lon_degrees.value(), 0);
|
||||
generate_frame_pos(frames[2], sym_icao.value_hex_u64(), 5000, field_lat_degrees.value(), field_lon_degrees.value(), 1);
|
||||
|
||||
memset(adsb_bin, 0, 112);
|
||||
memset(bin_ptr, 0, 240);
|
||||
|
||||
auto raw_ptr = frames[0].get_raw_data();
|
||||
|
||||
memcpy(bin_ptr, adsb_preamble, 16);
|
||||
|
||||
// Convert to binary (1 byte per bit, faster for baseband code)
|
||||
for (c = 0; c < 112; c++) {
|
||||
if ((frame.get_byte(c >> 3) << (c & 7)) & 0x80)
|
||||
adsb_bin[c] = 1;
|
||||
if ((raw_ptr[c >> 3] << (c & 7)) & 0x80) {
|
||||
bin_ptr[(c * 2) + 16] = 1;
|
||||
bin_ptr[(c * 2) + 16 + 1] = 0;
|
||||
} else {
|
||||
bin_ptr[(c * 2) + 16] = 0;
|
||||
bin_ptr[(c * 2) + 16 + 1] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Display in hex for debug
|
||||
//text_frame_a.set(to_string_hex_array(frame.get_byte(0), 7));
|
||||
//text_frame_b.set(to_string_hex_array(frame.get_byte(7), 7));
|
||||
text_frame_a.set(to_string_hex_array(frames[0].get_raw_data(), 7));
|
||||
text_frame_b.set(to_string_hex_array(frames[0].get_raw_data() + 7, 7));
|
||||
|
||||
button_callsign.set_text(callsign);
|
||||
}
|
||||
@@ -75,28 +83,78 @@ void ADSBTxView::generate_frame() {
|
||||
bool ADSBTxView::start_tx() {
|
||||
generate_frame();
|
||||
|
||||
memcpy(shared_memory.bb_data.data, adsb_bin, 112);
|
||||
baseband::set_adsb();
|
||||
|
||||
transmitter_model.set_tuning_frequency(434000000); // DEBUG
|
||||
transmitter_model.set_tuning_frequency(434000000);
|
||||
transmitter_model.set_sampling_rate(4000000U);
|
||||
transmitter_model.set_rf_amp(true);
|
||||
transmitter_model.set_vga(40);
|
||||
transmitter_model.set_baseband_bandwidth(2500000);
|
||||
transmitter_model.set_baseband_bandwidth(10000000);
|
||||
transmitter_model.enable();
|
||||
|
||||
return false; // DEBUG
|
||||
baseband::set_adsb();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ADSBTxView::on_txdone(const bool v) {
|
||||
//size_t sr;
|
||||
|
||||
if (v) {
|
||||
transmitter_model.disable();
|
||||
tx_view.set_transmitting(false);
|
||||
//progress.set_value(0);
|
||||
} else {
|
||||
//progress.set_value(n);
|
||||
}
|
||||
}
|
||||
|
||||
void ADSBTxView::rotate_frames() {
|
||||
// DEBUG
|
||||
uint8_t * bin_ptr = shared_memory.bb_data.data;
|
||||
uint8_t * raw_ptr;
|
||||
uint32_t frame_index = 0, plane_index = 0;
|
||||
uint32_t c, regen = 0;
|
||||
float offs = 0;
|
||||
|
||||
for (;;) {
|
||||
if (!regen) {
|
||||
regen = 10;
|
||||
|
||||
generate_frame_id(frames[0], plane_index, "DEMO" + to_string_dec_uint(plane_index));
|
||||
generate_frame_pos(frames[1], plane_index, 5000, plane_lats[plane_index]/8 + offs + 38.5, plane_lons[plane_index]/8 + 125.8, 0);
|
||||
generate_frame_pos(frames[2], plane_index, 5000, plane_lats[plane_index]/8 + offs + 38.5, plane_lons[plane_index]/8 + 125.8, 1);
|
||||
generate_frame_identity(frames[3], plane_index, 1337);
|
||||
|
||||
if (plane_index == 11)
|
||||
plane_index = 0;
|
||||
else
|
||||
plane_index++;
|
||||
|
||||
offs += 0.001;
|
||||
}
|
||||
|
||||
memset(bin_ptr, 0, 240);
|
||||
|
||||
raw_ptr = frames[frame_index].get_raw_data();
|
||||
|
||||
memcpy(bin_ptr, adsb_preamble, 16);
|
||||
|
||||
// Convert to binary (1 byte per bit, faster for baseband code)
|
||||
for (c = 0; c < 112; c++) {
|
||||
if ((raw_ptr[c >> 3] << (c & 7)) & 0x80) {
|
||||
bin_ptr[(c * 2) + 16] = 1;
|
||||
bin_ptr[(c * 2) + 16 + 1] = 0;
|
||||
} else {
|
||||
bin_ptr[(c * 2) + 16] = 0;
|
||||
bin_ptr[(c * 2) + 16 + 1] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
baseband::set_adsb();
|
||||
|
||||
chThdSleepMilliseconds(5);
|
||||
|
||||
if (frame_index == 3) {
|
||||
frame_index = 0;
|
||||
if (regen)
|
||||
regen--;
|
||||
} else {
|
||||
frame_index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,16 +184,14 @@ ADSBTxView::ADSBTxView(NavigationView& nav) {
|
||||
|
||||
options_format.set_by_value(17); // Mode S
|
||||
|
||||
options_format.on_change = [this](size_t i, int32_t v) {
|
||||
(void)i;
|
||||
(void)v;
|
||||
options_format.on_change = [this](size_t, int32_t) {
|
||||
generate_frame();
|
||||
};
|
||||
sym_icao.on_change = [this]() {
|
||||
generate_frame();
|
||||
};
|
||||
button_callsign.on_select = [this, &nav](Button&) {
|
||||
text_prompt(nav, &callsign, 9);
|
||||
text_prompt(nav, &callsign, 8);
|
||||
};
|
||||
|
||||
field_altitude.set_value(11000);
|
||||
@@ -146,19 +202,24 @@ ADSBTxView::ADSBTxView(NavigationView& nav) {
|
||||
field_lon_minutes.set_value(0);
|
||||
field_lon_seconds.set_value(0);
|
||||
|
||||
field_lat_degrees.on_change = [this](int32_t) {
|
||||
generate_frame();
|
||||
};
|
||||
field_lon_degrees.on_change = [this](int32_t) {
|
||||
generate_frame();
|
||||
};
|
||||
|
||||
for (c = 0; c < 4; c++)
|
||||
field_squawk.set_sym(c, 0);
|
||||
|
||||
generate_frame();
|
||||
|
||||
tx_view.on_edit_frequency = [this, &nav]() {
|
||||
// Shouldn't be able to edit frequency
|
||||
return;
|
||||
};
|
||||
receiver_model.set_tuning_frequency(434000000); // DEBUG
|
||||
|
||||
tx_view.on_start = [this]() {
|
||||
if (start_tx())
|
||||
tx_view.set_transmitting(true);
|
||||
//rotate_frames();
|
||||
};
|
||||
|
||||
tx_view.on_stop = [this]() {
|
||||
|
@@ -41,7 +41,7 @@ public:
|
||||
ADSBTxView(NavigationView& nav);
|
||||
~ADSBTxView();
|
||||
|
||||
void paint(Painter& painter) override;
|
||||
void paint(Painter&) override;
|
||||
|
||||
void focus() override;
|
||||
|
||||
@@ -54,16 +54,44 @@ private:
|
||||
SEQUENCE
|
||||
};
|
||||
|
||||
const float plane_lats[12] = {
|
||||
0,
|
||||
-1,
|
||||
-2,
|
||||
-3,
|
||||
-4,
|
||||
-5,
|
||||
-4.5,
|
||||
-5,
|
||||
-4,
|
||||
-3,
|
||||
-2,
|
||||
-1
|
||||
};
|
||||
const float plane_lons[12] = {
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
2,
|
||||
1,
|
||||
0,
|
||||
-1,
|
||||
-2,
|
||||
-1,
|
||||
-1,
|
||||
-1
|
||||
};
|
||||
|
||||
tx_modes tx_mode = IDLE;
|
||||
|
||||
std::string callsign = "KLM1023 ";
|
||||
std::string callsign = "PORTAPAC";
|
||||
|
||||
adsb_frame frame { };
|
||||
uint8_t adsb_bin[112]; // 112 bit data block
|
||||
ADSBFrame frames[4] { };
|
||||
|
||||
bool start_tx();
|
||||
void generate_frame();
|
||||
void generate_frame_pos();
|
||||
void rotate_frames();
|
||||
void on_txdone(const bool v);
|
||||
|
||||
const Style style_val {
|
||||
@@ -82,8 +110,8 @@ private:
|
||||
{ { 2 * 8, 4 * 8 }, "ICAO24:", Color::light_grey() },
|
||||
{ { 2 * 8, 7 * 8 }, "ID:", Color::light_grey() },
|
||||
{ { 2 * 8, 10 * 8 }, "Altitude: feet", Color::light_grey() },
|
||||
{ { 2 * 8, 12 * 8 }, "Latitude: * ' \"", Color::light_grey() }, // No ° symbol in 8x16 font
|
||||
{ { 2 * 8, 14 * 8 }, "Longitude: * ' \"", Color::light_grey() }, // No ° symbol in 8x16 font
|
||||
{ { 2 * 8, 12 * 8 }, "Latitude: * ' \"", Color::light_grey() }, // No ° symbol in 8x16 font
|
||||
{ { 2 * 8, 14 * 8 }, "Longitude: * ' \"", Color::light_grey() }, // No ° symbol in 8x16 font
|
||||
{ { 15 * 8, 18 * 8 }, "Squawk", Color::light_grey() }
|
||||
};
|
||||
|
||||
@@ -117,23 +145,23 @@ private:
|
||||
};
|
||||
|
||||
NumberField field_lat_degrees {
|
||||
{ 12 * 8, 6 * 16 }, 3, { -90, 90 }, 1, ' '
|
||||
{ 12 * 8, 6 * 16 }, 4, { -90, 90 }, 1, ' '
|
||||
};
|
||||
NumberField field_lat_minutes {
|
||||
{ 16 * 8, 6 * 16 }, 2, { 0, 59 }, 1, ' '
|
||||
{ 17 * 8, 6 * 16 }, 2, { 0, 59 }, 1, ' '
|
||||
};
|
||||
NumberField field_lat_seconds {
|
||||
{ 19 * 8, 6 * 16 }, 2, { 0, 59 }, 1, ' '
|
||||
{ 20 * 8, 6 * 16 }, 2, { 0, 59 }, 1, ' '
|
||||
};
|
||||
|
||||
NumberField field_lon_degrees {
|
||||
{ 12 * 8, 7 * 16 }, 3, { -90, 90 }, 1, ' '
|
||||
{ 12 * 8, 7 * 16 }, 4, { -180, 180 }, 1, ' '
|
||||
};
|
||||
NumberField field_lon_minutes {
|
||||
{ 16 * 8, 7 * 16 }, 2, { 0, 59 }, 1, ' '
|
||||
{ 17 * 8, 7 * 16 }, 2, { 0, 59 }, 1, ' '
|
||||
};
|
||||
NumberField field_lon_seconds {
|
||||
{ 19 * 8, 7 * 16 }, 2, { 0, 59 }, 1, ' '
|
||||
{ 20 * 8, 7 * 16 }, 2, { 0, 59 }, 1, ' '
|
||||
};
|
||||
|
||||
Checkbox check_emergency {
|
||||
@@ -160,8 +188,8 @@ private:
|
||||
|
||||
TransmitterView tx_view {
|
||||
16 * 16,
|
||||
1090000000,
|
||||
2000000,
|
||||
0,
|
||||
0,
|
||||
true
|
||||
};
|
||||
|
||||
|
@@ -76,7 +76,7 @@ void TransmitterView::on_tuning_frequency_changed(rf::Frequency f) {
|
||||
}
|
||||
|
||||
void TransmitterView::on_bandwidth_changed(uint32_t bandwidth) {
|
||||
transmitter_model.set_bandwidth(bandwidth);
|
||||
//transmitter_model.set_bandwidth(bandwidth);
|
||||
}
|
||||
|
||||
void TransmitterView::set_transmitting(const bool transmitting) {
|
||||
@@ -92,7 +92,7 @@ void TransmitterView::set_transmitting(const bool transmitting) {
|
||||
}
|
||||
|
||||
void TransmitterView::on_show() {
|
||||
field_frequency.set_value(receiver_model.tuning_frequency());
|
||||
//field_frequency.set_value(receiver_model.tuning_frequency());
|
||||
}
|
||||
|
||||
void TransmitterView::focus() {
|
||||
|
Reference in New Issue
Block a user