Fixed ADSB TX frame rotation

This commit is contained in:
furrtek 2017-08-12 09:54:58 +01:00
parent 482729918d
commit 7f97a090e4
7 changed files with 125 additions and 157 deletions

View File

@ -23,17 +23,15 @@
// Color bitmaps generated with: // Color bitmaps generated with:
// Gimp image > indexed colors (16), then "xxd -i *.bmp" // Gimp image > indexed colors (16), then "xxd -i *.bmp"
//TEST: ADS-B tx manchester encoder, velocity and squawk frames //TEST: ADS-B tx velocity and squawk frames
//TEST: Menuview refresh, seems to blink a lot //TEST: Menuview refresh, seems to blink a lot
//TEST: Check AFSK transmit end, skips last bits ? //TEST: Check AFSK transmit end, skips last bits ?
//TEST: Imperial in whipcalc //TEST: Imperial in whipcalc
//BUG: ADSB transmit baseband code works only if stuck in a loop (txdone message makes everything go nuts)
//BUG: CPLD-related rx ok, tx bad, see portapack.cpp lines 214+ to disable CPLD overlay //BUG: CPLD-related rx ok, tx bad, see portapack.cpp lines 214+ to disable CPLD overlay
//BUG: REPLAY See what's wrong with quality (format, or need for interpolation filter ?) //BUG: REPLAY See what's wrong with quality (format, or need for interpolation filter ?)
//BUG: SCANNER Lock on frequency, if frequency jump, still locked on first one //BUG: SCANNER Lock on frequency, if frequency jump, still locked on first one
//BUG: SCANNER Multiple slices //BUG: SCANNER Multiple slices
//BUG: REPLAY freezes when SD card not present
//BUG: RDS doesn't stop baseband when stopping tx ? //BUG: RDS doesn't stop baseband when stopping tx ?
//TODO: REPLAY Convert C16 to C8 on M0 core //TODO: REPLAY Convert C16 to C8 on M0 core

View File

@ -118,6 +118,8 @@ ADSBPositionView::ADSBPositionView(NavigationView& nav) {
} }
void ADSBPositionView::collect_frames(const uint32_t ICAO_address, std::vector<ADSBFrame>& frame_list) { void ADSBPositionView::collect_frames(const uint32_t ICAO_address, std::vector<ADSBFrame>& frame_list) {
if (!enabled) return;
ADSBFrame temp_frame; ADSBFrame temp_frame;
encode_frame_pos(temp_frame, ICAO_address, geopos.altitude(), encode_frame_pos(temp_frame, ICAO_address, geopos.altitude(),
@ -149,6 +151,8 @@ ADSBCallsignView::ADSBCallsignView(NavigationView& nav) {
} }
void ADSBCallsignView::collect_frames(const uint32_t ICAO_address, std::vector<ADSBFrame>& frame_list) { void ADSBCallsignView::collect_frames(const uint32_t ICAO_address, std::vector<ADSBFrame>& frame_list) {
if (!enabled) return;
ADSBFrame temp_frame; ADSBFrame temp_frame;
encode_frame_id(temp_frame, ICAO_address, callsign); encode_frame_id(temp_frame, ICAO_address, callsign);
@ -175,6 +179,8 @@ ADSBSpeedView::ADSBSpeedView() {
} }
void ADSBSpeedView::collect_frames(const uint32_t ICAO_address, std::vector<ADSBFrame>& frame_list) { void ADSBSpeedView::collect_frames(const uint32_t ICAO_address, std::vector<ADSBFrame>& frame_list) {
if (!enabled) return;
ADSBFrame temp_frame; ADSBFrame temp_frame;
encode_frame_velo(temp_frame, ICAO_address, field_speed.value(), encode_frame_velo(temp_frame, ICAO_address, field_speed.value(),
@ -193,6 +199,8 @@ ADSBSquawkView::ADSBSquawkView() {
} }
void ADSBSquawkView::collect_frames(const uint32_t ICAO_address, std::vector<ADSBFrame>& frame_list) { void ADSBSquawkView::collect_frames(const uint32_t ICAO_address, std::vector<ADSBFrame>& frame_list) {
if (!enabled) return;
ADSBFrame temp_frame; ADSBFrame temp_frame;
(void)ICAO_address; (void)ICAO_address;
@ -201,83 +209,35 @@ void ADSBSquawkView::collect_frames(const uint32_t ICAO_address, std::vector<ADS
frame_list.emplace_back(temp_frame); frame_list.emplace_back(temp_frame);
} }
void ADSBTxView::focus() { ADSBTXThread::ADSBTXThread(
tab_view.focus(); std::vector<ADSBFrame> frames
) : frames_ { std::move(frames) }
{
thread = chThdCreateFromHeap(NULL, 1024, NORMALPRIO + 10, ADSBTXThread::static_fn, this);
} }
ADSBTxView::~ADSBTxView() { ADSBTXThread::~ADSBTXThread() {
transmitter_model.disable(); if( thread ) {
baseband::shutdown(); chThdTerminate(thread);
chThdWait(thread);
thread = nullptr;
}
} }
void ADSBTxView::generate_frames() { msg_t ADSBTXThread::static_fn(void* arg) {
const uint32_t ICAO_address = sym_icao.value_hex_u64(); auto obj = static_cast<ADSBTXThread*>(arg);
obj->run();
/* This scheme kinda sucks. Each "tab"'s collect_frames method return 0;
* is called to generate its related frame(s). Getting values
* from each widget of each tab would be better ?
* */
view_position.collect_frames(ICAO_address, frames);
view_callsign.collect_frames(ICAO_address, frames);
view_speed.collect_frames(ICAO_address, frames);
view_squawk.collect_frames(ICAO_address, frames);
// DEBUG: Show how many frames were generated
text_frame.set(to_string_dec_uint(frames.size()) + " frame(s).");
//memset(bin_ptr, 0, 240);
//auto raw_ptr = frames[0].get_raw_data();
// The preamble isn't manchester encoded
//memcpy(bin_ptr, adsb_preamble, 16);
// Convert to binary with manchester encoding (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;
}
}*/
/*manchester_encode(bin_ptr + 16, raw_ptr, 112, 0);
// Display in hex for debug
text_frame.set(to_string_hex_array(frames[0].get_raw_data(), 14));
button_callsign.set_text(callsign);*/
} }
void ADSBTxView::start_tx() { void ADSBTXThread::run() {
generate_frames();
transmitter_model.set_sampling_rate(4000000U);
transmitter_model.set_rf_amp(true);
transmitter_model.set_baseband_bandwidth(10000000);
transmitter_model.enable();
baseband::set_adsb();
}
void ADSBTxView::on_txdone(const bool v) {
(void)v;
/*if (v) {
transmitter_model.disable();
tx_view.set_transmitting(false);
}*/
}
void ADSBTxView::rotate_frames() {
uint8_t * bin_ptr = shared_memory.bb_data.data; uint8_t * bin_ptr = shared_memory.bb_data.data;
uint8_t * raw_ptr; uint8_t * raw_ptr;
uint32_t frame_index = 0; //, plane_index = 0; uint32_t frame_index = 0; //, plane_index = 0;
uint32_t c; //, regen = 0; //uint32_t regen = 0;
//float offs = 0; //float offs = 0;
for (;;) { while( !chThdShouldTerminate() ) {
/*if (!regen) { /*if (!regen) {
regen = 10; regen = 10;
@ -294,28 +254,24 @@ void ADSBTxView::rotate_frames() {
offs += 0.001; offs += 0.001;
}*/ }*/
memset(bin_ptr, 0, 240); memset(bin_ptr, 0, 256); // 112 bits * 2 parts = 224 should be enough
raw_ptr = frames[frame_index].get_raw_data(); raw_ptr = frames_[frame_index].get_raw_data();
// The preamble isn't manchester encoded
memcpy(bin_ptr, adsb_preamble, 16); memcpy(bin_ptr, adsb_preamble, 16);
// Convert to binary (1 byte per bit, faster for baseband code) // Convert to binary (1 byte per bit, faster for baseband code)
for (c = 0; c < 112; c++) { manchester_encode(bin_ptr + 16, raw_ptr, 112, 0);
if ((raw_ptr[c >> 3] << (c & 7)) & 0x80) {
bin_ptr[(c * 2) + 16] = 1; // Display in hex for debug
bin_ptr[(c * 2) + 16 + 1] = 0; //text_frame.set(to_string_hex_array(frames[0].get_raw_data(), 14));
} else {
bin_ptr[(c * 2) + 16] = 0;
bin_ptr[(c * 2) + 16 + 1] = 1;
}
}
baseband::set_adsb(); baseband::set_adsb();
chThdSleepMilliseconds(50); chThdSleepMilliseconds(50);
if (frame_index == frames.size()) { if (frame_index == frames_.size()) {
frame_index = 0; frame_index = 0;
//if (regen) //if (regen)
// regen--; // regen--;
@ -325,6 +281,46 @@ void ADSBTxView::rotate_frames() {
} }
} }
void ADSBTxView::focus() {
tab_view.focus();
}
ADSBTxView::~ADSBTxView() {
transmitter_model.disable();
baseband::shutdown();
}
void ADSBTxView::generate_frames() {
const uint32_t ICAO_address = sym_icao.value_hex_u64();
frames.clear();
/* This scheme kinda sucks. Each "tab"'s collect_frames method
* is called to generate its related frame(s). Getting values
* from each widget of each tab would be better ?
* */
view_position.collect_frames(ICAO_address, frames);
view_callsign.collect_frames(ICAO_address, frames);
view_speed.collect_frames(ICAO_address, frames);
view_squawk.collect_frames(ICAO_address, frames);
// Show how many frames were generated
//text_frame.set(to_string_dec_uint(frames.size()) + " frame(s).");
}
void ADSBTxView::start_tx() {
generate_frames();
transmitter_model.set_sampling_rate(4000000U);
transmitter_model.set_rf_amp(true);
transmitter_model.set_baseband_bandwidth(10000000);
transmitter_model.enable();
baseband::set_adsb();
tx_thread = std::make_unique<ADSBTXThread>(frames);
}
ADSBTxView::ADSBTxView( ADSBTxView::ADSBTxView(
NavigationView& nav NavigationView& nav
) : nav_ { nav } ) : nav_ { nav }
@ -349,11 +345,16 @@ ADSBTxView::ADSBTxView(
view_speed.set_parent_rect(view_rect); view_speed.set_parent_rect(view_rect);
view_squawk.set_parent_rect(view_rect); view_squawk.set_parent_rect(view_rect);
tx_view.on_edit_frequency = [this, &nav]() {
auto new_view = nav.push<FrequencyKeypadView>(receiver_model.tuning_frequency());
new_view->on_changed = [this](rf::Frequency f) {
transmitter_model.set_tuning_frequency(f);
};
};
tx_view.on_start = [this]() { tx_view.on_start = [this]() {
start_tx(); start_tx();
tx_view.set_transmitting(true); tx_view.set_transmitting(true);
// Disable for DEBUG
//rotate_frames();
}; };
tx_view.on_stop = [this]() { tx_view.on_stop = [this]() {

View File

@ -152,6 +152,25 @@ private:
}; };
}; };
class ADSBTXThread {
public:
ADSBTXThread(std::vector<ADSBFrame> frames);
~ADSBTXThread();
ADSBTXThread(const ADSBTXThread&) = delete;
ADSBTXThread(ADSBTXThread&&) = delete;
ADSBTXThread& operator=(const ADSBTXThread&) = delete;
ADSBTXThread& operator=(ADSBTXThread&&) = delete;
private:
std::vector<ADSBFrame> frames_ { };
Thread* thread { nullptr };
static msg_t static_fn(void* arg);
void run();
};
class ADSBTxView : public View { class ADSBTxView : public View {
public: public:
ADSBTxView(NavigationView& nav); ADSBTxView(NavigationView& nav);
@ -203,8 +222,6 @@ private:
void start_tx(); void start_tx();
void generate_frames(); void generate_frames();
void rotate_frames();
void on_txdone(const bool v);
ADSBPositionView view_position { nav_ }; ADSBPositionView view_position { nav_ };
ADSBCallsignView view_callsign { nav_ }; ADSBCallsignView view_callsign { nav_ };
@ -239,13 +256,7 @@ private:
0 0
}; };
MessageHandlerRegistration message_handler_tx_done { std::unique_ptr<ADSBTXThread> tx_thread { };
Message::ID::TXDone,
[this](const Message* const p) {
const auto message = *reinterpret_cast<const TXDoneMessage*>(p);
this->on_txdone(message.done);
}
};
}; };
} /* namespace ui */ } /* namespace ui */

View File

@ -37,54 +37,14 @@ void ADSBTXProcessor::execute(const buffer_c8_t& buffer) {
if (!configured) return; if (!configured) return;
/*if (terminate) {
for (size_t i = 0; i < buffer.count; i++) { for (size_t i = 0; i < buffer.count; i++) {
buffer.p[i] = { 0, 0 };
}
terminate--;
if (!terminate) {
message.done = true;
shared_memory.application_queue.push(message);
configured = false;
return;
}
} else {*/
for (size_t i = 0; i < buffer.count; i++) {
/*if (active) {
if (!sample) {
sample = 300;
if (bit_pos >= 112) {
active = false; // Stop
cur_bit = 0;
} else {
cur_bit = shared_memory.bb_data.data[bit_pos];
bit_pos++;
}
} else
sample--;
if (!preamble) {
if (sample == 150)
cur_bit ^= 1; // Invert
}
} else {*/
/*cur_bit = 0;
if (bit_pos >= 16384) {
configured = false;
message.done = true;
shared_memory.application_queue.push(message);
}*/
if (bit_pos >= (240 << 1)) { if (bit_pos >= (240 << 1)) {
configured = false; configured = false;
terminate = 100;
cur_bit = 0; cur_bit = 0;
} else { } else {
cur_bit = shared_memory.bb_data.data[bit_pos >> 1]; cur_bit = shared_memory.bb_data.data[bit_pos >> 1];
bit_pos++; bit_pos++;
} }
//}
if (cur_bit) { if (cur_bit) {
// Crude AM // Crude AM
@ -94,7 +54,6 @@ void ADSBTXProcessor::execute(const buffer_c8_t& buffer) {
buffer.p[i] = { 0, 0 }; buffer.p[i] = { 0, 0 };
} }
} }
//}
} }
void ADSBTXProcessor::on_message(const Message* const p) { void ADSBTXProcessor::on_message(const Message* const p) {
@ -103,9 +62,7 @@ void ADSBTXProcessor::on_message(const Message* const p) {
if (message.id == Message::ID::ADSBConfigure) { if (message.id == Message::ID::ADSBConfigure) {
bit_pos = 0; bit_pos = 0;
phase = 0; phase = 0;
active = true;
configured = true; configured = true;
terminate = 0;
} }
} }

View File

@ -44,8 +44,6 @@ private:
{ 0, -127 } { 0, -127 }
}; };
bool active { };
uint32_t terminate { };
uint32_t bit_pos { 0 }; uint32_t bit_pos { 0 };
uint32_t cur_bit { 0 }; uint32_t cur_bit { 0 };
uint32_t phase { 0 }; uint32_t phase { 0 };

View File

@ -70,13 +70,16 @@ FormattedSymbols format_symbols(
return { hex_data, hex_error }; return { hex_data, hex_error };
} }
void manchester_encode(uint8_t * dest, uint8_t * src, size_t length, const size_t sense) { void manchester_encode(uint8_t * dest, uint8_t * src, const size_t length, const size_t sense) {
uint_fast8_t part = sense ? 0 : 0xFF; uint8_t part = sense ? 0 : 0xFF;
for (size_t c = 0; c < length; c++) { for (size_t c = 0; c < length; c++) {
if ((src[c >> 3] << (c & 7)) & 0x80) { if ((src[c >> 3] << (c & 7)) & 0x80) {
*(dest++) = part; *(dest++) = part;
*(dest++) = ~part; *(dest++) = ~part;
} else {
*(dest++) = ~part;
*(dest++) = part;
} }
} }
} }

View File

@ -67,6 +67,6 @@ FormattedSymbols format_symbols(
const ManchesterDecoder& decoder const ManchesterDecoder& decoder
); );
void manchester_encode(uint8_t * dest, uint8_t * src, size_t length, const size_t sense = 0); void manchester_encode(uint8_t * dest, uint8_t * src, const size_t length, const size_t sense = 0);
#endif/*__MANCHESTER_H__*/ #endif/*__MANCHESTER_H__*/