diff --git a/firmware/application/CMakeLists.txt b/firmware/application/CMakeLists.txt
index dc9e41d5c6e5c88e11c99fffc2f6aafcdb7ac3d2..f551f676ce8fab64c024edb1f4f3d00ed7fbb36c 100644
--- a/firmware/application/CMakeLists.txt
+++ b/firmware/application/CMakeLists.txt
@@ -214,7 +214,7 @@ set(CPPSRC
 	ui/ui_tabview.cpp
 	ui/ui_textentry.cpp
 	ui/ui_transmitter.cpp
-	apps/ui_about.cpp
+	apps/ui_about_simple.cpp
 	apps/ui_adsb_rx.cpp
 	apps/ui_adsb_tx.cpp
 	apps/ui_afsk_rx.cpp
diff --git a/firmware/application/apps/ais_app.cpp b/firmware/application/apps/ais_app.cpp
index 89244e87e7da56524b517610222255423388a950..7d42be8606f74fa2a08824b08e5d087c2b242db0 100644
--- a/firmware/application/apps/ais_app.cpp
+++ b/firmware/application/apps/ais_app.cpp
@@ -240,7 +240,7 @@ AISRecentEntryDetailView::AISRecentEntryDetailView(NavigationView& nav) {
 
 void AISRecentEntryDetailView::update_position() {
 	if (send_updates)
-		geomap_view->update_position(ais::format::latlon_float(entry_.last_position.latitude.normalized()), ais::format::latlon_float(entry_.last_position.longitude.normalized()));
+		geomap_view->update_position(ais::format::latlon_float(entry_.last_position.latitude.normalized()), ais::format::latlon_float(entry_.last_position.longitude.normalized()), (float)entry_.last_position.true_heading);
 }
 
 void AISRecentEntryDetailView::focus() {
diff --git a/firmware/application/apps/analog_audio_app.cpp b/firmware/application/apps/analog_audio_app.cpp
index 4f3d724ab733f5aadc388b1ada54f8ce99d8ad75..b8d79e3ec51ab173dfcfc561270b6b3dd880dd24 100644
--- a/firmware/application/apps/analog_audio_app.cpp
+++ b/firmware/application/apps/analog_audio_app.cpp
@@ -83,6 +83,32 @@ NBFMOptionsView::NBFMOptionsView(
 	};
 }
 
+/* SPECOptionsView *******************************************************/
+
+SPECOptionsView::SPECOptionsView(
+	AnalogAudioView* view, const Rect parent_rect, const Style* const style
+) : View { parent_rect }
+{
+	set_style(style);
+
+	add_children({
+		&label_config,
+		&options_config,
+		&text_speed,
+		&field_speed
+	});
+
+	options_config.set_selected_index(view->get_spec_bw_index());
+	options_config.on_change = [this, view](size_t n, OptionsField::value_t bw) {
+		view->set_spec_bw(n, bw);
+	};
+
+	field_speed.set_value(view->get_spec_trigger());
+	field_speed.on_change = [this, view](int32_t v) {
+		view->set_spec_trigger(v);
+	};
+}
+
 /* AnalogAudioView *******************************************************/
 
 AnalogAudioView::AnalogAudioView(
@@ -157,6 +183,29 @@ AnalogAudioView::AnalogAudioView(
     on_modulation_changed(static_cast<ReceiverModel::Mode>(modulation));
 }
 
+size_t AnalogAudioView::get_spec_bw_index() {
+    return spec_bw_index;
+}
+
+void AnalogAudioView::set_spec_bw(size_t index, uint32_t bw) {
+    spec_bw_index = index;
+    spec_bw = bw;
+
+    baseband::set_spectrum(bw, spec_trigger);
+    receiver_model.set_sampling_rate(bw);
+    receiver_model.set_baseband_bandwidth(bw/2);
+}
+
+uint16_t AnalogAudioView::get_spec_trigger() {
+    return spec_trigger;
+}
+
+void AnalogAudioView::set_spec_trigger(uint16_t trigger) {
+    spec_trigger = trigger;
+
+    baseband::set_spectrum(spec_bw, spec_trigger);
+}
+
 AnalogAudioView::~AnalogAudioView() {
 	// TODO: Manipulating audio codec here, and in ui_receiver.cpp. Good to do
 	// both?
@@ -272,6 +321,7 @@ void AnalogAudioView::on_show_options_modulation() {
 		break;
 	
 	case ReceiverModel::Mode::SpectrumAnalysis:
+		widget = std::make_unique<SPECOptionsView>(this, nbfm_view_rect, &style_options_group);
 		waterfall.show_audio_spectrum_view(false);
 		text_ctcss.hidden(true);
 		break;
@@ -315,15 +365,17 @@ void AnalogAudioView::update_modulation(const ReceiverModel::Mode modulation) {
 	}
 
 	baseband::run_image(image_tag);
-	
+
 	if (modulation == ReceiverModel::Mode::SpectrumAnalysis) {
-		baseband::set_spectrum(20000000, 127);
+		baseband::set_spectrum(spec_bw, spec_trigger);
 	}
 
 	const auto is_wideband_spectrum_mode = (modulation == ReceiverModel::Mode::SpectrumAnalysis);
 	receiver_model.set_modulation(modulation);
-	receiver_model.set_sampling_rate(is_wideband_spectrum_mode ? 20000000 : 3072000);
-	receiver_model.set_baseband_bandwidth(is_wideband_spectrum_mode ? 12000000 : 1750000);
+
+	receiver_model.set_sampling_rate(is_wideband_spectrum_mode ? spec_bw : 3072000);
+	receiver_model.set_baseband_bandwidth(is_wideband_spectrum_mode ? spec_bw/2 : 1750000);
+
 	receiver_model.enable();
 
 	// TODO: This doesn't belong here! There's a better way.
diff --git a/firmware/application/apps/analog_audio_app.hpp b/firmware/application/apps/analog_audio_app.hpp
index 993e611e0ce9b535326ecf5fb103972672c61f8e..80f3bbe6dff648de6373ca7b04899707ae8f9659 100644
--- a/firmware/application/apps/analog_audio_app.hpp
+++ b/firmware/application/apps/analog_audio_app.hpp
@@ -94,6 +94,43 @@ private:
 	};
 };
 
+class AnalogAudioView;
+
+class SPECOptionsView : public View {
+public:
+	SPECOptionsView(AnalogAudioView* view, const Rect parent_rect, const Style* const style);
+
+private:
+	Text label_config {
+		{ 0 * 8, 0 * 16, 2 * 8, 1 * 16 },
+		"BW",
+	};
+	OptionsField options_config {
+		{ 3 * 8, 0 * 16 },
+		4,
+		{
+			{ "20m ", 20000000 },
+			{ "10m ", 10000000 },
+			{ " 5m ", 5000000 },
+			{ " 2m ", 2000000 },
+			{ " 1m ", 1000000 },
+			{ "500k", 500000 },
+		}
+	};
+	
+	Text text_speed {
+		{ 9 * 8, 0 * 16, 8 * 8, 1 * 16 },
+		"SP   /63"
+	};
+	NumberField field_speed {
+		{ 12 * 8, 0 * 16 },
+		2,
+		{ 0, 63 },
+		1,
+		' ',
+	};
+};
+
 class AnalogAudioView : public View {
 public:
 	AnalogAudioView(NavigationView& nav);
@@ -106,13 +143,23 @@ public:
 	void focus() override;
 
 	std::string title() const override { return "Analog audio"; };
-	
+
+	size_t get_spec_bw_index();
+	void set_spec_bw(size_t index, uint32_t bw);
+
+	uint16_t get_spec_trigger();
+	void set_spec_trigger(uint16_t trigger);
+
 private:
 	static constexpr ui::Dim header_height = 3 * 16;
 
 	const Rect options_view_rect { 0 * 8, 1 * 16, 30 * 8, 1 * 16 };
 	const Rect nbfm_view_rect { 0 * 8, 1 * 16, 18 * 8, 1 * 16 };
 
+	size_t spec_bw_index = 0;
+	uint32_t spec_bw = 20000000;
+	uint16_t spec_trigger = 63;
+
 	NavigationView& nav_;
 	//bool exit_on_squelch { false };
 	
diff --git a/firmware/application/apps/ui_about_simple.cpp b/firmware/application/apps/ui_about_simple.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..2c6f796ed8539e9ad1d171201499878ade3031c9
--- /dev/null
+++ b/firmware/application/apps/ui_about_simple.cpp
@@ -0,0 +1,75 @@
+#include "ui_about_simple.hpp"
+
+namespace ui
+{
+    AboutView::AboutView(NavigationView &nav)
+    {
+        add_children({&console, &button_ok});
+
+        button_ok.on_select = [&nav](Button &) {
+            nav.pop();
+        };
+
+        console.writeln("\x1B\x07List of contributors:\x1B\x10");
+        console.writeln("");
+    }
+
+    void AboutView::update()
+    {
+        if (++timer > 200)
+        {
+            timer = 0;
+
+            switch (++frame)
+            {
+            case 1:
+                // TODO: Generate this automatically from github
+                // https://github.com/eried/portapack-mayhem/graphs/contributors?to=2022-01-01&from=2020-04-12&type=c
+                console.writeln("\x1B\x06Mayhem:\x1B\x10");
+                console.writeln("eried,euquiq,gregoryfenton");
+                console.writeln("johnelder,jwetzell,nnemanjan00");
+                console.writeln("N0vaPixel,klockee,jamesshao8");
+                console.writeln("");
+                break;
+
+            case 2:
+                // https://github.com/eried/portapack-mayhem/graphs/contributors?to=2020-04-12&from=2015-07-31&type=c
+                console.writeln("\x1B\x06Havoc:\x1B\x10");
+                console.writeln("furrtek,mrmookie,notpike");
+                console.writeln("mjwaxios,ImDroided,Giorgiofox");
+                console.writeln("F4GEV,z4ziggy,xmycroftx");
+                console.writeln("troussos,silascutler");
+                console.writeln("nickbouwhuis,msoose,leres");
+                console.writeln("joakar,dhoetger,clem-42");
+                console.writeln("brianlechthaler,ZeroChaos-...");
+                console.writeln("");
+                break;
+
+            case 3:
+                // https://github.com/eried/portapack-mayhem/graphs/contributors?from=2014-07-05&to=2015-07-31&type=c
+                console.writeln("\x1B\x06PortaPack:\x1B\x10");
+                console.writeln("jboone,argilo");
+                console.writeln("");
+                break;
+
+            case 4:
+                // https://github.com/mossmann/hackrf/graphs/contributors
+                console.writeln("\x1B\x06HackRF:\x1B\x10");
+                console.writeln("mossmann,dominicgs,bvernoux");
+                console.writeln("bgamari,schneider42,miek");
+                console.writeln("willcode,hessu,Sec42");
+                console.writeln("yhetti,ckuethe,smunaut");
+                console.writeln("wishi,mrbubble62,scateu...");
+                console.writeln("");
+                frame = 0; // Loop
+                break;
+            }
+        }
+    }
+
+    void AboutView::focus()
+    {
+        button_ok.focus();
+    }
+
+} /* namespace ui */
\ No newline at end of file
diff --git a/firmware/application/apps/ui_about_simple.hpp b/firmware/application/apps/ui_about_simple.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..a059011907ec2d333436566a68c87764375e2095
--- /dev/null
+++ b/firmware/application/apps/ui_about_simple.hpp
@@ -0,0 +1,40 @@
+#ifndef __UI_ABOUT_SIMPLE_H__
+#define __UI_ABOUT_SIMPLE_H__
+
+#include "ui_widget.hpp"
+#include "ui_navigation.hpp"
+#include "ui_font_fixed_8x16.hpp"
+
+#include <cstdint>
+
+namespace ui
+{
+    class AboutView : public View
+    {
+    public:
+        AboutView(NavigationView &nav);
+        void focus() override;
+        std::string title() const override { return "About"; };
+        int32_t timer{180};
+        short frame{0};
+
+    private:
+        void update();
+
+        Console console{
+            {0, 10, 240, 240}};
+
+        Button button_ok{
+            {240/3, 270, 240/3, 24},
+            "OK",
+        };
+
+        MessageHandlerRegistration message_handler_update{
+            Message::ID::DisplayFrameSync,
+            [this](const Message *const) {
+                this->update();
+            }};
+    };
+} // namespace ui
+
+#endif /*__UI_ABOUT_SIMPLE_H__*/
diff --git a/firmware/application/apps/ui_adsb_rx.cpp b/firmware/application/apps/ui_adsb_rx.cpp
index 76d22730c68b46d06a8bf76fb30d1ad5538ad770..ba08048129954ea195b44a6f871a886666c79abd 100644
--- a/firmware/application/apps/ui_adsb_rx.cpp
+++ b/firmware/application/apps/ui_adsb_rx.cpp
@@ -92,12 +92,16 @@ void ADSBRxDetailsView::update(const AircraftRecentEntry& entry) {
 		text_last_seen.set(to_string_dec_uint(age / 60) + " minutes ago");
 	
 	text_infos.set(entry_copy.info_string);
-	
+	if(entry_copy.velo.heading < 360 && entry_copy.velo.speed >=0){ //I don't like this but...
+		text_info2.set("Hdg:" + to_string_dec_uint(entry_copy.velo.heading) + " Spd:" + to_string_dec_int(entry_copy.velo.speed));
+	}else{
+		text_info2.set("");
+	}
 	text_frame_pos_even.set(to_string_hex_array(entry_copy.frame_pos_even.get_raw_data(), 14));
 	text_frame_pos_odd.set(to_string_hex_array(entry_copy.frame_pos_odd.get_raw_data(), 14));
 	
 	if (send_updates)
-		geomap_view->update_position(entry_copy.pos.latitude, entry_copy.pos.longitude);
+		geomap_view->update_position(entry_copy.pos.latitude, entry_copy.pos.longitude, entry_copy.velo.heading);
 }
 
 ADSBRxDetailsView::~ADSBRxDetailsView() {
@@ -123,6 +127,7 @@ ADSBRxDetailsView::ADSBRxDetailsView(
 		&text_airline,
 		&text_country,
 		&text_infos,
+		&text_info2,
 		&text_frame_pos_even,
 		&text_frame_pos_odd,
 		&button_see_map
@@ -172,7 +177,7 @@ ADSBRxDetailsView::ADSBRxDetailsView(
 			GeoPos::alt_unit::FEET,
 			entry_copy.pos.latitude,
 			entry_copy.pos.longitude,
-			0,
+			entry_copy.velo.heading,
 			[this]() {
 				send_updates = false;
 			});
@@ -199,7 +204,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()) {
 		rtcGetTime(&RTCD1, &datetime);
 		auto& entry = ::on_packet(recent, ICAO_address);
@@ -214,6 +219,7 @@ void ADSBRxView::on_frame(const ADSBFrameMessage * message) {
 		
 		if (frame.get_DF() == DF_ADSB) {
 			uint8_t msg_type = frame.get_msg_type();
+			uint8_t msg_sub = frame.get_msg_sub();
 			uint8_t * raw_data = frame.get_raw_data();
 			
 			if ((msg_type >= 1) && (msg_type <= 4)) {
@@ -224,10 +230,10 @@ void ADSBRxView::on_frame(const ADSBFrameMessage * message) {
 				entry.set_frame_pos(frame, raw_data[6] & 4);
 				
 				if (entry.pos.valid) {
-					str_info = "Alt:" + to_string_dec_uint(entry.pos.altitude) +
-						" Lat" + to_string_dec_int(entry.pos.latitude) +
+					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) +
+						" 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);
@@ -236,6 +242,13 @@ void ADSBRxView::on_frame(const ADSBFrameMessage * message) {
 					if (send_updates)
 						details_view->update(entry);
 				}
+			} else if(msg_type == 19 && msg_sub >= 1 && msg_sub <= 4){
+				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)
+					details_view->update(entry);
 			}
 		}
 		recent_entries_view.set_dirty(); 
diff --git a/firmware/application/apps/ui_adsb_rx.hpp b/firmware/application/apps/ui_adsb_rx.hpp
index c0316623394bdbc794d3f6a9351aa7e7e3154312..dd7adb5a5d5d33b46b3d1c9ff3719cd3302b382b 100644
--- a/firmware/application/apps/ui_adsb_rx.hpp
+++ b/firmware/application/apps/ui_adsb_rx.hpp
@@ -49,7 +49,7 @@ struct AircraftRecentEntry {
 	uint16_t hits { 0 };
 	uint32_t age { 0 };
 	adsb_pos pos { false, 0, 0, 0 };
-	
+	adsb_vel velo { false, 0, 999 };
 	ADSBFrame frame_pos_even { };
 	ADSBFrame frame_pos_odd { };
 	
@@ -86,6 +86,10 @@ struct AircraftRecentEntry {
 				pos = decode_frame_pos(frame_pos_even, frame_pos_odd);
 		}
 	}
+
+	void set_frame_velo(ADSBFrame& frame){
+		velo = decode_frame_velo(frame);
+	}
 	
 	void set_info_string(std::string& new_info_string) {
 		info_string = new_info_string;
@@ -146,8 +150,8 @@ private:
 		{ { 0 * 8, 2 * 16 }, "Last seen:", Color::light_grey() },
 		{ { 0 * 8, 3 * 16 }, "Airline:", Color::light_grey() },
 		{ { 0 * 8, 5 * 16 }, "Country:", Color::light_grey() },
-		{ { 0 * 8, 12 * 16 }, "Even position frame:", Color::light_grey() },
-		{ { 0 * 8, 14 * 16 }, "Odd position frame:", Color::light_grey() }
+		{ { 0 * 8, 13 * 16 }, "Even position frame:", Color::light_grey() },
+		{ { 0 * 8, 15 * 16 }, "Odd position frame:", Color::light_grey() }
 	};
 	
 	Text text_callsign {
@@ -174,17 +178,23 @@ private:
 		{ 0 * 8, 6 * 16, 30 * 8, 16 },
 		"-"
 	};
+
+	Text text_info2 {
+		{0*8, 7*16, 30*8, 16},
+		"-"
+	};
+
 	Text text_frame_pos_even {
-		{ 0 * 8, 13 * 16, 30 * 8, 16 },
+		{ 0 * 8, 14 * 16, 30 * 8, 16 },
 		"-"
 	};
 	Text text_frame_pos_odd {
-		{ 0 * 8, 15 * 16, 30 * 8, 16 },
+		{ 0 * 8, 16 * 16, 30 * 8, 16 },
 		"-"
 	};
 	
 	Button button_see_map {
-		{ 8 * 8, 8 * 16, 14 * 8, 3 * 16 },
+		{ 8 * 8, 9 * 16, 14 * 8, 3 * 16 },
 		"See on map"
 	};
 };
diff --git a/firmware/application/apps/ui_debug.cpp b/firmware/application/apps/ui_debug.cpp
index 6d81f620f229e8a22c1250b7946daf8dfc114093..8622911c9f7f133fe3f8a049d91ed20006bf2835 100644
--- a/firmware/application/apps/ui_debug.cpp
+++ b/firmware/application/apps/ui_debug.cpp
@@ -121,7 +121,7 @@ void TemperatureWidget::paint(Painter& painter) {
 }
 
 TemperatureWidget::temperature_t TemperatureWidget::temperature(const sample_t sensor_value) const {
-	return -45 + sensor_value * 5;
+	return -35 + sensor_value * 4;  //max2837 datasheet temp 25ºC has sensor value: 15
 }
 
 std::string TemperatureWidget::temperature_str(const temperature_t temperature) const {
diff --git a/firmware/application/apps/ui_debug.hpp b/firmware/application/apps/ui_debug.hpp
index 6589969841b91d11ad411f7455c2d9b9a1d9378b..1e3d60035eba60a794ebcda613c2b624745ebbe9 100644
--- a/firmware/application/apps/ui_debug.hpp
+++ b/firmware/application/apps/ui_debug.hpp
@@ -101,10 +101,10 @@ private:
 
 	std::string temperature_str(const temperature_t temperature) const;
 
-	static constexpr temperature_t display_temp_min = 0;
+	static constexpr temperature_t display_temp_min = -10;  //Accomodate negative values, present in cold startup cases
 	static constexpr temperature_t display_temp_scale = 3;
 	static constexpr int bar_width = 1;
-	static constexpr int temp_len = 3;
+	static constexpr int temp_len = 4; //Now scale shows up to 4 chars ("-10C")
 };
 
 class TemperatureView : public View {
diff --git a/firmware/application/apps/ui_mictx.cpp b/firmware/application/apps/ui_mictx.cpp
index 8145b28eca4b82c81cf0095b8017ecb5e872aa0d..0d7b23672cd38f1b702bc23e2bc0c5108bdd5f10 100644
--- a/firmware/application/apps/ui_mictx.cpp
+++ b/firmware/application/apps/ui_mictx.cpp
@@ -61,22 +61,22 @@ void MicTXView::configure_baseband() {
 
 void MicTXView::set_tx(bool enable) {
 	if (enable) {
+		if (rx_enabled)  //If audio RX is enabled
+			rxaudio(false); //Then turn off audio RX
 		transmitting = true;
 		configure_baseband();
 		transmitter_model.enable();
 		portapack::pin_i2s0_rx_sda.mode(3);		// This is already done in audio::init but gets changed by the CPLD overlay reprogramming
-		//gpio_tx.write(1);
-		//led_tx.on();
 	} else {
 		if (transmitting && rogerbeep_enabled) {
-			baseband::request_beep();
-			transmitting = false;
-		} else {
+			baseband::request_beep();	//Transmit the roger beep
+			transmitting = false;		//And flag the end of the transmission so ...
+		} else { // (if roger beep was enabled, this will be executed after the beep ends transmitting.
 			transmitting = false;
 			configure_baseband();
 			transmitter_model.disable();
-			//gpio_tx.write(0);
-			//led_tx.off();
+			if (rx_enabled)  //If audio RX is enabled and we've been transmitting
+				rxaudio(true); //Turn back on audio RX
 		}
 	}
 }
@@ -120,6 +120,39 @@ void MicTXView::do_timing() {
 
 void MicTXView::on_tuning_frequency_changed(rf::Frequency f) {
 	transmitter_model.set_tuning_frequency(f);
+	//if ( rx_enabled )
+		receiver_model.set_tuning_frequency(f); //Update freq also for RX
+}
+
+void MicTXView::rxaudio(bool is_on) {
+	if (is_on) {
+		audio::input::stop();
+		baseband::shutdown();
+		baseband::run_image(portapack::spi_flash::image_tag_nfm_audio);
+		receiver_model.set_modulation(ReceiverModel::Mode::NarrowbandFMAudio);
+		receiver_model.set_sampling_rate(3072000);
+		receiver_model.set_baseband_bandwidth(1750000);	
+		receiver_model.set_tuning_frequency(field_frequency.value()); //probably this too can be commented out.
+		receiver_model.enable();
+		audio::output::start();
+	} else {	//These incredibly convoluted steps are required for the vumeter to reappear when stopping RX.
+		receiver_model.disable();
+		baseband::shutdown();
+		baseband::run_image(portapack::spi_flash::image_tag_mic_tx);
+		audio::input::start();
+		transmitter_model.enable();		
+		portapack::pin_i2s0_rx_sda.mode(3);
+		transmitting = false;
+		configure_baseband();
+		transmitter_model.disable();
+	}
+}
+
+void MicTXView::on_headphone_volume_changed(int32_t v) {
+	//if (rx_enabled) {
+		const auto new_volume = volume_t::decibel(v - 99) + audio::headphone::volume_range().max;
+		receiver_model.set_headphone_volume(new_volume);
+	//}
 }
 
 MicTXView::MicTXView(
@@ -142,9 +175,12 @@ MicTXView::MicTXView(
 		&field_frequency,
 		&options_tone_key,
 		&check_rogerbeep,
+		&check_rxactive,
+		&field_volume,
+		&field_squelch,
 		&text_ptt
 	});
-	
+
 	tone_keys_populate(options_tone_key);
 	options_tone_key.on_change = [this](size_t i, int32_t) {
 		tone_key_index = i;
@@ -168,6 +204,7 @@ MicTXView::MicTXView(
 		new_view->on_changed = [this](rf::Frequency f) {
 			this->on_tuning_frequency_changed(f);
 			this->field_frequency.set_value(f);
+			set_dirty();
 		};
 	};
 	
@@ -178,16 +215,15 @@ MicTXView::MicTXView(
 	
 	check_va.on_select = [this](Checkbox&, bool v) {
 		va_enabled = v;
-		text_ptt.hidden(v);
-		set_dirty();
+		text_ptt.hidden(v);			//hide / show PTT text
+		check_rxactive.hidden(v); 	//hide / show the RX AUDIO
+		set_dirty();				//Refresh display
 	};
-	check_va.set_value(false);
 	
 	check_rogerbeep.on_select = [this](Checkbox&, bool v) {
 		rogerbeep_enabled = v;
 	};
-	check_rogerbeep.set_value(false);
-	
+
 	field_va_level.on_change = [this](int32_t v) {
 		va_level = v;
 		vumeter.set_mark(v);
@@ -203,7 +239,24 @@ MicTXView::MicTXView(
 		decay_ms = v;
 	};
 	field_va_decay.set_value(1000);
-	
+
+	check_rxactive.on_select = [this](Checkbox&, bool v) {
+		//vumeter.set_value(0);	//Start with a clean vumeter
+		rx_enabled = v;
+		check_va.hidden(v); 	//Hide or show voice activation
+		rxaudio(v);				//Activate-Deactivate audio rx accordingly
+		set_dirty();			//Refresh interface
+	};
+
+	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);	};
+
+	field_squelch.on_change = [this](int32_t v) { 
+		receiver_model.set_squelch_level(100 - v);	
+	};
+	field_squelch.set_value(0);
+	receiver_model.set_squelch_level(0);
+
 	transmitter_model.set_sampling_rate(sampling_rate);
 	transmitter_model.set_baseband_bandwidth(1750000);
 	
@@ -216,6 +269,8 @@ MicTXView::MicTXView(
 MicTXView::~MicTXView() {
 	audio::input::stop();
 	transmitter_model.disable();
+	if (rx_enabled) //Also turn off audio rx if enabled
+		rxaudio(false);
 	baseband::shutdown();
 }
 
diff --git a/firmware/application/apps/ui_mictx.hpp b/firmware/application/apps/ui_mictx.hpp
index 4cebe343c7ca62f7cac5ce476d903f3f7fa83935..0f27206c2f288eefa04bbdadeeb80beb34297f9f 100644
--- a/firmware/application/apps/ui_mictx.hpp
+++ b/firmware/application/apps/ui_mictx.hpp
@@ -30,6 +30,7 @@
 #include "transmitter_model.hpp"
 #include "tone_key.hpp"
 #include "message.hpp"
+#include "receiver_model.hpp"
 
 namespace ui {
 
@@ -54,11 +55,11 @@ public:
 			return false;
 	};
 	
-	std::string title() const override { return "Microphone TX"; };
+	std::string title() const override { return "Mic TX RX"; };
 
 private:
 	static constexpr uint32_t sampling_rate = 1536000U;
-	static constexpr uint32_t lcd_frame_duration = (256 * 1000UL) / 60;	// 1 frame @ 60fps in ms .8 fixed point
+	static constexpr uint32_t lcd_frame_duration = (256 * 1000UL) / 60;	// 1 frame @ 60fps in ms .8 fixed point  /60
 	
 	void update_vumeter();
 	void do_timing();
@@ -66,10 +67,14 @@ private:
 	void on_tuning_frequency_changed(rf::Frequency f);
 	void on_tx_progress(const bool done);
 	void configure_baseband();
+
+	void rxaudio(bool is_on);
+	void on_headphone_volume_changed(int32_t v);
 	
 	bool transmitting { false };
-	bool va_enabled { };
-	bool rogerbeep_enabled { };
+	bool va_enabled { false };
+	bool rogerbeep_enabled { false };
+	bool rx_enabled { false };
 	uint32_t tone_key_index { };
 	float mic_gain { 1.0 };
 	uint32_t audio_level { 0 };
@@ -80,23 +85,25 @@ private:
 	uint32_t decay_timer { 0 };
 	
 	Labels labels {
-		{ { 7 * 8, 1 * 8 }, "Mic. gain:", Color::light_grey() },
-		{ { 7 * 8, 4 * 8 }, "Frequency:", Color::light_grey() },
-		{ { 7 * 8, 6 * 8 }, "Bandwidth:   kHz", Color::light_grey() },
-		{ { 9 * 8, 13 * 8 }, "Level:   /255", Color::light_grey() },
-		{ { 9 * 8, 15 * 8 }, "Attack:   ms", Color::light_grey() },
-		{ { 9 * 8, 17 * 8 }, "Decay:    ms", Color::light_grey() },
-		{ { 7 * 8, 21 * 8 }, "Tone key:", Color::light_grey() }
+		{ { 3 * 8, 1 * 8 }, "MIC. GAIN:", Color::light_grey() },
+		{ { 3 * 8, 3 * 8 }, "FREQUENCY:", Color::light_grey() },
+		{ { 3 * 8, 5 * 8 }, "BANDWIDTH:   kHz", Color::light_grey() },
+		{ { 7 * 8, 11 * 8 }, "LEVEL:   /255", Color::light_grey() },
+		{ { 6 * 8, 13 * 8 }, "ATTACK:   ms", Color::light_grey() },
+		{ { 7 * 8, 15 * 8 }, "DECAY:    ms", Color::light_grey() },
+		{ { 4 * 8, 18 * 8 }, "TONE KEY:", Color::light_grey() },
+		{ { 9 * 8, 30 * 8 }, "VOL:", Color::light_grey() },
+		{ { 5 * 8, 32 * 8 }, "SQUELCH:", Color::light_grey() }
 	};
 	
 	VuMeter vumeter {
-		{ 1 * 8, 2 * 8, 5 * 8, 32 * 8 },
-		20,
-		false
+		{ 0 * 8, 1 * 8, 2 * 8, 33 * 8 },
+		12,
+		true
 	};
 	
 	OptionsField options_gain {
-		{ 17 * 8, 1 * 8 },
+		{ 13 * 8, 1 * 8 },
 		4,
 		{
 			{ "x0.5", 5 },
@@ -107,10 +114,10 @@ private:
 	};
 	
 	FrequencyField field_frequency {
-		{ 17 * 8, 4 * 8 },
+		{ 13 * 8, 3 * 8 },
 	};
 	NumberField field_bw {
-		{ 17 * 8, 6 * 8 },
+		{ 13 * 8, 5 * 8 },
 		3,
 		{ 0, 150 },
 		1,
@@ -118,28 +125,28 @@ private:
 	};
 	
 	Checkbox check_va {
-		{ 7 * 8, 10 * 8 },
+		{ 3 * 8, (9 * 8) - 4 },
 		7,
 		"Voice activation",
 		false
 	};
 	
 	NumberField field_va_level {
-		{ 15 * 8, 13 * 8 },
+		{ 13 * 8, 11 * 8 },
 		3,
 		{ 0, 255 },
 		2,
 		' '
 	};
 	NumberField field_va_attack {
-		{ 16 * 8, 15 * 8 },
+		{ 13 * 8, 13 * 8 },
 		3,
 		{ 0, 999 },
 		20,
 		' '
 	};
 	NumberField field_va_decay {
-		{ 15 * 8, 17 * 8 },
+		{ 13 * 8, 15 * 8 },
 		4,
 		{ 0, 9999 },
 		100,
@@ -147,28 +154,52 @@ private:
 	};
 	
 	OptionsField options_tone_key {
-		{ 7 * 8, 23 * 8 },
+		{ 10 * 8, 20 * 8 },
 		23,
 		{ }
 	};
 
 	Checkbox check_rogerbeep {
-		{ 7 * 8, 26 * 8 },
+		{ 3 * 8, 23 * 8 },
 		10,
 		"Roger beep",
 		false
 	};
+
+	Checkbox check_rxactive {
+		{ 3 * 8, (27 * 8) + 4 },
+		8,
+		"RX audio listening",
+		false
+	};
+
+	NumberField field_volume {
+		{ 13 * 8, 30 * 8 },
+		2,
+		{ 0, 99 },
+		1,
+		' ',
+	};
 	
+	NumberField field_squelch {
+		{ 13 * 8, 32 * 8 },
+		2,
+		{ 0, 99 },
+		1,
+		' ',
+	};
+
 	Text text_ptt {
-		{ 7 * 8, 17 * 16, 16 * 8, 16 },
+		{ 7 * 8, 35 * 8, 16 * 8, 16 },
 		"PTT: RIGHT BUTTON"
 	};
-	
+
+
 	MessageHandlerRegistration message_handler_lcd_sync {
 		Message::ID::DisplayFrameSync,
 		[this](const Message* const) {
-			this->update_vumeter();
 			this->do_timing();
+			this->update_vumeter();
 		}
 	};
 	
diff --git a/firmware/application/apps/ui_scanner.cpp b/firmware/application/apps/ui_scanner.cpp
index 26c00728662ef863bf9d2b704c3c0fa8352feabd..65c4788df405e73767ce3a88861c27460c8bd19f 100644
--- a/firmware/application/apps/ui_scanner.cpp
+++ b/firmware/application/apps/ui_scanner.cpp
@@ -22,10 +22,6 @@
 
 #include "ui_scanner.hpp"
 
-#include "baseband_api.hpp"
-#include "string_format.hpp"
-#include "audio.hpp"
-
 using namespace portapack;
 
 namespace ui {
@@ -38,6 +34,10 @@ ScannerThread::ScannerThread(
 }
 
 ScannerThread::~ScannerThread() {
+	stop();
+}
+
+void ScannerThread::stop() {
 	if( thread ) {
 		chThdTerminate(thread);
 		chThdWait(thread);
@@ -49,6 +49,28 @@ void ScannerThread::set_scanning(const bool v) {
 	_scanning = v;
 }
 
+bool ScannerThread::is_scanning() {
+	return _scanning;
+}
+
+void ScannerThread::set_freq_lock(const uint32_t v) {
+	_freq_lock = v;
+}
+
+uint32_t ScannerThread::is_freq_lock() {
+	return _freq_lock;
+}
+
+void ScannerThread::set_freq_del(const uint32_t v) {
+	_freq_del = v;
+}
+
+void ScannerThread::change_scanning_direction() {
+	_fwd = !_fwd;
+	chThdSleepMilliseconds(300);	//Give some pause after reversing scanning direction
+
+}
+
 msg_t ScannerThread::static_fn(void* arg) {
 	auto obj = static_cast<ScannerThread*>(arg);
 	obj->run();
@@ -56,36 +78,78 @@ msg_t ScannerThread::static_fn(void* arg) {
 }
 
 void ScannerThread::run() {
-	RetuneMessage message { };
-	uint32_t frequency_index = 0;
-	
-	while( !chThdShouldTerminate() ) {
-		if (_scanning) {
-			// Retune
-			receiver_model.set_tuning_frequency(frequency_list_[frequency_index]);
-			
-			message.range = frequency_index;
-			EventDispatcher::send_message(message);
-			
-			
-			frequency_index++;
-			if (frequency_index >= frequency_list_.size())
-				frequency_index = 0;
+	if (frequency_list_.size())	{					//IF THERE IS A FREQUENCY LIST ...	
+		RetuneMessage message { };
+		uint32_t frequency_index = frequency_list_.size();
+		bool restart_scan = false;					//Flag whenever scanning is restarting after a pause
+		while( !chThdShouldTerminate() ) {
+			if (_scanning) {						//Scanning
+				if (_freq_lock == 0) {				//normal scanning (not performing freq_lock)
+					if (!restart_scan) {			//looping at full speed
+						if (_fwd) {					//forward
+							frequency_index++;
+							if (frequency_index >= frequency_list_.size())
+								frequency_index = 0;	
+
+						} else {					//reverse
+							if (frequency_index < 1)
+								frequency_index = frequency_list_.size();	
+							frequency_index--;
+						}
+						receiver_model.set_tuning_frequency(frequency_list_[frequency_index]);	// Retune
+					}
+					else
+						restart_scan=false;			//Effectively skipping first retuning, giving system time
+				} 
+				message.range = frequency_index;	//Inform freq (for coloring purposes also!)
+				EventDispatcher::send_message(message);
+			} 
+			else {									//NOT scanning 									
+				if (_freq_del != 0) {				//There is a frequency to delete
+					for (uint16_t i = 0; i < frequency_list_.size(); i++) {	//Search for the freq to delete
+						if (frequency_list_[i] == _freq_del) 
+						{							//found: Erase it
+							frequency_list_.erase(frequency_list_.begin() + i);
+							if (i==0)				//set scan index one place back to compensate
+								i=frequency_list_.size();
+							else
+								i--;
+							break;
+						}
+					}
+					_freq_del = 0;					//deleted.
+				}
+				else {
+					restart_scan=true;					//Flag the need for skipping a cycle when restarting scan
+				}
+			}
+			chThdSleepMilliseconds(50);				//Needed to (eventually) stabilize the receiver into new freq
 		}
-		
-		chThdSleepMilliseconds(50);
 	}
 }
 
 void ScannerView::handle_retune(uint32_t i) {
-	text_cycle.set(	to_string_dec_uint(i) + "/" +
-					to_string_dec_uint(frequency_list.size()) + " : " +
-					to_string_dec_uint(frequency_list[i]) );
-	desc_cycle.set( description_list[i] );
+	switch (scan_thread->is_freq_lock())
+	{
+	case 0:										//NO FREQ LOCK, ONGOING STANDARD SCANNING
+		text_cycle.set( to_string_dec_uint(i + 1,3) );
+		current_index = i;		//since it is an ongoing scan, this is a new index
+		if (description_list[current_index].size() > 0) desc_cycle.set( description_list[current_index] );	//Show new description	
+		break;
+	case 1:										//STARTING LOCK FREQ
+		big_display.set_style(&style_yellow);
+		break;
+	case MAX_FREQ_LOCK:							//FREQ IS STRONG: GREEN and scanner will pause when on_statistics_update()
+		big_display.set_style(&style_green);
+		break;
+	default:	//freq lock is checking the signal, do not update display
+		return;
+	}
+	big_display.set(frequency_list[current_index]);	//UPDATE the big Freq after 0, 1 or MAX_FREQ_LOCK (at least, for color synching)
 }
 
 void ScannerView::focus() {
-	field_lna.focus();
+	field_mode.focus();
 }
 
 ScannerView::~ScannerView() {
@@ -94,9 +158,20 @@ ScannerView::~ScannerView() {
 	baseband::shutdown();
 }
 
+void ScannerView::show_max() {		//show total number of freqs to scan
+	if (frequency_list.size() == MAX_DB_ENTRY) {
+		text_max.set_style(&style_red);
+		text_max.set( "/ " + to_string_dec_uint(MAX_DB_ENTRY) + " (DB MAX!)");
+	}
+	else {
+		text_max.set_style(&style_grey);
+		text_max.set( "/ " + to_string_dec_uint(frequency_list.size()));
+	}
+}
+
 ScannerView::ScannerView(
-	NavigationView&
-)
+	NavigationView& nav
+	) : nav_ { nav }
 {
 	add_children({
 		&labels,
@@ -105,110 +180,340 @@ ScannerView::ScannerView(
 		&field_rf_amp,
 		&field_volume,
 		&field_bw,
-		&field_trigger,
 		&field_squelch,
 		&field_wait,
-		//&record_view,
+		&rssi,
 		&text_cycle,
+		&text_max,
 		&desc_cycle,
-		//&waterfall,
+		&big_display,
+		&button_manual_start,
+		&button_manual_end,
+		&field_mode,
+		&step_mode,
+		&button_manual_scan,
+		&button_pause,
+		&button_dir,
+		&button_audio_app,
+		&button_mic_app,
+		&button_add,
+		&button_remove
+
 	});
 
-	std::string scanner_file = "SCANNER";
-	if (load_freqman_file(scanner_file, database)) {
-		for(auto& entry : database) {
-			// FIXME
-			if (entry.type == RANGE) {
-				for (uint32_t i=entry.frequency_a; i < entry.frequency_b; i+= 1000000) {
-					frequency_list.push_back(i);
-					description_list.push_back("RNG " + to_string_dec_uint(entry.frequency_a) + ">" + to_string_dec_uint(entry.frequency_b));
-				}
-			} else {
-				frequency_list.push_back(entry.frequency_a);
-				description_list.push_back(entry.description);
-			}
+	def_step = change_mode(AM);	//Start on AM
+	field_mode.set_by_value(AM);	//Reflect the mode into the manual selector
+
+	//HELPER: Pre-setting a manual range, based on stored frequency
+	rf::Frequency stored_freq = persistent_memory::tuned_frequency();
+	frequency_range.min = stored_freq - 1000000;
+	button_manual_start.set_text(to_string_short_freq(frequency_range.min));
+	frequency_range.max = stored_freq + 1000000;
+	button_manual_end.set_text(to_string_short_freq(frequency_range.max));
+
+	button_manual_start.on_select = [this, &nav](Button& button) {
+		auto new_view = nav_.push<FrequencyKeypadView>(frequency_range.min);
+		new_view->on_changed = [this, &button](rf::Frequency f) {
+			frequency_range.min = f;
+			button_manual_start.set_text(to_string_short_freq(f));
+		};
+	};
+	
+	button_manual_end.on_select = [this, &nav](Button& button) {
+		auto new_view = nav.push<FrequencyKeypadView>(frequency_range.max);
+		new_view->on_changed = [this, &button](rf::Frequency f) {
+			frequency_range.max = f;
+			button_manual_end.set_text(to_string_short_freq(f));
+		};
+	};
+
+	button_pause.on_select = [this](Button&) {
+		if ( userpause )
+			user_resume();
+		else {
+			scan_pause();
+			button_pause.set_text("RESUME");	//PAUSED, show resume
+			userpause=true;
 		}
-	} else {
-		// DEBUG
-		// TODO: Clean this
-		frequency_list.push_back(466025000);
-		description_list.push_back("POCSAG-France");
-		frequency_list.push_back(466050000);
-		description_list.push_back("POCSAG-France");
-		frequency_list.push_back(466075000);
-		description_list.push_back("POCSAG-France");
-		frequency_list.push_back(466175000);
-		description_list.push_back("POCSAG-France");
-		frequency_list.push_back(466206250);
-		description_list.push_back("POCSAG-France");
-		frequency_list.push_back(466231250);
-		description_list.push_back("POCSAG-France");
-	}
+	};
 
-	field_bw.set_selected_index(2);
-	field_bw.on_change = [this](size_t n, OptionsField::value_t) {
-		receiver_model.set_nbfm_configuration(n);
+	button_audio_app.on_select = [this](Button&) {
+		scan_thread->stop();
+		nav_.pop();
+		nav_.push<AnalogAudioView>();
 	};
 
-	field_wait.on_change = [this](int32_t v) {
-		wait = v;
+	button_mic_app.on_select = [this](Button&) {
+		scan_thread->stop();
+		nav_.pop();
+		nav_.push<MicTXView>();
 	};
-	field_wait.set_value(5);
 
-	field_trigger.on_change = [this](int32_t v) {
-		trigger = v;
+	button_remove.on_select = [this](Button&) {
+		if (frequency_list.size() > current_index) {
+			if (scan_thread->is_scanning())			//STOP Scanning if necessary
+				scan_thread->set_scanning(false);
+			scan_thread->set_freq_del(frequency_list[current_index]);
+			description_list.erase(description_list.begin() + current_index);
+			frequency_list.erase(frequency_list.begin() + current_index);
+			show_max();								//UPDATE new list size on screen
+			desc_cycle.set(" ");					//Clean up description (cosmetic detail)
+			scan_thread->set_freq_lock(0); 			//Reset the scanner lock
+			if ( userpause ) 						//If user-paused, resume
+				user_resume();
+		}
 	};
-	field_trigger.set_value(30);
-	
-	field_squelch.set_value(receiver_model.squelch_level());
-	field_squelch.on_change = [this](int32_t v) {
-		squelch = v;
-		receiver_model.set_squelch_level(v);
+
+	button_manual_scan.on_select = [this](Button&) {
+		if (!frequency_range.min || !frequency_range.max) {
+			nav_.display_modal("Error", "Both START and END freqs\nneed a value");
+		} else if (frequency_range.min > frequency_range.max) {
+			nav_.display_modal("Error", "END freq\nis lower than START");
+		} else {
+		audio::output::stop();
+		scan_thread->stop();	//STOP SCANNER THREAD
+		frequency_list.clear();
+		description_list.clear();
+		def_step = step_mode.selected_index_value();		//Use def_step from manual selector
+
+		description_list.push_back(
+			"M:" + to_string_short_freq(frequency_range.min) + " >"
+	 		+ to_string_short_freq(frequency_range.max) + " S:" 
+	 		+ to_string_short_freq(def_step)
+		);
+
+		rf::Frequency frequency = frequency_range.min;
+		while (frequency_list.size() < MAX_DB_ENTRY &&  frequency <= frequency_range.max) { //add manual range				
+			frequency_list.push_back(frequency);
+			description_list.push_back("");				//If empty, will keep showing the last description
+			frequency+=def_step;
+		}
+		show_max();
+		if ( userpause ) 						//If user-paused, resume
+			user_resume();
+		big_display.set_style(&style_grey);		//Back to grey color
+		start_scan_thread(); //RESTART SCANNER THREAD
+		}
 	};
 
+	field_mode.on_change = [this](size_t, OptionsField::value_t v) {
+		receiver_model.disable();
+		baseband::shutdown();
+		change_mode(v);
+		if ( !scan_thread->is_scanning() ) 						//for some motive, audio output gets stopped.
+			audio::output::start();								//So if scan was stopped we resume audio
+		receiver_model.enable(); 
+	};
 
-	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);
+	button_dir.on_select = [this](Button&) {
+		scan_thread->change_scanning_direction();
+		if ( userpause ) 						//If user-paused, resume
+			user_resume();
+		big_display.set_style(&style_grey);		//Back to grey color
 	};
-	
-	audio::output::start();
-	
-	audio::output::mute();
-	baseband::run_image(portapack::spi_flash::image_tag_nfm_audio);
-	receiver_model.set_modulation(ReceiverModel::Mode::NarrowbandFMAudio);
-	receiver_model.set_sampling_rate(3072000);
-	receiver_model.set_baseband_bandwidth(1750000);
-	receiver_model.enable();
-	receiver_model.set_squelch_level(0);
-	receiver_model.set_nbfm_configuration(field_bw.selected_index());
-	audio::output::unmute();
-	
-	// TODO: Scanning thread here
-	scan_thread = std::make_unique<ScannerThread>(frequency_list);
+
+	button_add.on_select = [this](Button&) {  //frequency_list[current_index]
+		File scanner_file;
+		auto result = scanner_file.open("FREQMAN/SCANNER.TXT");	//First search if freq is already in txt
+		if (!result.is_valid()) {
+			std::string frequency_to_add = "f=" 
+				+ to_string_dec_uint(frequency_list[current_index] / 1000) 
+				+ to_string_dec_uint(frequency_list[current_index] % 1000UL, 3, '0');
+			char one_char[1];		//Read it char by char
+			std::string line;		//and put read line in here
+			bool found=false;
+			for (size_t pointer=0; pointer < scanner_file.size();pointer++) {
+
+				scanner_file.seek(pointer);
+				scanner_file.read(one_char, 1);
+				if ((int)one_char[0] > 31) {			//ascii space upwards
+					line += one_char[0];				//Add it to the textline
+				}
+				else if (one_char[0] == '\n') {			//New Line
+					if (line.compare(0, frequency_to_add.size(),frequency_to_add) == 0) {
+						found=true;
+						break;
+					}
+					line.clear();						//Ready for next textline
+				}
+			}
+			if (found) {
+				nav_.display_modal("Error", "Frequency already exists");
+				big_display.set(frequency_list[current_index]);		//After showing an error
+			}
+			else {
+				auto result = scanner_file.append("FREQMAN/SCANNER.TXT"); //Second: append if it is not there
+				scanner_file.write_line(frequency_to_add + ",d=ADD FQ");
+			}
+		} else
+		{
+			nav_.display_modal("Error", "Cannot open SCANNER.TXT\nfor appending freq.");
+			big_display.set(frequency_list[current_index]);		//After showing an error
+		}
+	};
+
+	//PRE-CONFIGURATION:
+	field_wait.on_change = [this](int32_t v) {	wait = v;	}; 	field_wait.set_value(5);
+	field_squelch.on_change = [this](int32_t v) {	squelch = v;	}; 	field_squelch.set_value(-10);
+	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);	};
+	// LEARN FREQUENCIES
+	std::string scanner_txt = "SCANNER";
+	if ( load_freqman_file(scanner_txt, database)  ) {
+		for(auto& entry : database) {									// READ LINE PER LINE
+			if (frequency_list.size() < MAX_DB_ENTRY) {					//We got space!
+				if (entry.type == RANGE)  {								//RANGE	
+					switch (entry.step) {
+					case AM_US:	def_step = 10000;  	break ;
+					case AM_EUR:def_step = 9000;  	break ;
+					case NFM_1: def_step = 12500;  	break ;
+					case NFM_2: def_step = 6250;	break ;	
+					case FM_1:	def_step = 100000; 	break ;
+					case FM_2:	def_step = 50000; 	break ;
+					case N_1:	def_step = 25000;  	break ;
+					case N_2:	def_step = 250000; 	break ;
+					case AIRBAND:def_step= 8330;  	break ;
+					}
+					frequency_list.push_back(entry.frequency_a);		//Store starting freq and description
+					description_list.push_back("R:" + to_string_short_freq(entry.frequency_a)
+						+ " >" + to_string_short_freq(entry.frequency_b)
+						+ " S:" + to_string_short_freq(def_step));
+					while (frequency_list.size() < MAX_DB_ENTRY && entry.frequency_a <= entry.frequency_b) { //add the rest of the range
+						entry.frequency_a+=def_step;
+						frequency_list.push_back(entry.frequency_a);
+						description_list.push_back("");				//Token (keep showing the last description)
+					}
+				} else if ( entry.type == SINGLE)  {
+					frequency_list.push_back(entry.frequency_a);
+					description_list.push_back("S: " + entry.description);
+				}
+				show_max();
+			}
+			else
+			{
+				break; //No more space: Stop reading the txt file !
+			}		
+		}
+	} 
+	else 
+	{
+		desc_cycle.set(" NO SCANNER.TXT FILE ..." );
+	}
+	audio::output::stop();
+	step_mode.set_by_value(def_step); //Impose the default step into the manual step selector
+	start_scan_thread();
 }
 
 void ScannerView::on_statistics_update(const ChannelStatistics& statistics) {
-	int32_t max_db = statistics.max_db;
-	
-	if (timer <= wait)
-		timer++;
-	
-	if (max_db < -trigger) {
-		if (timer == wait) {
-			//audio::output::stop();
-			scan_thread->set_scanning(true);
+	if ( !userpause ) 									//Scanning not user-paused
+	{
+		if (timer >= (wait * 10) ) 
+		{
+			timer = 0;
+			scan_resume();
+		} 
+		else if (!timer) 
+		{
+			if (statistics.max_db > squelch ) {  		//There is something on the air...(statistics.max_db > -squelch) 
+				if (scan_thread->is_freq_lock() >= MAX_FREQ_LOCK) { //checking time reached
+					scan_pause();
+					timer++;	
+				} else {
+					scan_thread->set_freq_lock( scan_thread->is_freq_lock() + 1 ); //in lock period, still analyzing the signal
+				}
+			} else {									//There is NOTHING on the air
+				if (scan_thread->is_freq_lock() > 0) {	//But are we already in freq_lock ?
+					big_display.set_style(&style_grey);	//Back to grey color
+					scan_thread->set_freq_lock(0); 		//Reset the scanner lock, since there is no signal
+				}				
+			}
+		} 
+		else 	//Ongoing wait time
+		{
+				timer++;
 		}
-	} else {
-		//audio::output::start();
-		scan_thread->set_scanning(false);
-		timer = 0;
 	}
 }
 
+void ScannerView::scan_pause() {
+	if (scan_thread->is_scanning()) {
+		scan_thread->set_freq_lock(0); 		//Reset the scanner lock (because user paused, or MAX_FREQ_LOCK reached) for next freq scan	
+		scan_thread->set_scanning(false); // WE STOP SCANNING
+		audio::output::start();
+	}
+}
+
+void ScannerView::scan_resume() {
+	audio::output::stop();
+	big_display.set_style(&style_grey);		//Back to grey color
+	if (!scan_thread->is_scanning())
+		scan_thread->set_scanning(true);   // RESUME!
+}
+
+void ScannerView::user_resume() {
+	timer = wait * 10;					//Will trigger a scan_resume() on_statistics_update, also advancing to next freq.
+	button_pause.set_text("PAUSE");		//Show button for pause
+	userpause=false;					//Resume scanning
+}
+
 void ScannerView::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);
 }
 
-} /* namespace ui */
+size_t ScannerView::change_mode(uint8_t new_mod) { //Before this, do a scan_thread->stop();  After this do a start_scan_thread()
+	using option_t = std::pair<std::string, int32_t>;
+	using options_t = std::vector<option_t>;
+	options_t bw;
+	field_bw.on_change = [this](size_t n, OptionsField::value_t) {	};
+
+	switch (new_mod) {
+	case NFM:	//bw 16k (2) default
+		bw.emplace_back("8k5", 0);
+		bw.emplace_back("11k", 0);
+		bw.emplace_back("16k", 0);			
+		field_bw.set_options(bw);
+
+		baseband::run_image(portapack::spi_flash::image_tag_nfm_audio);
+		receiver_model.set_modulation(ReceiverModel::Mode::NarrowbandFMAudio);
+		field_bw.set_selected_index(2);
+		receiver_model.set_nbfm_configuration(field_bw.selected_index());
+		field_bw.on_change = [this](size_t n, OptionsField::value_t) { 	receiver_model.set_nbfm_configuration(n); };
+		receiver_model.set_sampling_rate(3072000);	receiver_model.set_baseband_bandwidth(1750000);	
+		break;
+	case AM:
+		bw.emplace_back("DSB", 0);
+		bw.emplace_back("USB", 0);
+		bw.emplace_back("LSB", 0);
+		field_bw.set_options(bw);
+
+		baseband::run_image(portapack::spi_flash::image_tag_am_audio);
+		receiver_model.set_modulation(ReceiverModel::Mode::AMAudio);
+		field_bw.set_selected_index(0);
+		receiver_model.set_am_configuration(field_bw.selected_index());
+		field_bw.on_change = [this](size_t n, OptionsField::value_t) { receiver_model.set_am_configuration(n);	};		
+		receiver_model.set_sampling_rate(2000000);receiver_model.set_baseband_bandwidth(2000000); 
+		break;
+	case WFM:
+		bw.emplace_back("16k", 0);
+		field_bw.set_options(bw);
+
+		baseband::run_image(portapack::spi_flash::image_tag_wfm_audio);
+		receiver_model.set_modulation(ReceiverModel::Mode::WidebandFMAudio);
+		field_bw.set_selected_index(0);
+		receiver_model.set_wfm_configuration(field_bw.selected_index());
+		field_bw.on_change = [this](size_t n, OptionsField::value_t) {	receiver_model.set_wfm_configuration(n); };
+		receiver_model.set_sampling_rate(3072000);	receiver_model.set_baseband_bandwidth(2000000);	
+		break;
+	}
+
+	return mod_step[new_mod];
+}
+
+void ScannerView::start_scan_thread() {
+	receiver_model.enable(); 
+	receiver_model.set_squelch_level(0);
+	scan_thread = std::make_unique<ScannerThread>(frequency_list);
+}
+
+} /* namespace ui */
\ No newline at end of file
diff --git a/firmware/application/apps/ui_scanner.hpp b/firmware/application/apps/ui_scanner.hpp
index b5d17c228a0347c2d769c2e92f23d00cc13040d2..d2befbfe9fdf876d7ef97353c34610e89c8022a5 100644
--- a/firmware/application/apps/ui_scanner.hpp
+++ b/firmware/application/apps/ui_scanner.hpp
@@ -20,20 +20,46 @@
  * Boston, MA 02110-1301, USA.
  */
 
+#include "ui.hpp"
 #include "receiver_model.hpp"
-
 #include "ui_receiver.hpp"
 #include "ui_font_fixed_8x16.hpp"
 #include "freqman.hpp"
+#include "analog_audio_app.hpp"
+#include "audio.hpp"
+#include "ui_mictx.hpp"
+#include "portapack_persistent_memory.hpp"
+#include "baseband_api.hpp"
+#include "string_format.hpp"
+#include "file.hpp"
+
+
+#define MAX_DB_ENTRY 500
+#define MAX_FREQ_LOCK 10 		//50ms cycles scanner locks into freq when signal detected, to verify signal is not spureous
 
 namespace ui {
 
+enum modulation_type { AM = 0,WFM,NFM };
+	
+string const mod_name[3] = {"AM", "WFM", "NFM"};
+size_t const mod_step[3] = {9000, 100000, 12500 };
+
 class ScannerThread {
 public:
 	ScannerThread(std::vector<rf::Frequency> frequency_list);
 	~ScannerThread();
-	
+
 	void set_scanning(const bool v);
+	bool is_scanning();
+
+	void set_freq_lock(const uint32_t v);
+	uint32_t is_freq_lock();
+
+	void set_freq_del(const uint32_t v);
+
+	void change_scanning_direction();
+
+	void stop();
 
 	ScannerThread(const ScannerThread&) = delete;
 	ScannerThread(ScannerThread&&) = delete;
@@ -45,38 +71,81 @@ private:
 	Thread* thread { nullptr };
 	
 	bool _scanning { true };
-
+	bool _fwd { true };
+	uint32_t _freq_lock { 0 };
+	uint32_t _freq_del { 0 };
 	static msg_t static_fn(void* arg);
-	
 	void run();
 };
 
 class ScannerView : public View {
 public:
-	ScannerView(NavigationView&);
+	ScannerView(NavigationView& nav);
 	~ScannerView();
 	
 	void focus() override;
+
+	void big_display_freq(rf::Frequency f);
+
+	const Style style_grey {		// scanning
+		.font = font::fixed_8x16,
+		.background = Color::black(),
+		.foreground = Color::grey(),
+	};
 	
-	std::string title() const override { return "Scanner"; };
+	const Style style_yellow {		//Found signal
+		.font = font::fixed_8x16,
+		.background = Color::black(),
+		.foreground = Color::dark_yellow(),
+	};
+
+	const Style style_green {		//Found signal
+		.font = font::fixed_8x16,
+		.background = Color::black(),
+		.foreground = Color::green(),
+	};
+
+	const Style style_red {		//erasing freq
+		.font = font::fixed_8x16,
+		.background = Color::black(),
+		.foreground = Color::red(),
+	};
+
+	std::string title() const override { return "SCANNER"; };
+	std::vector<rf::Frequency> frequency_list{ };
+	std::vector<string> description_list { };
+
+//void set_parent_rect(const Rect new_parent_rect) override;
 
 private:
+	NavigationView& nav_;
+
+	void start_scan_thread();
+	size_t change_mode(uint8_t mod_type);
+	void show_max();
+	void scan_pause();
+	void scan_resume();
+	void user_resume();
+
 	void on_statistics_update(const ChannelStatistics& statistics);
 	void on_headphone_volume_changed(int32_t v);
 	void handle_retune(uint32_t i);
-	
-	std::vector<rf::Frequency> frequency_list { };
-	std::vector<string> description_list { };
-	int32_t trigger { 0 };
+
+	jammer::jammer_range_t frequency_range { false, 0, 0 };  //perfect for manual scan task too...
 	int32_t squelch { 0 };
 	uint32_t timer { 0 };
 	uint32_t wait { 0 };
+	size_t	def_step { 0 };
 	freqman_db database { };
+	uint32_t current_index { 0 };
+	bool userpause { false };
 	
 	Labels labels {
-		{ { 0 * 8, 0 * 16 }, "LNA:    TRIGGER:  /99   VOL:", Color::light_grey() },
-		{ { 0 * 8, 1 * 16 }, "VGA:    SQUELCH:  /99   AMP:", Color::light_grey() },
-		{ { 0 * 8, 2 * 16 }, " BW:       WAIT:", Color::light_grey() },
+		{ { 0 * 8, 0 * 16 }, "LNA:   VGA:   AMP:  VOL:", Color::light_grey() },
+		{ { 0 * 8, 1* 16 }, "BW:    SQUELCH:   db WAIT:", Color::light_grey() },
+		{ { 3 * 8, 10 * 16 }, "START        END     MANUAL", Color::light_grey() },
+		{ { 0 * 8, (26 * 8) + 4 }, "MODE:", Color::light_grey() },
+		{ { 11 * 8, (26 * 8) + 4 }, "STEP:", Color::light_grey() },
 	};
 	
 	LNAGainField field_lna {
@@ -84,15 +153,15 @@ private:
 	};
 
 	VGAGainField field_vga {
-		{ 4 * 8, 1 * 16 }
+		{ 11 * 8, 0 * 16 }
 	};
 	
 	RFAmpField field_rf_amp {
-		{ 28 * 8, 1 * 16 }
+		{ 18 * 8, 0 * 16 }
 	};
 	
 	NumberField field_volume {
-		{ 28 * 8, 0 * 16 },
+		{ 24 * 8, 0 * 16 },
 		2,
 		{ 0, 99 },
 		1,
@@ -100,46 +169,118 @@ private:
 	};
 
 	OptionsField field_bw {
-		{ 4 * 8, 2 * 16 },
-		3,
-		{
-			{ "8k5", 0 },
-			{ "11k", 0 },
-			{ "16k", 0 },
-		}
-	};
+		{ 3 * 8, 1 * 16 },
+		4,
+		{ }
+	};		
 
-	NumberField field_trigger {
-		{ 16 * 8, 0 * 16 },
-		2,
-		{ 0, 99 },
-		1,
-		' ',
-	};
-	
 	NumberField field_squelch {
-		{ 16 * 8, 1 * 16 },
-		2,
-		{ 0, 99 },
+		{ 15 * 8, 1 * 16 },
+		3,
+ 		{ -90, 20 },
 		1,
 		' ',
 	};
 
 	NumberField field_wait {
-		{ 16 * 8, 2 * 16 },
+		{ 26 * 8, 1 * 16 },
 		2,
 		{ 0, 99 },
 		1,
 		' ',
 	};
 
+	RSSI rssi {
+		{ 0 * 16, 2 * 16, 15 * 16, 8 },
+	}; 
+
 	Text text_cycle {
-		{ 0, 5 * 16, 240, 16 },
-		"--/--"
+		{ 0, 3 * 16, 3 * 8, 16 },  
+	};
+
+	Text text_max {
+		{ 4 * 8, 3 * 16, 18 * 8, 16 },  
 	};
+	
 	Text desc_cycle {
-		{0, 6 * 16, 240, 16 },
-		" "
+		{0, 4 * 16, 240, 16 },	   
+	};
+
+	BigFrequency big_display {		//Show frequency in glamour
+		{ 4, 6 * 16, 28 * 8, 52 },
+		0
+	};
+
+	Button button_manual_start {
+		{ 0 * 8, 11 * 16, 11 * 8, 28 },
+		""
+	};
+
+	Button button_manual_end {
+		{ 12 * 8, 11 * 16, 11 * 8, 28 },
+		""
+	};
+
+	Button button_manual_scan {
+		{ 24 * 8, 11 * 16, 6 * 8, 28 },
+		"SCAN"
+	};
+
+	OptionsField field_mode {
+		{ 5 * 8, (26 * 8) + 4 },
+		6,
+		{
+			{ " AM  ", 0 },
+			{ " WFM ", 1 },
+			{ " NFM ", 2 },
+		}
+	};
+
+	OptionsField step_mode {
+		{ 17 * 8, (26 * 8) + 4 },
+		12,
+		{
+			{ "5Khz (SA AM)", 	5000 },
+			{ "9Khz (EU AM)", 	9000 },
+			{ "10Khz(US AM)", 	10000 },
+			{ "50Khz (FM1)", 	50000 },
+			{ "100Khz(FM2)", 	100000 },
+			{ "6.25khz(NFM)",	6250 },
+			{ "12.5khz(NFM)",	12500 },
+			{ "25khz (N1)",		25000 },
+			{ "250khz (N2)",	250000 },
+			{ "8.33khz(AIR)",	8330 }
+		}
+	};
+
+	Button button_pause {
+		{ 0, (15 * 16) - 4, 72, 28 },
+		"PAUSE"
+	};
+
+	Button button_dir {
+		{ 0,  (35 * 8) - 4, 72, 28 },
+		"FW><RV"
+	};
+
+	Button button_audio_app {
+		{ 84, (15 * 16) - 4, 72, 28 },
+		"AUDIO"
+	};
+
+	Button button_mic_app {
+		{ 84,  (35 * 8) - 4, 72, 28 },
+		"MIC TX"
+	};
+
+	Button button_add {
+		{ 168, (15 * 16) - 4, 72, 28 },
+		"ADD FQ"
+	};
+
+	Button button_remove {
+		{ 168, (35 * 8) - 4, 72, 28 },
+		"DEL FQ"
 	};
 	
 	std::unique_ptr<ScannerThread> scan_thread { };
@@ -160,4 +301,4 @@ private:
 	};
 };
 
-} /* namespace ui */
+} /* namespace ui */
\ No newline at end of file
diff --git a/firmware/application/apps/ui_sonde.cpp b/firmware/application/apps/ui_sonde.cpp
index 16506b3f179fa9dcf7704d78767fb59b5a1fece3..e61139acdcf74529124248c2790dd7fd72657b98 100644
--- a/firmware/application/apps/ui_sonde.cpp
+++ b/firmware/application/apps/ui_sonde.cpp
@@ -54,7 +54,7 @@ SondeView::SondeView(NavigationView& nav) {
 	});
 
 	field_frequency.set_value(target_frequency_);
-	field_frequency.set_step(10000);
+	field_frequency.set_step(500);		//euquiq: was 10000, but we are using this for fine-tunning
 	field_frequency.on_change = [this](rf::Frequency f) {
 		set_target_frequency(f);
 		field_frequency.set_value(f);
@@ -86,12 +86,12 @@ SondeView::SondeView(NavigationView& nav) {
 
 	button_see_map.on_select = [this, &nav](Button&) {
 		nav.push<GeoMapView>(
-			"",
-			altitude,
+			sonde_id,
+			gps_info.alt,
 			GeoPos::alt_unit::METERS,
-			latitude,
-			longitude,
-			0);
+			gps_info.lat,
+			gps_info.lon,
+			999); //set a dummy heading out of range to draw a cross...probably not ideal?
 	};
 	
 	logger = std::make_unique<SondeLogger>();
@@ -113,16 +113,15 @@ void SondeView::on_packet(const sonde::Packet& packet) {
 	//const auto hex_formatted = packet.symbols_formatted();
 	
 	text_signature.set(packet.type_string());
-	text_serial.set(packet.serial_number());
+	sonde_id = packet.serial_number();	//used also as tag on the geomap
+	text_serial.set(sonde_id);
 	text_voltage.set(unit_auto_scale(packet.battery_voltage(), 2, 3) + "V");
+
+	gps_info = packet.get_GPS_data();
 	
-	altitude = packet.GPS_altitude();
-	latitude = packet.GPS_latitude();
-	longitude = packet.GPS_longitude();
-	
-	geopos.set_altitude(altitude);
-	geopos.set_lat(latitude);
-	geopos.set_lon(longitude);
+	geopos.set_altitude(gps_info.alt);
+	geopos.set_lat(gps_info.lat);
+	geopos.set_lon(gps_info.lon);
 	
 	if (logger && logging) {
 		logger->on_packet(packet);
diff --git a/firmware/application/apps/ui_sonde.hpp b/firmware/application/apps/ui_sonde.hpp
index 5dc7fe86a4a2c17e8fbb593c00fad08a4e01c98b..9e7743b1a8ae0f4af0d14561e7927102bea5d0a6 100644
--- a/firmware/application/apps/ui_sonde.hpp
+++ b/firmware/application/apps/ui_sonde.hpp
@@ -65,11 +65,10 @@ public:
 
 private:
 	std::unique_ptr<SondeLogger> logger { };
-	uint32_t target_frequency_ { 402000000 };
+	uint32_t target_frequency_ { 402700000 };
 	bool logging { false };
-	int32_t altitude { 0 };
-	float latitude { 0 };
-	float longitude { 0 };
+	sonde::GPS_data gps_info;
+	std::string sonde_id;
 	
 	Labels labels {
 		{ { 0 * 8, 2 * 16 }, "Signature:", Color::light_grey() },
diff --git a/firmware/application/apps/ui_view_wav.cpp b/firmware/application/apps/ui_view_wav.cpp
index daa12a8b33e4849b20c5f21244c34d6cebe3f0ad..0ec1dba696332c1e62810309f6b0b2898d1bdb36 100644
--- a/firmware/application/apps/ui_view_wav.cpp
+++ b/firmware/application/apps/ui_view_wav.cpp
@@ -81,15 +81,6 @@ void ViewWavView::load_wav(std::filesystem::path file_path) {
 	int16_t sample;
 	uint32_t average;
 
-	if (!wav_reader->open(file_path)) {
-		nav_.display_modal("Error", "Couldn't open file.", INFO, nullptr);
-		return;
-	}
-	
-	if ((wav_reader->channels() != 1) || (wav_reader->bits_per_sample() != 16)) {
-		nav_.display_modal("Error", "Wrong format.\nWav viewer only accepts\n16-bit mono files.", INFO, nullptr);
-		return;
-	}
 	
 	text_filename.set(file_path.filename().string());
 	auto ms_duration = wav_reader->ms_duration();
@@ -148,10 +139,18 @@ ViewWavView::ViewWavView(
 		&field_cursor_b,
 		&text_delta
 	});
-	
+	reset_controls();
 	button_open.on_select = [this, &nav](Button&) {
 		auto open_view = nav.push<FileLoadView>(".WAV");
 		open_view->on_changed = [this](std::filesystem::path file_path) {
+			if (!wav_reader->open(file_path)) {
+		nav_.display_modal("Error", "Couldn't open file.", INFO, nullptr);
+		return;
+	}
+	if ((wav_reader->channels() != 1) || (wav_reader->bits_per_sample() != 16)) {
+		nav_.display_modal("Error", "Wrong format.\nWav viewer only accepts\n16-bit mono files.", INFO, nullptr);
+		return;
+	}
 			load_wav(file_path);
 			field_pos_seconds.focus();
 		};
@@ -176,7 +175,6 @@ ViewWavView::ViewWavView(
 		refresh_measurements();
 	};
 	
-	reset_controls();
 }
 
 void ViewWavView::focus() {
diff --git a/firmware/application/freqman.hpp b/firmware/application/freqman.hpp
index daaad1efb98db4d63b41d4b925f516fea9846e6f..dca1f3645e8883152031c5e88751cdc79d447f8e 100644
--- a/firmware/application/freqman.hpp
+++ b/firmware/application/freqman.hpp
@@ -48,11 +48,28 @@ enum freqman_entry_type {
 	RANGE
 };
 
+//Entry step placed for AlainD freqman version (or any other enhanced version)
+enum freqman_entry_step {
+	STEP_DEF = 0,	// default
+	AM_US,			// 10 Khz   AM/CB
+	AM_EUR,			// 9 Khz	LW/MW
+	NFM_1,			// 12,5 Khz (Analogic PMR 446)
+	NFM_2,			// 6,25 Khz  (Digital PMR 446)
+	FM_1,			// 100 Khz
+	FM_2,			// 50 Khz
+	N_1,			// 25 Khz
+	N_2,			// 250 Khz
+	AIRBAND,		// AIRBAND 8,33 Khz
+	ERROR_STEP
+};
+
+// freqman_entry_step step added, as above, to provide compatibility / future enhancement.
 struct freqman_entry {
 	rf::Frequency frequency_a { 0 };
 	rf::Frequency frequency_b { 0 };
 	std::string description { };
 	freqman_entry_type type { };
+	freqman_entry_step step { };
 };
 
 using freqman_db = std::vector<freqman_entry>;
diff --git a/firmware/application/string_format.cpp b/firmware/application/string_format.cpp
index a62ce1ae32e312ddfd7a14888220ccb60305ddc5..fd7fb1a3c96c8b179d7855691cd88b47e126bc72 100644
--- a/firmware/application/string_format.cpp
+++ b/firmware/application/string_format.cpp
@@ -113,7 +113,8 @@ std::string to_string_dec_int(
 }
 
 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');
+	//was...		 to_string_dec_int(f / 1000000,4)
+	auto final_str = to_string_dec_int(f / 1000000) + "." + to_string_dec_int((f / 100) % 10000, 4, '0');
 	return final_str;
 }
 
diff --git a/firmware/application/ui/ui_btngrid.cpp b/firmware/application/ui/ui_btngrid.cpp
index 0c756af4e03660247755dfbbc289b055e053756d..2ad7907eb55524615a912563be7d54c0710546f1 100644
--- a/firmware/application/ui/ui_btngrid.cpp
+++ b/firmware/application/ui/ui_btngrid.cpp
@@ -95,6 +95,15 @@ void BtnGridView::set_parent_rect(const Rect new_parent_rect) {
 	update_items();
 }
 
+void BtnGridView::set_arrow_enabled(bool new_value) {
+	if(new_value){
+		add_child(&arrow_more);
+	}
+	else{
+		remove_child(&arrow_more);
+	}
+};
+
 void BtnGridView::on_tick_second() {
 	if (more && blink)
 		arrow_more.set_foreground(Color::white());
diff --git a/firmware/application/ui/ui_btngrid.hpp b/firmware/application/ui/ui_btngrid.hpp
index 1ce14ccacf7bacd793c990b64ebf6fa6179c3c5e..5f922f78b11a6aca0ed5da85972bcf9c7d121677 100644
--- a/firmware/application/ui/ui_btngrid.hpp
+++ b/firmware/application/ui/ui_btngrid.hpp
@@ -62,6 +62,7 @@ public:
 	uint32_t highlighted_index();
 
 	void set_parent_rect(const Rect new_parent_rect) override;
+	void set_arrow_enabled(bool new_value);
 	void on_focus() override;
 	void on_blur() override;
 	bool on_key(const KeyEvent event) override;
diff --git a/firmware/application/ui/ui_geomap.cpp b/firmware/application/ui/ui_geomap.cpp
index f907825a7466204ffb30928e91f355456f337eff..91fcb545e648737c5c1bc70478b794944e0759fb 100644
--- a/firmware/application/ui/ui_geomap.cpp
+++ b/firmware/application/ui/ui_geomap.cpp
@@ -59,7 +59,7 @@ GeoPos::GeoPos(
 	set_altitude(0);
 	set_lat(0);
 	set_lon(0);
-	
+
 	const auto changed_fn = [this](int32_t) {
 		float lat_value = lat();
 		float lon_value = lon();
@@ -163,15 +163,22 @@ void GeoMap::paint(Painter& painter) {
 		prev_x_pos = x_pos;
 		prev_y_pos = y_pos;
 	}
-	
+	//center tag above point
+	if(tag_.find_first_not_of(' ') != tag_.npos){ //only draw tag if we have something other than spaces
+		painter.draw_string(r.center() - Point(((int)tag_.length() * 8 / 2), 2 * 16), style(), tag_);
+	}
 	if (mode_ == PROMPT) {
 		// Cross
 		display.fill_rectangle({ r.center() - Point(16, 1), { 32, 2 } }, Color::red());
 		display.fill_rectangle({ r.center() - Point(1, 16), { 2, 32 } }, Color::red());
-	} else {
+	} else if (angle_ < 360){
+		//if we have a valid angle draw bearing
 		draw_bearing(r.center(), angle_, 10, Color::red());
-		//center tag above bearing
-		painter.draw_string(r.center() - Point(((int)tag_.length() * 8 / 2), 2 * 16), style(), tag_);
+	}
+	else {
+		//draw a small cross
+		display.fill_rectangle({ r.center() - Point(8, 1), { 16, 2 } }, Color::red());
+		display.fill_rectangle({ r.center() - Point(1, 8), { 2, 16 } }, Color::red());
 	}
 }
 
@@ -231,7 +238,7 @@ void GeoMap::set_mode(GeoMapMode mode) {
 	mode_ = mode;
 }
 
-void GeoMap::draw_bearing(const Point origin, const uint32_t angle, uint32_t size, const Color color) {
+void GeoMap::draw_bearing(const Point origin, const uint16_t angle, uint32_t size, const Color color) {
 	Point arrow_a, arrow_b, arrow_c;
 	
 	for (size_t thickness = 0; thickness < 3; thickness++) {
@@ -254,11 +261,12 @@ void GeoMapView::focus() {
 		nav_.display_modal("No map", "No world_map.bin file in\n/ADSB/ directory", ABORT, nullptr);
 }
 
-void GeoMapView::update_position(float lat, float lon) {
+void GeoMapView::update_position(float lat, float lon, uint16_t angle) {
 	lat_ = lat;
 	lon_ = lon;
 	geopos.set_lat(lat_);
 	geopos.set_lon(lon_);
+	geomap.set_angle(angle);
 	geomap.move(lon_, lat_);
 	geomap.set_dirty();
 }
@@ -269,7 +277,7 @@ void GeoMapView::setup() {
 	geopos.set_altitude(altitude_);
 	geopos.set_lat(lat_);
 	geopos.set_lon(lon_);
-	
+
 	geopos.on_change = [this](int32_t altitude, float lat, float lon) {
 		altitude_ = altitude;
 		lat_ = lat;
@@ -307,7 +315,7 @@ GeoMapView::GeoMapView(
 	GeoPos::alt_unit altitude_unit,
 	float lat,
 	float lon,
-	float angle,
+	uint16_t angle,
 	const std::function<void(void)> on_close
 ) : nav_ (nav),
 	altitude_ (altitude),
@@ -328,6 +336,7 @@ GeoMapView::GeoMapView(
 	
 	geomap.set_mode(mode_);
 	geomap.set_tag(tag);
+	geomap.set_angle(angle);
 	geomap.move(lon_, lat_);
 	
 	geopos.set_read_only(true);
diff --git a/firmware/application/ui/ui_geomap.hpp b/firmware/application/ui/ui_geomap.hpp
index 45a9479b1046db1ab0acbdb83e0e8cb5a20ec132..30fd69830436364a5df3e5ef6d6fc1f603e7ee84 100644
--- a/firmware/application/ui/ui_geomap.hpp
+++ b/firmware/application/ui/ui_geomap.hpp
@@ -129,8 +129,12 @@ public:
 		tag_ = new_tag;
 	}
 
+	void set_angle(uint16_t new_angle){
+		angle_ = new_angle;
+	}
+
 private:
-	void draw_bearing(const Point origin, const uint32_t angle, uint32_t size, const Color color);
+	void draw_bearing(const Point origin, const uint16_t angle, uint32_t size, const Color color);
 	
 	GeoMapMode mode_ { };
 	File map_file { };
@@ -141,7 +145,7 @@ private:
 	int32_t prev_x_pos { 0xFFFF }, prev_y_pos { 0xFFFF };
 	float lat_ { };
 	float lon_ { };
-	float angle_ { };
+	uint16_t angle_ { };
 	std::string tag_ { };
 };
 
@@ -154,7 +158,7 @@ public:
 		GeoPos::alt_unit altitude_unit,
 		float lat,
 		float lon,
-		float angle,
+		uint16_t angle,
 		const std::function<void(void)> on_close = nullptr
 	);
 	GeoMapView(NavigationView& nav,
@@ -173,7 +177,7 @@ public:
 	
 	void focus() override;
 	
-	void update_position(float lat, float lon);
+	void update_position(float lat, float lon, uint16_t angle);
 	
 	std::string title() const override { return "Map view"; };
 
@@ -190,7 +194,7 @@ private:
 	GeoPos::alt_unit altitude_unit_ { };
 	float lat_ { };
 	float lon_ { };
-	float angle_ { };
+	uint16_t angle_ { };
 	std::function<void(void)> on_close_ { nullptr };
 	
 	bool map_opened { };
diff --git a/firmware/application/ui_navigation.cpp b/firmware/application/ui_navigation.cpp
index e4ee6490babe8bd438cc10dd0ec8b8fc33844d95..01782d891aeabe66a5ceeba2e0e91e449be504d4 100644
--- a/firmware/application/ui_navigation.cpp
+++ b/firmware/application/ui_navigation.cpp
@@ -30,7 +30,7 @@
 #include "bmp_modal_warning.hpp"
 #include "portapack_persistent_memory.hpp"
 
-#include "ui_about.hpp"
+#include "ui_about_simple.hpp"
 #include "ui_adsb_rx.hpp"
 #include "ui_adsb_tx.hpp"
 #include "ui_afsk_rx.hpp"
@@ -303,7 +303,36 @@ void SystemStatusView::on_camera() {
 }
 
 void SystemStatusView::on_title() {
-	nav_.push<AboutView>();
+	if(nav_.is_top())
+		nav_.push<AboutView>();
+	else
+		nav_.pop();
+}
+
+/* Information View *****************************************************/
+
+InformationView::InformationView(
+	NavigationView& nav
+) : nav_ (nav)
+{
+		static constexpr Style style_infobar {
+		.font = font::fixed_8x16,
+		.background = {33, 33, 33},
+		.foreground = Color::white(),
+	};
+
+	add_children({
+	&backdrop,
+	&version,
+	&ltime
+	});
+
+	version.set_style(&style_infobar);
+	ltime.set_style(&style_infobar);
+	ltime.set_seconds_enabled(true);
+	ltime.set_date_enabled(false);
+
+	set_dirty();
 }
 
 /* Navigation ************************************************************/
@@ -416,7 +445,7 @@ ReceiversMenuView::ReceiversMenuView(NavigationView& nav) {
 		{ "Analog TV", 	ui::Color::yellow(),	&bitmap_icon_sstv,		[&nav](){ nav.push<AnalogTvView>(); } },
 		{ "ERT Meter", 	ui::Color::green(), 	&bitmap_icon_ert,		[&nav](){ nav.push<ERTAppView>(); } },
 		{ "POCSAG", 	ui::Color::green(),		&bitmap_icon_pocsag,	[&nav](){ nav.push<POCSAGAppView>(); } },
-		{ "Radiosnde", 	ui::Color::yellow(),	&bitmap_icon_sonde,		[&nav](){ nav.push<SondeView>(); } },
+		{ "Radiosnde", 	ui::Color::green(),		&bitmap_icon_sonde,		[&nav](){ nav.push<SondeView>(); } },
 		{ "TPMS Cars", 	ui::Color::green(),		&bitmap_icon_tpms,		[&nav](){ nav.push<TPMSAppView>(); } },
 		/*{ "APRS", 		ui::Color::dark_grey(),	&bitmap_icon_aprs,		[&nav](){ nav.push<NotImplementedView>(); } },
 		{ "DMR", 		ui::Color::dark_grey(),	&bitmap_icon_dmr,		[&nav](){ nav.push<NotImplementedView>(); } },
@@ -502,6 +531,7 @@ SystemMenuView::SystemMenuView(NavigationView& nav) {
 		//{ "About", 		ui::Color::cyan(),			nullptr,				[&nav](){ nav.push<AboutView>(); } }
 	});
 	set_max_rows(2); // allow wider buttons
+	set_arrow_enabled(false);
 	//set_highlighted(1);		// Startup selection
 }
 
@@ -522,6 +552,7 @@ SystemView::SystemView(
 	set_style(&style_default);
 
 	constexpr ui::Dim status_view_height = 16;
+	constexpr ui::Dim info_view_height = 16;
 	
 	add_child(&status_view);
 	status_view.set_parent_rect({
@@ -537,13 +568,29 @@ SystemView::SystemView(
 		{ 0, status_view_height },
 		{ parent_rect.width(), static_cast<ui::Dim>(parent_rect.height() - status_view_height) }
 	});
+
+	add_child(&info_view);
+	info_view.set_parent_rect({
+		{0, 19 * 16},
+		{ parent_rect.width(), info_view_height }
+	});
+
 	navigation_view.on_view_changed = [this](const View& new_view) {
+		
+		if(!this->navigation_view.is_top()){
+			remove_child(&info_view);
+		}
+		else{
+			add_child(&info_view);
+		}
+		
 		this->status_view.set_back_enabled(!this->navigation_view.is_top());
 		this->status_view.set_title_image_enabled(this->navigation_view.is_top());
-		this->status_view.set_dirty();
 		this->status_view.set_title(new_view.title());
+		this->status_view.set_dirty();
+		
 	};
-	
+
 
 	// portapack::persistent_memory::set_playdead_sequence(0x8D1);
 				
@@ -557,6 +604,9 @@ SystemView::SystemView(
 		
 		if (portapack::persistent_memory::config_splash())
 			navigation_view.push<BMPView>();
+			status_view.set_back_enabled(false);
+			status_view.set_title_image_enabled(true);
+			status_view.set_dirty();
 		//else
 		//	navigation_view.push<SystemMenuView>();
 			
diff --git a/firmware/application/ui_navigation.hpp b/firmware/application/ui_navigation.hpp
index 8754d35d9547ddab86454b4d74114facc3b3877e..6d95eefe2c8d351a8b0f28b1e799d22dffb46f08 100644
--- a/firmware/application/ui_navigation.hpp
+++ b/firmware/application/ui_navigation.hpp
@@ -110,7 +110,7 @@ public:
 	void set_title(const std::string new_value);
 
 private:
-	static constexpr auto default_title = "        v1.1.1"; // TODO: Move the version somewhere
+	static constexpr auto default_title = "";
 	
 	NavigationView& nav_;
 
@@ -208,6 +208,29 @@ private:
 	};
 };
 
+class InformationView : public View {
+public:
+	InformationView(NavigationView& nav);
+	
+private:
+	static constexpr auto version_string = "v1.2";
+	NavigationView& nav_;
+
+	Rectangle backdrop {
+		{ 0, 0 * 16, 240, 16 },
+		{33, 33, 33}
+	};
+
+	Text version {
+		{2, 0, 11 * 8, 16},
+		version_string
+	};
+	
+	LiveDateTime ltime {
+		{174, 0, 8 * 8, 16}
+	};
+};
+
 class BMPView : public View {
 public:
 	BMPView(NavigationView& nav);
@@ -262,6 +285,7 @@ public:
 
 private:
 	SystemStatusView status_view { navigation_view };
+	InformationView info_view { navigation_view };
 	NavigationView navigation_view { };
 	Context& context_;
 };
diff --git a/firmware/baseband/proc_sonde.hpp b/firmware/baseband/proc_sonde.hpp
index de15fff0818c4a4be0c9597265fc49c77d52e3fe..92e535803d83eb92bd6744d56cc299661b4248c6 100644
--- a/firmware/baseband/proc_sonde.hpp
+++ b/firmware/baseband/proc_sonde.hpp
@@ -140,7 +140,8 @@ private:
 		}
 	};
 	PacketBuilder<BitPattern, NeverMatch, FixedLength> packet_builder_fsk_4800_Vaisala {
-		{ 0b00001000011011010101001110001000, 32, 1 },
+		{ 0b00001000011011010101001110001000, 32, 1 }, //euquiq Header detects 4 of 8 bytes 0x10B6CA11 /this is in raw format) (these bits are not passed at the beginning of packet)
+		//{ 0b0000100001101101010100111000100001000100011010010100100000011111, 64, 1 }, //euquiq whole header detection would be 8 bytes.
 		{ },
 		{ 320 * 8 },
 		[this](const baseband::Packet& packet) {
diff --git a/firmware/common/adsb.cpp b/firmware/common/adsb.cpp
index c730bbecbb97bd18c434b056e52a4f2cbf492099..3f8f4c23118cac696de720a8a580e23763d2ec1c 100644
--- a/firmware/common/adsb.cpp
+++ b/firmware/common/adsb.cpp
@@ -300,8 +300,8 @@ void encode_frame_velo(ADSBFrame& frame, const uint32_t ICAO_address, const uint
 	
 	v_rate_coded = (v_rate / 64) + 1;
 	
-	velo_ew_abs = abs(velo_ew);
-	velo_ns_abs = abs(velo_ns);
+	velo_ew_abs = abs(velo_ew) + 1; 
+	velo_ns_abs = abs(velo_ns) + 1;
 	v_rate_coded_abs = abs(v_rate_coded);
 	
 	make_frame_adsb(frame, ICAO_address);
@@ -317,4 +317,52 @@ void encode_frame_velo(ADSBFrame& frame, const uint32_t ICAO_address, const uint
 	frame.make_CRC();
 }
 
+// Decoding method from dump1090
+adsb_vel decode_frame_velo(ADSBFrame& frame){
+	adsb_vel velo {false, 0, 0};
+
+	uint8_t * frame_data = frame.get_raw_data();
+	uint8_t velo_type = frame.get_msg_sub();
+
+	if(velo_type >= 1 && velo_type <= 4){ //vertical rate is always present
+
+		velo.v_rate = (((frame_data[8] & 0x07 ) << 6) | ((frame_data[9]) >> 2) - 1) * 64;
+
+		if((frame_data[8] & 0x8) >> 3) velo.v_rate *= -1; //check v_rate sign
+	}
+
+	if(velo_type == 1 || velo_type == 2){ //Ground Speed
+		int32_t raw_ew = ((frame_data[5] & 0x03) << 8) | frame_data[6];
+		int32_t velo_ew = raw_ew - 1; //velocities are all offset by one (this is part of the spec)
+
+		int32_t raw_ns = ((frame_data[7] & 0x7f) << 3) | (frame_data[8] >> 5);
+		int32_t velo_ns = raw_ns - 1;
+
+		if (velo_type == 2){ // supersonic indicator so multiply by 4
+			velo_ew = velo_ew << 2;
+			velo_ns = velo_ns << 2;
+		}
+
+		if(frame_data[5]&0x04) velo_ew *= -1; //check ew direction sign
+		if(frame_data[7]&0x80) velo_ns *= -1; //check ns direction sign
+
+		velo.speed = sqrt(velo_ns*velo_ns + velo_ew*velo_ew);
+		
+		if(velo.speed){
+			//calculate heading in degrees from ew/ns velocities
+			int16_t heading_temp = (int16_t)(atan2(velo_ew,velo_ns) * 180.0 / pi); 
+			// We don't want negative values but a 0-360 scale. 
+			if (heading_temp < 0) heading_temp += 360.0;
+			velo.heading = (uint16_t)heading_temp;
+		}
+		
+	}else if(velo_type == 3 || velo_type == 4){ //Airspeed
+		velo.valid = frame_data[5] & (1<<2);
+		velo.heading = ((((frame_data[5] & 0x03)<<8) | frame_data[6]) * 45) << 7;
+	} 
+
+	return velo;
+
+}
+
 } /* namespace adsb */
diff --git a/firmware/common/adsb.hpp b/firmware/common/adsb.hpp
index 4e042ff21f6f17ee83c6df62ff30fe8212d6afe8..82d177e496e383e84bc7d14542e28e1d6f6d74ac 100644
--- a/firmware/common/adsb.hpp
+++ b/firmware/common/adsb.hpp
@@ -56,6 +56,13 @@ struct adsb_pos {
 	int32_t altitude;
 };
 
+struct adsb_vel {
+	bool valid;
+	int32_t speed;  //knot
+	uint16_t heading; //degree
+	int32_t v_rate; //ft/min
+};
+
 const float CPR_MAX_VALUE = 131072.0;
 
 const float adsb_lat_lut[58] = {
@@ -89,6 +96,8 @@ adsb_pos decode_frame_pos(ADSBFrame& frame_even, ADSBFrame& frame_odd);
 void encode_frame_velo(ADSBFrame& frame, const uint32_t ICAO_address, const uint32_t speed,
 	const float angle, const int32_t v_rate);
 
+adsb_vel decode_frame_velo(ADSBFrame& frame);
+
 //void encode_frame_emergency(ADSBFrame& frame, const uint32_t ICAO_address, const uint8_t code);
 
 void encode_frame_squawk(ADSBFrame& frame, const uint32_t squawk);
diff --git a/firmware/common/adsb_frame.hpp b/firmware/common/adsb_frame.hpp
index 36685843d0e849d3262068bd5ec3b91c300487d9..a93abe6fb5403578dc009e0886f3e74a15222a49 100644
--- a/firmware/common/adsb_frame.hpp
+++ b/firmware/common/adsb_frame.hpp
@@ -41,6 +41,10 @@ public:
 		return (raw_data[4] >> 3);
 	}
 
+	uint8_t get_msg_sub() {
+		return (raw_data[4] & 7);
+	}
+
 	uint32_t get_ICAO_address() {
 		return (raw_data[1] << 16) + (raw_data[2] << 8) + raw_data[3];
 	}
diff --git a/firmware/common/sonde_packet.cpp b/firmware/common/sonde_packet.cpp
index 22f547938ab7376ce3daffea29cc0b1481513fd5..b1c22430cddf9232cc02f8d13ecc7f362846c9d3 100644
--- a/firmware/common/sonde_packet.cpp
+++ b/firmware/common/sonde_packet.cpp
@@ -22,9 +22,25 @@
 
 #include "sonde_packet.hpp"
 #include "string_format.hpp"
+#include <cstring>
+//#include <complex>
 
 namespace sonde {
 
+//Defines for Vaisala RS41, from https://github.com/rs1729/RS/blob/master/rs41/rs41sg.c
+#define MASK_LEN 64
+#define pos_FrameNb   0x37	//0x03B  // 2 byte
+#define pos_SondeID   0x39	//0x03D  // 8 byte
+#define pos_Voltage   0x041	//0x045  // 3 bytes (but first one is the important one) voltage x 10 ie: 26 = 2.6v
+#define pos_CalData   0x04E	//0x052  // 1 byte, counter 0x00..0x32
+#define pos_GPSweek   0x091	//0x095  // 2 byte
+#define pos_GPSTOW    0x093	//0x097  // 4 byte
+#define pos_GPSecefX  0x110	//0x114  // 4 byte
+#define pos_GPSecefY  0x114	//0x118  // 4 byte (not actually used since Y and Z are following X, and grabbed in that same loop)
+#define pos_GPSecefZ  0x118	//0x11C  // 4 byte (same as Y)
+
+#define PI 3.1415926535897932384626433832795  //3.1416 //(3.1415926535897932384626433832795)
+
 Packet::Packet(
 	const baseband::Packet& packet,
 	const Type type
@@ -60,37 +76,65 @@ Packet::Type Packet::type() const {
 	return type_;
 }
 
-/*uint8_t Packet::vaisala_descramble(const uint32_t pos) {
-	return reader_raw.read(pos * 8, 8) ^ vaisala_mask[pos & 63];
-};*/
-
-uint32_t Packet::GPS_altitude() const {
-	if ((type_ == Type::Meteomodem_M10) || (type_ == Type::Meteomodem_M2K2))
-		return (reader_bi_m.read(22 * 8, 32) / 1000) - 48;
-	else if (type_ == Type::Vaisala_RS41_SG) {
-		/*uint32_t altitude_ecef = 0;
-		for (uint32_t i = 0; i < 4; i++)
-			altitude_ecef = (altitude_ecef << 8) + vaisala_descramble(0x11C + i);*/
-		// TODO: and a bunch of maths (see ecef2elli() from RS1729)
-		return 0;
-	} else
-		return 0;	// Unknown
-}
-
-float Packet::GPS_latitude() const {
-	if ((type_ == Type::Meteomodem_M10) || (type_ == Type::Meteomodem_M2K2))
-		return reader_bi_m.read(14 * 8, 32) / ((1ULL << 32) / 360.0);
-	//else if (type_ == Type::Vaisala_RS41_SG)
-	//	return vaisala_descramble();
-	else
-		return 0;	// Unknown
-}
+//euquiq here:
+//RS41SG 320 bits header, 320bytes frame (or more if it is an "extended frame")
+//The raw data is xor-scrambled with the values in the 64 bytes vaisala_mask (see.hpp)
+
+
+uint8_t Packet::vaisala_descramble(const uint32_t pos) const {
+	//return reader_raw.read(pos * 8, 8) ^ vaisala_mask[pos & 63];  
+	// packet_[i]; its a bit;  packet_.size the total (should be 2560 bits)
+	uint8_t value = 0;
+	for (uint8_t i = 0; i < 8; i++) 
+		value = (value << 1) | packet_[(pos * 8) + (7 -i)];	//get the byte from the bits collection
+
+	//packetReader reader { packet_ };				//This works just as above.
+	//value = reader.read(pos * 8,8);
+	//shift pos because first 4 bytes are consumed by proc_sonde in finding the vaisala signature
+	uint32_t mask_pos = pos + 4;
+	value = value ^ vaisala_mask[mask_pos % MASK_LEN];	//descramble with the xor pseudorandom table
+	return value;
+};
+
+GPS_data Packet::get_GPS_data() const {
+	GPS_data result;
+	if ((type_ == Type::Meteomodem_M10) || (type_ == Type::Meteomodem_M2K2)) {
+
+		result.alt = (reader_bi_m.read(22 * 8, 32) / 1000) - 48;
+		result.lat = reader_bi_m.read(14 * 8, 32) / ((1ULL << 32) / 360.0);
+		result.lon = reader_bi_m.read(18 * 8, 32) / ((1ULL << 32) / 360.0);
+
+	} else if (type_ == Type::Vaisala_RS41_SG) {
+
+		uint8_t XYZ_bytes[4];
+		int32_t XYZ; // 32bit
+		double_t X[3];
+		for (int32_t k = 0; k < 3; k++) {		//Get X,Y,Z ECEF position from GPS
+			for (int32_t i = 0; i < 4; i++)		//each one is 4 bytes (32 bits)
+				XYZ_bytes[i] = vaisala_descramble(pos_GPSecefX + (4*k) + i);
+			memcpy(&XYZ, XYZ_bytes, 4);
+			X[k] = XYZ / 100.0;
+		}
+
+		double_t a = 6378137.0;
+		double_t b = 6356752.31424518;
+		double_t e  = sqrt( (a*a - b*b) / (a*a) );
+		double_t ee = sqrt( (a*a - b*b) / (b*b) );
+
+		double_t lam = atan2( X[1] , X[0] );
+		double_t p = sqrt( X[0]*X[0] + X[1]*X[1] );
+		double_t t = atan2( X[2]*a , p*b );
+		double_t phi = atan2( X[2] + ee*ee * b * sin(t)*sin(t)*sin(t) ,
+					p - e*e * a * cos(t)*cos(t)*cos(t) );
+
+		double_t R = a / sqrt( 1 - e*e*sin(phi)*sin(phi) );
+
+		result.alt = p / cos(phi) - R;
+		result.lat = phi*180/PI;
+		result.lon = lam*180/PI;
 
-float Packet::GPS_longitude() const {
-	if ((type_ == Type::Meteomodem_M10) || (type_ == Type::Meteomodem_M2K2))
-		return reader_bi_m.read(18 * 8, 32) / ((1ULL << 32) / 360.0);
-	else
-		return 0;	// Unknown
+	}
+	return result;
 }
 
 uint32_t Packet::battery_voltage() const {
@@ -98,8 +142,13 @@ uint32_t Packet::battery_voltage() const {
 		return (reader_bi_m.read(69 * 8, 8) + (reader_bi_m.read(70 * 8, 8) << 8)) * 1000 / 150;
 	else if (type_ == Type::Meteomodem_M2K2)
 		return reader_bi_m.read(69 * 8, 8) * 66;	// Actually 65.8
-	else
+	 else if (type_ == Type::Vaisala_RS41_SG) {
+		uint32_t voltage = vaisala_descramble(pos_Voltage) * 100; 	//byte 69 = voltage * 10 (check if this value needs to be multiplied)
+		return voltage;
+	 }
+	else {
 		return 0;	// Unknown
+	}		
 }
 
 std::string Packet::type_string() const {
@@ -127,12 +176,33 @@ std::string Packet::serial_number() const {
 			to_string_dec_uint(reader_bi_m.read(93 * 8 + 24, 3), 1) +
 			to_string_dec_uint(reader_bi_m.read(93 * 8 + 27, 13), 4, '0');
 	
-	} else
+	} else if(type() == Type::Vaisala_RS41_SG) {
+		std::string serial_id = "";
+		uint8_t achar;
+		for (uint8_t i=0; i<8; i++) {	//euquiq: Serial ID is 8 bytes long, each byte a char
+			achar = vaisala_descramble(pos_SondeID + i);
+			if (achar < 32 || achar > 126) return "?"; //Maybe there are ids with less than 8 bytes and this is not OK.
+			serial_id += (char)achar;
+		}
+		return serial_id;
+	} else 
 		return "?";
 }
 
 FormattedSymbols Packet::symbols_formatted() const {
-	return format_symbols(decoder_);
+	if (type() == Type::Vaisala_RS41_SG) {	//Euquiq: now we distinguish different types
+		uint32_t bytes = packet_.size() / 8;  //Need the byte amount, which if full, it SHOULD be 320 size() should return 2560
+		std::string hex_data;
+		std::string hex_error;
+		hex_data.reserve(bytes * 2); //2 hexa chars per byte
+		hex_error.reserve(1);				
+		for (uint32_t i=0; i < bytes; i++) //log will show the packet starting on the last 4 bytes from signature 93DF1A60
+			hex_data += to_string_hex(vaisala_descramble(i),2);
+		return { hex_data, hex_error };
+
+	} else {
+		return format_symbols(decoder_);
+	}
 }
 
 bool Packet::crc_ok() const {
diff --git a/firmware/common/sonde_packet.hpp b/firmware/common/sonde_packet.hpp
index 4ecbc08a475e09e8337e72b2029fdc227c859294..746d42e3117d2a20bd0ba8a6c159c5d41bc5b1b8 100644
--- a/firmware/common/sonde_packet.hpp
+++ b/firmware/common/sonde_packet.hpp
@@ -32,6 +32,12 @@
 
 namespace sonde {
 
+	struct GPS_data {
+		uint32_t alt { 0 };
+		float lat { 0 };
+		float lon { 0 };
+	};
+
 class Packet {
 public:
 	enum class Type : uint32_t {
@@ -41,7 +47,7 @@ public:
 		Meteomodem_M2K2 = 3,
 		Vaisala_RS41_SG = 4,
 	};
-	
+
 	Packet(const baseband::Packet& packet, const Type type);
 
 	size_t length() const;
@@ -56,9 +62,7 @@ public:
 	std::string serial_number() const;
 	uint32_t battery_voltage() const;
 	
-	uint32_t GPS_altitude() const;
-	float GPS_latitude() const;
-	float GPS_longitude() const;
+	GPS_data get_GPS_data() const;
 
 	FormattedSymbols symbols_formatted() const;
 
@@ -75,17 +79,20 @@ private:
 		0xD0, 0xBC, 0xB4, 0xB6, 0x06, 0xAA, 0xF4, 0x23,
 		0x78, 0x6E, 0x3B, 0xAE, 0xBF, 0x7B, 0x4C, 0xC1
 	};
+
+	GPS_data ecef_to_gps() const;
 	
-	//uint8_t vaisala_descramble(const uint32_t pos);
+	uint8_t vaisala_descramble(uint32_t pos) const;
 
 	const baseband::Packet packet_;
 	const BiphaseMDecoder decoder_;
 	const FieldReader<BiphaseMDecoder, BitRemapNone> reader_bi_m;
 	Type type_;
 
+	using packetReader = FieldReader<baseband::Packet, BitRemapByteReverse>; //baseband::Packet instead of BiphaseMDecoder
 	bool crc_ok_M10() const;
 };
 
 } /* namespace sonde */
 
-#endif/*__SONDE_PACKET_H__*/
+#endif/*__SONDE_PACKET_H__*/
\ No newline at end of file
diff --git a/firmware/common/ui_widget.cpp b/firmware/common/ui_widget.cpp
index c7427d478a058f0aecc0386dfe0b26e826a07728..a9333eae3511ac8c27d39964f14cdaf4226f8fb0 100644
--- a/firmware/common/ui_widget.cpp
+++ b/firmware/common/ui_widget.cpp
@@ -409,10 +409,26 @@ void Labels::paint(Painter& painter) {
 
 void LiveDateTime::on_tick_second() {
 	rtcGetTime(&RTCD1, &datetime);
+	text = "";
 	
-	text = to_string_dec_uint(datetime.month(), 2, '0') + "/" + to_string_dec_uint(datetime.day(), 2, '0') + " " +
-			to_string_dec_uint(datetime.hour(), 2, '0') + ":" + to_string_dec_uint(datetime.minute(), 2, '0');
+	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(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--;
+		}
+	}
 	set_dirty();
 }
 
@@ -444,6 +460,14 @@ void LiveDateTime::paint(Painter& painter) {
 	);
 }
 
+void LiveDateTime::set_date_enabled(bool new_value){
+	this->date_enabled = new_value;
+}
+
+void LiveDateTime::set_seconds_enabled(bool new_value) {
+	this->seconds_enabled = new_value;
+}
+
 /* BigFrequency **********************************************************/
 
 BigFrequency::BigFrequency(
@@ -1760,13 +1784,13 @@ void VuMeter::paint(Painter& painter) {
 				lit = true;
 			
 			if (bar == 0)
-				color = lit ? Color::red() : Color::dark_red();
+				color = lit ? Color::red() : Color::dark_grey();
 			else if (bar == 1)
-				color = lit ? Color::orange() : Color::dark_orange();
+				color = lit ? Color::orange() : Color::dark_grey();
 			else if ((bar == 2) || (bar == 3))
-				color = lit ? Color::yellow() : Color::dark_yellow();
+				color = lit ? Color::yellow() : Color::dark_grey();
 			else
-				color = lit ? Color::green() : Color::dark_green();
+				color = lit ? Color::green() : Color::dark_grey();
 			
 			painter.fill_rectangle({ pos.x(), pos.y() + (Coord)(bar * (LED_height + 1)), width, (Coord)LED_height }, color);
 		}
diff --git a/firmware/common/ui_widget.hpp b/firmware/common/ui_widget.hpp
index 61ffeb7258125103085e40dbb03f4cd8e8cb192c..51de42773a9539f299ff32ce9696f1325e7cdde2 100644
--- a/firmware/common/ui_widget.hpp
+++ b/firmware/common/ui_widget.hpp
@@ -243,7 +243,10 @@ public:
 	~LiveDateTime();
 
 	void paint(Painter& painter) override;
-	
+
+	void set_seconds_enabled(bool new_value);
+	void set_date_enabled(bool new_value);
+
 	std::string& string() {
 		return text;
 	}
@@ -251,6 +254,10 @@ public:
 private:
 	void on_tick_second();
 	
+	uint16_t init_delay = 4;
+	bool date_enabled = true;
+	bool seconds_enabled = false;
+	
 	rtc::RTC datetime { };
 	SignalToken signal_token_tick_second { };
 	std::string text { };