Infrared: fix RAW parsing in cli. Remove dead sources. (#1255)
* Infrared: fix RAW parsing in cli. Remove dead sources.
This commit is contained in:
		
							parent
							
								
									8d737133fe
								
							
						
					
					
						commit
						8a81b79e00
					
				| @ -1,6 +1,5 @@ | ||||
| #include <furi_hal_delay.h> | ||||
| #include <infrared.h> | ||||
| #include <app_template.h> | ||||
| #include <cli/cli.h> | ||||
| #include <cmsis_os2.h> | ||||
| #include <infrared_worker.h> | ||||
| @ -86,7 +85,7 @@ static void infrared_cli_print_usage(void) { | ||||
|     } | ||||
|     printf("\r\n"); | ||||
|     printf("\tRaw format:\r\n"); | ||||
|     printf("\tir_tx RAW F:<frequency> DC:<duty_cycle> <sample0> <sample1>...\r\n"); | ||||
|     printf("\tir tx RAW F:<frequency> DC:<duty_cycle> <sample0> <sample1>...\r\n"); | ||||
|     printf( | ||||
|         "\tFrequency (%d - %d), Duty cycle (0 - 100), max 512 samples\r\n", | ||||
|         INFRARED_MIN_FREQUENCY, | ||||
| @ -178,7 +177,7 @@ static void infrared_cli_start_ir(Cli* cli, string_t args, void* context) { | ||||
|                 break; | ||||
|             } | ||||
|             if(string_get_cstr(args)[size] == ' ') { | ||||
|                 string_right(args, size); | ||||
|                 string_right(args, size + 1); | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|  | ||||
| @ -1,443 +0,0 @@ | ||||
| #include "file_worker.h" | ||||
| #include <m-string.h> | ||||
| #include <lib/toolbox/hex.h> | ||||
| #include <dialogs/dialogs.h> | ||||
| #include <furi.h> | ||||
| 
 | ||||
| struct FileWorker { | ||||
|     Storage* api; | ||||
|     bool silent; | ||||
|     File* file; | ||||
| }; | ||||
| 
 | ||||
| bool file_worker_check_common_errors(FileWorker* file_worker); | ||||
| void file_worker_show_error_internal(FileWorker* file_worker, const char* error_text); | ||||
| bool file_worker_read_internal(FileWorker* file_worker, void* buffer, uint16_t bytes_to_read); | ||||
| bool file_worker_write_internal( | ||||
|     FileWorker* file_worker, | ||||
|     const void* buffer, | ||||
|     uint16_t bytes_to_write); | ||||
| bool file_worker_tell_internal(FileWorker* file_worker, uint64_t* position); | ||||
| bool file_worker_seek_internal(FileWorker* file_worker, uint64_t position, bool from_start); | ||||
| 
 | ||||
| FileWorker* file_worker_alloc(bool _silent) { | ||||
|     FileWorker* file_worker = malloc(sizeof(FileWorker)); | ||||
|     file_worker->silent = _silent; | ||||
|     file_worker->api = furi_record_open("storage"); | ||||
|     file_worker->file = storage_file_alloc(file_worker->api); | ||||
| 
 | ||||
|     return file_worker; | ||||
| } | ||||
| 
 | ||||
| void file_worker_free(FileWorker* file_worker) { | ||||
|     storage_file_free(file_worker->file); | ||||
|     furi_record_close("storage"); | ||||
|     free(file_worker); | ||||
| } | ||||
| 
 | ||||
| bool file_worker_open( | ||||
|     FileWorker* file_worker, | ||||
|     const char* filename, | ||||
|     FS_AccessMode access_mode, | ||||
|     FS_OpenMode open_mode) { | ||||
|     bool result = storage_file_open(file_worker->file, filename, access_mode, open_mode); | ||||
| 
 | ||||
|     if(!result) { | ||||
|         file_worker_show_error_internal(file_worker, "Cannot open\nfile"); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     return file_worker_check_common_errors(file_worker); | ||||
| } | ||||
| 
 | ||||
| bool file_worker_close(FileWorker* file_worker) { | ||||
|     if(storage_file_is_open(file_worker->file)) { | ||||
|         storage_file_close(file_worker->file); | ||||
|     } | ||||
| 
 | ||||
|     return file_worker_check_common_errors(file_worker); | ||||
| } | ||||
| 
 | ||||
| bool file_worker_mkdir(FileWorker* file_worker, const char* dirname) { | ||||
|     FS_Error fs_result = storage_common_mkdir(file_worker->api, dirname); | ||||
| 
 | ||||
|     if(fs_result != FSE_OK && fs_result != FSE_EXIST) { | ||||
|         file_worker_show_error_internal(file_worker, "Cannot create\nfolder"); | ||||
|         return false; | ||||
|     }; | ||||
| 
 | ||||
|     return file_worker_check_common_errors(file_worker); | ||||
| } | ||||
| 
 | ||||
| bool file_worker_remove(FileWorker* file_worker, const char* filename) { | ||||
|     FS_Error fs_result = storage_common_remove(file_worker->api, filename); | ||||
|     if(fs_result != FSE_OK && fs_result != FSE_NOT_EXIST) { | ||||
|         file_worker_show_error_internal(file_worker, "Cannot remove\nold file"); | ||||
|         return false; | ||||
|     }; | ||||
| 
 | ||||
|     return file_worker_check_common_errors(file_worker); | ||||
| } | ||||
| 
 | ||||
| void file_worker_get_next_filename( | ||||
|     FileWorker* file_worker, | ||||
|     const char* dirname, | ||||
|     const char* filename, | ||||
|     const char* fileextension, | ||||
|     string_t nextfilename) { | ||||
|     string_t temp_str; | ||||
|     string_init(temp_str); | ||||
|     uint16_t num = 0; | ||||
| 
 | ||||
|     string_printf(temp_str, "%s/%s%s", dirname, filename, fileextension); | ||||
| 
 | ||||
|     while(storage_common_stat(file_worker->api, string_get_cstr(temp_str), NULL) == FSE_OK) { | ||||
|         num++; | ||||
|         string_printf(temp_str, "%s/%s%d%s", dirname, filename, num, fileextension); | ||||
|     } | ||||
| 
 | ||||
|     if(num) { | ||||
|         string_printf(nextfilename, "%s%d", filename, num); | ||||
|     } else { | ||||
|         string_printf(nextfilename, "%s", filename); | ||||
|     } | ||||
| 
 | ||||
|     string_clear(temp_str); | ||||
| } | ||||
| 
 | ||||
| bool file_worker_read(FileWorker* file_worker, void* buffer, uint16_t bytes_to_read) { | ||||
|     if(!file_worker_read_internal(file_worker, buffer, bytes_to_read)) { | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     return file_worker_check_common_errors(file_worker); | ||||
| } | ||||
| 
 | ||||
| bool file_worker_read_until(FileWorker* file_worker, string_t str_result, char separator) { | ||||
|     string_reset(str_result); | ||||
|     const uint8_t buffer_size = 32; | ||||
|     uint8_t buffer[buffer_size]; | ||||
| 
 | ||||
|     do { | ||||
|         uint16_t read_count = storage_file_read(file_worker->file, buffer, buffer_size); | ||||
|         if(storage_file_get_error(file_worker->file) != FSE_OK) { | ||||
|             file_worker_show_error_internal(file_worker, "Cannot read\nfile"); | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         bool result = false; | ||||
|         for(uint16_t i = 0; i < read_count; i++) { | ||||
|             if(buffer[i] == separator) { | ||||
|                 uint64_t position; | ||||
|                 if(!file_worker_tell_internal(file_worker, &position)) { | ||||
|                     return false; | ||||
|                 } | ||||
| 
 | ||||
|                 position = position - read_count + i + 1; | ||||
| 
 | ||||
|                 if(!file_worker_seek_internal(file_worker, position, true)) { | ||||
|                     return false; | ||||
|                 } | ||||
| 
 | ||||
|                 result = true; | ||||
|                 break; | ||||
|             } else { | ||||
|                 string_push_back(str_result, buffer[i]); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         if(result || read_count == 0) { | ||||
|             break; | ||||
|         } | ||||
|     } while(true); | ||||
| 
 | ||||
|     return file_worker_check_common_errors(file_worker); | ||||
| } | ||||
| 
 | ||||
| bool file_worker_read_hex(FileWorker* file_worker, uint8_t* buffer, uint16_t bytes_to_read) { | ||||
|     uint8_t hi_nibble_value, low_nibble_value; | ||||
|     uint8_t text[2]; | ||||
| 
 | ||||
|     for(uint8_t i = 0; i < bytes_to_read; i++) { | ||||
|         if(i != 0) { | ||||
|             // space
 | ||||
|             if(!file_worker_read_internal(file_worker, text, 1)) { | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // actual data
 | ||||
|         if(!file_worker_read_internal(file_worker, text, 2)) { | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         // convert hex value to byte
 | ||||
|         if(hex_char_to_hex_nibble(text[0], &hi_nibble_value) && | ||||
|            hex_char_to_hex_nibble(text[1], &low_nibble_value)) { | ||||
|             buffer[i] = (hi_nibble_value << 4) | low_nibble_value; | ||||
|         } else { | ||||
|             file_worker_show_error_internal(file_worker, "Cannot parse\nfile"); | ||||
|             return false; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return file_worker_check_common_errors(file_worker); | ||||
| } | ||||
| 
 | ||||
| bool file_worker_tell(FileWorker* file_worker, uint64_t* position) { | ||||
|     if(!file_worker_tell_internal(file_worker, position)) { | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     return file_worker_check_common_errors(file_worker); | ||||
| } | ||||
| 
 | ||||
| bool file_worker_seek(FileWorker* file_worker, uint64_t position, bool from_start) { | ||||
|     if(!file_worker_seek_internal(file_worker, position, from_start)) { | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     return file_worker_check_common_errors(file_worker); | ||||
| } | ||||
| 
 | ||||
| bool file_worker_write(FileWorker* file_worker, const void* buffer, uint16_t bytes_to_write) { | ||||
|     if(!file_worker_write_internal(file_worker, buffer, bytes_to_write)) { | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     return file_worker_check_common_errors(file_worker); | ||||
| } | ||||
| 
 | ||||
| bool file_worker_write_hex(FileWorker* file_worker, const uint8_t* buffer, uint16_t bytes_to_write) { | ||||
|     const uint8_t byte_text_size = 3; | ||||
|     char byte_text[byte_text_size]; | ||||
| 
 | ||||
|     for(uint8_t i = 0; i < bytes_to_write; i++) { | ||||
|         sniprintf(byte_text, byte_text_size, "%02X", buffer[i]); | ||||
| 
 | ||||
|         if(i != 0) { | ||||
|             // space
 | ||||
|             const char* space = " "; | ||||
|             if(!file_worker_write_internal(file_worker, space, 1)) { | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         if(!file_worker_write_internal(file_worker, byte_text, 2)) { | ||||
|             return false; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return file_worker_check_common_errors(file_worker); | ||||
| } | ||||
| 
 | ||||
| void file_worker_show_error(FileWorker* file_worker, const char* error_text) { | ||||
|     UNUSED(file_worker); | ||||
|     DialogsApp* dialogs = furi_record_open("dialogs"); | ||||
| 
 | ||||
|     DialogMessage* message = dialog_message_alloc(); | ||||
|     dialog_message_set_text(message, error_text, 88, 32, AlignCenter, AlignCenter); | ||||
|     dialog_message_set_icon(message, &I_SDQuestion_35x43, 5, 6); | ||||
|     dialog_message_set_buttons(message, "Back", NULL, NULL); | ||||
|     dialog_message_show(dialogs, message); | ||||
|     dialog_message_free(message); | ||||
| 
 | ||||
|     furi_record_close("dialogs"); | ||||
| } | ||||
| 
 | ||||
| bool file_worker_file_select( | ||||
|     FileWorker* file_worker, | ||||
|     const char* path, | ||||
|     const char* extension, | ||||
|     char* result, | ||||
|     uint8_t result_size, | ||||
|     const char* selected_filename) { | ||||
|     UNUSED(file_worker); | ||||
|     DialogsApp* dialogs = furi_record_open("dialogs"); | ||||
|     bool ret = | ||||
|         dialog_file_select_show(dialogs, path, extension, result, result_size, selected_filename); | ||||
|     furi_record_close("dialogs"); | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| bool file_worker_check_common_errors(FileWorker* file_worker) { | ||||
|     UNUSED(file_worker); | ||||
|     //TODO remove
 | ||||
|     /* TODO: [FL-1431] Add return value to file_parser.get_sd_api().check_error() and replace get_fs_info(). */ | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| void file_worker_show_error_internal(FileWorker* file_worker, const char* error_text) { | ||||
|     if(!file_worker->silent) { | ||||
|         file_worker_show_error(file_worker, error_text); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| bool file_worker_read_internal(FileWorker* file_worker, void* buffer, uint16_t bytes_to_read) { | ||||
|     uint16_t read_count = storage_file_read(file_worker->file, buffer, bytes_to_read); | ||||
| 
 | ||||
|     if(storage_file_get_error(file_worker->file) != FSE_OK || read_count != bytes_to_read) { | ||||
|         file_worker_show_error_internal(file_worker, "Cannot read\nfile"); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool file_worker_write_internal( | ||||
|     FileWorker* file_worker, | ||||
|     const void* buffer, | ||||
|     uint16_t bytes_to_write) { | ||||
|     uint16_t write_count = storage_file_write(file_worker->file, buffer, bytes_to_write); | ||||
| 
 | ||||
|     if(storage_file_get_error(file_worker->file) != FSE_OK || write_count != bytes_to_write) { | ||||
|         file_worker_show_error_internal(file_worker, "Cannot write\nto file"); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool file_worker_tell_internal(FileWorker* file_worker, uint64_t* position) { | ||||
|     *position = storage_file_tell(file_worker->file); | ||||
| 
 | ||||
|     if(storage_file_get_error(file_worker->file) != FSE_OK) { | ||||
|         file_worker_show_error_internal(file_worker, "Cannot tell\nfile offset"); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool file_worker_seek_internal(FileWorker* file_worker, uint64_t position, bool from_start) { | ||||
|     storage_file_seek(file_worker->file, position, from_start); | ||||
|     if(storage_file_get_error(file_worker->file) != FSE_OK) { | ||||
|         file_worker_show_error_internal(file_worker, "Cannot seek\nfile"); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool file_worker_read_until_buffered( | ||||
|     FileWorker* file_worker, | ||||
|     string_t str_result, | ||||
|     char* file_buf, | ||||
|     size_t* file_buf_cnt, | ||||
|     size_t file_buf_size, | ||||
|     char separator) { | ||||
|     furi_assert(string_capacity(str_result) > 0); | ||||
| 
 | ||||
|     // fs_api->file.read now supports up to 512 bytes reading at a time
 | ||||
|     furi_assert(file_buf_size <= 512); | ||||
| 
 | ||||
|     string_reset(str_result); | ||||
|     size_t newline_index = 0; | ||||
|     bool found_eol = false; | ||||
|     bool max_length_exceeded = false; | ||||
|     size_t max_length = string_capacity(str_result) - 1; | ||||
| 
 | ||||
|     while(1) { | ||||
|         if(*file_buf_cnt > 0) { | ||||
|             size_t end_index = 0; | ||||
|             char* endline_ptr = (char*)memchr(file_buf, separator, *file_buf_cnt); | ||||
|             newline_index = endline_ptr - file_buf; | ||||
| 
 | ||||
|             if(endline_ptr == 0) { | ||||
|                 end_index = *file_buf_cnt; | ||||
|             } else if(newline_index < *file_buf_cnt) { | ||||
|                 end_index = newline_index + 1; | ||||
|                 found_eol = true; | ||||
|             } else { | ||||
|                 furi_assert(0); | ||||
|             } | ||||
| 
 | ||||
|             if(max_length && (string_size(str_result) + end_index > max_length)) | ||||
|                 max_length_exceeded = true; | ||||
| 
 | ||||
|             if(!max_length_exceeded) { | ||||
|                 for(size_t i = 0; i < end_index; ++i) { | ||||
|                     string_push_back(str_result, file_buf[i]); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             memmove(file_buf, &file_buf[end_index], *file_buf_cnt - end_index); | ||||
|             *file_buf_cnt = *file_buf_cnt - end_index; | ||||
|             if(found_eol) break; | ||||
|         } | ||||
| 
 | ||||
|         *file_buf_cnt += storage_file_read( | ||||
|             file_worker->file, &file_buf[*file_buf_cnt], file_buf_size - *file_buf_cnt); | ||||
|         if(storage_file_get_error(file_worker->file) != FSE_OK) { | ||||
|             file_worker_show_error_internal(file_worker, "Cannot read\nfile"); | ||||
|             string_reset(str_result); | ||||
|             *file_buf_cnt = 0; | ||||
|             break; | ||||
|         } | ||||
|         if(*file_buf_cnt == 0) { | ||||
|             break; // end of reading
 | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if(max_length_exceeded) string_reset(str_result); | ||||
| 
 | ||||
|     return string_size(str_result) || *file_buf_cnt; | ||||
| } | ||||
| 
 | ||||
| bool file_worker_get_value_from_key( | ||||
|     FileWorker* file_worker, | ||||
|     string_t key, | ||||
|     char delimiter, | ||||
|     string_t value) { | ||||
|     bool found = false; | ||||
|     string_t next_line; | ||||
|     string_t next_key; | ||||
|     string_init(next_line); | ||||
|     string_init(next_key); | ||||
|     size_t delim_pos = 0; | ||||
| 
 | ||||
|     while(file_worker_read_until(file_worker, next_line, '\n')) { | ||||
|         delim_pos = string_search_char(next_line, delimiter); | ||||
|         if(delim_pos == STRING_FAILURE) { | ||||
|             break; | ||||
|         } | ||||
|         string_set_n(next_key, next_line, 0, delim_pos); | ||||
|         if(string_equal_p(next_key, key)) { | ||||
|             string_right(next_line, delim_pos); | ||||
|             string_strim(next_line); | ||||
|             string_set(value, next_line); | ||||
|             found = true; | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     string_clear(next_line); | ||||
|     string_clear(next_key); | ||||
|     return found; | ||||
| } | ||||
| 
 | ||||
| bool file_worker_rename(FileWorker* file_worker, const char* old_path, const char* new_path) { | ||||
|     FS_Error fs_result = storage_common_rename(file_worker->api, old_path, new_path); | ||||
| 
 | ||||
|     if(fs_result != FSE_OK && fs_result != FSE_EXIST) { | ||||
|         file_worker_show_error_internal(file_worker, "Cannot rename\n file/directory"); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     return file_worker_check_common_errors(file_worker); | ||||
| } | ||||
| 
 | ||||
| bool file_worker_check_errors(FileWorker* file_worker) { | ||||
|     return file_worker_check_common_errors(file_worker); | ||||
| } | ||||
| 
 | ||||
| bool file_worker_is_file_exist(FileWorker* file_worker, const char* filename, bool* exist) { | ||||
|     File* file = storage_file_alloc(file_worker->api); | ||||
| 
 | ||||
|     *exist = storage_file_open(file, filename, FSAM_READ, FSOM_OPEN_EXISTING); | ||||
|     storage_file_close(file); | ||||
|     storage_file_free(file); | ||||
| 
 | ||||
|     bool result = file_worker_check_common_errors(file_worker); | ||||
|     return result; | ||||
| } | ||||
| @ -1,249 +0,0 @@ | ||||
| #pragma once | ||||
| #include <m-string.h> | ||||
| #include <storage/storage.h> | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief File operations helper class. | ||||
|  * Automatically opens API records, shows error message on error. | ||||
|  */ | ||||
| typedef struct FileWorker FileWorker; | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief Allocate FileWorker | ||||
|  *  | ||||
|  * @param silent do not show errors except from file_worker_show_error fn | ||||
|  * @return FileWorker*  | ||||
|  */ | ||||
| FileWorker* file_worker_alloc(bool silent); | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief free FileWorker | ||||
|  *  | ||||
|  * @param file_worker  | ||||
|  */ | ||||
| void file_worker_free(FileWorker* file_worker); | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief Open file | ||||
|  *  | ||||
|  * @param file_worker FileWorker instance  | ||||
|  * @param filename  | ||||
|  * @param access_mode  | ||||
|  * @param open_mode  | ||||
|  * @return true on success | ||||
|  */ | ||||
| bool file_worker_open( | ||||
|     FileWorker* file_worker, | ||||
|     const char* filename, | ||||
|     FS_AccessMode access_mode, | ||||
|     FS_OpenMode open_mode); | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief Close file | ||||
|  *  | ||||
|  * @param file_worker FileWorker instance  | ||||
|  * @return true on success | ||||
|  */ | ||||
| bool file_worker_close(FileWorker* file_worker); | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief Creates a directory. Doesn't show error if directory exist.  | ||||
|  *  | ||||
|  * @param file_worker FileWorker instance  | ||||
|  * @param dirname  | ||||
|  * @return true on success | ||||
|  */ | ||||
| bool file_worker_mkdir(FileWorker* file_worker, const char* dirname); | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief Removes the file. Doesn't show error if file doesn't exist. | ||||
|  *  | ||||
|  * @param file_worker FileWorker instance  | ||||
|  * @param filename  | ||||
|  * @return true on success   | ||||
|  */ | ||||
| bool file_worker_remove(FileWorker* file_worker, const char* filename); | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief Get next free filename. | ||||
|  *  | ||||
|  * @param file_worker FileWorker instance  | ||||
|  * @param dirname  | ||||
|  * @param filename  | ||||
|  * @param fileextension  | ||||
|  * @param nextfilename return name | ||||
|  */ | ||||
| void file_worker_get_next_filename( | ||||
|     FileWorker* file_worker, | ||||
|     const char* dirname, | ||||
|     const char* filename, | ||||
|     const char* fileextension, | ||||
|     string_t nextfilename); | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief Reads data from a file. | ||||
|  *  | ||||
|  * @param file_worker FileWorker instance  | ||||
|  * @param buffer  | ||||
|  * @param bytes_to_read  | ||||
|  * @return true on success   | ||||
|  */ | ||||
| bool file_worker_read(FileWorker* file_worker, void* buffer, uint16_t bytes_to_read); | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief Reads data from a file until separator or EOF is found.  | ||||
|  * Moves seek pointer to the next symbol after the separator. The separator is not included in the result. | ||||
|  *  | ||||
|  * @param file_worker FileWorker instance  | ||||
|  * @param result  | ||||
|  * @param separator  | ||||
|  * @return true on success   | ||||
|  */ | ||||
| bool file_worker_read_until(FileWorker* file_worker, string_t result, char separator); | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief Reads data in hexadecimal space-delimited format. For example "AF FF" in a file - [175, 255] in a read buffer. | ||||
|  *  | ||||
|  * @param file_worker FileWorker instance  | ||||
|  * @param buffer  | ||||
|  * @param bytes_to_read  | ||||
|  * @return true on success   | ||||
|  */ | ||||
| bool file_worker_read_hex(FileWorker* file_worker, uint8_t* buffer, uint16_t bytes_to_read); | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief Read seek pointer value | ||||
|  *  | ||||
|  * @param file_worker FileWorker instance  | ||||
|  * @param position  | ||||
|  * @return true on success   | ||||
|  */ | ||||
| bool file_worker_tell(FileWorker* file_worker, uint64_t* position); | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief Set seek pointer value | ||||
|  *  | ||||
|  * @param file_worker FileWorker instance  | ||||
|  * @param position  | ||||
|  * @param from_start  | ||||
|  * @return true on success   | ||||
|  */ | ||||
| bool file_worker_seek(FileWorker* file_worker, uint64_t position, bool from_start); | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief Write data to file. | ||||
|  *  | ||||
|  * @param file_worker FileWorker instance  | ||||
|  * @param buffer  | ||||
|  * @param bytes_to_write  | ||||
|  * @return true on success   | ||||
|  */ | ||||
| bool file_worker_write(FileWorker* file_worker, const void* buffer, uint16_t bytes_to_write); | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief Write data to file in hexadecimal space-delimited format. For example [175, 255] in a write buffer - "AF FF" in a file. | ||||
|  *  | ||||
|  * @param file_worker FileWorker instance  | ||||
|  * @param buffer  | ||||
|  * @param bytes_to_write  | ||||
|  * @return true on success   | ||||
|  */ | ||||
| bool file_worker_write_hex(FileWorker* file_worker, const uint8_t* buffer, uint16_t bytes_to_write); | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief Show system file error message | ||||
|  *  | ||||
|  * @param file_worker FileWorker instance  | ||||
|  * @param error_text  | ||||
|  */ | ||||
| void file_worker_show_error(FileWorker* file_worker, const char* error_text); | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief Show system file select widget | ||||
|  *  | ||||
|  * @param file_worker FileWorker instance  | ||||
|  * @param path path to directory | ||||
|  * @param extension file extension to be offered for selection | ||||
|  * @param selected_filename buffer where the selected filename will be saved | ||||
|  * @param selected_filename_size and the size of this buffer | ||||
|  * @param preselected_filename filename to be preselected | ||||
|  * @return bool whether a file was selected | ||||
|  */ | ||||
| bool file_worker_file_select( | ||||
|     FileWorker* file_worker, | ||||
|     const char* path, | ||||
|     const char* extension, | ||||
|     char* selected_filename, | ||||
|     uint8_t selected_filename_size, | ||||
|     const char* preselected_filename); | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief Reads data from a file until separator or EOF is found. | ||||
|  * The separator is included in the result. | ||||
|  * | ||||
|  * @param file_worker FileWorker instance | ||||
|  * @param str_result | ||||
|  * @param file_buf | ||||
|  * @param file_buf_cnt | ||||
|  * @param max_length | ||||
|  * @param separator | ||||
|  * @return true on success | ||||
|  */ | ||||
| bool file_worker_read_until_buffered( | ||||
|     FileWorker* file_worker, | ||||
|     string_t str_result, | ||||
|     char* file_buf, | ||||
|     size_t* file_buf_cnt, | ||||
|     size_t max_length, | ||||
|     char separator); | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief Gets value from key | ||||
|  * | ||||
|  * @param file_worker FileWorker instance | ||||
|  * @param key key | ||||
|  * @param delimeter key-value delimeter | ||||
|  * @param value value for given key | ||||
|  * @return true on success | ||||
|  */ | ||||
| bool file_worker_get_value_from_key( | ||||
|     FileWorker* file_worker, | ||||
|     string_t key, | ||||
|     char delimiter, | ||||
|     string_t value); | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief Check whether file exist or not | ||||
|  * | ||||
|  * @param file_worker FileWorker instance | ||||
|  * @param filename | ||||
|  * @param exist - flag to show file exist | ||||
|  * @return true on success | ||||
|  */ | ||||
| bool file_worker_is_file_exist(FileWorker* file_worker, const char* filename, bool* exist); | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief Rename file or directory | ||||
|  * | ||||
|  * @param file_worker FileWorker instance | ||||
|  * @param old_filename | ||||
|  * @param new_filename | ||||
|  * @return true on success | ||||
|  */ | ||||
| bool file_worker_rename(FileWorker* file_worker, const char* old_path, const char* new_path); | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief Check errors | ||||
|  * | ||||
|  * @param file_worker FileWorker instance | ||||
|  * @return true on success | ||||
|  */ | ||||
| bool file_worker_check_errors(FileWorker* file_worker); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
| @ -1,94 +0,0 @@ | ||||
| #include "file_worker_cpp.h" | ||||
| #include <lib/toolbox/hex.h> | ||||
| 
 | ||||
| FileWorkerCpp::FileWorkerCpp(bool _silent) { | ||||
|     file_worker = file_worker_alloc(_silent); | ||||
| } | ||||
| 
 | ||||
| FileWorkerCpp::~FileWorkerCpp() { | ||||
|     file_worker_free(file_worker); | ||||
| } | ||||
| 
 | ||||
| bool FileWorkerCpp::open(const char* filename, FS_AccessMode access_mode, FS_OpenMode open_mode) { | ||||
|     return file_worker_open(file_worker, filename, access_mode, open_mode); | ||||
| } | ||||
| 
 | ||||
| bool FileWorkerCpp::close() { | ||||
|     return file_worker_close(file_worker); | ||||
| } | ||||
| 
 | ||||
| bool FileWorkerCpp::mkdir(const char* dirname) { | ||||
|     return file_worker_mkdir(file_worker, dirname); | ||||
| } | ||||
| 
 | ||||
| bool FileWorkerCpp::remove(const char* filename) { | ||||
|     return file_worker_remove(file_worker, filename); | ||||
| } | ||||
| 
 | ||||
| bool FileWorkerCpp::read(void* buffer, uint16_t bytes_to_read) { | ||||
|     return file_worker_read(file_worker, buffer, bytes_to_read); | ||||
| } | ||||
| 
 | ||||
| bool FileWorkerCpp::read_until(string_t str_result, char separator) { | ||||
|     return file_worker_read_until(file_worker, str_result, separator); | ||||
| } | ||||
| 
 | ||||
| bool FileWorkerCpp::read_hex(uint8_t* buffer, uint16_t bytes_to_read) { | ||||
|     return file_worker_read_hex(file_worker, buffer, bytes_to_read); | ||||
| } | ||||
| 
 | ||||
| bool FileWorkerCpp::tell(uint64_t* position) { | ||||
|     return file_worker_tell(file_worker, position); | ||||
| } | ||||
| 
 | ||||
| bool FileWorkerCpp::seek(uint64_t position, bool from_start) { | ||||
|     return file_worker_seek(file_worker, position, from_start); | ||||
| } | ||||
| 
 | ||||
| bool FileWorkerCpp::write(const void* buffer, uint16_t bytes_to_write) { | ||||
|     return file_worker_write(file_worker, buffer, bytes_to_write); | ||||
| } | ||||
| 
 | ||||
| bool FileWorkerCpp::write_hex(const uint8_t* buffer, uint16_t bytes_to_write) { | ||||
|     return file_worker_write_hex(file_worker, buffer, bytes_to_write); | ||||
| } | ||||
| 
 | ||||
| void FileWorkerCpp::show_error(const char* error_text) { | ||||
|     file_worker_show_error(file_worker, error_text); | ||||
| } | ||||
| 
 | ||||
| bool FileWorkerCpp::file_select( | ||||
|     const char* path, | ||||
|     const char* extension, | ||||
|     char* result, | ||||
|     uint8_t result_size, | ||||
|     const char* selected_filename) { | ||||
|     return file_worker_file_select( | ||||
|         file_worker, path, extension, result, result_size, selected_filename); | ||||
| } | ||||
| 
 | ||||
| bool FileWorkerCpp::read_until_buffered( | ||||
|     string_t str_result, | ||||
|     char* file_buf, | ||||
|     size_t* file_buf_cnt, | ||||
|     size_t max_length, | ||||
|     char separator) { | ||||
|     return file_worker_read_until_buffered( | ||||
|         file_worker, str_result, file_buf, file_buf_cnt, max_length, separator); | ||||
| } | ||||
| 
 | ||||
| bool FileWorkerCpp::get_value_from_key(string_t key, char delimiter, string_t value) { | ||||
|     return file_worker_get_value_from_key(file_worker, key, delimiter, value); | ||||
| } | ||||
| 
 | ||||
| bool FileWorkerCpp::is_file_exist(const char* filename, bool* exist) { | ||||
|     return file_worker_is_file_exist(file_worker, filename, exist); | ||||
| } | ||||
| 
 | ||||
| bool FileWorkerCpp::rename(const char* old_path, const char* new_path) { | ||||
|     return file_worker_rename(file_worker, old_path, new_path); | ||||
| } | ||||
| 
 | ||||
| bool FileWorkerCpp::check_errors() { | ||||
|     return file_worker_check_errors(file_worker); | ||||
| } | ||||
| @ -1,190 +0,0 @@ | ||||
| #pragma once | ||||
| #include "file_worker.h" | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief File operations helper class. | ||||
|  * Automatically opens API records, shows error message on error. | ||||
|  */ | ||||
| class FileWorkerCpp { | ||||
| public: | ||||
|     FileWorkerCpp(bool silent = false); | ||||
|     ~FileWorkerCpp(); | ||||
| 
 | ||||
|     /**
 | ||||
|      * @brief Open file | ||||
|      *  | ||||
|      * @param filename  | ||||
|      * @param access_mode  | ||||
|      * @param open_mode  | ||||
|      * @return true on success | ||||
|      */ | ||||
|     bool open(const char* filename, FS_AccessMode access_mode, FS_OpenMode open_mode); | ||||
| 
 | ||||
|     /**
 | ||||
|      * @brief Close file | ||||
|      *  | ||||
|      * @return true on success | ||||
|      */ | ||||
|     bool close(); | ||||
| 
 | ||||
|     /**
 | ||||
|      * @brief Creates a directory. Doesn't show error if directory exist.  | ||||
|      *  | ||||
|      * @param dirname  | ||||
|      * @return true on success | ||||
|      */ | ||||
|     bool mkdir(const char* dirname); | ||||
| 
 | ||||
|     /**
 | ||||
|      * @brief Removes the file. Doesn't show error if file doesn't exist. | ||||
|      *  | ||||
|      * @param filename  | ||||
|      * @return true on success   | ||||
|      */ | ||||
|     bool remove(const char* filename); | ||||
| 
 | ||||
|     /**
 | ||||
|      * @brief Reads data from a file. | ||||
|      *  | ||||
|      * @param buffer  | ||||
|      * @param bytes_to_read  | ||||
|      * @return true on success   | ||||
|      */ | ||||
|     bool read(void* buffer, uint16_t bytes_to_read = 1); | ||||
| 
 | ||||
|     /**
 | ||||
|      * @brief Reads data from a file until separator or EOF is found.  | ||||
|      * Moves seek pointer to the next symbol after the separator. The separator is not included in the result. | ||||
|      *  | ||||
|      * @param result  | ||||
|      * @param separator  | ||||
|      * @return true on success   | ||||
|      */ | ||||
|     bool read_until(string_t result, char separator = '\n'); | ||||
| 
 | ||||
|     /**
 | ||||
|      * @brief Reads data in hexadecimal space-delimited format. For example "AF FF" in a file - [175, 255] in a read buffer. | ||||
|      *  | ||||
|      * @param buffer  | ||||
|      * @param bytes_to_read  | ||||
|      * @return true on success   | ||||
|      */ | ||||
|     bool read_hex(uint8_t* buffer, uint16_t bytes_to_read = 1); | ||||
| 
 | ||||
|     /**
 | ||||
|      * @brief Read seek pointer value | ||||
|      *  | ||||
|      * @param position  | ||||
|      * @return true on success   | ||||
|      */ | ||||
|     bool tell(uint64_t* position); | ||||
| 
 | ||||
|     /**
 | ||||
|      * @brief Set seek pointer value | ||||
|      *  | ||||
|      * @param position  | ||||
|      * @param from_start  | ||||
|      * @return true on success   | ||||
|      */ | ||||
|     bool seek(uint64_t position, bool from_start); | ||||
| 
 | ||||
|     /**
 | ||||
|      * @brief Write data to file. | ||||
|      *  | ||||
|      * @param buffer  | ||||
|      * @param bytes_to_write  | ||||
|      * @return true on success   | ||||
|      */ | ||||
|     bool write(const void* buffer, uint16_t bytes_to_write = 1); | ||||
| 
 | ||||
|     /**
 | ||||
|      * @brief Write data to file in hexadecimal space-delimited format. For example [175, 255] in a write buffer - "AF FF" in a file. | ||||
|      *  | ||||
|      * @param buffer  | ||||
|      * @param bytes_to_write  | ||||
|      * @return true on success   | ||||
|      */ | ||||
|     bool write_hex(const uint8_t* buffer, uint16_t bytes_to_write = 1); | ||||
| 
 | ||||
|     /**
 | ||||
|      * @brief Show system file error message | ||||
|      *  | ||||
|      * @param error_text  | ||||
|      */ | ||||
|     void show_error(const char* error_text); | ||||
| 
 | ||||
|     /**
 | ||||
|      * @brief Show system file select widget | ||||
|      *  | ||||
|      * @param path  | ||||
|      * @param extension  | ||||
|      * @param result  | ||||
|      * @param result_size  | ||||
|      * @param selected_filename  | ||||
|      * @return true if file was selected | ||||
|      */ | ||||
|     bool file_select( | ||||
|         const char* path, | ||||
|         const char* extension, | ||||
|         char* result, | ||||
|         uint8_t result_size, | ||||
|         const char* selected_filename); | ||||
| 
 | ||||
|     /**
 | ||||
|      * @brief Reads data from a file until separator or EOF is found. | ||||
|      * Moves seek pointer to the next symbol after the separator. The separator is included in the result. | ||||
|      * | ||||
|      * @param result | ||||
|      * @param file_buf | ||||
|      * @param file_buf_cnt | ||||
|      * @param max_length | ||||
|      * @param separator | ||||
|      * @return true on success | ||||
|      */ | ||||
|     bool read_until_buffered( | ||||
|         string_t str_result, | ||||
|         char* file_buf, | ||||
|         size_t* file_buf_cnt, | ||||
|         size_t max_length, | ||||
|         char separator = '\n'); | ||||
| 
 | ||||
|     /**
 | ||||
|      * @brief Gets value from key | ||||
|      * | ||||
|      * @param file_worker FileWorker instance | ||||
|      * @param key key | ||||
|      * @param delimeter key-value delimeter | ||||
|      * @param value value for given key | ||||
|      * @return true on success | ||||
|      */ | ||||
|     bool get_value_from_key(string_t key, char delimiter, string_t value); | ||||
| 
 | ||||
|     /**
 | ||||
|      * @brief Check whether file exist or not | ||||
|      * | ||||
|      * @param file_worker FileWorker instance | ||||
|      * @param filename | ||||
|      * @param exist - flag to show file exist | ||||
|      * @return true on success | ||||
|      */ | ||||
|     bool is_file_exist(const char* filename, bool* exist); | ||||
| 
 | ||||
|     /**
 | ||||
|      * @brief Rename file or directory | ||||
|      * | ||||
|      * @param old_filename | ||||
|      * @param new_filename | ||||
|      * @return true on success | ||||
|      */ | ||||
|     bool rename(const char* old_path, const char* new_path); | ||||
| 
 | ||||
|     /**
 | ||||
|      * @brief Check errors | ||||
|      * | ||||
|      * @return true if no errors | ||||
|      */ | ||||
|     bool check_errors(); | ||||
| 
 | ||||
| private: | ||||
|     FileWorker* file_worker; | ||||
| }; | ||||
| @ -1,102 +0,0 @@ | ||||
| #include "app_template.h" | ||||
| 
 | ||||
| /*
 | ||||
| To use this example you need to rename | ||||
| AppExampleState - class to hold app state | ||||
| AppExampleEvent - class to hold app event | ||||
| AppExample      - app class | ||||
| app_cpp_example - function that launch app | ||||
| */ | ||||
| 
 | ||||
| // event enumeration type
 | ||||
| typedef uint8_t event_t; | ||||
| 
 | ||||
| // app state class
 | ||||
| class AppExampleState { | ||||
| public: | ||||
|     // state data
 | ||||
|     uint8_t example_data; | ||||
| 
 | ||||
|     // state initializer
 | ||||
|     AppExampleState() { | ||||
|         example_data = 0; | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| // app events class
 | ||||
| class AppExampleEvent { | ||||
| public: | ||||
|     // events enum
 | ||||
|     static const event_t EventTypeTick = 0; | ||||
|     static const event_t EventTypeKey = 1; | ||||
| 
 | ||||
|     // payload
 | ||||
|     union { | ||||
|         InputEvent input; | ||||
|     } value; | ||||
| 
 | ||||
|     // event type
 | ||||
|     event_t type; | ||||
| }; | ||||
| 
 | ||||
| // our app derived from base AppTemplate class
 | ||||
| // with template variables <state, events>
 | ||||
| class AppExample : public AppTemplate<AppExampleState, AppExampleEvent> { | ||||
| public: | ||||
|     uint8_t run(); | ||||
|     void render(Canvas* canvas); | ||||
| }; | ||||
| 
 | ||||
| // start app
 | ||||
| uint8_t AppExample::run() { | ||||
|     // here we dont need to acquire or release state
 | ||||
|     // because before we call app_ready our application is "single threaded"
 | ||||
|     state.example_data = 12; | ||||
| 
 | ||||
|     // signal that we ready to render and ipc
 | ||||
|     app_ready(); | ||||
| 
 | ||||
|     // from here, any data that pass in render function must be guarded
 | ||||
|     // by calling acquire_state and release_state
 | ||||
| 
 | ||||
|     AppExampleEvent event; | ||||
|     while(1) { | ||||
|         if(get_event(&event, 1000)) { | ||||
|             if(event.type == AppExampleEvent::EventTypeKey) { | ||||
|                 // press events
 | ||||
|                 if(event.value.input.type == InputTypeShort && | ||||
|                    event.value.input.key == InputKeyBack) { | ||||
|                     printf("bye!\n"); | ||||
|                     return exit(); | ||||
|                 } | ||||
| 
 | ||||
|                 if(event.value.input.type == InputTypeShort && | ||||
|                    event.value.input.key == InputKeyUp) { | ||||
|                     // to read or write state you need to execute
 | ||||
|                     // acquire modify release state
 | ||||
|                     acquire_state(); | ||||
|                     state.example_data = 24; | ||||
|                     release_state(); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // signal to force gui update
 | ||||
|         update_gui(); | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
| // render app
 | ||||
| void AppExample::render(Canvas* canvas) { | ||||
|     // here you dont need to call acquire_state or release_state
 | ||||
|     // to read or write app state, that already handled by caller
 | ||||
|     canvas_set_color(canvas, ColorBlack); | ||||
|     canvas_set_font(canvas, FontPrimary); | ||||
|     canvas_draw_str(canvas, 2, state.example_data, "Example app"); | ||||
| } | ||||
| 
 | ||||
| // app enter function
 | ||||
| extern "C" uint8_t app_cpp_example(void* p) { | ||||
|     AppExample* app = new AppExample(); | ||||
|     return app->run(); | ||||
| } | ||||
| @ -1,113 +0,0 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include "callback-connector.h" | ||||
| #include <furi.h> | ||||
| #include <furi_hal.h> | ||||
| #include <gui/gui.h> | ||||
| #include <input/input.h> | ||||
| 
 | ||||
| // simple app class with template variables <state, events>
 | ||||
| template <class TState, class TEvent> class AppTemplate { | ||||
| public: | ||||
|     ViewPort* view_port; | ||||
|     osMessageQueueId_t event_queue; | ||||
|     TState state; | ||||
|     ValueMutex state_mutex; | ||||
|     Gui* gui; | ||||
| 
 | ||||
|     AppTemplate(); | ||||
|     ~AppTemplate(); | ||||
|     void input_callback(InputEvent* input_event, void* ctx); | ||||
|     void draw_callback(Canvas* canvas, void* ctx); | ||||
|     virtual void render(Canvas* canvas) = 0; | ||||
|     void acquire_state(void); | ||||
|     void release_state(void); | ||||
|     bool get_event(TEvent* event, uint32_t timeout); | ||||
|     void app_ready(void); | ||||
|     uint8_t exit(void); | ||||
|     void update_gui(void); | ||||
| }; | ||||
| 
 | ||||
| template <class TState, class TEvent> AppTemplate<TState, TEvent>::AppTemplate() { | ||||
|     // allocate events queue
 | ||||
|     event_queue = osMessageQueueNew(10, sizeof(TEvent), NULL); | ||||
| 
 | ||||
|     // allocate valuemutex
 | ||||
|     // TODO: use plain os mutex?
 | ||||
|     if(!init_mutex(&state_mutex, &state, sizeof(TState))) { | ||||
|         printf("cannot create mutex\n"); | ||||
|         furi_crash(NULL); | ||||
|     } | ||||
| 
 | ||||
|     // open gui
 | ||||
|     gui = (Gui*)furi_record_open("gui"); | ||||
| 
 | ||||
|     // allocate view_port
 | ||||
|     view_port = view_port_alloc(); | ||||
| } | ||||
| 
 | ||||
| template <class TState, class TEvent> AppTemplate<TState, TEvent>::~AppTemplate() { | ||||
| } | ||||
| 
 | ||||
| // generic input callback
 | ||||
| template <class TState, class TEvent> | ||||
| void AppTemplate<TState, TEvent>::input_callback(InputEvent* input_event, void* ctx) { | ||||
|     AppTemplate* app = static_cast<AppTemplate*>(ctx); | ||||
| 
 | ||||
|     TEvent event; | ||||
|     event.type = TEvent::EventTypeKey; | ||||
|     event.value.input = *input_event; | ||||
|     osMessageQueuePut(app->event_queue, &event, 0, 0); | ||||
| } | ||||
| 
 | ||||
| // generic draw callback
 | ||||
| template <class TState, class TEvent> | ||||
| void AppTemplate<TState, TEvent>::draw_callback(Canvas* canvas, void* ctx) { | ||||
|     AppTemplate* app = static_cast<AppTemplate*>(ctx); | ||||
|     app->acquire_state(); | ||||
| 
 | ||||
|     canvas_clear(canvas); | ||||
|     app->render(canvas); | ||||
| 
 | ||||
|     app->release_state(); | ||||
| } | ||||
| 
 | ||||
| template <class TState, class TEvent> void AppTemplate<TState, TEvent>::acquire_state(void) { | ||||
|     acquire_mutex(&state_mutex, osWaitForever); | ||||
| } | ||||
| 
 | ||||
| template <class TState, class TEvent> void AppTemplate<TState, TEvent>::release_state(void) { | ||||
|     release_mutex(&state_mutex, &state); | ||||
| } | ||||
| 
 | ||||
| template <class TState, class TEvent> | ||||
| bool AppTemplate<TState, TEvent>::get_event(TEvent* event, uint32_t timeout) { | ||||
|     osStatus_t event_status = osMessageQueueGet(event_queue, event, NULL, timeout); | ||||
| 
 | ||||
|     return (event_status == osOK); | ||||
| } | ||||
| 
 | ||||
| // signal that app is ready, and we can render something
 | ||||
| // also unblock dependent tasks
 | ||||
| template <class TState, class TEvent> void AppTemplate<TState, TEvent>::app_ready(void) { | ||||
|     // connect view_port with input callback
 | ||||
|     auto input_cb_ref = cbc::obtain_connector(this, &AppTemplate::input_callback); | ||||
|     view_port_input_callback_set(view_port, input_cb_ref, this); | ||||
| 
 | ||||
|     // connect view_port with draw callback
 | ||||
|     auto draw_cb_ref = cbc::obtain_connector(this, &AppTemplate::draw_callback); | ||||
|     view_port_draw_callback_set(view_port, draw_cb_ref, this); | ||||
| 
 | ||||
|     // add view_port
 | ||||
|     gui_add_view_port(gui, view_port, GuiLayerFullscreen); | ||||
| } | ||||
| 
 | ||||
| template <class TState, class TEvent> uint8_t AppTemplate<TState, TEvent>::exit(void) { | ||||
|     // TODO remove all view_ports create by app
 | ||||
|     view_port_enabled_set(view_port, false); | ||||
|     return 255; | ||||
| } | ||||
| 
 | ||||
| template <class TState, class TEvent> void AppTemplate<TState, TEvent>::update_gui(void) { | ||||
|     view_port_update(view_port); | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 あく
						あく