Merge branch 'next'

This commit is contained in:
eried 2021-11-01 11:46:06 +01:00
commit cf906684cc
42 changed files with 680 additions and 131 deletions

View File

@ -139,7 +139,12 @@ void ReplayAppView::start() {
}
);
}
field_rfgain.on_change = [this](int32_t v) {
tx_gain = v;
};
field_rfgain.set_value(tx_gain);
receiver_model.set_tx_gain(tx_gain);
radio::enable({
receiver_model.tuning_frequency(),
sample_rate * 8 ,
@ -180,6 +185,8 @@ ReplayAppView::ReplayAppView(
NavigationView& nav
) : nav_ (nav)
{
tx_gain = 35;field_rfgain.set_value(tx_gain);
baseband::run_image(portapack::spi_flash::image_tag_replay);
add_children({
@ -190,7 +197,7 @@ ReplayAppView::ReplayAppView(
&text_duration,
&progressbar,
&field_frequency,
&field_lna,
&field_rfgain,
&field_rf_amp,
&check_loop,
&button_play,

View File

@ -51,6 +51,7 @@ private:
static constexpr ui::Dim header_height = 3 * 16;
uint32_t sample_rate = 0;
int32_t tx_gain { 47 };
static constexpr uint32_t baseband_bandwidth = 2500000;
const size_t read_size { 16384 };
const size_t buffer_count { 3 };
@ -75,7 +76,7 @@ private:
bool ready_signal { false };
Labels labels {
{ { 10 * 8, 2 * 16 }, "LNA: A:", Color::light_grey() }
{ { 10 * 8, 2 * 16 }, "GAIN A:", Color::light_grey() }
};
Button button_open {
@ -103,8 +104,13 @@ private:
FrequencyField field_frequency {
{ 0 * 8, 2 * 16 },
};
LNAGainField field_lna {
{ 14 * 8, 2 * 16 }
NumberField field_rfgain {
{ 14 * 8, 2 * 16 },
2,
{ 0, 47 },
1,
' '
};
RFAmpField field_rf_amp {
{ 19 * 8, 2 * 16 }

View File

@ -31,8 +31,9 @@ namespace ui
console.writeln("N0vaPixel,klockee,GullCode");
console.writeln("jamesshao8,ITAxReal,rascafr");
console.writeln("mcules,dqs105,strijar");
console.writeln("zhang00963,RedFox-Fr");
console.writeln("East2West,fossum");
console.writeln("zhang00963,RedFox-Fr,aldude999");
console.writeln("East2West,fossum,ArjanOnwezen");
console.writeln("vXxOinvizioNxX,teixeluis");
console.writeln("");
break;

View File

@ -20,6 +20,8 @@
* Boston, MA 02110-1301, USA.
*/
#include <strings.h>
#include "ui_adsb_rx.hpp"
#include "ui_alphanum.hpp"
@ -205,7 +207,7 @@ void ADSBRxView::on_frame(const ADSBFrameMessage * message) {
auto frame = message->frame;
uint32_t ICAO_address = frame.get_ICAO_address();
if (frame.check_CRC() && frame.get_ICAO_address()) {
if (frame.check_CRC() && ICAO_address) {
rtcGetTime(&RTCD1, &datetime);
auto& entry = ::on_packet(recent, ICAO_address);
frame.set_rx_timestamp(datetime.minute() * 60 + datetime.second());
@ -222,33 +224,49 @@ void ADSBRxView::on_frame(const ADSBFrameMessage * message) {
uint8_t msg_sub = frame.get_msg_sub();
uint8_t * raw_data = frame.get_raw_data();
if ((msg_type >= 1) && (msg_type <= 4)) {
if ((msg_type >= AIRCRAFT_ID_L) && (msg_type <= AIRCRAFT_ID_H)) {
callsign = decode_frame_id(frame);
entry.set_callsign(callsign);
logentry+=callsign+" ";
} else if (((msg_type >= 9) && (msg_type <= 18)) || ((msg_type >= 20) && (msg_type <= 22))) {
}
//
else if (((msg_type >= AIRBORNE_POS_BARO_L) && (msg_type <= AIRBORNE_POS_BARO_H)) ||
((msg_type >= AIRBORNE_POS_GPS_L) && (msg_type <= AIRBORNE_POS_GPS_H))) {
entry.set_frame_pos(frame, raw_data[6] & 4);
if (entry.pos.valid) {
str_info = "Alt:" + to_string_dec_int(entry.pos.altitude) +
" Lat:" + to_string_dec_int(entry.pos.latitude) +
"." + to_string_dec_int((int)abs(entry.pos.latitude * 1000) % 100, 2, '0') +
" Lon:" + to_string_dec_int(entry.pos.longitude) +
"." + to_string_dec_int((int)abs(entry.pos.longitude * 1000) % 100, 2, '0');
entry.set_info_string(str_info);
logentry+=str_info+ " ";
" Lat:" + to_string_decimal(entry.pos.latitude, 2) +
" Lon:" + to_string_decimal(entry.pos.longitude, 2);
if (send_updates)
// printing the coordinates in the log file with more
// resolution, as we are not constrained by screen
// real estate there:
std::string log_info = "Alt:" + to_string_dec_int(entry.pos.altitude) +
" Lat:" + to_string_decimal(entry.pos.latitude, 7) +
" Lon:" + to_string_decimal(entry.pos.longitude, 7);
entry.set_info_string(str_info);
logentry+=log_info + " ";
// we only want to update the details view if the frame
// we received has the same ICAO address, i.e. belongs to
// the same aircraft:
if(send_updates && details_view->get_current_entry().ICAO_address == ICAO_address) {
details_view->update(entry);
}
}
} else if(msg_type == 19 && msg_sub >= 1 && msg_sub <= 4){
} else if(msg_type == AIRBORNE_VEL && msg_sub >= VEL_GND_SUBSONIC && msg_sub <= VEL_AIR_SUPERSONIC){
entry.set_frame_velo(frame);
logentry += "Type:" + to_string_dec_uint(msg_sub) +
" Hdg:" + to_string_dec_uint(entry.velo.heading) +
" Spd: "+ to_string_dec_int(entry.velo.speed);
if (send_updates)
// same here:
if (send_updates && details_view->get_current_entry().ICAO_address == ICAO_address) {
details_view->update(entry);
}
}
}
recent_entries_view.set_dirty();

View File

@ -36,9 +36,33 @@ using namespace adsb;
namespace ui {
#define ADSB_DECAY_A 10 // In seconds
#define ADSB_DECAY_B 30
#define ADSB_DECAY_C 60 // Can be used for removing old entries, RecentEntries already caps to 64
#define ADSB_DECAY_A 10 // In seconds
#define ADSB_DECAY_B 30
#define ADSB_DECAY_C 60 // Can be used for removing old entries, RecentEntries already caps to 64
#define AIRCRAFT_ID_L 1 // aircraft ID message type (lowest type id)
#define AIRCRAFT_ID_H 4 // aircraft ID message type (highest type id)
#define SURFACE_POS_L 5 // surface position (lowest type id)
#define SURFACE_POS_H 8 // surface position (highest type id)
#define AIRBORNE_POS_BARO_L 9 // airborne position (lowest type id)
#define AIRBORNE_POS_BARO_H 18 // airborne position (highest type id)
#define AIRBORNE_VEL 19 // airborne velocities
#define AIRBORNE_POS_GPS_L 20 // airborne position (lowest type id)
#define AIRBORNE_POS_GPS_H 22 // airborne position (highest type id)
#define RESERVED_L 23 // reserved for other uses
#define RESERVED_H 31 // reserved for other uses
#define VEL_GND_SUBSONIC 1
#define VEL_GND_SUPERSONIC 2
#define VEL_AIR_SUBSONIC 3
#define VEL_AIR_SUPERSONIC 4
#define O_E_FRAME_TIMEOUT 20 // timeout between odd and even frames
struct AircraftRecentEntry {
using Key = uint32_t;
@ -49,7 +73,7 @@ struct AircraftRecentEntry {
uint16_t hits { 0 };
uint32_t age { 0 };
adsb_pos pos { false, 0, 0, 0 };
adsb_vel velo { false, 0, 999 };
adsb_vel velo { false, 0, 999, 0 };
ADSBFrame frame_pos_even { };
ADSBFrame frame_pos_odd { };
@ -82,7 +106,7 @@ struct AircraftRecentEntry {
frame_pos_odd = frame;
if (!frame_pos_even.empty() && !frame_pos_odd.empty()) {
if (abs(frame_pos_even.get_rx_timestamp() - frame_pos_odd.get_rx_timestamp()) < 20)
if (abs(frame_pos_even.get_rx_timestamp() - frame_pos_odd.get_rx_timestamp()) < O_E_FRAME_TIMEOUT)
pos = decode_frame_pos(frame_pos_even, frame_pos_odd);
}
}
@ -137,6 +161,8 @@ public:
void update(const AircraftRecentEntry& entry);
std::string title() const override { return "Details"; };
AircraftRecentEntry get_current_entry() { return entry_copy; }
private:
AircraftRecentEntry entry_copy { 0 };

View File

@ -48,7 +48,7 @@ void RecentEntriesTable<APRSRecentEntries>::draw(
) {
char aged_color;
Color target_color;
auto entry_age = entry.age;
// auto entry_age = entry.age;
target_color = Color::green();
@ -342,7 +342,7 @@ void APRSDetailsView::set_entry(const APRSRecentEntry& entry){
void APRSDetailsView::update() {
if(!hidden()){
uint32_t age = entry_copy.age;
//uint32_t age = entry_copy.age;
console.clear(true);
console.write(entry_copy.info_string);

View File

@ -48,6 +48,9 @@ FreqManBaseView::FreqManBaseView(
} else
error_ = ERROR_NOFILES;
// initialize
change_category(last_category_id);
// Default function
on_change_category = [this](int32_t category_id) {
change_category(category_id);

View File

@ -64,7 +64,7 @@ protected:
OptionsField options_category {
{ 9 * 8, 4 },
12,
14,
{ }
};
@ -103,19 +103,19 @@ private:
};
Labels labels {
{ { 2 * 8, 14 * 8 }, "Save as:", Color::white() }
{ { 1 * 8, 12 * 8 }, "Save as:", Color::white() }
};
Button button_save_name {
{ 2 * 8, 17 * 8, 14 * 8, 48 },
{ 1 * 8, 17 * 8, 12 * 8, 48 },
"Name (set)"
};
Button button_save_timestamp {
{ 2 * 8, 25 * 8, 14 * 8, 48 },
{ 1 * 8, 25 * 8, 12 * 8, 48 },
"Timestamp:"
};
LiveDateTime live_timestamp {
{ 17 * 8, 27 * 8, 11 * 8, 16 }
{ 14 * 8, 27 * 8, 16 * 8, 16 }
};
};

View File

@ -285,15 +285,17 @@ SetUIView::SetUIView(NavigationView& nav) {
&checkbox_bloff,
&options_bloff,
&checkbox_showsplash,
&checkbox_showclock,
&options_clockformat,
&button_ok
});
checkbox_speaker.set_value(persistent_memory::config_speaker());
checkbox_showsplash.set_value(persistent_memory::config_splash());
checkbox_showclock.set_value(!persistent_memory::hide_clock());
//checkbox_login.set_value(persistent_memory::config_login());
uint32_t backlight_timer = persistent_memory::config_backlight_timer();
if (backlight_timer) {
checkbox_bloff.set_value(true);
options_bloff.set_by_value(backlight_timer);
@ -301,6 +303,12 @@ SetUIView::SetUIView(NavigationView& nav) {
options_bloff.set_selected_index(0);
}
if (persistent_memory::clock_with_date()) {
options_clockformat.set_selected_index(1);
} else {
options_clockformat.set_selected_index(0);
}
checkbox_speaker.on_select = [this](Checkbox&, bool v) {
if (v) audio::output::speaker_mute(); //Just mute audio if speaker is disabled
@ -316,7 +324,14 @@ SetUIView::SetUIView(NavigationView& nav) {
else
persistent_memory::set_config_backlight_timer(0);
if (checkbox_showclock.value()){
if (options_clockformat.selected_index() == 1)
persistent_memory::set_clock_with_date(true);
else
persistent_memory::set_clock_with_date(false);
}
persistent_memory::set_config_splash(checkbox_showsplash.value());
persistent_memory::set_clock_hidden(!checkbox_showclock.value());
//persistent_memory::set_config_login(checkbox_login.value());
nav.pop();
};

View File

@ -51,8 +51,8 @@ public:
private:
Labels labels {
{ { 6 * 8, 7 * 16 }, "YYYY/MM/DD HH:MM:SS", Color::grey() },
{ { 10 * 8, 9 * 16 }, "/ / : :", Color::light_grey() }
{ { 6 * 8, 7 * 16 }, "YYYY-MM-DD HH:MM:SS", Color::grey() },
{ { 10 * 8, 9 * 16 }, "- - : :", Color::light_grey() }
};
NumberField field_year {
@ -226,19 +226,19 @@ private:
};*/
Checkbox checkbox_speaker {
{ 3 * 8, 2 * 16 },
{ 3 * 8, 4 * 16 },
20,
"Hide H1 Speaker option"
};
Checkbox checkbox_bloff {
{ 3 * 8, 5 * 16 },
{ 3 * 8, 6 * 16 },
20,
"Backlight off after:"
};
OptionsField options_bloff {
{ 52, 6 * 16 + 8 },
10,
{ 52, 7 * 16 + 8 },
20,
{
{ "5 seconds", 5 },
{ "15 seconds", 15 },
@ -252,10 +252,25 @@ private:
Checkbox checkbox_showsplash {
{ 3 * 8, 9 * 16 },
11,
20,
"Show splash"
};
Checkbox checkbox_showclock {
{ 3 * 8, 11 * 16 },
20,
"Show clock with:"
};
OptionsField options_clockformat {
{ 52, 12 * 16 + 8 },
20,
{
{ "time only", 0 },
{ "time and date", 1 }
}
};
Button button_ok {
{ 2 * 8, 16 * 16, 12 * 8, 32 },
"Save"

View File

@ -22,6 +22,7 @@
#include "ui_sonde.hpp"
#include "baseband_api.hpp"
#include "audio.hpp"
#include "portapack.hpp"
#include <cstring>
@ -50,6 +51,8 @@ SondeView::SondeView(NavigationView& nav) {
&field_lna,
&field_vga,
&rssi,
&field_volume,
&check_beep,
&check_log,
&check_crc,
&text_signature,
@ -63,6 +66,9 @@ SondeView::SondeView(NavigationView& nav) {
&button_see_map
});
// start from the frequency currently stored in the receiver_model:
target_frequency_ = receiver_model.tuning_frequency();
field_frequency.set_value(target_frequency_);
field_frequency.set_step(500); //euquiq: was 10000, but we are using this for fine-tunning
field_frequency.on_change = [this](rf::Frequency f) {
@ -80,6 +86,10 @@ SondeView::SondeView(NavigationView& nav) {
geopos.set_read_only(true);
check_beep.on_select = [this](Checkbox&, bool v) {
beep = v;
};
check_log.on_select = [this](Checkbox&, bool v) {
logging = v;
};
@ -107,16 +117,37 @@ SondeView::SondeView(NavigationView& nav) {
gps_info.lon,
999); //set a dummy heading out of range to draw a cross...probably not ideal?
};
logger = std::make_unique<SondeLogger>();
if (logger)
logger->append(u"sonde.txt");
// initialize audio:
field_volume.set_value((receiver_model.headphone_volume() - audio::headphone::volume_range().max).decibel() + 99);
field_volume.on_change = [this](int32_t v) {
this->on_headphone_volume_changed(v);
};
audio::output::start();
audio::output::speaker_unmute();
// inject a PitchRSSIConfigureMessage in order to arm
// the pitch rssi events that will be used by the
// processor:
const PitchRSSIConfigureMessage message { true, 0 };
shared_memory.application_queue.push(message);
baseband::set_pitch_rssi(0, true);
}
SondeView::~SondeView() {
baseband::set_pitch_rssi(0, false);
radio::disable();
baseband::shutdown();
audio::output::stop();
}
void SondeView::focus() {
@ -156,18 +187,31 @@ void SondeView::on_packet(const sonde::Packet &packet)
}
gps_info = packet.get_GPS_data();
geopos.set_altitude(gps_info.alt);
geopos.set_lat(gps_info.lat);
geopos.set_lon(gps_info.lon);
if (logger && logging)
if (logger && logging) {
logger->on_packet(packet);
}
if(beep) {
baseband::request_beep();
}
}
}
void SondeView::on_headphone_volume_changed(int32_t v) {
const auto new_volume = volume_t::decibel(v - 99) + audio::headphone::volume_range().max;
receiver_model.set_headphone_volume(new_volume);
}
void SondeView::set_target_frequency(const uint32_t new_value) {
target_frequency_ = new_value;
radio::set_tuning_frequency(tuning_frequency());
//radio::set_tuning_frequency(tuning_frequency());
// we better remember the tuned frequency, by using this function instead:
receiver_model.set_tuning_frequency(target_frequency_);
}
uint32_t SondeView::tuning_frequency() const {

View File

@ -55,7 +55,7 @@ class SondeView : public View {
public:
static constexpr uint32_t sampling_rate = 2457600;
static constexpr uint32_t baseband_bandwidth = 1750000;
SondeView(NavigationView& nav);
~SondeView();
@ -68,10 +68,14 @@ private:
uint32_t target_frequency_ { 402700000 };
bool logging { false };
bool use_crc { false };
bool beep { false };
sonde::GPS_data gps_info { };
sonde::temp_humid temp_humid_info { };
std::string sonde_id { };
// AudioOutput audio_output { };
Labels labels {
{ { 4 * 8, 2 * 16 }, "Type:", Color::light_grey() },
{ { 6 * 8, 3 * 16 }, "ID:", Color::light_grey() },
@ -103,14 +107,29 @@ private:
{ 21 * 8, 0, 6 * 8, 4 },
};
NumberField field_volume {
{ 28 * 8, 0 * 16 },
2,
{ 0, 99 },
1,
' ',
};
Checkbox check_beep {
{ 22 * 8, 6 * 16 },
3,
"Beep"
};
Checkbox check_log {
{ 23 * 8, 6 * 16 },
{ 22 * 8, 8 * 16 },
3,
"Log"
};
Checkbox check_crc {
{ 23 * 8, 8 * 16 },
{ 22 * 8, 10 * 16 },
3,
"CRC"
};
@ -170,7 +189,10 @@ private:
};
void on_packet(const sonde::Packet& packet);
void on_headphone_volume_changed(int32_t v);
void set_target_frequency(const uint32_t new_value);
uint32_t tuning_frequency() const;
};

View File

@ -140,6 +140,9 @@ Continuous (Fox-oring)
#include "sd_card.hpp"
#include <string.h>
#include "rffc507x.hpp" /* c/m, avoiding initial short ON Ant_DC_Bias pulse, from cold reset */
rffc507x::RFFC507x first_if;
static void event_loop() {
ui::Context context;
@ -160,6 +163,7 @@ static void event_loop() {
}
int main(void) {
first_if.init(); /* To avoid initial short Ant_DC_Bias pulse ,we need quick set up GP01_RFF507X =1 */
if( portapack::init() ) {
portapack::display.init();

View File

@ -83,7 +83,7 @@ TransmitterModel transmitter_model;
TemperatureLogger temperature_logger;
bool antenna_bias { false };
uint8_t bl_tick_counter { 0 };
uint32_t bl_tick_counter { 0 };
void set_antenna_bias(const bool v) {
antenna_bias = v;

View File

@ -54,7 +54,7 @@ extern TransmitterModel transmitter_model;
extern bool speaker_mode;
void set_speaker_mode(const bool v);
extern uint8_t bl_tick_counter;
extern uint32_t bl_tick_counter;
extern bool antenna_bias;
extern TemperatureLogger temperature_logger;

View File

@ -111,14 +111,12 @@ void set_direction(const rf::Direction new_direction) {
// Hack to fix the CPLD (clocking ?) bug: toggle CPLD SRAM overlay depending on new direction
// Use CPLD's EEPROM config when transmitting
// Use the SRAM overlay when receiving
if (direction != new_direction) {
if (new_direction == rf::Direction::Transmit) {
hackrf::cpld::init_from_eeprom();
} else {
if( !hackrf::cpld::load_sram() ) {
chSysHalt();
}
}
// teixeluis: undone "Hack to fix the CPLD (clocking ?) bug".
// Apparently with current CPLD code from the hackrf repo,
// toggling CPLD overlay should no longer be necessary:
if (direction != new_direction && new_direction == rf::Direction::Transmit) {
hackrf::cpld::init_from_eeprom();
}
direction = new_direction;

View File

@ -171,7 +171,11 @@ void ReceiverModel::enable() {
update_baseband_bandwidth();
update_sampling_rate();
update_modulation();
// TODO: would challenge if this should belong to the
// receiver_model namespace:
update_headphone_volume();
led_rx.on();
}
@ -182,6 +186,10 @@ void ReceiverModel::disable() {
// TODO: Responsibility for enabling/disabling the radio is muddy.
// Some happens in ReceiverModel, some inside radio namespace.
radio::disable();
// TODO: we are doing this repeatedly in different levels of the
// call stack. Keeping it for now, but there seem to be too many
// redundant calls:
led_rx.off();
}

View File

@ -112,6 +112,23 @@ std::string to_string_dec_int(
return q;
}
std::string to_string_decimal(float decimal, int8_t precision) {
double integer_part;
double fractional_part;
std::string result;
fractional_part = modf(decimal, &integer_part) * pow(10, precision);
if (fractional_part < 0) {
fractional_part = -fractional_part;
}
result = to_string_dec_int(integer_part) + "." + to_string_dec_uint(fractional_part, precision, '0');
return result;
}
std::string to_string_short_freq(const uint64_t f) {
auto final_str = to_string_dec_int(f / 1000000,4) + "." + to_string_dec_int((f / 100) % 10000, 4, '0');
return final_str;
@ -165,8 +182,8 @@ std::string to_string_datetime(const rtc::RTC& value, const TimeFormat format) {
std::string string { "" };
if (format == YMDHMS) {
string += to_string_dec_uint(value.year(), 4) + "/" +
to_string_dec_uint(value.month(), 2, '0') + "/" +
string += to_string_dec_uint(value.year(), 4) + "-" +
to_string_dec_uint(value.month(), 2, '0') + "-" +
to_string_dec_uint(value.day(), 2, '0') + " ";
}
@ -189,11 +206,11 @@ std::string to_string_timestamp(const rtc::RTC& value) {
}
std::string to_string_FAT_timestamp(const FATTimestamp& timestamp) {
return to_string_dec_uint((timestamp.FAT_date >> 9) + 1980) + "/" +
to_string_dec_uint((timestamp.FAT_date >> 5) & 0xF, 2) + "/" +
to_string_dec_uint((timestamp.FAT_date & 0x1F), 2) + " " +
to_string_dec_uint((timestamp.FAT_time >> 11), 2) + ":" +
to_string_dec_uint((timestamp.FAT_time >> 5) & 0x3F, 2);
return to_string_dec_uint((timestamp.FAT_date >> 9) + 1980) + "-" +
to_string_dec_uint((timestamp.FAT_date >> 5) & 0xF, 2, '0') + "-" +
to_string_dec_uint((timestamp.FAT_date & 0x1F), 2, '0') + " " +
to_string_dec_uint((timestamp.FAT_time >> 11), 2, '0') + ":" +
to_string_dec_uint((timestamp.FAT_time >> 5) & 0x3F, 2, '0');
}
std::string unit_auto_scale(double n, const uint32_t base_nano, uint32_t precision) {

View File

@ -43,6 +43,8 @@ const char unit_prefix[7] { 'n', 'u', 'm', 0, 'k', 'M', 'G' };
std::string to_string_bin(const uint32_t n, const uint8_t l = 0);
std::string to_string_dec_uint(const uint32_t n, const int32_t l = 0, const char fill = ' ');
std::string to_string_dec_int(const int32_t n, const int32_t l = 0, const char fill = 0);
std::string to_string_decimal(float decimal, int8_t precision);
std::string to_string_hex(const uint64_t n, const int32_t l = 0);
std::string to_string_hex_array(uint8_t * const array, const int32_t l = 0);

View File

@ -63,17 +63,9 @@ GeoPos::GeoPos(
const auto changed_fn = [this](int32_t) {
float lat_value = lat();
float lon_value = lon();
double integer_part;
double fractional_part;
fractional_part = modf(lat_value, &integer_part) * 100000;
if (fractional_part < 0)
fractional_part = -fractional_part;
text_lat_decimal.set(to_string_dec_int(integer_part) + "." + to_string_dec_uint(fractional_part, 5));
fractional_part = modf(lon_value, &integer_part) * 100000;
if (fractional_part < 0)
fractional_part = -fractional_part;
text_lon_decimal.set(to_string_dec_int(integer_part) + "." + to_string_dec_uint(fractional_part, 5));
text_lat_decimal.set(to_string_decimal(lat_value, 5));
text_lon_decimal.set(to_string_decimal(lon_value, 5));
if (on_change && report_change)
on_change(altitude(), lat_value, lon_value);

View File

@ -75,8 +75,9 @@ void RSSI::paint(Painter& painter) {
Color::black()
);
if (pitch_rssi_enabled)
if (pitch_rssi_enabled) {
baseband::set_pitch_rssi((avg_ - raw_min) * 2000 / raw_delta, true);
}
}
void RSSI::set_pitch_rssi(bool enabled) {

View File

@ -103,6 +103,7 @@ void TransmitterView::set_transmitting(const bool transmitting) {
void TransmitterView::on_show() {
field_frequency.set_value(transmitter_model.tuning_frequency());
field_frequency_step.set_by_value(receiver_model.frequency_step());
field_gain.set_value(transmitter_model.tx_gain());
field_amp.set_value(transmitter_model.rf_amp() ? 14 : 0);
@ -122,6 +123,7 @@ TransmitterView::TransmitterView(
add_children({
&field_frequency,
&field_frequency_step,
&text_gain,
&field_gain,
&button_start,
@ -157,6 +159,10 @@ TransmitterView::TransmitterView(
if (on_edit_frequency)
on_edit_frequency();
};
field_frequency_step.on_change = [this](size_t, OptionsField::value_t v) {
this->field_frequency.set_step(v);
};
field_gain.on_change = [this](uint32_t tx_gain) {
on_tx_gain_changed(tx_gain);

View File

@ -124,11 +124,11 @@ private:
};
Text text_bw {
{ 11 * 8, 1 * 8, 9 * 8, 1 * 16 },
"BW: kHz"
{ 18 * 8, 1 * 8, 3 * 8, 1 * 16 },
"kHz"
};
NumberField field_bw {
{ 14 * 8, 1 * 8 },
{ 15 * 8, 1 * 8 },
3,
{ 1, 150 },
1,
@ -152,6 +152,10 @@ private:
{ 21 * 8, 1 * 8, 9 * 8, 32 },
"START"
};
FrequencyStepView field_frequency_step {
{ 10 * 8 - 4, 1 * 8 },
};
void on_tuning_frequency_changed(rf::Frequency f);
void on_channel_bandwidth_changed(uint32_t channel_bandwidth);

View File

@ -68,7 +68,7 @@
#include "ui_view_wav.hpp"
#include "ui_whipcalc.hpp"
#include "acars_app.hpp"
//#include "acars_app.hpp"
#include "ais_app.hpp"
#include "analog_audio_app.hpp"
#include "analog_tv_app.hpp"
@ -350,13 +350,21 @@ InformationView::InformationView(
});
version.set_style(&style_infobar);
ltime.set_hide_clock(portapack::persistent_memory::hide_clock());
ltime.set_style(&style_infobar);
ltime.set_seconds_enabled(true);
ltime.set_date_enabled(false);
ltime.set_date_enabled(portapack::persistent_memory::clock_with_date());
set_dirty();
}
void InformationView::refresh() {
ltime.set_hide_clock(portapack::persistent_memory::hide_clock());
ltime.set_seconds_enabled(true);
ltime.set_date_enabled(portapack::persistent_memory::clock_with_date());
}
/* Navigation ************************************************************/
bool NavigationView::is_top() const {
@ -387,6 +395,7 @@ void NavigationView::pop() {
update_view();
}
}
void NavigationView::pop_modal() {
@ -606,6 +615,7 @@ SystemView::SystemView(
}
else{
add_child(&info_view);
info_view.refresh();
}
this->status_view.set_back_enabled(!this->navigation_view.is_top());

View File

@ -212,7 +212,7 @@ private:
class InformationView : public View {
public:
InformationView(NavigationView& nav);
void refresh();
private:
static constexpr auto version_string = "v1.4.0";
NavigationView& nav_;
@ -228,8 +228,10 @@ private:
};
LiveDateTime ltime {
{174, 0, 8 * 8, 16}
{86, 0, 19 * 8, 16}
};
};
class BMPView : public View {

View File

@ -114,7 +114,7 @@ AM::AM() {
void AM::execute(const buffer_s16_t& audio, const buffer_c8_t& buffer) {
int32_t sample = 0;
int8_t re, im;
int8_t re = 0, im = 0;
float q = 0.0;
for (size_t counter = 0; counter < buffer.count; counter++) {
@ -125,8 +125,8 @@ void AM::execute(const buffer_s16_t& audio, const buffer_c8_t& buffer) {
q = sample / 32768.0f;
q *= 64.0f;
switch (mode) {
case Mode::AM: re = q + 20; im = q + 20;
case Mode::DSB: re = q; im = q;
case Mode::AM: re = q + 20; im = q + 20; break;
case Mode::DSB: re = q; im = q; break;
default: break;
}
buffer.p[counter] = { re, im };

View File

@ -141,12 +141,11 @@ bool APRSRxProcessor::parse_bit(const uint8_t current_bit){
uint8_t decoded_bit = ~(current_bit ^ last_bit) & 0x1;
last_bit = current_bit;
int16_t log = decoded_bit == 0 ? -32768 : 32767;
//if( stream ) {
// const size_t bytes_to_write = sizeof(log) * 1;
// const auto result = stream->write(&log, bytes_to_write);
// }
//int16_t log = decoded_bit == 0 ? -32768 : 32767;
//if(stream){
// const size_t bytes_to_write = sizeof(log) * 1;
// const auto result = stream->write(&log, bytes_to_write);
//}
if(decoded_bit & 0x1){
if(ones_count < 8){

View File

@ -26,9 +26,16 @@
#include "event_m4.hpp"
#include "audio_output.hpp"
SondeProcessor::SondeProcessor() {
decim_0.configure(taps_11k0_decim_0.taps, 33554432);
decim_1.configure(taps_11k0_decim_1.taps, 131072);
audio_output.configure(false);
tone_gen.configure(BEEP_BASE_FREQ, 1.0, ToneGen::tone_type::sine, AUDIO_SAMPLE_RATE);
}
void SondeProcessor::execute(const buffer_c8_t& buffer) {
@ -47,10 +54,97 @@ void SondeProcessor::execute(const buffer_c8_t& buffer) {
clock_recovery_fsk_4800(mf.get_output());
}
}
if(pitch_rssi_enabled) {
if(beep_play) {
// if we let the buffer underrun, for some reason
// once it starts looping it ignores zero (silence)
// samples, so we need to keep feeding the buffer
// and not be able to take advantage of the circular
// buffer loop:
//beep_play = false;
generate_beep();
}
if(silence_play) {
//silence_play = false;
generate_silence();
}
}
}
void SondeProcessor::on_message(const Message* const msg) {
switch(msg->id) {
case Message::ID::RequestSignal:
if ((*reinterpret_cast<const RequestSignalMessage*>(msg)).signal == RequestSignalMessage::Signal::BeepRequest) {
float rssi_ratio = (float) last_rssi / (float) RSSI_CEILING;
int beep_duration = 0;
if(rssi_ratio <= PROPORTIONAL_BEEP_THRES) {
beep_duration = BEEP_MIN_DURATION;
}
else if(rssi_ratio < 1) {
beep_duration = (int) rssi_ratio * BEEP_DURATION_RANGE + BEEP_MIN_DURATION;
}
else {
beep_duration = BEEP_DURATION_RANGE + BEEP_MIN_DURATION;
}
play_beep();
chThdSleepMilliseconds(beep_duration);
stop_beep();
}
break;
case Message::ID::PitchRSSIConfigure:
pitch_rssi_config(*reinterpret_cast<const PitchRSSIConfigureMessage*>(msg));
break;
default:
break;
}
}
void SondeProcessor::play_beep() {
beep_play = true;
silence_play = false;
}
void SondeProcessor::stop_beep() {
beep_play = false;
silence_play = true;
}
void SondeProcessor::generate_beep() {
// here we let the samples be created using the ToneGen class:
for(uint8_t i = 0; i < sizeof(audio_buffer.p); i++) {
audio_buffer.p[i] = (int16_t) ((tone_gen.process(0) >> 16) & 0x0000FFFF);
}
audio_output.write(audio_buffer);
}
void SondeProcessor::generate_silence() {
for(uint8_t i = 0; i < sizeof(audio_buffer.p); i++) {
audio_buffer.p[i] = 0;
}
audio_output.write(audio_buffer);
}
void SondeProcessor::pitch_rssi_config(const PitchRSSIConfigureMessage& message) {
pitch_rssi_enabled = message.enabled;
uint32_t freq = (int) ((float) message.rssi * (float) RSSI_PITCH_WEIGHT + (float) BEEP_BASE_FREQ);
last_rssi = message.rssi;
tone_gen.configure(freq, 1.0, ToneGen::tone_type::sine, AUDIO_SAMPLE_RATE);
}
int main() {
EventDispatcher event_dispatcher { std::make_unique<SondeProcessor>() };
event_dispatcher.run();
return 0;
}

View File

@ -88,19 +88,51 @@
#include "message.hpp"
#include "portapack_shared_memory.hpp"
#include "audio_output.hpp"
#include "tone_gen.hpp"
#include "buffer.hpp"
#include <cstdint>
#include <cstddef>
#include <bitset>
#define BEEP_MIN_DURATION 60
#define BEEP_DURATION_RANGE 100
#define BEEP_BASE_FREQ 200
#define RSSI_CEILING 1000
#define PROPORTIONAL_BEEP_THRES 0.8
#define RSSI_PITCH_WEIGHT 0.5
#define AUDIO_SAMPLE_RATE 24000
class SondeProcessor : public BasebandProcessor {
public:
SondeProcessor();
void execute(const buffer_c8_t& buffer) override;
void on_message(const Message* const msg);
private:
static constexpr size_t baseband_fs = 2457600;
std::array<int16_t, 32> audio { };
const buffer_s16_t audio_buffer {
(int16_t*) audio.data(),
sizeof(audio) / sizeof(int16_t)
};
AudioOutput audio_output { };
bool beep_play { false };
bool silence_play { false };
bool pitch_rssi_enabled { false };
uint32_t last_rssi { 0 };
ToneGen tone_gen { };
BasebandThread baseband_thread { baseband_fs, this, NORMALPRIO + 20, baseband::Direction::Receive };
RSSIThread rssi_thread { NORMALPRIO + 10 };
@ -149,6 +181,23 @@ private:
shared_memory.application_queue.push(message);
}
};
void play_beep();
void stop_beep();
/**
* Used for filling the audio buffer with the waveform
* generated by the ToneGen class:
*
*/
void generate_beep();
/**
* Used for filling the audio buffer with silence:
*/
void generate_silence();
void pitch_rssi_config(const PitchRSSIConfigureMessage& message);
};
#endif/*__PROC_ERT_H__*/

View File

@ -23,18 +23,56 @@
#include "tone_gen.hpp"
#include "sine_table_int8.hpp"
int32_t ToneGen::tone_sine() {
int32_t tone_sample = sine_table_i8[tone_phase_] * 0x1000000;
tone_phase_ += delta_;
return tone_sample;
}
int32_t ToneGen::tone_square() {
int32_t tone_sample = 0;
if(tone_phase_ < (UINT32_MAX / 2)) {
tone_sample = INT32_MAX;
}
else {
tone_sample = INT32_MIN;
}
tone_phase_ += delta_;
return tone_sample;
}
void ToneGen::configure(const uint32_t delta, const float tone_mix_weight) {
delta_ = delta;
delta_ = (uint8_t) ((delta & 0xFF000000U) >> 24);
tone_mix_weight_ = tone_mix_weight;
input_mix_weight_ = 1.0 - tone_mix_weight;
current_tone_type_ = sine;
}
void ToneGen::configure(const uint32_t freq, const float tone_mix_weight, const tone_type tone_type, const uint32_t sample_rate) {
delta_ = (uint8_t) ((freq * sizeof(sine_table_i8)) / sample_rate);
tone_mix_weight_ = tone_mix_weight;
input_mix_weight_ = 1.0 - tone_mix_weight;
current_tone_type_ = tone_type;
}
int32_t ToneGen::process(const int32_t sample_in) {
if (!delta_)
return sample_in;
int32_t tone_sample = sine_table_i8[(tone_phase_ & 0xFF000000U) >> 24];
tone_phase_ += delta_;
int32_t tone_sample = 0;
if(current_tone_type_ == sine) {
tone_sample = tone_sine();
}
else if(current_tone_type_ == square) {
tone_sample = tone_square();
}
return (sample_in * input_mix_weight_) + (tone_sample * tone_mix_weight_);
}

View File

@ -28,19 +28,36 @@
class ToneGen {
public:
enum tone_type { sine, square };
/*ToneGen(const size_t sample_rate
) : sample_rate_ { sample_rate }
{};*/
void configure(const uint32_t delta, const float tone_mix_weight);
void configure(const uint32_t freq, const float tone_mix_weight, const tone_type tone_type, const uint32_t sample_rate);
int32_t process(const int32_t sample_in);
private:
//size_t sample_rate_;
tone_type current_tone_type_ { sine };
float input_mix_weight_ { 1 };
float tone_mix_weight_ { 0 };
uint32_t delta_ { 0 };
uint32_t tone_phase_ { 0 };
uint8_t delta_ { 0 };
uint8_t tone_phase_ { 0 };
/**
* Generator function which selects every other sample from the reference sine waveform to the output sample:
*/
int32_t tone_sine();
/**
* Generator function for square waves:
*/
int32_t tone_square();
};
#endif
#endif /* __TONE_GEN_H__ */

View File

@ -141,7 +141,11 @@ float cpr_mod(float a, float b) {
return a - (b * floor(a / b));
}
int cpr_NL(float lat) {
int cpr_NL_precise(float lat) {
return (int) floor(2 * PI / acos(1 - ((1 - cos(PI / (2 * NZ))) / pow(cos(PI * lat / 180), 2))));
}
int cpr_NL_approx(float lat) {
if (lat < 0)
lat = -lat; // Symmetry
@ -150,7 +154,19 @@ int cpr_NL(float lat) {
return 59 - c;
}
return 1;
return 1;
}
int cpr_NL(float lat) {
// TODO prove that the approximate function is good
// enough for the precision we need. Uncomment if
// that is true. No performance penalty was noticed
// from testing, but if you find it might be an issue,
// switch to cpr_NL_approx() instead:
//return cpr_NL_approx(lat);
return cpr_NL_precise(lat);
}
int cpr_N(float lat, int is_odd) {
@ -185,18 +201,18 @@ void encode_frame_pos(ADSBFrame& frame, const uint32_t ICAO_address, const int32
// CPR encoding
// Info from: http://antena.fe.uni-lj.si/literatura/Razno/Avionika/modes/CPRencoding.pdf
delta_lat = 360.0 / ((4.0 * 15.0) - time_parity); // NZ = 15
yz = floor(131072.0 * (cpr_mod(latitude, delta_lat) / delta_lat) + 0.5);
rlat = delta_lat * ((yz / 131072.0) + floor(latitude / delta_lat));
delta_lat = 360.0 / ((4.0 * NZ) - time_parity); // NZ = 15
yz = floor(CPR_MAX_VALUE * (cpr_mod(latitude, delta_lat) / delta_lat) + 0.5);
rlat = delta_lat * ((yz / CPR_MAX_VALUE) + floor(latitude / delta_lat));
if ((cpr_NL(rlat) - time_parity) > 0)
delta_lon = 360.0 / cpr_N(rlat, time_parity);
else
delta_lon = 360.0;
xz = floor(131072.0 * (cpr_mod(longitude, delta_lon) / delta_lon) + 0.5);
xz = floor(CPR_MAX_VALUE * (cpr_mod(longitude, delta_lon) / delta_lon) + 0.5);
lat = cpr_mod(yz, 131072.0);
lon = cpr_mod(xz, 131072.0);
lat = cpr_mod(yz, CPR_MAX_VALUE);
lon = cpr_mod(xz, CPR_MAX_VALUE);
frame.push_byte((altitude_coded << 4) | ((uint32_t)time_parity << 2) | (lat >> 15)); // T = 0
frame.push_byte(lat >> 7);
@ -258,7 +274,7 @@ adsb_pos decode_frame_pos(ADSBFrame& frame_even, ADSBFrame& frame_odd) {
// Compute longitude
if (time_even > time_odd) {
// Use even frame
// Use even frame2
ni = cpr_N(latE, 0);
Dlon = 360.0 / ni;
@ -279,7 +295,7 @@ adsb_pos decode_frame_pos(ADSBFrame& frame_even, ADSBFrame& frame_odd) {
position.latitude = latO;
}
if (position.longitude > 180) position.longitude -= 360;
if (position.longitude >= 180) position.longitude -= 360;
position.valid = true;

View File

@ -83,6 +83,10 @@ const float adsb_lat_lut[58] = {
86.53536998, 87.00000000
};
const float PI = 3.14159265358979323846;
const float NZ = 15.0;
void make_frame_adsb(ADSBFrame& frame, const uint32_t ICAO_address);
void encode_frame_id(ADSBFrame& frame, const uint32_t ICAO_address, const std::string& callsign);

View File

@ -339,9 +339,9 @@ private:
std::string lat_str = "";
std::string lng_str = "";
bool is_north;
bool is_west;
uint8_t lng_offset;
bool is_north = false;
bool is_west = false;
uint8_t lng_offset = 0;
for(uint8_t i = DESTINATION_START; i < DESTINATION_START + ADDRESS_SIZE - 1; i++){
uint8_t ascii = payload[i] >> 1;

View File

@ -224,9 +224,17 @@ void set_playdead_sequence(const uint32_t new_value) {
// ui_config is an uint32_t var storing information bitwise
// bits 0,1,2 store the backlight timer
// bits 31, 30,29,28,27 stores the different single bit configs depicted below
// bits 31, 30,29,28,27, 26, 25 stores the different single bit configs depicted below
// bits on position 4 to 19 (16 bits) store the clkout frequency
bool hide_clock() { // clock hidden from main menu
return data->ui_config & (1 << 25);
}
bool clock_with_date() { // show clock with date, if not hidden
return data->ui_config & (1 << 26);
}
bool clkout_enabled() {
return data->ui_config & (1 << 27);
}
@ -251,6 +259,14 @@ uint32_t config_backlight_timer() {
return timer_seconds[data->ui_config & 7]; //first three bits, 8 possible values
}
void set_clock_hidden(bool v) {
data->ui_config = (data->ui_config & ~(1 << 25)) | (v << 25);
}
void set_clock_with_date(bool v) {
data->ui_config = (data->ui_config & ~(1 << 26)) | (v << 26);
}
void set_clkout_enabled(bool v) {
data->ui_config = (data->ui_config & ~(1 << 27)) | (v << 27);
}

View File

@ -75,11 +75,15 @@ bool stealth_mode();
void set_stealth_mode(const bool v);
bool config_splash();
bool hide_clock();
bool clock_with_date();
bool config_login();
bool config_speaker();
uint32_t config_backlight_timer();
void set_config_splash(bool v);
void set_clock_hidden(bool v);
void set_clock_with_date(bool v);
void set_config_login(bool v);
void set_config_speaker(bool v);
void set_config_backlight_timer(uint32_t i);

View File

@ -44,4 +44,5 @@ static const int8_t sine_table_i8[256] = {
-49, -46, -43, -40, -37, -34, -31, -28, -25, -22, -19, -16, -13, -9, -6, -3
};
#endif/*__SINE_TABLE_I8_H__*/

View File

@ -410,23 +410,29 @@ void Labels::paint(Painter& painter) {
void LiveDateTime::on_tick_second() {
rtcGetTime(&RTCD1, &datetime);
text = "";
if(date_enabled){
text = to_string_dec_uint(datetime.month(), 2, '0') + "/" + to_string_dec_uint(datetime.day(), 2, '0') + " ";
}
text = text + to_string_dec_uint(datetime.hour(), 2, '0') + ":" + to_string_dec_uint(datetime.minute(), 2, '0');
if(!hide_clock) {
if(date_enabled){
text = to_string_dec_uint(datetime.year(), 4, '0') + "-" +
to_string_dec_uint(datetime.month(), 2, '0') + "-" +
to_string_dec_uint(datetime.day(), 2, '0') + " ";
}
else{
text = " ";
}
text = text + to_string_dec_uint(datetime.hour(), 2, '0') + ":" + to_string_dec_uint(datetime.minute(), 2, '0');
if(seconds_enabled){
text += ":";
if(seconds_enabled){
text += ":";
if(init_delay==0)
text += to_string_dec_uint(datetime.second(), 2, '0');
else
{
// Placeholder while the seconds are not updated
text += "XX";
init_delay--;
if(init_delay==0)
text += to_string_dec_uint(datetime.second(), 2, '0');
else
{
// Placeholder while the seconds are not updated
text += "XX";
init_delay--;
}
}
}
set_dirty();
@ -459,6 +465,9 @@ void LiveDateTime::paint(Painter& painter) {
text
);
}
void LiveDateTime::set_hide_clock(bool new_value){
this->hide_clock = new_value;
}
void LiveDateTime::set_date_enabled(bool new_value){
this->date_enabled = new_value;

View File

@ -244,6 +244,7 @@ public:
void paint(Painter& painter) override;
void set_hide_clock(bool new_value);
void set_seconds_enabled(bool new_value);
void set_date_enabled(bool new_value);
@ -255,6 +256,7 @@ private:
void on_tick_second();
uint16_t init_delay = 4;
bool hide_clock = false;
bool date_enabled = true;
bool seconds_enabled = false;

46
sdcard/FREQMAN/GSM-NL.TXT Normal file
View File

@ -0,0 +1,46 @@
a=703000000,b=713000000,d=5G 700u Vodafone
a=713000000,b=723000000,d=5G 700u KPN
a=723000000,b=733000000,d=5G 700u T-Mobile
a=758000000,b=768000000,d=5G 700d Vodafone
a=768000000,b=778000000,d=5G 700d KPN
a=778000000,b=788000000,d=5G 700d T-Mobile
a=791000000,b=801000000,d=4G 800d T-Mobile
a=801000000,b=811000000,d=4G 800d Vodafone
a=811000000,b=821000000,d=4G 800d KPN
a=832000000,b=842000000,d=4G 800u T-Mobile
a=842000000,b=852000000,d=4G 800u Vodafone
a=852000000,b=862000000,d=4G 800u KPN
a=880000000,b=890000000,d=2G_3G 900u Vodafone
a=890000000,b=900000000,d=2G_3G 900u KPN
a=900000000,b=915000000,d=4G 900u T-Mobile
a=925000000,b=935000000,d=2G_3G 900d Vodafone
a=935000000,b=945000000,d=2G_3G 900d KPN
a=945000000,b=960000000,d=4G 900d T-Mobile
a=1452000000,b=1467000000,d=2G_3G 1400d Vodafone
a=1467000000,b=1482000000,d=2G_3G 1400d KPN
a=1482000000,b=1492000000,d=4G 1400d T-Mobile
a=1710000000,b=1730000000,d=4G 1800u KPN
a=1730000000,b=1750000000,d=4G 1800u Vodafone
a=1750000000,b=1780000000,d=4G 1800u T-Mobile
a=1805000000,b=1825000000,d=4G 1800d KPN
a=1825000000,b=1845000000,d=4G 1800d Vodafone
a=1845000000,b=1875000000,d=4G 1800d T-Mobile
a=1920000000,b=1940000000,d=3G_4G 2100u Vodafone
a=1940000000,b=1960000000,d=3G_4G 2100u T-Mobile
a=1960000000,b=1980000000,d=3G_4G 2100u KPN
a=2110000000,b=2130000000,d=3G_4G 2100d Vodafone
a=2130000000,b=2150000000,d=3G_4G 2100d T-Mobile
a=2150000000,b=2170000000,d=3G_4G 2100d KPN
a=2500000000,b=2510000000,d=LTE 2600u Vodafone
a=2510000000,b=2530000000,d=LTE 2600u Vodafone
a=2530000000,b=2535000000,d=LTE 2600u T-Mobile
a=2535000000,b=2545000000,d=LTE 2600u KPN
a=2545000000,b=2565000000,d=LTE 2600u T-Mobile
a=2565000000,b=2590000000,d=4G 2600d_u T-Mobile
a=2590000000,b=2620000000,d=4G 2600d_u KPN
a=2620000000,b=2630000000,d=LTE 2600d Vodafone
a=2630000000,b=2650000000,d=LTE 2600d Vodafone
a=2650000000,b=2655000000,d=LTE 2600d T-Mobile
a=2655000000,b=2665000000,d=LTE 2600d KPN
a=2665000000,b=2685000000,d=LTE 2600d T-Mobile
a=2685000000,b=2690000000,d=UNKNOWNd_u 2600 T-Mobile

7
sdcard/FREQMAN/ISM.TXT Normal file
View File

@ -0,0 +1,7 @@
f=13560000,d=Worldwide 13.56 MHz
f=27120000,d=Worldwide 27MHz
f=40660000,d=Worldwide 40MHz
f=433920000,d=ITU Reg 1 433 MHz
f=915000000,d=ITU Reg 2 915 MHz
f=2450000000,d=Worldwide 2.4 GHz
f=5800000000,d=Worldwide 5.8 GHz

View File

@ -0,0 +1,46 @@
f=400500000,d=AU SE
f=401000000,d=FR
f=401100000,d=CZ
f=401400000,d=FR
f=401500000,d=AU
f=401590000,d=FR
f=401600000,d=FR
f=402000000,d=BR FR GR IT RS
f=402010000,d=TR
f=402200000,d=GR
f=402500000,d=AU DE
f=402740000,d=GR
f=402790000,d=RS
f=402800000,d=GB IT RS
f=402870000,d=BE
f=403000000,d=BE BR CZ HU IE IT NL
f=403010000,d=DE NL TR
f=403150000,d=DE
f=403200000,d=HU
f=403500000,d=BE HU
f=403530000,d=BY
f=403600000,d=RO
f=403700000,d=BR GB
f=403820000,d=RO
f=403900000,d=NL
f=403920000,d=RO
f=403810000,d=DE
f=404000000,d=BR CZ ES IT US
f=404010000,d=US
f=404020000,d=US
f=404100000,d=GB
f=404300000,d=DE
f=404310000,d=DE
f=404380000,d=GB
f=404400000,d=GB
f=404710000,d=DE
f=404800000,d=IT
f=405000000,d=ES
f=405010000,d=FR
f=405030000,d=BY
f=405100000,d=GB
f=405300000,d=BY ES IE SE
f=405600000,d=GB
f=405680000,d=GB
f=405700000,d=DE GB
f=405900000,d=DE