From 76737bf5f829247c4646a110252231808bf4e69e Mon Sep 17 00:00:00 2001
From: euquiq <31453004+euquiq@users.noreply.github.com>
Date: Sat, 15 Aug 2020 18:58:47 -0300
Subject: [PATCH] Touchscreen sensitivity configuration

Now the user can choose between STANDARD, ENHANCED and EXTREME touchscreen sensitivity, upon entering the Calibration App.

This will help performing the calibration  on those clone H1 portapacks carrying a "less than optimal" sensitivty touchscreen.

After calibrating the touchscreen, the user will be presented -as before- with an option for saving the calibration data. Now, also, the sensitivity index will be saved too, so the touchscreen will be easier to use in every normal operation.
---
 .../application/apps/ui_touch_calibration.cpp | 30 +++++++++++++++++--
 .../application/apps/ui_touch_calibration.hpp | 19 +++++++++++-
 firmware/application/touch.cpp                | 17 ++++++++---
 firmware/application/touch.hpp                |  3 +-
 .../common/portapack_persistent_memory.cpp    | 14 +++++++++
 .../common/portapack_persistent_memory.hpp    |  2 ++
 6 files changed, 77 insertions(+), 8 deletions(-)

diff --git a/firmware/application/apps/ui_touch_calibration.cpp b/firmware/application/apps/ui_touch_calibration.cpp
index a5a7c348..57766af0 100644
--- a/firmware/application/apps/ui_touch_calibration.cpp
+++ b/firmware/application/apps/ui_touch_calibration.cpp
@@ -34,6 +34,8 @@ TouchCalibrationView::TouchCalibrationView(
 	calibration { touch::default_calibration() }
 {
 	add_children({
+		&labels,
+		&field_sensitivity,
 		&image_calibrate_0,
 		&image_calibrate_1,
 		&image_calibrate_2,
@@ -51,9 +53,31 @@ TouchCalibrationView::TouchCalibrationView(
 	button_cancel.on_select = [this](Button&){ this->on_cancel(); };
 	button_ok.on_select = [this](Button&){ this->on_ok(); };
 
+	field_sensitivity.set_by_value(persistent_memory::touchsensible());
+	adjust_sensitivity(field_sensitivity.selected_index_value());
+	field_sensitivity.on_change = [this](size_t, OptionsField::value_t v) {
+		adjust_sensitivity(v);
+	};
+
 	set_phase(Phase::Calibrate0);
 }
 
+void TouchCalibrationView::adjust_sensitivity(uint32_t level) {
+	switch (level) {
+	case 2:		//ENHANCED
+		r_touch_threshold = 480;
+		samples_limit = 30;
+		break;
+	case 3:		//EXTREME
+		r_touch_threshold = 320;
+		samples_limit = 20;
+		break;
+	default:	//STANDARD (original values)
+		r_touch_threshold = 640;
+		samples_limit = 40;
+	}
+}
+
 void TouchCalibrationView::focus() {
 	button_cancel.focus();
 }
@@ -155,6 +179,8 @@ void TouchCalibrationView::touch_complete() {
 void TouchCalibrationView::on_ok() {
 	if( phase == Phase::Success ) {
 		persistent_memory::set_touch_calibration(calibration);
+		persistent_memory::set_touchsensible(field_sensitivity.selected_index_value()); //Save current sensitivity index	
+		touch::r_touch_threshold = r_touch_threshold; //Pass the sensitivity threshold into the touch routine	
 		nav.pop();
 	}
 	if( phase == Phase::Failure ) {
@@ -185,7 +211,7 @@ void TouchCalibrationView::on_frame_sync() {
 	const auto x = metrics.x * 1024;
 	const auto y = metrics.y * 1024;
 
-	if( metrics.r < 640.0f ) {
+	if( metrics.r < r_touch_threshold ) {  //euquiq was hardcoded to 640.0f
 		if( samples_count > 0 ) {
 			average.x = ((average.x * 7) + x) / 8;
 			average.y = ((average.y * 7) + y) / 8;
@@ -203,4 +229,4 @@ void TouchCalibrationView::on_frame_sync() {
 	}
 }
 
-} /* namespace ui */
+} /* namespace ui */
\ No newline at end of file
diff --git a/firmware/application/apps/ui_touch_calibration.hpp b/firmware/application/apps/ui_touch_calibration.hpp
index b47fc859..69c7a294 100644
--- a/firmware/application/apps/ui_touch_calibration.hpp
+++ b/firmware/application/apps/ui_touch_calibration.hpp
@@ -62,7 +62,10 @@ private:
 	void on_ok();
 	void on_cancel();
 
-	const uint32_t samples_limit { 40 };
+	void adjust_sensitivity(uint32_t level);
+	float r_touch_threshold = 640;
+
+	uint32_t samples_limit { 40 };
 	const uint32_t verify_d_sq_max = 10 * 10;
 
 	uint32_t samples_count { 0 };
@@ -115,6 +118,20 @@ private:
 		Color::black()
 	};
 
+	Labels labels {
+		{ { 5 * 8, 16 * 8 }, "TOUCH SENSITIVITY:", Color::light_grey() }
+	};
+
+	OptionsField field_sensitivity {
+		{ 9 * 8, 18 * 8 },
+		10,
+		{
+			{ " STANDARD ", 1 },
+			{ " ENHANCED ", 2 },
+			{ " EXTREME  ", 3 },
+		}
+	};
+
 	Text label_calibrate {
 		{ 16, 5 * 16, 26 * 8, 1 * 16 },
 		"Touch targets to calibrate"
diff --git a/firmware/application/touch.cpp b/firmware/application/touch.cpp
index d3fc6c92..f468223c 100644
--- a/firmware/application/touch.cpp
+++ b/firmware/application/touch.cpp
@@ -85,18 +85,27 @@ const Calibration default_calibration() {
 };
 
 void Manager::feed(const Frame& frame) {
-	// touch_debounce.feed(touch_raw);
 	const auto touch_raw = frame.touch;
-	//const auto touch_stable = touch_debounce.state();
 	const auto touch_stable = frame.touch;
 	bool touch_pressure = false;
 
 	// Only feed coordinate averaging if there's a touch.
-	// TODO: Separate threshold to gate coordinates for filtering?
 	if( touch_raw ) {
 		const auto metrics = calculate_metrics(frame);
 
-		// TODO: Add touch pressure hysteresis?
+		if (!r_touch_threshold) {	//Assigns the correct value from persistent memory at startup
+			switch (persistent_memory::touchsensible()) { 
+			case 2:	//Enhanced
+				r_touch_threshold = 480;
+				break;
+			case 3:	//Extreme
+				r_touch_threshold = 320;
+				break;
+			default:	//standard
+				r_touch_threshold = 640;
+			}
+		}
+
 		touch_pressure = (metrics.r < r_touch_threshold);
 		if( touch_pressure ) {
 			filter_x.feed(metrics.x * 1024);
diff --git a/firmware/application/touch.hpp b/firmware/application/touch.hpp
index ebea3c92..8ef5884e 100644
--- a/firmware/application/touch.hpp
+++ b/firmware/application/touch.hpp
@@ -40,6 +40,8 @@ constexpr sample_t sample_max = 1023;
 
 constexpr sample_t touch_threshold = sample_max / 5;
 
+static float r_touch_threshold { 0 };
+
 struct Samples {
 	sample_t xp;
 	sample_t xn;
@@ -212,7 +214,6 @@ private:
 		TouchDetected,
 	};
 
-	static constexpr float r_touch_threshold = 640;
 	static constexpr size_t touch_count_threshold { 3 };
 	static constexpr uint32_t touch_stable_bound { 8 };
 
diff --git a/firmware/common/portapack_persistent_memory.cpp b/firmware/common/portapack_persistent_memory.cpp
index 1772fb24..1dbebae4 100644
--- a/firmware/common/portapack_persistent_memory.cpp
+++ b/firmware/common/portapack_persistent_memory.cpp
@@ -63,6 +63,10 @@ using modem_repeat_range_t = range_t<int32_t>;
 constexpr modem_repeat_range_t modem_repeat_range { 1, 99 };
 constexpr int32_t modem_repeat_reset_value { 5 };
 
+using touchsensible_range_t = range_t<uint32_t>;
+constexpr touchsensible_range_t touchsensible_range { 1, 3 };
+constexpr uint32_t touchsensible_reset_value { 2 };
+
 /* struct must pack the same way on M4 and M0 cores. */
 struct data_t {
 	int64_t tuned_frequency;
@@ -91,6 +95,7 @@ struct data_t {
 	uint32_t pocsag_ignore_address;
 	
 	int32_t tone_mix;
+	uint32_t touchsense_level;
 };
 
 static_assert(sizeof(data_t) <= backup_ram.size(), "Persistent memory structure too large for VBAT-maintained region");
@@ -185,6 +190,15 @@ void set_modem_repeat(const uint32_t new_value) {
 	data->modem_repeat = modem_repeat_range.clip(new_value);
 }
 
+uint32_t touchsensible() {
+	touchsensible_range.reset_if_outside(data->touchsense_level, touchsensible_reset_value);
+	return data->touchsense_level;
+}
+
+void set_touchsensible(const uint32_t new_value) {
+	data->touchsense_level = touchsensible_range.clip(new_value);
+}
+
 serial_format_t serial_format() {
 	return data->serial_format;
 }
diff --git a/firmware/common/portapack_persistent_memory.hpp b/firmware/common/portapack_persistent_memory.hpp
index be740edb..0c311c59 100644
--- a/firmware/common/portapack_persistent_memory.hpp
+++ b/firmware/common/portapack_persistent_memory.hpp
@@ -78,11 +78,13 @@ bool config_splash();
 bool config_login();
 bool config_speaker();
 uint32_t config_backlight_timer();
+uint32_t touchsensible();
 
 void set_config_splash(bool v);
 void set_config_login(bool v);
 void set_config_speaker(bool new_value); 
 void set_config_backlight_timer(uint32_t i);
+void set_touchsensible(const uint32_t new_value);
 
 //uint8_t ui_config_textentry();
 //void set_config_textentry(uint8_t new_value);
-- 
GitLab