From 30db22828c42c498ae7e3a00dc2074967b4eba78 Mon Sep 17 00:00:00 2001
From: furrtek <furrtekC@gmail.com>
Date: Thu, 23 May 2019 05:20:01 +0100
Subject: [PATCH] Fileman empty directory bugfix
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Ajouté trames + config collier LGE
---
 firmware/application/apps/lge_app.cpp    |  80 +++++++++--
 firmware/application/apps/lge_app.hpp    |  83 +++++++++---
 firmware/application/apps/replay_app.cpp |   4 +-
 firmware/application/apps/ui_fileman.cpp | 165 ++++++++++++-----------
 firmware/application/apps/ui_fileman.hpp |   5 +-
 5 files changed, 218 insertions(+), 119 deletions(-)

diff --git a/firmware/application/apps/lge_app.cpp b/firmware/application/apps/lge_app.cpp
index b0be496f..265a20e5 100644
--- a/firmware/application/apps/lge_app.cpp
+++ b/firmware/application/apps/lge_app.cpp
@@ -64,6 +64,15 @@ void LGEView::generate_lge_frame(const uint8_t command, const uint16_t address_a
 		console.write(to_string_hex(b, 2) + " ");
 }
 
+void LGEView::generate_frame_touche() {
+	// 0001.89s
+	// 0D 96 02 12 0E 00 46 28 01 45 27 01 44 23 66 30
+	std::vector<uint8_t> data { 0x46, 0x28, 0x01, 0x45, 0x27, 0x01, 0x44, 0x23 };
+	
+	console.write("\n\x1B\x07Touche:\x1B\x10");
+	generate_lge_frame(0x96, (field_joueur.value() << 8) | field_salle.value(), 0x0001, data);
+}
+
 void LGEView::generate_frame_pseudo() {
 	// 0040.48s:
 	// 30 02 1A 00 19 00 FF 00 02 19 42 52 45 42 49 53 20 00 00 00 00 00 00 00 00 00
@@ -112,7 +121,7 @@ void LGEView::generate_frame_equipe() {
 	// 0041.83s:
 	// 3D 03 FF FF FF FF 02 03 01 52 4F 55 47 45 00 00 00 00 00 00 00 00 00 00 00 00
 	// 02 56 45 52 54 45 00 00 00 00 00 00 00 00 00 00 00 01 03 42 4C 45 55 45 00 00
-	// 00 00 00 00 00 00 00 00 00 02 43 29 
+	// 00 00 00 00 00 00 00 00 00 02 43 29
 
 	std::vector<uint8_t> data { };
 	std::array<uint8_t, 2> data_header = { 0x02, 0x01 };
@@ -142,7 +151,7 @@ void LGEView::generate_frame_broadcast_pseudo() {
 	// 0043.86s:
 	// 3D 04 FF FF FF FF 02 03 19 42 52 45 42 49 53 20 00 00 00 00 00 00 00 00 00 04
 	// 07 50 4F 4E 45 59 20 00 00 00 00 00 00 00 00 00 00 05 1B 41 42 42 59 20 00 00
-	// 00 00 00 00 00 00 00 00 00 04 0A 02 
+	// 00 00 00 00 00 00 00 00 00 04 0A 02
 
 	std::vector<uint8_t> data { };
 	std::array<uint8_t, 2> data_header = { 0x02, 0x01 };
@@ -172,7 +181,7 @@ void LGEView::generate_frame_broadcast_pseudo() {
 
 void LGEView::generate_frame_start() {
 	// 0166.13s:
-	// 0A 05 FF FF FF FF 02 EC FF FF FF A3 35 
+	// 0A 05 FF FF FF FF 02 EC FF FF FF A3 35
 	std::vector<uint8_t> data { 0x02, 0xEC, 0xFF, 0xFF, 0xFF };
 	
 	//data[0] = field_salle.value();	// ?
@@ -182,12 +191,48 @@ void LGEView::generate_frame_start() {
 }
 
 void LGEView::generate_frame_gameover() {
-	std::vector<uint8_t> data { field_salle.value() };
+	std::vector<uint8_t> data { (uint8_t)field_salle.value() };
 	
 	console.write("\n\x1B\x0CGameover:\x1B\x10");
 	generate_lge_frame(0x0D, data);
 }
 
+void LGEView::generate_frame_collier() {
+	uint8_t flags = 0;
+	
+	// Custom
+	// 0C 00 13 37 13 37 id flags channel playerid zapduty zaptime checksum CRC CRC
+	// channel: field_channel
+	// playerid: field_joueur
+	// zapduty: field_power
+	// zaptime: field_duration
+	
+	if (checkbox_heartbeat.value())
+		flags |= 1;
+	if (checkbox_rxtick.value())
+		flags |= 2;
+	
+	uint8_t checksum = 0;
+	uint8_t id = (uint8_t)field_id.value();
+	
+	std::vector<uint8_t> data {
+		id,
+		flags,
+		(uint8_t)field_salle.value(),
+		(uint8_t)field_joueur.value(),
+		(uint8_t)field_power.value(),
+		(uint8_t)(field_duration.value() * 10)
+	};
+	
+	for (auto &v : data)
+		checksum += v;
+	
+	data.push_back(checksum - id);
+	
+	console.write("\n\x1B\x06" "Config:\x1B\x10");
+	generate_lge_frame(0x00, 0x3713, 0x3713, data);
+}
+
 void LGEView::start_tx() {
 	if (tx_mode == ALL) {
 		transmitter_model.set_tuning_frequency(channels[channel_index]);
@@ -217,11 +262,11 @@ void LGEView::on_tx_progress(const uint32_t progress, const bool done) {
 	
 	transmitter_model.disable();
 	
-	if (repeats < 2) {
+	/*if (repeats < 2) {
 		chThdSleep(100);
 		repeats++;
 		start_tx();
-	} else {
+	} else {*/
 		if (tx_mode == ALL) {
 			if (channel_index < 2) {
 				channel_index++;
@@ -233,7 +278,7 @@ void LGEView::on_tx_progress(const uint32_t progress, const bool done) {
 		} else {
 			stop_tx();
 		}
-	}
+	//}
 }
 
 LGEView::LGEView(NavigationView& nav) {
@@ -246,6 +291,11 @@ LGEView::LGEView(NavigationView& nav) {
 		&button_texte,
 		&field_equipe,
 		&field_joueur,
+		&field_id,
+		&field_power,
+		&field_duration,
+		&checkbox_heartbeat,
+		&checkbox_rxtick,
 		&checkbox_channels,
 		&console,
 		&tx_view
@@ -254,7 +304,9 @@ LGEView::LGEView(NavigationView& nav) {
 	field_salle.set_value(1);
 	field_equipe.set_value(1);
 	field_joueur.set_value(1);
-	checkbox_channels.set_value(true);
+	field_id.set_value(1);
+	field_power.set_value(1);
+	field_duration.set_value(2);
 	
 	button_texte.on_select = [this, &nav](Button&) {
 		text_prompt(
@@ -277,15 +329,19 @@ LGEView::LGEView(NavigationView& nav) {
 		if (tx_mode == IDLE) {
 			auto i = options_trame.selected_index_value();
 			if (i == 0)
-				generate_frame_pseudo();
+				generate_frame_touche();
 			else if (i == 1)
-				generate_frame_equipe();
+				generate_frame_pseudo();
 			else if (i == 2)
-				generate_frame_broadcast_pseudo();
+				generate_frame_equipe();
 			else if (i == 3)
-				generate_frame_start();
+				generate_frame_broadcast_pseudo();
 			else if (i == 4)
+				generate_frame_start();
+			else if (i == 5)
 				generate_frame_gameover();
+			else if (i == 6)
+				generate_frame_collier();
 			
 			repeats = 0;
 			channel_index = 0;
diff --git a/firmware/application/apps/lge_app.hpp b/firmware/application/apps/lge_app.hpp
index 2fdea120..81825800 100644
--- a/firmware/application/apps/lge_app.hpp
+++ b/firmware/application/apps/lge_app.hpp
@@ -67,37 +67,52 @@ private:
 		generate_lge_frame(command, 0xFFFF, 0xFFFF, data);
 	}
 	void generate_lge_frame(const uint8_t command, const uint16_t address_a, const uint16_t address_b, std::vector<uint8_t>& data);
+	void generate_frame_touche();
 	void generate_frame_pseudo();
 	void generate_frame_equipe();
 	void generate_frame_broadcast_pseudo();
 	void generate_frame_start();
 	void generate_frame_gameover();
+	void generate_frame_collier();
 	
 	void on_tx_progress(const uint32_t progress, const bool done);
 	
 	Labels labels {
-		{ { 7 * 8, 1 * 8 }, "NO FUN ALLOWED !", Color::red() },
-		{ { 4 * 8, 4 * 8 }, "Trame:", Color::light_grey() },
-		{ { 4 * 8, 6 * 8 }, "Salle:", Color::light_grey() },
-		{ { 14 * 8, 6 * 8 }, "Texte:", Color::light_grey() },
-		{ { 3 * 8, 8 * 8 }, "Equipe:", Color::light_grey() },
-		{ { 3 * 8, 10 * 8 }, "Joueur:", Color::light_grey() }
+		//{ { 7 * 8, 1 * 8 }, "NO FUN ALLOWED !", Color::red() },
+		{ { 1 * 8, 1 * 8 }, "Trame:", Color::light_grey() },
+		{ { 1 * 8, 3 * 8 }, "Salle:", Color::light_grey() },
+		{ { 14 * 8, 3 * 8 }, "Texte:", Color::light_grey() },
+		{ { 0 * 8, 5 * 8 }, "Equipe:", Color::light_grey() },
+		{ { 0 * 8, 7 * 8 }, "Joueur:", Color::light_grey() },
+		{ { 0 * 8, 10 * 8 }, "Collier:", Color::light_grey() },
+		{ { 4 * 8, 12 * 8 }, "ID:", Color::light_grey() },
+		{ { 3 * 8, 14 * 8 }, "Pow:  /10", Color::light_grey() },
+		{ { 1 * 8, 16 * 8 }, "Duree:  x100ms", Color::light_grey() }
 	};
 	
 	OptionsField options_trame {
-		{ 10 * 8, 4 * 8 },
-		16,
+		{ 7 * 8, 1 * 8 },
+		13,
 		{
-			{ "Set pseudo", 0 },
-			{ "Set equipe", 1 },
-			{ "Broadcast pseudo", 2 },
-			{ "Start", 3 },
-			{ "Game over", 4 }
+			{ "Touche", 0 },
+			{ "Set pseudo", 1 },
+			{ "Set equipe", 2 },
+			{ "Brdcst pseudo", 3 },
+			{ "Start", 4 },
+			{ "Game over", 5 },
+			{ "Set collier", 6 }
 		}
 	};
 	
+	Checkbox checkbox_channels {
+		{ 20 * 8, 1 * 8 },
+		7,
+		"All ch.",
+		true
+	};
+	
 	NumberField field_salle {
-		{ 10 * 8, 6 * 8 },
+		{ 7 * 8, 3 * 8 },
 		1,
 		{ 1, 2 },
 		1,
@@ -105,12 +120,12 @@ private:
 	};
 	
 	Button button_texte {
-		{ 14 * 8, 8 * 8, 16 * 8, 3 * 8 },
+		{ 14 * 8, 5 * 8, 16 * 8, 3 * 8 },
 		"ABCDEF"
 	};
 	
 	NumberField field_equipe {
-		{ 10 * 8, 8 * 8 },
+		{ 7 * 8, 5 * 8 },
 		1,
 		{ 1, 6 },
 		1,
@@ -118,17 +133,45 @@ private:
 	};
 	
 	NumberField field_joueur {
-		{ 10 * 8, 10 * 8 },
+		{ 7 * 8, 7 * 8 },
 		2,
 		{ 1, 50 },
 		1,
 		'0'
 	};
 	
-	Checkbox checkbox_channels {
+	Checkbox checkbox_heartbeat {
+		{ 17 * 8, 12 * 8 },
+		9,
+		"Heartbeat",
+		true
+	};
+	Checkbox checkbox_rxtick {
+		{ 17 * 8, 15 * 8 },
+		7,
+		"RX tick",
+		true
+	};
+	NumberField field_id {
+		{ 7 * 8, 12 * 8 },
+		1,
+		{ 1, 2 },
+		1,
+		'0'
+	};
+	NumberField field_power {
 		{ 7 * 8, 14 * 8 },
-		12,
-		"All channels"
+		2,
+		{ 1, 10 },
+		1,
+		'0'
+	};
+	NumberField field_duration {
+		{ 7 * 8, 16 * 8 },
+		2,
+		{ 1, 25 },
+		1,
+		'0'
 	};
 	
 	Console console {
diff --git a/firmware/application/apps/replay_app.cpp b/firmware/application/apps/replay_app.cpp
index 8bde0c2f..21bf10d6 100644
--- a/firmware/application/apps/replay_app.cpp
+++ b/firmware/application/apps/replay_app.cpp
@@ -218,8 +218,8 @@ ReplayAppView::ReplayAppView(
 	};
 	
 	button_open.on_select = [this, &nav](Button&) {
-		auto new_view = nav.push<FileLoadView>(".C16");
-		new_view->on_changed = [this](std::filesystem::path new_file_path) {
+		auto open_view = nav.push<FileLoadView>(".C16");
+		open_view->on_changed = [this](std::filesystem::path new_file_path) {
 			on_file_changed(new_file_path);
 		};
 	};
diff --git a/firmware/application/apps/ui_fileman.cpp b/firmware/application/apps/ui_fileman.cpp
index d5a1edf6..e10f61fb 100644
--- a/firmware/application/apps/ui_fileman.cpp
+++ b/firmware/application/apps/ui_fileman.cpp
@@ -39,15 +39,24 @@ void FileManBaseView::load_directory_contents(const std::filesystem::path& dir_p
 	auto filtering = (bool)extension_filter.size();
 	
 	// List directories and files, put directories up top
+	if (dir_path.string().length())
+		entry_list.push_back({ u"..", 0, true });
+	
 	for (const auto& entry : std::filesystem::directory_iterator(dir_path, u"*")) {
 		if (std::filesystem::is_regular_file(entry.status())) {
 			if (entry.path().string().length()) {
-				auto entry_extension = entry.path().extension().string();
-			
-				for (auto &c: entry_extension)
-					c = toupper(c);
+				bool matched = true;
+				if (filtering) {
+					auto entry_extension = entry.path().extension().string();
 				
-				if ((entry_extension == extension_filter) || !filtering)
+					for (auto &c: entry_extension)
+						c = toupper(c);
+					
+					if (entry_extension != extension_filter)
+						matched = false;
+				}
+				
+				if (matched)
 					entry_list.push_back({ entry.path(), (uint32_t)entry.size(), false });
 			}
 		} else if (std::filesystem::is_directory(entry.status())) {
@@ -57,15 +66,26 @@ void FileManBaseView::load_directory_contents(const std::filesystem::path& dir_p
 }
 
 std::filesystem::path FileManBaseView::get_selected_path() {
-	std::string selected_path_str = current_path.string();
+	auto selected_path_str = current_path.string();
+	auto entry_path = entry_list[menu_view.highlighted_index()].entry_path.string();
 	
-	if (selected_path_str.back() != '/')
-		selected_path_str += '/';
-	selected_path_str += (entry_list[menu_view.highlighted_index()].entry_path.string());
+	if (entry_path == "..") {
+		selected_path_str = get_parent_dir().string();
+	} else {
+		if (selected_path_str.back() != '/')
+			selected_path_str += '/';
+		
+		selected_path_str += entry_path;
+	}
 	
 	return selected_path_str;
 }
 
+std::filesystem::path FileManBaseView::get_parent_dir() {
+	auto current_path_str = current_path.string();
+	return current_path.string().substr(0, current_path_str.find_last_of('/'));
+}
+
 FileManBaseView::FileManBaseView(
 	NavigationView& nav,
 	std::string filter
@@ -83,12 +103,8 @@ FileManBaseView::FileManBaseView(
 		&button_exit
 	});
 
-	// Go back one level on left
 	menu_view.on_left = [&nav, this]() {
-		std::string current_path_str = current_path.string();
-		
-		current_path_str = current_path_str.substr(0, current_path_str.find_last_of('/'));
-		load_directory_contents(current_path_str);
+		load_directory_contents(get_parent_dir());
 		refresh_list();
 	};
 	
@@ -107,73 +123,66 @@ void FileManBaseView::focus() {
 }
 
 void FileManBaseView::refresh_list() {
-	if (!entry_list.size()) {
-		// Hide widgets, show warning
-		if (on_refresh_widgets)
-			on_refresh_widgets(true);
-	} else {
-		// Hide warning, show widgets
-		if (on_refresh_widgets)
-			on_refresh_widgets(false);
+	if (on_refresh_widgets)
+		on_refresh_widgets(false);
+
+	menu_view.clear();
 	
-		menu_view.clear();
+	for (size_t n = 0; n < entry_list.size(); n++) {
+		auto entry = &entry_list[n];
+		auto entry_name = entry->entry_path.filename().string().substr(0, 20);
 		
-		for (size_t n = 0; n < entry_list.size(); n++) {
-			auto entry = &entry_list[n];
-			auto entry_name = entry->entry_path.filename().string().substr(0, 20);
+		if (entry->is_directory) {
 			
-			if (entry->is_directory) {
-				
-				menu_view.add_item({
-					entry_name,
-					ui::Color::yellow(),
-					&bitmap_icon_dir,
-					[this](){
-						if (on_select_entry)
-							on_select_entry();
-					}
-				});
-				
-			} else {
-				
-				auto file_size = entry->size;
-				size_t suffix_index = 0;
-				
-				while (file_size >= 1024) {
-					file_size /= 1024;
-					suffix_index++;
-				}
-				if (suffix_index > 4)
-					suffix_index = 4;
-				
-				std::string size_str = to_string_dec_uint(file_size) + suffix[suffix_index];
-				
-				auto entry_extension = entry->entry_path.extension().string();
-				for (auto &c: entry_extension)
-					c = toupper(c);
-				
-				// Associate extension to icon and color
-				size_t c;
-				for (c = 0; c < file_types.size() - 1; c++) {
-					if (entry_extension == file_types[c].extension)
-						break;
+			menu_view.add_item({
+				entry_name,
+				ui::Color::yellow(),
+				&bitmap_icon_dir,
+				[this](){
+					if (on_select_entry)
+						on_select_entry();
 				}
-				
-				menu_view.add_item({
-					entry_name + std::string(21 - entry_name.length(), ' ') + size_str,
-					file_types[c].color,
-					file_types[c].icon,
-					[this](){
-						if (on_select_entry)
-							on_select_entry();
-					}
-				});
-				
+			});
+			
+		} else {
+			
+			auto file_size = entry->size;
+			size_t suffix_index = 0;
+			
+			while (file_size >= 1024) {
+				file_size /= 1024;
+				suffix_index++;
+			}
+			if (suffix_index > 4)
+				suffix_index = 4;
+			
+			std::string size_str = to_string_dec_uint(file_size) + suffix[suffix_index];
+			
+			auto entry_extension = entry->entry_path.extension().string();
+			for (auto &c: entry_extension)
+				c = toupper(c);
+			
+			// Associate extension to icon and color
+			size_t c;
+			for (c = 0; c < file_types.size() - 1; c++) {
+				if (entry_extension == file_types[c].extension)
+					break;
 			}
+			
+			menu_view.add_item({
+				entry_name + std::string(21 - entry_name.length(), ' ') + size_str,
+				file_types[c].color,
+				file_types[c].icon,
+				[this](){
+					if (on_select_entry)
+						on_select_entry();
+				}
+			});
+			
 		}
-		
-		menu_view.set_highlighted(0);	// Refresh
 	}
+	
+	menu_view.set_highlighted(0);	// Refresh
 }
 
 /*void FileSaveView::on_save_name() {
@@ -200,8 +209,6 @@ FileSaveView::FileSaveView(
 }*/
 
 void FileLoadView::refresh_widgets(const bool v) {
-	menu_view.hidden(v);
-	text_empty.hidden(!v);
 	set_dirty();
 }
 
@@ -215,8 +222,7 @@ FileLoadView::FileLoadView(
 	};
 	
 	add_children({
-		&menu_view,
-		&text_empty
+		&menu_view
 	});
 	
 	// Resize menu view to fill screen
@@ -254,8 +260,6 @@ void FileManagerView::refresh_widgets(const bool v) {
 	button_rename.hidden(v);
 	button_new_dir.hidden(v);
 	button_delete.hidden(v);
-	menu_view.hidden(v);
-	text_empty.hidden(!v);
 	set_dirty();
 }
 
@@ -273,7 +277,6 @@ FileManagerView::FileManagerView(
 	
 	add_children({
 		&menu_view,
-		&text_empty,
 		&labels,
 		&text_date,
 		&button_rename,
diff --git a/firmware/application/apps/ui_fileman.hpp b/firmware/application/apps/ui_fileman.hpp
index e408d0fb..42c921ca 100644
--- a/firmware/application/apps/ui_fileman.hpp
+++ b/firmware/application/apps/ui_fileman.hpp
@@ -80,6 +80,7 @@ protected:
 	std::string extension_filter { "" };
 	
 	void change_category(int32_t category_id);
+	std::filesystem::path get_parent_dir();
 	void refresh_list();
 	
 	Labels labels {
@@ -94,10 +95,6 @@ protected:
 		{ 0, 2 * 8, 240, 26 * 8 },
 		true
 	};
-	Text text_empty {
-		{ 7 * 8, 12 * 8, 16 * 8, 16 },
-		"Empty directory !",
-	};
 	
 	Button button_exit {
 		{ 20 * 8, 34 * 8, 10 * 8, 4 * 8 },
-- 
GitLab