| 
									
										
										
										
											2016-04-10 17:16:39 -07:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This file is part of PortaPack. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is free software; you can redistribute it and/or modify | 
					
						
							|  |  |  |  * it under the terms of the GNU General Public License as published by | 
					
						
							|  |  |  |  * the Free Software Foundation; either version 2, or (at your option) | 
					
						
							|  |  |  |  * any later version. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is distributed in the hope that it will be useful, | 
					
						
							|  |  |  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  |  * GNU General Public License for more details. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * You should have received a copy of the GNU General Public License | 
					
						
							|  |  |  |  * along with this program; see the file COPYING.  If not, write to | 
					
						
							|  |  |  |  * the Free Software Foundation, Inc., 51 Franklin Street, | 
					
						
							|  |  |  |  * Boston, MA 02110-1301, USA. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "ui_sd_card_debug.hpp"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "string_format.hpp"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "file.hpp"
 | 
					
						
							|  |  |  | #include "lfsr_random.hpp"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "ff.h"
 | 
					
						
							| 
									
										
										
										
											2016-05-09 22:44:50 -07:00
										 |  |  | #include "diskio.h"
 | 
					
						
							| 
									
										
										
										
											2016-04-10 17:16:39 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include "ch.h"
 | 
					
						
							|  |  |  | #include "hal.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class SDCardTestThread { | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  | 	enum Result { | 
					
						
							|  |  |  | 		FailCompare = -8, | 
					
						
							|  |  |  | 		FailReadIncomplete = -7, | 
					
						
							|  |  |  | 		FailWriteIncomplete = -6, | 
					
						
							|  |  |  | 		FailAbort = -5, | 
					
						
							|  |  |  | 		FailFileOpenRead = -4, | 
					
						
							|  |  |  | 		FailFileOpenWrite = -3, | 
					
						
							|  |  |  | 		FailHeap = -2, | 
					
						
							|  |  |  | 		FailThread = -1, | 
					
						
							|  |  |  | 		Incomplete = 0, | 
					
						
							|  |  |  | 		OK = 1, | 
					
						
							|  |  |  | 	}; | 
					
						
							| 
									
										
										
										
											2020-06-09 23:43:45 +02:00
										 |  |  | 	std::string ResultStr[10] = { | 
					
						
							|  |  |  | 		"Compare", | 
					
						
							|  |  |  | 		"Read incomplete", | 
					
						
							|  |  |  | 		"Write incomplete", | 
					
						
							|  |  |  | 		"Abort", | 
					
						
							|  |  |  | 		"File Open Read", | 
					
						
							|  |  |  | 		"File Open Write", | 
					
						
							|  |  |  | 		"Heap", | 
					
						
							|  |  |  | 		"Thread", | 
					
						
							|  |  |  | 		"Incomplete", | 
					
						
							|  |  |  | 		"OK", | 
					
						
							|  |  |  | 	}; | 
					
						
							| 
									
										
										
										
											2016-04-10 17:16:39 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	struct Stats { | 
					
						
							|  |  |  | 		halrtcnt_t write_duration_min { 0 }; | 
					
						
							|  |  |  | 		halrtcnt_t write_duration_max { 0 }; | 
					
						
							|  |  |  | 		halrtcnt_t write_test_duration { 0 }; | 
					
						
							| 
									
										
										
										
											2016-08-21 22:15:19 -07:00
										 |  |  | 		File::Size write_bytes { 0 }; | 
					
						
							| 
									
										
										
										
											2016-04-10 17:16:39 -07:00
										 |  |  | 		size_t write_count { 0 }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		halrtcnt_t read_duration_min { 0 }; | 
					
						
							|  |  |  | 		halrtcnt_t read_duration_max { 0 }; | 
					
						
							|  |  |  | 		halrtcnt_t read_test_duration { 0 }; | 
					
						
							| 
									
										
										
										
											2016-08-21 22:15:19 -07:00
										 |  |  | 		File::Size read_bytes { 0 }; | 
					
						
							| 
									
										
										
										
											2016-04-10 17:16:39 -07:00
										 |  |  | 		size_t read_count { 0 }; | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	SDCardTestThread( | 
					
						
							|  |  |  | 	) { | 
					
						
							| 
									
										
										
										
											2016-08-21 22:16:08 -07:00
										 |  |  | 		thread = chThdCreateFromHeap(NULL, 3072, NORMALPRIO + 10, SDCardTestThread::static_fn, this); | 
					
						
							| 
									
										
										
										
											2016-04-10 17:16:39 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Result result() const { | 
					
						
							|  |  |  | 		return _result; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	const Stats& stats() const { | 
					
						
							|  |  |  | 		return _stats; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	~SDCardTestThread() { | 
					
						
							|  |  |  | 		chThdTerminate(thread); | 
					
						
							|  |  |  | 		chThdWait(thread); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | private: | 
					
						
							| 
									
										
										
										
											2016-08-21 22:15:19 -07:00
										 |  |  | 	static constexpr File::Size write_size = 16384; | 
					
						
							|  |  |  | 	static constexpr File::Size bytes_to_write = 16 * 1024 * 1024; | 
					
						
							|  |  |  | 	static constexpr File::Size bytes_to_read = bytes_to_write; | 
					
						
							| 
									
										
										
										
											2016-04-10 17:16:39 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	static Thread* thread; | 
					
						
							|  |  |  | 	volatile Result _result { Result::Incomplete }; | 
					
						
							| 
									
										
										
										
											2016-11-26 16:50:44 -08:00
										 |  |  | 	Stats _stats { }; | 
					
						
							| 
									
										
										
										
											2016-04-10 17:16:39 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	static msg_t static_fn(void* arg) { | 
					
						
							|  |  |  | 		auto obj = static_cast<SDCardTestThread*>(arg); | 
					
						
							|  |  |  | 		obj->_result = obj->run(); | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Result run() { | 
					
						
							| 
									
										
										
										
											2016-08-21 18:06:39 -07:00
										 |  |  | 		const std::filesystem::path filename { u"_PPTEST_.DAT" }; | 
					
						
							| 
									
										
										
										
											2016-04-10 17:16:39 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		const auto write_result = write(filename); | 
					
						
							|  |  |  | 		if( write_result != Result::OK ) { | 
					
						
							|  |  |  | 			return write_result; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if( _stats.write_bytes < bytes_to_write ) { | 
					
						
							|  |  |  | 			return Result::FailWriteIncomplete; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if( chThdShouldTerminate() ) { | 
					
						
							|  |  |  | 			return Result::FailAbort; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		const auto read_result = read(filename); | 
					
						
							|  |  |  | 		if( read_result != Result::OK ) { | 
					
						
							|  |  |  | 			return read_result; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-21 18:06:39 -07:00
										 |  |  | 		f_unlink(reinterpret_cast<const TCHAR*>(filename.c_str())); | 
					
						
							| 
									
										
										
										
											2016-04-10 17:16:39 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if( _stats.read_bytes < bytes_to_read ) { | 
					
						
							|  |  |  | 			return Result::FailReadIncomplete; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if( chThdShouldTerminate() ) { | 
					
						
							|  |  |  | 			return Result::FailAbort; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return Result::OK; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-21 18:06:39 -07:00
										 |  |  | 	Result write(const std::filesystem::path& filename) { | 
					
						
							| 
									
										
										
										
											2016-04-10 17:16:39 -07:00
										 |  |  | 		const auto buffer = std::make_unique<std::array<uint8_t, write_size>>(); | 
					
						
							|  |  |  | 		if( !buffer ) { | 
					
						
							|  |  |  | 			return Result::FailHeap; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-16 14:01:44 -07:00
										 |  |  | 		File file; | 
					
						
							|  |  |  | 		auto file_create_error = file.create(filename); | 
					
						
							|  |  |  | 		if( file_create_error.is_valid() ) { | 
					
						
							| 
									
										
										
										
											2016-04-10 17:16:39 -07:00
										 |  |  | 			return Result::FailFileOpenWrite; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		lfsr_word_t v = 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		const halrtcnt_t test_start = halGetCounterValue(); | 
					
						
							| 
									
										
										
										
											2016-05-16 14:01:44 -07:00
										 |  |  | 		while( !chThdShouldTerminate() && (_stats.write_bytes < bytes_to_write) ) { | 
					
						
							| 
									
										
										
										
											2016-04-10 17:16:39 -07:00
										 |  |  | 			lfsr_fill(v, | 
					
						
							|  |  |  | 				reinterpret_cast<lfsr_word_t*>(buffer->data()), | 
					
						
							|  |  |  | 				sizeof(*buffer.get()) / sizeof(lfsr_word_t) | 
					
						
							|  |  |  | 			); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			const halrtcnt_t write_start = halGetCounterValue(); | 
					
						
							| 
									
										
										
										
											2016-05-16 14:01:44 -07:00
										 |  |  | 			const auto result_write = file.write(buffer->data(), buffer->size()); | 
					
						
							|  |  |  | 			if( result_write.is_error() ) { | 
					
						
							| 
									
										
										
										
											2016-04-10 17:16:39 -07:00
										 |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			const halrtcnt_t write_end = halGetCounterValue(); | 
					
						
							|  |  |  | 			_stats.write_bytes += buffer->size(); | 
					
						
							|  |  |  | 			_stats.write_count++; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			const halrtcnt_t write_duration = write_end - write_start; | 
					
						
							|  |  |  | 			if( (_stats.write_duration_min == 0) || (write_duration < _stats.write_duration_min) ) { | 
					
						
							|  |  |  | 				_stats.write_duration_min = write_duration; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if( write_duration > _stats.write_duration_max ) { | 
					
						
							|  |  |  | 				_stats.write_duration_max = write_duration; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-30 15:09:34 -07:00
										 |  |  | 		file.sync(); | 
					
						
							| 
									
										
										
										
											2016-04-10 17:16:39 -07:00
										 |  |  | 		 | 
					
						
							|  |  |  | 		const halrtcnt_t test_end = halGetCounterValue(); | 
					
						
							|  |  |  | 		_stats.write_test_duration = test_end - test_start; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return Result::OK; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-21 18:06:39 -07:00
										 |  |  | 	Result read(const std::filesystem::path& filename) { | 
					
						
							| 
									
										
										
										
											2016-04-10 17:16:39 -07:00
										 |  |  | 		const auto buffer = std::make_unique<std::array<uint8_t, write_size>>(); | 
					
						
							|  |  |  | 		if( !buffer ) { | 
					
						
							|  |  |  | 			return Result::FailHeap; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-16 14:01:44 -07:00
										 |  |  | 		File file; | 
					
						
							|  |  |  | 		auto file_open_error = file.open(filename); | 
					
						
							|  |  |  | 		if( file_open_error.is_valid() ) { | 
					
						
							| 
									
										
										
										
											2016-04-10 17:16:39 -07:00
										 |  |  | 			return Result::FailFileOpenRead; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		lfsr_word_t v = 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		const halrtcnt_t test_start = halGetCounterValue(); | 
					
						
							| 
									
										
										
										
											2016-05-16 14:01:44 -07:00
										 |  |  | 		while( !chThdShouldTerminate() && (_stats.read_bytes < bytes_to_read) ) { | 
					
						
							| 
									
										
										
										
											2016-04-10 17:16:39 -07:00
										 |  |  | 			const halrtcnt_t read_start = halGetCounterValue(); | 
					
						
							| 
									
										
										
										
											2016-05-16 14:01:44 -07:00
										 |  |  | 			const auto result_read = file.read(buffer->data(), buffer->size()); | 
					
						
							|  |  |  | 			if( result_read.is_error() ) { | 
					
						
							| 
									
										
										
										
											2016-04-10 17:16:39 -07:00
										 |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			const halrtcnt_t read_end = halGetCounterValue(); | 
					
						
							|  |  |  | 			_stats.read_bytes += buffer->size(); | 
					
						
							|  |  |  | 			_stats.read_count++; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			const halrtcnt_t read_duration = read_end - read_start; | 
					
						
							|  |  |  | 			if( (_stats.read_duration_min == 0) || (read_duration < _stats.read_duration_min) ) { | 
					
						
							|  |  |  | 				_stats.read_duration_min = read_duration; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if( read_duration > _stats.read_duration_max ) { | 
					
						
							|  |  |  | 				_stats.read_duration_max = read_duration; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if( !lfsr_compare(v, | 
					
						
							|  |  |  | 				reinterpret_cast<lfsr_word_t*>(buffer->data()), | 
					
						
							|  |  |  | 				sizeof(*buffer.get()) / sizeof(lfsr_word_t)) | 
					
						
							|  |  |  | 			) { | 
					
						
							|  |  |  | 				return Result::FailCompare; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-30 15:09:34 -07:00
										 |  |  | 		file.sync(); | 
					
						
							| 
									
										
										
										
											2016-04-10 17:16:39 -07:00
										 |  |  | 		 | 
					
						
							|  |  |  | 		const halrtcnt_t test_end = halGetCounterValue(); | 
					
						
							|  |  |  | 		_stats.read_test_duration = test_end - test_start; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return Result::OK; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Thread* SDCardTestThread::thread { nullptr }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace ui { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | SDCardDebugView::SDCardDebugView(NavigationView& nav) { | 
					
						
							| 
									
										
										
										
											2016-09-05 14:53:04 -07:00
										 |  |  | 	add_children({ | 
					
						
							| 
									
										
										
										
											2016-04-10 17:16:39 -07:00
										 |  |  | 		&text_title, | 
					
						
							| 
									
										
										
										
											2016-05-09 22:44:50 -07:00
										 |  |  | 		&text_csd_title, | 
					
						
							|  |  |  | 		&text_csd_value_3, | 
					
						
							|  |  |  | 		&text_csd_value_2, | 
					
						
							|  |  |  | 		&text_csd_value_1, | 
					
						
							|  |  |  | 		&text_csd_value_0, | 
					
						
							| 
									
										
										
										
											2016-04-10 17:16:39 -07:00
										 |  |  | 		&text_bus_width_title, | 
					
						
							|  |  |  | 		&text_bus_width_value, | 
					
						
							| 
									
										
										
										
											2016-05-09 22:49:26 -07:00
										 |  |  | 		&text_card_type_title, | 
					
						
							|  |  |  | 		&text_card_type_value, | 
					
						
							| 
									
										
										
										
											2016-04-10 17:16:39 -07:00
										 |  |  | 		&text_block_size_title, | 
					
						
							|  |  |  | 		&text_block_size_value, | 
					
						
							|  |  |  | 		&text_block_count_title, | 
					
						
							|  |  |  | 		&text_block_count_value, | 
					
						
							|  |  |  | 		&text_capacity_title, | 
					
						
							|  |  |  | 		&text_capacity_value, | 
					
						
							|  |  |  | 		&text_test_write_time_title, | 
					
						
							|  |  |  | 		&text_test_write_time_value, | 
					
						
							|  |  |  | 		&text_test_write_rate_title, | 
					
						
							|  |  |  | 		&text_test_write_rate_value, | 
					
						
							|  |  |  | 		&text_test_read_time_title, | 
					
						
							|  |  |  | 		&text_test_read_time_value, | 
					
						
							|  |  |  | 		&text_test_read_rate_title, | 
					
						
							|  |  |  | 		&text_test_read_rate_value, | 
					
						
							|  |  |  | 		&button_test, | 
					
						
							|  |  |  | 		&button_ok, | 
					
						
							| 
									
										
										
										
											2016-09-05 14:53:04 -07:00
										 |  |  | 	}); | 
					
						
							| 
									
										
										
										
											2016-04-10 17:16:39 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	button_test.on_select = [this](Button&){ this->on_test(); }; | 
					
						
							|  |  |  | 	button_ok.on_select = [&nav](Button&){ nav.pop(); }; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void SDCardDebugView::on_show() { | 
					
						
							|  |  |  | 	sd_card_status_signal_token = sd_card::status_signal += [this](const sd_card::Status status) { | 
					
						
							|  |  |  | 		this->on_status(status); | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 	on_status(sd_card::status()); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void SDCardDebugView::on_hide() { | 
					
						
							|  |  |  | 	sd_card::status_signal -= sd_card_status_signal_token; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void SDCardDebugView::focus() { | 
					
						
							|  |  |  | 	button_ok.focus(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-09 21:53:01 -07:00
										 |  |  | static std::string format_3dot3_string(const uint32_t value_in_thousandths) { | 
					
						
							|  |  |  | 	if( value_in_thousandths < 1000000U ) { | 
					
						
							|  |  |  | 		const uint32_t thousandths_part = value_in_thousandths % 1000; | 
					
						
							|  |  |  | 		const uint32_t integer_part = value_in_thousandths / 1000U; | 
					
						
							|  |  |  | 		return to_string_dec_uint(integer_part, 3) + "." + to_string_dec_uint(thousandths_part, 3, '0'); | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		return "HHH.HHH"; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static std::string format_bytes_size_string(uint64_t value) { | 
					
						
							|  |  |  | 	static const std::array<char, 5> suffix { { ' ', 'K', 'M', 'G', 'T' } }; | 
					
						
							|  |  |  | 	size_t suffix_index = 1; | 
					
						
							|  |  |  | 	while( (value >= 1000000U) && (suffix_index < suffix.size()) ) { | 
					
						
							|  |  |  | 		value /= 1000U; | 
					
						
							|  |  |  | 		suffix_index++; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return format_3dot3_string(value) + " " + suffix[suffix_index] + "B"; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-10 17:16:39 -07:00
										 |  |  | void SDCardDebugView::on_status(const sd_card::Status) { | 
					
						
							|  |  |  | 	text_bus_width_value.set(""); | 
					
						
							| 
									
										
										
										
											2016-05-09 22:49:26 -07:00
										 |  |  | 	text_card_type_value.set(""); | 
					
						
							| 
									
										
										
										
											2016-05-09 22:44:50 -07:00
										 |  |  | 	text_csd_value_0.set(""); | 
					
						
							|  |  |  | 	text_csd_value_1.set(""); | 
					
						
							|  |  |  | 	text_csd_value_2.set(""); | 
					
						
							|  |  |  | 	text_csd_value_3.set(""); | 
					
						
							| 
									
										
										
										
											2016-04-10 17:16:39 -07:00
										 |  |  | 	text_block_size_value.set(""); | 
					
						
							|  |  |  | 	text_block_count_value.set(""); | 
					
						
							|  |  |  | 	text_capacity_value.set(""); | 
					
						
							|  |  |  | 	text_test_write_time_value.set(""); | 
					
						
							|  |  |  | 	text_test_write_rate_value.set(""); | 
					
						
							|  |  |  | 	text_test_read_time_value.set(""); | 
					
						
							|  |  |  | 	text_test_read_rate_value.set(""); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	const bool is_inserted = sdcIsCardInserted(&SDCD1); | 
					
						
							|  |  |  | 	if( is_inserted ) { | 
					
						
							|  |  |  | 		const auto card_width_flags = LPC_SDMMC->CTYPE & 0x10001; | 
					
						
							|  |  |  | 		size_t card_width = 0; | 
					
						
							|  |  |  | 		switch(card_width_flags) { | 
					
						
							|  |  |  | 		case 0x00000: card_width = 1; break; | 
					
						
							|  |  |  | 		case 0x00001: card_width = 4; break; | 
					
						
							|  |  |  | 		case 0x10001: card_width = 8; break; | 
					
						
							|  |  |  | 		default: break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		text_bus_width_value.set(card_width ? to_string_dec_uint(card_width, 1) : "X"); | 
					
						
							| 
									
										
										
										
											2016-05-09 22:49:26 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// TODO: Implement Text class right-justify!
 | 
					
						
							|  |  |  | 		BYTE card_type; | 
					
						
							|  |  |  | 		disk_ioctl(0, MMC_GET_TYPE, &card_type); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		std::string formatted_card_type; | 
					
						
							|  |  |  | 		switch(card_type & SDC_MODE_CARDTYPE_MASK) { | 
					
						
							|  |  |  | 		case SDC_MODE_CARDTYPE_SDV11: formatted_card_type = "SD V1.1"; break; | 
					
						
							|  |  |  | 		case SDC_MODE_CARDTYPE_SDV20: formatted_card_type = "SD V2.0"; break; | 
					
						
							|  |  |  | 		case SDC_MODE_CARDTYPE_MMC:   formatted_card_type = "MMC";     break; | 
					
						
							|  |  |  | 		default: formatted_card_type = "???"; break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if( card_type & SDC_MODE_HIGH_CAPACITY ) { | 
					
						
							|  |  |  | 			formatted_card_type += ", SDHC"; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		text_card_type_value.set(formatted_card_type); | 
					
						
							| 
									
										
										
										
											2016-05-09 22:44:50 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		std::array<uint32_t, 4> csd; | 
					
						
							|  |  |  | 		disk_ioctl(0, MMC_GET_CSD, csd.data()); | 
					
						
							|  |  |  | 		text_csd_value_3.set(to_string_hex(csd[3], 8)); | 
					
						
							|  |  |  | 		text_csd_value_2.set(to_string_hex(csd[2], 8)); | 
					
						
							|  |  |  | 		text_csd_value_1.set(to_string_hex(csd[1], 8)); | 
					
						
							|  |  |  | 		text_csd_value_0.set(to_string_hex(csd[0], 8)); | 
					
						
							| 
									
										
										
										
											2016-04-10 17:16:39 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		BlockDeviceInfo block_device_info; | 
					
						
							|  |  |  | 		if( sdcGetInfo(&SDCD1, &block_device_info) == CH_SUCCESS ) { | 
					
						
							|  |  |  | 			text_block_size_value.set(to_string_dec_uint(block_device_info.blk_size, 5)); | 
					
						
							|  |  |  | 			text_block_count_value.set(to_string_dec_uint(block_device_info.blk_num, 9)); | 
					
						
							|  |  |  | 			const uint64_t capacity = block_device_info.blk_size * uint64_t(block_device_info.blk_num); | 
					
						
							| 
									
										
										
										
											2016-05-09 21:53:01 -07:00
										 |  |  | 			text_capacity_value.set(format_bytes_size_string(capacity)); | 
					
						
							| 
									
										
										
										
											2016-04-10 17:16:39 -07:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static std::string format_ticks_as_ms(const halrtcnt_t value) { | 
					
						
							|  |  |  | 	const uint32_t us = uint64_t(value) * 1000000U / halGetCounterFrequency(); | 
					
						
							| 
									
										
										
										
											2016-05-09 21:53:01 -07:00
										 |  |  | 	return format_3dot3_string(us); | 
					
						
							| 
									
										
										
										
											2016-04-10 17:16:39 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-21 22:15:19 -07:00
										 |  |  | static std::string format_bytes_per_ticks_as_mib(const File::Size bytes, const halrtcnt_t ticks) { | 
					
						
							| 
									
										
										
										
											2016-04-10 17:16:39 -07:00
										 |  |  | 	const uint32_t bps = uint64_t(bytes) * halGetCounterFrequency() / ticks; | 
					
						
							|  |  |  | 	const uint32_t kbps = bps / 1000U; | 
					
						
							| 
									
										
										
										
											2016-05-09 21:53:01 -07:00
										 |  |  | 	return format_3dot3_string(kbps); | 
					
						
							| 
									
										
										
										
											2016-04-10 17:16:39 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void SDCardDebugView::on_test() { | 
					
						
							|  |  |  | 	text_test_write_time_value.set(""); | 
					
						
							|  |  |  | 	text_test_write_rate_value.set(""); | 
					
						
							|  |  |  | 	text_test_read_time_value.set(""); | 
					
						
							|  |  |  | 	text_test_read_rate_value.set(""); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	SDCardTestThread thread; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// uint32_t spinner_phase = 0;
 | 
					
						
							|  |  |  | 	while( thread.result() == SDCardTestThread::Result::Incomplete ) { | 
					
						
							|  |  |  | 		chThdSleepMilliseconds(100); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// spinner_phase += 1;
 | 
					
						
							|  |  |  | 		// char c = '*';
 | 
					
						
							|  |  |  | 		// switch(spinner_phase % 4) {
 | 
					
						
							|  |  |  | 		// case 0: c = '-';  break;
 | 
					
						
							|  |  |  | 		// case 1: c = '\\'; break;
 | 
					
						
							|  |  |  | 		// case 2: c = '|';  break;
 | 
					
						
							|  |  |  | 		// case 3: c = '/';  break;
 | 
					
						
							|  |  |  | 		// default: c = '*'; break;
 | 
					
						
							|  |  |  | 		// }
 | 
					
						
							|  |  |  | 		// text_test_write_value.set({ c });
 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if( thread.result() == SDCardTestThread::Result::OK ) { | 
					
						
							|  |  |  | 		const auto stats = thread.stats(); | 
					
						
							|  |  |  | 		const auto write_duration_avg = stats.write_test_duration / stats.write_count; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		text_test_write_time_value.set( | 
					
						
							|  |  |  | 			format_ticks_as_ms(stats.write_duration_min) + "/" + | 
					
						
							|  |  |  | 			format_ticks_as_ms(write_duration_avg) + "/" + | 
					
						
							|  |  |  | 			format_ticks_as_ms(stats.write_duration_max) | 
					
						
							|  |  |  | 		); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		text_test_write_rate_value.set( | 
					
						
							|  |  |  | 			format_bytes_per_ticks_as_mib(stats.write_bytes, stats.write_duration_min * stats.write_count) + " " + | 
					
						
							|  |  |  | 			format_bytes_per_ticks_as_mib(stats.write_bytes, stats.write_test_duration) | 
					
						
							|  |  |  | 		); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		const auto read_duration_avg = stats.read_test_duration / stats.read_count; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		text_test_read_time_value.set( | 
					
						
							|  |  |  | 			format_ticks_as_ms(stats.read_duration_min) + "/" + | 
					
						
							|  |  |  | 			format_ticks_as_ms(read_duration_avg) + "/" + | 
					
						
							|  |  |  | 			format_ticks_as_ms(stats.read_duration_max) | 
					
						
							|  |  |  | 		); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		text_test_read_rate_value.set( | 
					
						
							|  |  |  | 			format_bytes_per_ticks_as_mib(stats.read_bytes, stats.read_duration_min * stats.read_count) + " " + | 
					
						
							|  |  |  | 			format_bytes_per_ticks_as_mib(stats.read_bytes, stats.read_test_duration) | 
					
						
							|  |  |  | 		); | 
					
						
							|  |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2020-06-09 23:43:45 +02:00
										 |  |  | 		text_test_write_time_value.set("Fail: " + thread.ResultStr[thread.result() + 8]); | 
					
						
							| 
									
										
										
										
											2016-04-10 17:16:39 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } /* namespace ui */ |