├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── LICENSE ├── README.md ├── src ├── tefs │ ├── CMakeLists.txt │ ├── tefs.c │ └── tefs.h ├── tefs_configuration.h └── tefs_stdio │ ├── CMakeLists.txt │ ├── tefs_stdio.c │ └── tefs_stdio.h └── unit_tests ├── CMakeLists.txt ├── run_tefs.c ├── test_tefs.c └── test_tefs_stdio.c /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | *.ko 4 | *.obj 5 | *.elf 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Libraries 12 | *.lib 13 | *.a 14 | *.la 15 | *.lo 16 | 17 | # Shared objects (inc. Windows DLLs) 18 | *.dll 19 | *.so 20 | *.so.* 21 | *.dylib 22 | 23 | # Executables 24 | *.exe 25 | *.out 26 | *.app 27 | *.i*86 28 | *.x86_64 29 | *.hex 30 | 31 | # Debug files 32 | *.dSYM/ 33 | 34 | # Data files 35 | *.raw 36 | 37 | .project 38 | .settings 39 | .classpath 40 | .sass-cache/ 41 | .idea/ 42 | 43 | # OS generated files 44 | */.DS_Store 45 | .DS_Store 46 | .DS_Store? 47 | ._* 48 | .Spotlight-V100 49 | .Trashes 50 | Icon? 51 | ehthumbs.db 52 | Thumbs.db 53 | 54 | # Packages 55 | *.7z 56 | *.dmg 57 | *.gz 58 | *.iso 59 | *.jar 60 | *.rar 61 | *.tar 62 | *.zip -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "unit_tests/planck_unit"] 2 | path = unit_tests/planck_unit 3 | url = git@github.com:iondbproject/PlanckUnit.git 4 | [submodule "src/tefs/sd_spi"] 5 | path = src/tefs/sd_spi 6 | url = git@github.com:wpenson/SD_SPI_Communication_Library.git 7 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | 3 | SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 4 | SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -Wall") 5 | 6 | add_subdirectory(src/tefs/) 7 | add_subdirectory(src/tefs_stdio/) 8 | add_subdirectory(unit_tests/) 9 | add_subdirectory(src/tefs/sd_spi/src/) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TEFS - Tiny Embedded File System 2 | TEFS is a lightweight, alternative file system designed for microcontrollers which is not FAT. It is written in C and it has a small RAM and program space footprint. It utilizes a custom SD/MMC SPI communications library to read from and write an SD card. Specifically, it can be adapted to work with block based storage device that have an FTL such as SD cards, etc. It works with Arduino out of the box and can easily be ported to different platforms. 3 | 4 | TEFS uses a tree index structure instead a structure such as the File Allocation Table for files so it has some advantages and disadvantages when compared to FAT. From comparing benchmarks of TEFS against FAT filesystems on microcontrollers, FAT performs better when the are fewer files, smaller files, and files are created and removed frequently. However, TEFS performs better when there are many files, larger files, and files are opened and closed often but not created and removed as often. TEFS also has a smaller code size than the Arduino SdFat and FatFs libraries. It can also have long file names as well as custom metadata for each file. 5 | 6 | ## Usage 7 | If you want to use TEFS with the Arduino IDE, you must put the required source files in a single folder with your `.ino` file. A python flatting script is provided that does this for you. 8 | 9 | If you are not using the Arduino IDE, you must add the code specific to your platform in the `src/tefs/sd_spi/src/device/sd_spi_platform_dependencies.c` file if you are using an SD card. A CMake configuration is also provided that you can adapt and use for compiling to your microcontroller. 10 | 11 | TEFS can be used either as a block level interface or as an interface similar to the standard input/output file operations in C. If you wish to just use the block level interface exclusively, delete `tefs_stdio.h` and `tefs_stdio.c` from your project folder. 12 | 13 | Precompiler options for TEFS can be found in the `tefs_configuration.h` file. 14 | 15 | ## Examples 16 | #### Formatting 17 | You storage device must be formatted with TEFS to work. Here is a sketch for the Arduino that demonstrates how to format your storage device: 18 | ```C 19 | #include 20 | #include "tefs.h" 21 | 22 | #define CHIP_SELECT_PIN 4 // Set this to your chip select (CS) pin. 23 | 24 | void setup() 25 | { 26 | Serial.begin(115200); 27 | 28 | if (sd_spi_init(CHIP_SELECT_PIN) != SD_ERR_OK) 29 | { 30 | Serial.println(F("SD card failed to initialize.")); 31 | return; 32 | } 33 | 34 | Serial.println(F("SD card initialized successfully!")); 35 | Serial.println(F("Formatting card with TEFS.")); 36 | 37 | // Page size of 512 bytes, 64 page cluster size (32KB per cluster), hash size of 4 bytes, 32 byte meta data entry size, and file size that is 12 bytes max. 38 | if (tefs_format_device(sd_spi_card_size(), 512, 64, 4, 32, 12) != TEFS_ERR_OK) { 39 | Serial.print(F("Format failed.\n")); 40 | } 41 | 42 | Serial.print(F("Format Successful!\n")); 43 | } 44 | 45 | void loop() {} 46 | ``` 47 | 48 | #### Opening, Closing, and Deleting Files Using the Faster Page Interface 49 | ```C 50 | #include 51 | #include "tefs.h" 52 | 53 | void setup() 54 | { 55 | // Error checking and formatting removed for brevity. 56 | 57 | // Create a file_t file struture and then open a file with the name "file.txt". If the file doesn't already exist, it will be created. 58 | file_t file; 59 | tefs_open(&file, "file.txt"); 60 | 61 | char str[13] = "Hello World!"; 62 | tefs_write(&file, 0, str, sizeof(str) * sizeof(char), 0); // Write a string of 13 bytes in length to the first page and first byte in that page for the file. 63 | 64 | tefs_close(&file); // Close the file. 65 | tefs_remove("file.txt"); // Delete the file. 66 | } 67 | 68 | void loop() {} 69 | ``` 70 | 71 | #### Opening, Closing, and Deleting Files Using the C File Interface 72 | ```C 73 | #include 74 | #include "tefs.h" 75 | #include "tefs_stdio.h" // Include if you wish to use the C standard input/output file 76 | 77 | void setup() 78 | { 79 | // Error checking and formatting removed for brevity. 80 | 81 | // Create a T_FILE file struture pointer and then open a file with the name "file.txt". If the file doesn't already exist, it will be created. 82 | T_FILE *file; 83 | file = t_fopen("file.txt", "wb"); 84 | 85 | char str[13] = "Hello World!"; 86 | t_fwrite(str, sizeof(char), sizeof(str), file); // Write a string of 13 characters in length. 87 | 88 | t_fclose(file); // Close the file. 89 | t_remove("file.txt"); // Delete the file. 90 | } 91 | 92 | void loop() {} 93 | ``` 94 | 95 | ## Support 96 | If there are any bugs, create a new issue with a detailed description of your bug. If you have any questions or suggestions, please send me an email. Feel free to contribute to this repository. Any improvements will be greatly appreciated. 97 | 98 | ## Author 99 | Wade Penson 100 | 101 | wpenson@alumni.ubc.ca 102 | -------------------------------------------------------------------------------- /src/tefs/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | project(tefs) 3 | 4 | set(SOURCE_FILES 5 | tefs.c 6 | tefs.h 7 | ../tefs_configuration.h) 8 | 9 | add_definitions(${sd_spi_emulator_DEFINITIONS}) 10 | 11 | add_library(${PROJECT_NAME} STATIC ${SOURCE_FILES}) 12 | 13 | # Required on Unix OS family to be able to be linked into shared libraries. 14 | set_target_properties(${PROJECT_NAME} PROPERTIES POSITION_INDEPENDENT_CODE ON) 15 | 16 | # Change sd_spi_emulator to sd_spi_device if you want to use TEFS on device 17 | target_link_libraries(${PROJECT_NAME} sd_spi_emulator) -------------------------------------------------------------------------------- /src/tefs/tefs.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************/ 2 | /** 3 | @file tefs.c 4 | @author Wade Penson 5 | @date June, 2015 6 | @brief TEFS (Tiny Embedded File System) implementation. 7 | 8 | @copyright Copyright 2015 Wade Penson 9 | 10 | @license Licensed under the Apache License, Version 2.0 (the "License"); 11 | you may not use this file except in compliance with the License. 12 | You may obtain a copy of the License at 13 | 14 | http://www.apache.org/licenses/LICENSE-2.0 15 | 16 | Unless required by applicable law or agreed to in writing, software 17 | distributed under the License is distributed on an "AS IS" BASIS, 18 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 19 | implied. See the License for the specific language governing 20 | permissions and limitations under the License. 21 | */ 22 | /******************************************************************************/ 23 | 24 | #include "tefs.h" 25 | 26 | #if defined(USE_SD) 27 | /** Current bit that represents a free block in the state section. */ 28 | static uint32_t state_section_bit = 0xFFFFFFFF; 29 | /** The size of the state section. */ 30 | static uint32_t state_section_size = 0; 31 | /** Keeps track if the state section is empty or not. */ 32 | static uint8_t is_block_pool_empty = 0; 33 | #endif 34 | 35 | /** The number of pages that the device has. */ 36 | static uint32_t number_of_pages = 0; 37 | /** The size of a page in bytes. */ 38 | static uint16_t page_size = 0; 39 | /** The number of addresses that can fit into a block. */ 40 | static uint32_t addresses_per_block = 0; 41 | /** The size of a block in pages. */ 42 | static uint16_t block_size = 0; 43 | /** The size of an address in bytes. */ 44 | static uint8_t address_size = 0; 45 | /** The power of 2 exponent for the size of a page (used to improve 46 | performance). */ 47 | static uint8_t page_size_exponent = 0; 48 | /** The power of 2 exponent for the number of addresses that can fit into a 49 | block (used to improve performance). */ 50 | static uint8_t addresses_per_block_exponent = 0; 51 | /** The power of 2 exponent for the size of a block (used to improve 52 | performance). */ 53 | static uint8_t block_size_exponent = 0; 54 | /** The power of 2 exponent for the size of an address (used to improve 55 | performance). */ 56 | static uint8_t address_size_exponent = 0; 57 | /** The size of a hash value. Either 2 or 4 bytes. */ 58 | static uint8_t hash_size = 0; 59 | /** The size of a metadata entry. */ 60 | static uint16_t metadata_size = 0; 61 | /** The max size for a file name. */ 62 | static uint16_t max_file_name_size = 0; 63 | /** Metadata entries file used by the directory. */ 64 | static file_t metadata; 65 | /** Hash entries file used by the directory. */ 66 | static file_t hash_entries; 67 | 68 | #if defined(TEFS_CONTINUOUS_SUPPORT) 69 | /** Determines if continuous writing or reading is in progress. */ 70 | static uint8_t is_read_write_continuous = 0; 71 | #endif 72 | 73 | /** 74 | @brief Finds the directory entry corresponding to the file name. The page 75 | address along with the byte in that page is returned for the 76 | location in the metadata file. If 77 | 78 | @param[in] file_name Name of file as char array with null bit. 79 | @param[out] dir_page_address Page in the metadata file where the metadata entry is. 80 | @param[out] dir_byte_in_page Byte in the page of the file where the metadata entry is. 81 | @param file_operation 0 == find but return an error if the file was not found 82 | 1 == find + create file if doesn't exist 83 | 2 == remove directory entry for the file 84 | 85 | @return An error code as defined by one of the TEFS_ERR_* definitions. 86 | */ 87 | static int8_t 88 | tefs_find_file_directory_entry( 89 | char *file_name, 90 | uint32_t *dir_page_address, 91 | uint16_t *dir_byte_in_page, 92 | uint8_t file_operation 93 | ); 94 | 95 | /** 96 | @brief Reserves a block and returns the address to the start of the block. 97 | 98 | @param[out] *block_address Reserved block address 99 | 100 | @return An error code as defined by one of the TEFS_ERR_* definitions. 101 | */ 102 | static int8_t 103 | tefs_reserve_device_block( 104 | uint32_t *block_address 105 | ); 106 | 107 | /** 108 | @brief Releases a block. 109 | 110 | @param block_address The address of the block to release. 111 | 112 | @return An error code as defined by one of the TEFS_ERR_* definitions. 113 | */ 114 | static int8_t 115 | tefs_release_device_block( 116 | uint32_t block_address 117 | ); 118 | 119 | /** 120 | @brief Erases a block and fills it with zeros. 121 | 122 | @param block_address The address of the block to erase. 123 | 124 | @return An error code as defined by one of the TEFS_ERR_* definitions. 125 | */ 126 | static int8_t 127 | tefs_erase_block( 128 | uint32_t block_address 129 | ); 130 | 131 | #if defined(USE_SD) 132 | /** 133 | @brief Finds the next empty block in the block state section. 134 | 135 | @param *state_section_bit The bit that represents the next empty block. 136 | 137 | @return An error code as defined by one of the TEFS_ERR_* definitions. 138 | */ 139 | static int8_t 140 | tefs_find_next_empty_block( 141 | uint32_t *state_section_bit 142 | ); 143 | #endif 144 | 145 | /** 146 | @brief This maps a logical page in the file to the location of the 147 | pointer in the root index block. 148 | 149 | @param page The logical page in the file. 150 | 151 | @param[out] *page_in_root_index The page in the root index where the pointer is. 152 | 153 | @param[out] *byte_in_root_index_page The byte in the page of the root index where the pointer is. 154 | */ 155 | static void 156 | tefs_map_page_to_root_index_address( 157 | uint32_t page, 158 | uint16_t *page_in_root_index, 159 | uint16_t *byte_in_root_index_page 160 | ); 161 | 162 | /** 163 | @brief This maps a logical page in the file to the location of the 164 | pointer in the child index block. 165 | 166 | @param page The logical page in the file. 167 | 168 | @param[out] *page_in_child_index The page in the child index where the pointer is. 169 | 170 | @param[out] *byte_in_child_index_page The byte in the page of the child index where the pointer is. 171 | */ 172 | static void 173 | tefs_map_page_to_child_index_address( 174 | uint32_t page, 175 | uint16_t *page_in_child_index, 176 | uint16_t *byte_in_child_index_page 177 | ); 178 | 179 | /** 180 | @brief Writes out the file size to the directory entry of the file. 181 | 182 | @param file A file_t structure. 183 | 184 | @return An error code as defined by one of the TEFS_ERR_* definitions. 185 | */ 186 | static int8_t 187 | tefs_update_file_size( 188 | file_t *file 189 | ); 190 | 191 | /** 192 | @brief Finds the bit position from the right for a number that is of power 2. 193 | 194 | @param number A number that is a power of 2. 195 | 196 | @return The bit position. 197 | */ 198 | static uint8_t 199 | tefs_power_of_two_exponent( 200 | uint32_t number 201 | ); 202 | 203 | /** 204 | @brief Gets the data from the information section of the card and loads it into memory. 205 | 206 | @return An error code as defined by one of the TEFS_ERR_* definitions. 207 | */ 208 | static int8_t 209 | tefs_load_card_data( 210 | void 211 | ); 212 | 213 | /** 214 | @brief DJB2a hash function that hashes strings. 215 | 216 | @param *str A string with a null byte at the end. 217 | 218 | @return The hash of the string. 219 | */ 220 | static uint32_t 221 | hash_string( 222 | char *str 223 | ); 224 | 225 | int8_t 226 | tefs_format_device( 227 | uint32_t num_pages, 228 | uint16_t physical_page_size, 229 | uint16_t logical_block_size, 230 | uint8_t hash_size, 231 | uint16_t metadata_size, 232 | uint16_t max_file_name_size, 233 | uint8_t erase_before_format 234 | ) 235 | { 236 | if (erase_before_format) 237 | { 238 | #if defined(USE_SD) 239 | /* Erase the storage device before formatting. */ 240 | if (sd_spi_erase_all()) 241 | { 242 | return TEFS_ERR_ERASE; 243 | } 244 | #endif 245 | /* TODO: Add erase for dataflash */ 246 | } 247 | 248 | /* Determine the size of an address. */ 249 | if (num_pages < POW_2_TO(16)) 250 | { 251 | address_size = 2; 252 | address_size_exponent = 1; 253 | } 254 | else 255 | { 256 | address_size = 4; 257 | address_size_exponent = 2; 258 | } 259 | 260 | page_size = physical_page_size; 261 | block_size = logical_block_size; 262 | page_size_exponent = tefs_power_of_two_exponent(physical_page_size); 263 | block_size_exponent = tefs_power_of_two_exponent(logical_block_size); 264 | 265 | #if defined(USE_SD) 266 | /* Calculate the state section size. */ 267 | /* TODO: Get the number of bits instead of bytes */ 268 | //uint32_t state_section_size_in_bits = ((format_info->number_of_pages - info_section_size) - 1) / (format_info->block_size) + 1; 269 | uint32_t state_section_size_in_bytes = 270 | DIV_BY_POW_2_EXP(num_pages - TEFS_INFO_SECTION_SIZE, block_size_exponent + 3); 271 | 272 | state_section_size = DIV_BY_POW_2_EXP(state_section_size_in_bytes - 1, page_size_exponent) + 1; 273 | #endif 274 | 275 | #if defined(USE_DATAFLASH) && defined(USE_FTL) 276 | /* Reserve the pages required for the info page, and directory. */ 277 | uint32_t i; 278 | for (i = 0; i < TEFS_INFO_SECTION_SIZE + directory_size; i++) 279 | { 280 | flare_logical_page_t p; 281 | flare_GetPage(&ftl, &p); 282 | } 283 | #endif 284 | 285 | uint16_t current_byte = 0; 286 | uint8_t data = 0; 287 | 288 | /* Fill the info block with zeros first. */ 289 | for (current_byte = 0; current_byte < physical_page_size; current_byte++) 290 | { 291 | if (device_write(0, &data, 1, current_byte)) 292 | { 293 | return TEFS_ERR_WRITE; 294 | } 295 | } 296 | 297 | data = TEFS_CHECK_FLAG; 298 | 299 | /* Write the check flag. */ 300 | for (current_byte = 0; current_byte < 4; current_byte++) 301 | { 302 | if (device_write(0, &data, 1, current_byte)) 303 | { 304 | return TEFS_ERR_WRITE; 305 | } 306 | } 307 | 308 | /* Write the number of pages that the device has. */ 309 | if (device_write(0, &num_pages, 4, current_byte)) 310 | { 311 | return TEFS_ERR_WRITE; 312 | } 313 | 314 | current_byte += 4; 315 | 316 | /* Write the physical page size. */ 317 | if (device_write(0, &page_size_exponent, 1, current_byte)) 318 | { 319 | return TEFS_ERR_WRITE; 320 | } 321 | 322 | current_byte += 1; 323 | 324 | /* Write the block size. */ 325 | if (device_write(0, &block_size_exponent, 1, current_byte)) 326 | { 327 | return TEFS_ERR_WRITE; 328 | } 329 | 330 | current_byte += 1; 331 | 332 | /* Write the address size. */ 333 | if (device_write(0, &address_size_exponent, 1, current_byte)) 334 | { 335 | return TEFS_ERR_WRITE; 336 | } 337 | 338 | current_byte += 1; 339 | 340 | /* Write the size of a hash value. */ 341 | if (device_write(0, &hash_size, 1, current_byte)) 342 | { 343 | return TEFS_ERR_WRITE; 344 | } 345 | 346 | current_byte += 1; 347 | 348 | /* Write the size of a metadata record. */ 349 | if (device_write(0, &metadata_size, 2, current_byte)) 350 | { 351 | return TEFS_ERR_WRITE; 352 | } 353 | 354 | current_byte += 2; 355 | 356 | /* Write the max size for a file name. */ 357 | if (device_write(0, &max_file_name_size, 2, current_byte)) 358 | { 359 | return TEFS_ERR_WRITE; 360 | } 361 | 362 | current_byte += 2; 363 | 364 | #if defined(USE_SD) 365 | /* Write the state section size. */ 366 | if (device_write(0, &state_section_size, 4, current_byte)) 367 | { 368 | return TEFS_ERR_WRITE; 369 | } 370 | 371 | current_byte += 4; 372 | #endif 373 | 374 | /* Write out the metadata for the hash entries file and meta data file. */ 375 | uint8_t i; 376 | for (i = 0; i < 2; i++) { 377 | int8_t response; 378 | 379 | /* Get the child index block address and the data block address for the file. */ 380 | uint32_t child_index_block_address = MULT_BY_POW_2_EXP((uint32_t) (i * 2), block_size_exponent) + 381 | (1 + state_section_size); 382 | uint32_t data_block_address = MULT_BY_POW_2_EXP((uint32_t) (i * 2 + 1), block_size_exponent) + 383 | (1 + state_section_size); 384 | 385 | /* Set file size to 0 for hash file directory entry. */ 386 | uint32_t zero = 0; 387 | if (device_write(0, &zero, TEFS_DIR_EOF_PAGE_SIZE, current_byte)) 388 | { 389 | return TEFS_ERR_WRITE; 390 | } 391 | 392 | current_byte += TEFS_DIR_EOF_PAGE_SIZE; 393 | 394 | if (device_write(0, &zero, TEFS_DIR_EOF_BYTE_SIZE, current_byte)) 395 | { 396 | return TEFS_ERR_WRITE; 397 | } 398 | 399 | current_byte += TEFS_DIR_EOF_BYTE_SIZE; 400 | 401 | /* Write root index block address to the information page. */ 402 | if (device_write(0, &child_index_block_address, address_size, current_byte)) 403 | { 404 | return TEFS_ERR_WRITE; 405 | } 406 | 407 | current_byte += 4; 408 | 409 | /* Write the first data block address to the beginning of the root index. */ 410 | if (device_write(child_index_block_address, &data_block_address, address_size, 0)) 411 | { 412 | return TEFS_ERR_WRITE; 413 | } 414 | } 415 | 416 | /* Write out the state section. Set the first four bits as 0 since the */ 417 | #if defined(USE_SD) 418 | uint32_t current_page; 419 | data = 0xFF; 420 | 421 | for (current_page = TEFS_INFO_SECTION_SIZE; 422 | current_page < state_section_size + TEFS_INFO_SECTION_SIZE; 423 | current_page++) 424 | { 425 | for (current_byte = 0; 426 | current_byte < physical_page_size; 427 | current_byte++) 428 | { 429 | if (current_page == state_section_size && current_byte == 430 | MOD_BY_POW_2(state_section_size_in_bytes, POW_2_TO(page_size_exponent))) 431 | { 432 | data = 0; 433 | } 434 | 435 | if (sd_spi_write(current_page, &data, 1, current_byte)) 436 | { 437 | return TEFS_ERR_WRITE; 438 | } 439 | } 440 | } 441 | 442 | data = 0x0F; 443 | if (sd_spi_write(1, &data, 1, 0)) 444 | { 445 | return TEFS_ERR_WRITE; 446 | } 447 | #endif 448 | 449 | if (device_flush()) 450 | { 451 | return TEFS_ERR_WRITE; 452 | } 453 | 454 | /* Address size is set to 0 so that the data is loaded from the card into memory. */ 455 | address_size = 0; 456 | 457 | return TEFS_ERR_OK; 458 | } 459 | 460 | int8_t 461 | tefs_open( 462 | file_t *file, 463 | char *file_name 464 | ) 465 | { 466 | int8_t response; 467 | 468 | /* Load the data from the information page if it has not been previously loaded. */ 469 | if (address_size == 0) 470 | { 471 | if ((response = tefs_load_card_data())) 472 | { 473 | return response; 474 | } 475 | } 476 | 477 | /* Get the size of the file name. Return an error if it exceeds the max length. */ 478 | uint16_t file_name_size = 0; 479 | while (file_name[file_name_size] != '\0') 480 | { 481 | file_name_size++; 482 | } 483 | 484 | if (file_name_size > max_file_name_size) 485 | { 486 | return TEFS_ERR_FILE_NAME_TOO_LONG; 487 | } 488 | 489 | if ((response = tefs_find_file_directory_entry(file_name, &(file->directory_page), &(file->directory_byte), 1)) != 490 | TEFS_NEW_FILE && response != TEFS_ERR_OK) 491 | { 492 | return response; 493 | } 494 | 495 | file->root_index_block_address = 0; 496 | file->child_index_block_address = 0; 497 | file->data_block_address = 0; 498 | 499 | uint16_t meta_entry_byte = file->directory_byte; 500 | 501 | if (response == TEFS_NEW_FILE) /* Create a new file */ 502 | { 503 | uint8_t zero = 0; 504 | 505 | /* Write out zero to the status for now to avoid writing past the end of the file. */ 506 | if ((response = tefs_write(&metadata, file->directory_page, &zero, 1, meta_entry_byte))) 507 | { 508 | return response; 509 | } 510 | 511 | meta_entry_byte++; 512 | 513 | /* Set file size to 0 for directory entry. */ 514 | file->eof_page = 0; 515 | file->eof_byte = 0; 516 | if ((response = tefs_write(&metadata, file->directory_page, &(file->eof_page), 517 | TEFS_DIR_EOF_PAGE_SIZE, meta_entry_byte))) 518 | { 519 | return response; 520 | } 521 | 522 | meta_entry_byte += TEFS_DIR_EOF_PAGE_SIZE; 523 | 524 | if ((response = tefs_write(&metadata, file->directory_page, &(file->eof_byte), 525 | TEFS_DIR_EOF_BYTE_SIZE, meta_entry_byte))) 526 | { 527 | return response; 528 | } 529 | 530 | meta_entry_byte += TEFS_DIR_EOF_BYTE_SIZE; 531 | 532 | /* Write root index block address to directory for file ID. */ 533 | if ((response = tefs_reserve_device_block(&(file->child_index_block_address)))) 534 | { 535 | return response; 536 | } 537 | 538 | if ((response = tefs_write(&metadata, file->directory_page, &(file->child_index_block_address), 539 | 4, meta_entry_byte))) 540 | { 541 | return response; 542 | } 543 | 544 | meta_entry_byte += TEFS_DIR_ROOT_INDEX_ADDRESS_SIZE; 545 | 546 | /* Write file name to directory entry and pad with null chars. */ 547 | if ((response = tefs_write(&metadata, file->directory_page, file_name, file_name_size, meta_entry_byte))) 548 | { 549 | return response; 550 | } 551 | 552 | meta_entry_byte += file_name_size; 553 | 554 | /* Write out the file name and pad it up until the max length. */ 555 | uint8_t i; 556 | for (i = 0; i < max_file_name_size - file_name_size; i++) 557 | { 558 | char null_char = '\0'; 559 | if ((response = tefs_write(&metadata, file->directory_page, &null_char, 1, meta_entry_byte))) 560 | { 561 | return response; 562 | } 563 | 564 | meta_entry_byte++; 565 | } 566 | 567 | // TODO: Write out metadata 568 | 569 | /* Pad the rest of the metadata entry with 0s. */ 570 | while (MOD_BY_POW_2(meta_entry_byte, metadata_size) != 0) 571 | { 572 | if ((response = tefs_write(&metadata, file->directory_page, &zero, 1, meta_entry_byte))) 573 | { 574 | return response; 575 | } 576 | 577 | meta_entry_byte++; 578 | } 579 | 580 | /* Change status to IN_USE for directory entry. */ 581 | uint8_t status = TEFS_IN_USE; 582 | if ((response = tefs_write(&metadata, file->directory_page, &status, 1, file->directory_byte))) 583 | { 584 | return response; 585 | } 586 | 587 | /* Write first data block address to first child index block. */ 588 | if ((response = tefs_reserve_device_block(&(file->data_block_address))) 589 | != 0 && response != TEFS_ERR_DEVICE_FULL) 590 | { 591 | return response; 592 | } 593 | 594 | if (device_write(file->child_index_block_address, &(file->data_block_address), address_size, 0)) 595 | { 596 | return TEFS_ERR_WRITE; 597 | } 598 | 599 | if (device_flush()) 600 | { 601 | return TEFS_ERR_WRITE; 602 | } 603 | } 604 | else /* Open an existing file. */ 605 | { 606 | meta_entry_byte += TEFS_DIR_STATUS_SIZE; 607 | 608 | /* Read the file size. */ 609 | if ((response = tefs_read(&metadata, file->directory_page, &(file->eof_page), 610 | TEFS_DIR_EOF_PAGE_SIZE, meta_entry_byte))) 611 | { 612 | return response; 613 | } 614 | 615 | meta_entry_byte += TEFS_DIR_EOF_PAGE_SIZE; 616 | 617 | if ((response = tefs_read(&metadata, file->directory_page, &(file->eof_byte), 618 | TEFS_DIR_EOF_BYTE_SIZE, meta_entry_byte))) 619 | { 620 | return response; 621 | } 622 | 623 | meta_entry_byte += TEFS_DIR_EOF_BYTE_SIZE; 624 | 625 | /* Read the file pointer. */ 626 | if ((response = tefs_read(&metadata, file->directory_page, &(file->root_index_block_address), 627 | address_size, meta_entry_byte))) 628 | { 629 | return response; 630 | } 631 | 632 | if (file->eof_page >= MULT_BY_POW_2_EXP(block_size, page_size_exponent - address_size_exponent)) 633 | { 634 | /* Read the first child index block address. */ 635 | if (device_read(file->root_index_block_address, &(file->child_index_block_address), address_size, 0)) 636 | { 637 | return TEFS_ERR_READ; 638 | } 639 | 640 | /* Read the first data block address. */ 641 | if (device_read(file->child_index_block_address, &(file->data_block_address), address_size, 0)) 642 | { 643 | return TEFS_ERR_READ; 644 | } 645 | } 646 | else 647 | { 648 | file->child_index_block_address = file->root_index_block_address; 649 | 650 | /* Read the first data block address. */ 651 | if (device_read(file->child_index_block_address, &(file->data_block_address), address_size, 0)) 652 | { 653 | return TEFS_ERR_READ; 654 | } 655 | } 656 | } 657 | 658 | file->data_block_number = 0; 659 | file->current_page_number = 0; 660 | file->is_file_size_consistent = 1; 661 | 662 | return TEFS_ERR_OK; 663 | } 664 | 665 | int8_t 666 | tefs_exists( 667 | char *file_name 668 | ) 669 | { 670 | int8_t response; 671 | 672 | /* Load the data from the information page if it has not been previously loaded. */ 673 | if (address_size == 0) 674 | { 675 | if ((response = tefs_load_card_data())) 676 | { 677 | return response; 678 | } 679 | } 680 | 681 | uint32_t directory_page; 682 | uint16_t directory_byte; 683 | 684 | if (tefs_find_file_directory_entry(file_name, &directory_page, &directory_byte, 0)) 685 | { 686 | return 0; 687 | } 688 | 689 | /* Check if the status for the file's directory entry is set to IN_USE. */ 690 | uint8_t status; 691 | if ((response = tefs_read(&metadata, directory_page, &status, 1, directory_byte))) 692 | { 693 | return response; 694 | } 695 | 696 | if (status == TEFS_IN_USE) 697 | { 698 | return 1; 699 | } 700 | 701 | return 0; 702 | } 703 | 704 | int8_t 705 | tefs_close( 706 | file_t *file 707 | ) 708 | { 709 | if (tefs_flush(file)) 710 | { 711 | return TEFS_ERR_WRITE; 712 | } 713 | 714 | return TEFS_ERR_OK; 715 | } 716 | 717 | int8_t 718 | tefs_remove( 719 | char *file_name 720 | ) 721 | { 722 | int8_t response; 723 | 724 | /* Load the data from the information page if it has not been previously loaded. */ 725 | if (address_size == 0) 726 | { 727 | if ((response = tefs_load_card_data())) 728 | { 729 | return response; 730 | } 731 | } 732 | 733 | uint32_t directory_page; 734 | uint16_t directory_byte; 735 | 736 | if ((response = tefs_find_file_directory_entry(file_name, &directory_page, &directory_byte, 2))) 737 | { 738 | return response; 739 | } 740 | 741 | uint32_t root_index_block_address = 0; 742 | 743 | /* Get the root index block address for the file. */ 744 | if ((response = tefs_read(&metadata, directory_page, &root_index_block_address, TEFS_DIR_ROOT_INDEX_ADDRESS_SIZE, 745 | directory_byte + TEFS_DIR_STATUS_SIZE + TEFS_DIR_EOF_BYTE_SIZE + TEFS_DIR_EOF_PAGE_SIZE))) 746 | { 747 | return response; 748 | } 749 | 750 | uint16_t root_index_current_byte; 751 | uint16_t root_index_current_page; 752 | 753 | uint32_t eof_page; 754 | 755 | /* Read the file size. */ 756 | if ((response = tefs_read(&metadata, directory_page, &(eof_page), TEFS_DIR_EOF_PAGE_SIZE, directory_byte + TEFS_DIR_STATUS_SIZE))) 757 | { 758 | return response; 759 | } 760 | 761 | uint16_t page_in_root_index; 762 | uint16_t byte_in_root_index_page; 763 | tefs_map_page_to_root_index_address(eof_page, &page_in_root_index, &byte_in_root_index_page); 764 | 765 | uint16_t page_in_child_index; 766 | uint16_t byte_in_child_index_page; 767 | tefs_map_page_to_child_index_address(eof_page, &page_in_child_index, &byte_in_child_index_page); 768 | 769 | int8_t past_end = 0; 770 | 771 | /* Release all blocks that are in the file. */ 772 | for (root_index_current_page = 0; 773 | root_index_current_page <= page_in_root_index && !past_end; 774 | root_index_current_page++) 775 | { 776 | for (root_index_current_byte = 0; 777 | root_index_current_byte < page_size && !past_end; 778 | root_index_current_byte += address_size) 779 | { 780 | uint32_t child_index_block_address = 0; 781 | 782 | if (eof_page >= MULT_BY_POW_2_EXP(block_size, page_size_exponent - address_size_exponent)) 783 | { 784 | if (device_read(root_index_block_address + root_index_current_page, &child_index_block_address, 785 | address_size, root_index_current_byte)) 786 | { 787 | return TEFS_ERR_READ; 788 | } 789 | } 790 | else 791 | { 792 | child_index_block_address = root_index_block_address; 793 | } 794 | 795 | uint16_t child_index_current_page; 796 | 797 | for (child_index_current_page = 0; 798 | child_index_current_page < block_size && !past_end; 799 | child_index_current_page++) 800 | { 801 | uint16_t child_index_current_byte; 802 | 803 | for (child_index_current_byte = 0; 804 | child_index_current_byte < page_size && !past_end; 805 | child_index_current_byte += address_size) 806 | { 807 | uint32_t data_block_address = 0; 808 | 809 | if (device_read(child_index_block_address + child_index_current_page, 810 | &data_block_address, address_size, 811 | child_index_current_byte)) 812 | { 813 | return TEFS_ERR_READ; 814 | } 815 | 816 | /* Release data block. */ 817 | if ((response = tefs_release_device_block(data_block_address))) 818 | { 819 | return response; 820 | } 821 | 822 | if (root_index_current_page == page_in_root_index && root_index_current_byte == byte_in_root_index_page && 823 | child_index_current_page == page_in_child_index && child_index_current_byte == byte_in_child_index_page) 824 | { 825 | past_end = 1; 826 | } 827 | } 828 | } 829 | 830 | /* Release child index block. */ 831 | if ((response = tefs_release_device_block(child_index_block_address))) 832 | { 833 | return response; 834 | } 835 | } 836 | } 837 | 838 | if (eof_page >= MULT_BY_POW_2_EXP(block_size, page_size_exponent - address_size_exponent)) 839 | { 840 | /* Release root index block. */ 841 | if ((response = tefs_release_device_block(root_index_block_address))) 842 | { 843 | return response; 844 | } 845 | } 846 | 847 | /* Change file status to deleted. */ 848 | uint8_t status = TEFS_DELETED; 849 | 850 | if ((response = tefs_write(&metadata, directory_page, &status, 1, directory_byte))) 851 | { 852 | return response; 853 | } 854 | 855 | if (device_flush()) 856 | { 857 | return TEFS_ERR_WRITE; 858 | } 859 | 860 | return TEFS_ERR_OK; 861 | } 862 | 863 | int8_t 864 | tefs_write( 865 | file_t *file, 866 | uint32_t file_page_address, 867 | void *data, 868 | uint16_t number_of_bytes, 869 | uint16_t byte_offset 870 | ) 871 | { 872 | uint8_t is_new_page = 0; 873 | 874 | if (file_page_address == file->eof_page) 875 | { 876 | if (byte_offset > file->eof_byte) 877 | { 878 | return TEFS_ERR_WRITE_PAST_END; 879 | } 880 | else if (byte_offset + number_of_bytes > file->eof_byte) 881 | { 882 | if (file->eof_byte == 0 || sd_spi_current_buffered_block() == file->data_block_address + 883 | MOD_BY_POW_2(file_page_address, block_size)) 884 | { 885 | is_new_page = 1; 886 | } 887 | 888 | file->eof_byte = byte_offset + number_of_bytes; 889 | } 890 | 891 | file->is_file_size_consistent = 0; 892 | 893 | if (file->eof_byte == page_size) 894 | { 895 | file->eof_byte = 0; 896 | file->eof_page++; 897 | 898 | if (file->eof_page == MULT_BY_POW_2_EXP(block_size, page_size_exponent - address_size_exponent + block_size_exponent)) 899 | { 900 | int8_t response; 901 | 902 | /* Write first child index block address to root index block. */ 903 | if ((response = tefs_reserve_device_block(&(file->root_index_block_address)))) 904 | { 905 | return response; 906 | } 907 | 908 | if (device_write(file->root_index_block_address, &(file->child_index_block_address), address_size, 0)) 909 | { 910 | return TEFS_ERR_WRITE; 911 | } 912 | 913 | if (file->directory_page == 0xFFFFFFFF) 914 | { 915 | if (device_write(0, &(file->root_index_block_address), address_size, file->directory_byte + max_file_name_size + TEFS_DIR_STATUS_SIZE + TEFS_DIR_EOF_PAGE_SIZE + TEFS_DIR_EOF_BYTE_SIZE)) 916 | { 917 | return TEFS_ERR_WRITE; 918 | } 919 | } 920 | else 921 | { 922 | if ((response = tefs_write(&metadata, file->directory_page, &(file->root_index_block_address), address_size, file->directory_byte + max_file_name_size + TEFS_DIR_STATUS_SIZE + TEFS_DIR_EOF_PAGE_SIZE + TEFS_DIR_EOF_BYTE_SIZE))) 923 | { 924 | return response; 925 | } 926 | } 927 | } 928 | } 929 | } 930 | else if (file_page_address > file->eof_page) 931 | { 932 | return TEFS_ERR_WRITE_PAST_END; 933 | } 934 | 935 | /* Check if page address is in the same block as the current data block. 936 | If it is, write the data. Otherwise, get the new data block address 937 | from the root index block and then write to the page in that new data block. */ 938 | if (file_page_address == file->current_page_number || 939 | DIV_BY_POW_2_EXP(file_page_address, block_size_exponent) == 940 | file->data_block_number) 941 | { 942 | sd_spi_dirty_write = is_new_page; 943 | 944 | if (device_write(file->data_block_address + 945 | MOD_BY_POW_2(file_page_address, block_size), data, 946 | number_of_bytes, byte_offset)) 947 | { 948 | return TEFS_ERR_WRITE; 949 | } 950 | 951 | sd_spi_dirty_write = 0; 952 | } 953 | else 954 | { 955 | /* Check if the page is in the same child index block. If not, get the 956 | address from the root index block or create a new child index block if it 957 | does not exist. */ 958 | uint16_t child_block_number = (uint16_t) DIV_BY_POW_2_EXP(file_page_address, block_size_exponent + addresses_per_block_exponent); 959 | 960 | if (DIV_BY_POW_2_EXP(file->data_block_number, addresses_per_block_exponent) != child_block_number) 961 | { 962 | uint16_t page_in_root_index; 963 | uint16_t byte_in_root_index_page; 964 | tefs_map_page_to_root_index_address(file_page_address, &page_in_root_index, &byte_in_root_index_page); 965 | 966 | /* Make sure that the file has not reached its max capacity. */ 967 | if (page_in_root_index >= block_size) 968 | { 969 | return TEFS_ERR_FILE_FULL; 970 | } 971 | 972 | file->child_index_block_address = 0; 973 | 974 | if (file->is_file_size_consistent) 975 | { 976 | if (device_read(file->root_index_block_address + page_in_root_index, 977 | &(file->child_index_block_address), address_size, 978 | byte_in_root_index_page)) 979 | { 980 | return TEFS_ERR_READ; 981 | } 982 | } 983 | else 984 | { 985 | int8_t response; 986 | if ((response = tefs_reserve_device_block(&(file->child_index_block_address)))) 987 | { 988 | return response; 989 | } 990 | 991 | if (byte_in_root_index_page == 0) 992 | { 993 | sd_spi_dirty_write = 1; 994 | } 995 | 996 | if (device_write(file->root_index_block_address + page_in_root_index, 997 | &(file->child_index_block_address), 998 | address_size, byte_in_root_index_page)) 999 | { 1000 | return TEFS_ERR_WRITE; 1001 | } 1002 | 1003 | sd_spi_dirty_write = 0; 1004 | } 1005 | } 1006 | 1007 | /* Get the data block from the child index block. */ 1008 | uint16_t page_in_child_index; 1009 | uint16_t byte_in_child_index_page; 1010 | tefs_map_page_to_child_index_address(file_page_address, &page_in_child_index, &byte_in_child_index_page); 1011 | 1012 | file->data_block_address = 0; 1013 | 1014 | if (file->is_file_size_consistent) 1015 | { 1016 | if (device_read(file->child_index_block_address + page_in_child_index, 1017 | &(file->data_block_address), address_size, 1018 | byte_in_child_index_page)) 1019 | { 1020 | return TEFS_ERR_READ; 1021 | } 1022 | } 1023 | else 1024 | { 1025 | int8_t response; 1026 | if ((response = tefs_reserve_device_block(&(file->data_block_address)))) 1027 | { 1028 | return response; 1029 | } 1030 | 1031 | if (byte_in_child_index_page == 0) 1032 | { 1033 | sd_spi_dirty_write = 1; 1034 | } 1035 | 1036 | if (device_write(file->child_index_block_address + page_in_child_index, 1037 | &(file->data_block_address), address_size, 1038 | byte_in_child_index_page)) 1039 | { 1040 | return TEFS_ERR_WRITE; 1041 | } 1042 | 1043 | sd_spi_dirty_write = 0; 1044 | } 1045 | 1046 | sd_spi_dirty_write = is_new_page; 1047 | 1048 | if (device_write(file->data_block_address, data, number_of_bytes, 1049 | byte_offset)) 1050 | { 1051 | return TEFS_ERR_WRITE; 1052 | } 1053 | 1054 | sd_spi_dirty_write = 0; 1055 | file->data_block_number = DIV_BY_POW_2_EXP(file_page_address, block_size_exponent); 1056 | } 1057 | 1058 | #if defined(UPDATE_FS_PAGE_CONSISTENCY) 1059 | /* Update file size. */ 1060 | if (!file->is_file_size_consistent && file_page_address != file->current_page_number) 1061 | { 1062 | int8_t err; 1063 | if (err = tefs_update_file_size(file)) 1064 | { 1065 | return err; 1066 | } 1067 | 1068 | file->is_file_size_consistent = 1; 1069 | } 1070 | #elif defined(UPDATE_FS_RECORD_CONSISTENCY) 1071 | if (!file->is_file_size_consistent) 1072 | { 1073 | int8_t err; 1074 | if (err = tefs_update_file_size(file)) 1075 | { 1076 | return err; 1077 | } 1078 | 1079 | file->is_file_size_consistent = 1; 1080 | } 1081 | #endif 1082 | 1083 | file->current_page_number = file_page_address; 1084 | 1085 | return TEFS_ERR_OK; 1086 | } 1087 | 1088 | int8_t 1089 | tefs_flush( 1090 | file_t *file 1091 | ) 1092 | { 1093 | if (device_flush()) 1094 | { 1095 | return TEFS_ERR_WRITE; 1096 | } 1097 | 1098 | /* Update file size. */ 1099 | if (!file->is_file_size_consistent) 1100 | { 1101 | int8_t err; 1102 | if ((err = tefs_update_file_size(file))) 1103 | { 1104 | return err; 1105 | } 1106 | } 1107 | 1108 | return TEFS_ERR_OK; 1109 | } 1110 | 1111 | int8_t 1112 | tefs_read( 1113 | file_t *file, 1114 | uint32_t file_page_address, 1115 | void *buffer, 1116 | uint16_t number_of_bytes, 1117 | uint16_t byte_offset 1118 | ) 1119 | { 1120 | #if defined(UPDATE_FS_PAGE_CONSISTENCY) 1121 | /* Update file size if necessary. */ 1122 | if (!file->is_file_size_consistent && file_page_address != file->current_page_number) 1123 | { 1124 | int8_t err; 1125 | if ((err = tefs_update_file_size(file))) 1126 | { 1127 | return err; 1128 | } 1129 | } 1130 | #endif 1131 | 1132 | if (file_page_address == file->eof_page) 1133 | { 1134 | if (byte_offset > file->eof_byte) 1135 | { 1136 | return TEFS_ERR_EOF; 1137 | } 1138 | else if (byte_offset + number_of_bytes > file->eof_byte) 1139 | { 1140 | return TEFS_ERR_EOF; 1141 | } 1142 | } 1143 | else if (file_page_address > file->eof_page) 1144 | { 1145 | return TEFS_ERR_EOF; 1146 | } 1147 | 1148 | /* Check if page address is in the same block as the current data block. 1149 | If it is, read the data. Otherwise, get the new data block address 1150 | from the root index block and then read to the page in that new data block. */ 1151 | if (file_page_address == file->current_page_number || 1152 | DIV_BY_POW_2_EXP(file_page_address, block_size_exponent) == file->data_block_number) 1153 | { 1154 | if (device_read(file->data_block_address + MOD_BY_POW_2(file_page_address, block_size), 1155 | buffer, number_of_bytes, byte_offset)) 1156 | { 1157 | return TEFS_ERR_READ; 1158 | } 1159 | } 1160 | else 1161 | { 1162 | /* Check if the page is in the same child index block. If not, get the 1163 | address from the root index block or throw an error if it does not 1164 | exist. */ 1165 | uint16_t child_block_number = (uint16_t) DIV_BY_POW_2_EXP(file_page_address, block_size_exponent + addresses_per_block_exponent); 1166 | 1167 | if (DIV_BY_POW_2_EXP(file->data_block_number, addresses_per_block_exponent) != child_block_number) 1168 | { 1169 | uint16_t page_in_root_index; 1170 | uint16_t byte_in_root_index_page; 1171 | tefs_map_page_to_root_index_address(file_page_address, &page_in_root_index, &byte_in_root_index_page); 1172 | 1173 | /* Make sure that the file has not reached its max capacity. */ 1174 | if (page_in_root_index >= block_size) 1175 | { 1176 | return TEFS_ERR_FILE_FULL; 1177 | } 1178 | 1179 | file->child_index_block_address = 0; 1180 | 1181 | if (device_read(file->root_index_block_address + page_in_root_index, 1182 | &(file->child_index_block_address), address_size, 1183 | byte_in_root_index_page)) 1184 | { 1185 | return TEFS_ERR_READ; 1186 | } 1187 | } 1188 | 1189 | /* Get the data block from the child index block. */ 1190 | uint16_t page_in_child_index; 1191 | uint16_t byte_in_child_index_page; 1192 | tefs_map_page_to_child_index_address(file_page_address, &page_in_child_index, &byte_in_child_index_page); 1193 | 1194 | file->data_block_address = 0; 1195 | 1196 | if (device_read(file->child_index_block_address + page_in_child_index, 1197 | &(file->data_block_address), address_size, 1198 | byte_in_child_index_page)) 1199 | { 1200 | return TEFS_ERR_READ; 1201 | } 1202 | 1203 | if (device_read(file->data_block_address, buffer, number_of_bytes, 1204 | byte_offset)) 1205 | { 1206 | return TEFS_ERR_READ; 1207 | } 1208 | 1209 | file->data_block_number = DIV_BY_POW_2_EXP(file_page_address, block_size_exponent); 1210 | } 1211 | 1212 | file->current_page_number = file_page_address; 1213 | 1214 | return TEFS_ERR_OK; 1215 | } 1216 | 1217 | int8_t 1218 | tefs_release_block( 1219 | file_t *file, 1220 | uint32_t file_block_address 1221 | ) 1222 | { 1223 | uint16_t child_block_number = (uint16_t) DIV_BY_POW_2_EXP(file_block_address, addresses_per_block_exponent); 1224 | uint16_t page_in_root_index = DIV_BY_POW_2_EXP(child_block_number, page_size_exponent - address_size_exponent); 1225 | uint16_t byte_in_root_index_page = (uint16_t) (MULT_BY_POW_2_EXP(child_block_number, address_size_exponent) & (addresses_per_block - 1)); 1226 | 1227 | uint32_t block_in_child_index = DIV_BY_POW_2_EXP(file_block_address, block_size_exponent) & (addresses_per_block - 1); 1228 | uint16_t page_in_child_index = (uint16_t) DIV_BY_POW_2_EXP(block_in_child_index, page_size_exponent - address_size_exponent); 1229 | uint16_t byte_in_child_index_page = (uint16_t) (MULT_BY_POW_2_EXP(block_in_child_index, address_size_exponent) & (page_size - 1)); 1230 | 1231 | if (file_block_address != file->data_block_number) 1232 | { 1233 | /* Check if the block is in the same child index block. If not, get the 1234 | address from the root index block. */ 1235 | if (DIV_BY_POW_2_EXP(file->data_block_number, addresses_per_block_exponent) != 1236 | child_block_number) 1237 | { 1238 | if (device_read(file->root_index_block_address + page_in_root_index, 1239 | &(file->child_index_block_address), address_size, 1240 | byte_in_root_index_page)) 1241 | { 1242 | return TEFS_ERR_READ; 1243 | } 1244 | 1245 | if (file->child_index_block_address == TEFS_EMPTY || 1246 | file->child_index_block_address == TEFS_DELETED) 1247 | { 1248 | return TEFS_ERR_UNRELEASED_BLOCK; 1249 | } 1250 | } 1251 | 1252 | /* Get the data block from the child index block. */ 1253 | if (device_read(file->child_index_block_address + page_in_child_index, 1254 | &(file->data_block_address), address_size, 1255 | byte_in_child_index_page)) 1256 | { 1257 | return TEFS_ERR_READ; 1258 | } 1259 | 1260 | if (file->data_block_address == TEFS_EMPTY || 1261 | file->data_block_address == TEFS_DELETED) 1262 | { 1263 | return TEFS_ERR_UNRELEASED_BLOCK; 1264 | } 1265 | 1266 | file->data_block_number = file_block_address; 1267 | } 1268 | 1269 | /* Release block. */ 1270 | int8_t response; 1271 | 1272 | if ((response = tefs_release_device_block(file->data_block_address))) 1273 | { 1274 | return response; 1275 | } 1276 | 1277 | /* Remove the address from the child index block. */ 1278 | uint8_t byte_buffer = TEFS_DELETED; 1279 | 1280 | if (device_write(file->child_index_block_address + page_in_child_index, 1281 | &byte_buffer, 1, byte_in_child_index_page)) 1282 | { 1283 | return TEFS_ERR_WRITE; 1284 | } 1285 | 1286 | byte_buffer = 0; 1287 | uint8_t current_byte = 1; 1288 | 1289 | while (current_byte < address_size) 1290 | { 1291 | if (device_write(file->child_index_block_address + page_in_child_index, 1292 | &byte_buffer, 1, 1293 | byte_in_child_index_page + current_byte)) 1294 | { 1295 | return TEFS_ERR_WRITE; 1296 | } 1297 | 1298 | current_byte++; 1299 | } 1300 | 1301 | uint8_t contains_blocks = 0; 1302 | 1303 | /* Scan child index block to see if it's tefs_empty. */ 1304 | for (page_in_child_index = 0; 1305 | page_in_child_index < block_size && !contains_blocks; 1306 | page_in_child_index++) 1307 | { 1308 | for (byte_in_child_index_page = 0; 1309 | byte_in_child_index_page < page_size && !contains_blocks; 1310 | byte_in_child_index_page++) 1311 | { 1312 | if (device_read(file->child_index_block_address + page_in_child_index, 1313 | &byte_buffer, 1, byte_in_child_index_page)) 1314 | { 1315 | return TEFS_ERR_READ; 1316 | } 1317 | 1318 | if (byte_buffer != TEFS_DELETED && byte_buffer != TEFS_EMPTY) 1319 | { 1320 | contains_blocks = 1; 1321 | } 1322 | } 1323 | } 1324 | 1325 | /* Remove child index block from root index block if it's tefs_empty. */ 1326 | if (!contains_blocks) 1327 | { 1328 | byte_buffer = TEFS_DELETED; 1329 | 1330 | if (device_write(file->root_index_block_address + page_in_root_index, &byte_buffer, 1331 | 1, byte_in_root_index_page)) 1332 | { 1333 | return TEFS_ERR_WRITE; 1334 | } 1335 | 1336 | byte_buffer = 0; 1337 | current_byte = 1; 1338 | 1339 | while (current_byte < address_size) 1340 | { 1341 | if (device_write(file->root_index_block_address + page_in_root_index, 1342 | &byte_buffer, 1, byte_in_root_index_page + current_byte)) 1343 | { 1344 | return TEFS_ERR_WRITE; 1345 | } 1346 | 1347 | current_byte++; 1348 | } 1349 | 1350 | if ((response = tefs_release_device_block(file->child_index_block_address))) 1351 | { 1352 | return response; 1353 | } 1354 | } 1355 | 1356 | if (device_flush()) 1357 | { 1358 | return TEFS_ERR_WRITE; 1359 | } 1360 | 1361 | return TEFS_ERR_OK; 1362 | } 1363 | 1364 | static int8_t 1365 | tefs_find_file_directory_entry( 1366 | char *file_name, 1367 | uint32_t *dir_page_address, 1368 | uint16_t *dir_byte_in_page, 1369 | uint8_t file_operation 1370 | ) 1371 | { 1372 | uint32_t name_hash_value = hash_string(file_name); 1373 | uint16_t small_name_hash = (uint16_t) name_hash_value; 1374 | 1375 | uint16_t deleted_hash_page = 0xFFFF; 1376 | uint16_t deleted_hash_byte = 0; 1377 | uint32_t deleted_dir_page_address = 0; 1378 | uint16_t deleted_dir_byte_in_page = 0; 1379 | 1380 | *dir_page_address = 0; 1381 | *dir_byte_in_page = 0; 1382 | 1383 | int8_t response; 1384 | uint16_t current_page = 0; 1385 | uint16_t current_byte = 0; 1386 | while (1) 1387 | { 1388 | uint32_t entry_hash_value = 0; 1389 | if ((response = tefs_read(&hash_entries, current_page, &entry_hash_value, hash_size, current_byte)) != TEFS_ERR_EOF && response != TEFS_ERR_OK) 1390 | { 1391 | return response; 1392 | } 1393 | 1394 | if (response == TEFS_ERR_EOF) /* Reached the end of the hash entries file. */ 1395 | { 1396 | if (file_operation == 1) /* Create file */ 1397 | { 1398 | if (deleted_hash_page <= current_page) 1399 | { 1400 | current_page = deleted_hash_page; 1401 | current_byte = deleted_hash_byte; 1402 | 1403 | *dir_page_address = deleted_dir_page_address; 1404 | *dir_byte_in_page = deleted_dir_byte_in_page; 1405 | } 1406 | 1407 | /* Write out hash value to hash entries file. */ 1408 | if ((response = tefs_write(&hash_entries, current_page, 1409 | (hash_size == 4) ? &name_hash_value : &small_name_hash, hash_size, 1410 | current_byte))) 1411 | { 1412 | return response; 1413 | } 1414 | 1415 | return TEFS_NEW_FILE; 1416 | } 1417 | else if (response == TEFS_ERR_EOF) 1418 | { 1419 | return TEFS_ERR_FILE_NOT_FOUND; 1420 | } 1421 | } 1422 | else if (entry_hash_value == name_hash_value) /* Found file hash */ 1423 | { 1424 | int8_t status; 1425 | if ((response = tefs_read(&metadata, *dir_page_address, &status, 1, *dir_byte_in_page))) 1426 | { 1427 | return response; 1428 | } 1429 | 1430 | if (status != TEFS_EMPTY || status != TEFS_DELETED) 1431 | { 1432 | /* Check if it is the actual file by comparing file names. */ 1433 | int16_t count = -1; 1434 | char c = ' '; 1435 | 1436 | while (count == -1 || (c != '\0' && file_name[count] != '\0' && c == file_name[count] && count < max_file_name_size)) 1437 | { 1438 | if ((response = tefs_read(&metadata, *dir_page_address, &c, 1, *dir_byte_in_page + TEFS_DIR_STATIC_DATA_SIZE + (uint16_t) (count + 1)))) 1439 | { 1440 | return response; 1441 | } 1442 | 1443 | count++; 1444 | } 1445 | 1446 | if (c == file_name[count]) 1447 | { 1448 | if (file_operation == 2) /* Remove file */ 1449 | { 1450 | entry_hash_value = 0; 1451 | if ((response = tefs_write(&hash_entries, current_page, &entry_hash_value, hash_size, current_byte))) 1452 | { 1453 | return response; 1454 | } 1455 | } 1456 | 1457 | return TEFS_ERR_OK; 1458 | } 1459 | } 1460 | } 1461 | else if (file_operation == 1 && entry_hash_value == 0 && deleted_hash_page == 0xFFFF) /* Found a deleted entry. */ 1462 | { 1463 | deleted_hash_page = current_page; 1464 | deleted_hash_byte = current_byte; 1465 | 1466 | deleted_dir_page_address = *dir_page_address; 1467 | deleted_dir_byte_in_page = *dir_byte_in_page; 1468 | } 1469 | 1470 | if ((uint32_t)*dir_byte_in_page + metadata_size >= page_size) 1471 | { 1472 | (*dir_page_address)++; 1473 | *dir_byte_in_page = 0; 1474 | } 1475 | else 1476 | { 1477 | *dir_byte_in_page += metadata_size; 1478 | } 1479 | 1480 | current_byte += hash_size; 1481 | 1482 | if (current_byte >= page_size) 1483 | { 1484 | current_page++; 1485 | current_byte = 0; 1486 | } 1487 | } 1488 | } 1489 | 1490 | static int8_t 1491 | tefs_write_metadata( 1492 | file_t file, 1493 | void *data, 1494 | uint16_t number_of_byte 1495 | ) 1496 | { 1497 | return TEFS_ERR_OK; 1498 | } 1499 | 1500 | static int8_t 1501 | tefs_reserve_device_block( 1502 | uint32_t *block_address 1503 | ) 1504 | { 1505 | #if defined(USE_SD) 1506 | if (is_block_pool_empty) 1507 | { 1508 | return TEFS_ERR_DEVICE_FULL; 1509 | } 1510 | 1511 | uint8_t byte_buffer = 0; 1512 | 1513 | /* Read in byte. */ 1514 | if (device_read(DIV_BY_POW_2_EXP(DIV_BY_POW_2_EXP(state_section_bit, 3), page_size_exponent) + 1, &byte_buffer, 1, (uint16_t) MOD_BY_POW_2(DIV_BY_POW_2_EXP(state_section_bit, 3), page_size))) 1515 | { 1516 | return TEFS_ERR_READ; 1517 | } 1518 | 1519 | /* Check if the block has already been reserved. */ 1520 | if (!(byte_buffer & POW_2_TO(7 - MOD_BY_POW_2(state_section_bit, 8)))) 1521 | { 1522 | return TEFS_ERR_OK; 1523 | } 1524 | 1525 | /* Toggle state bit in byte from 1 to 0. */ 1526 | byte_buffer &= (uint8_t) ~POW_2_TO(7 - MOD_BY_POW_2(state_section_bit, 8)); 1527 | 1528 | /* Write out the byte */ 1529 | if (device_write(DIV_BY_POW_2_EXP(DIV_BY_POW_2_EXP(state_section_bit, 3), page_size_exponent) + 1, &byte_buffer, 1, (uint16_t) MOD_BY_POW_2(DIV_BY_POW_2_EXP(state_section_bit, 3), page_size))) 1530 | { 1531 | return TEFS_ERR_WRITE; 1532 | } 1533 | 1534 | *block_address = MULT_BY_POW_2_EXP(state_section_bit, block_size_exponent) + (1 + state_section_size); 1535 | state_section_bit++; 1536 | 1537 | /* Find the next unreserved block. */ 1538 | int8_t response; 1539 | 1540 | if ((response = tefs_find_next_empty_block(&state_section_bit))) 1541 | { 1542 | return response; 1543 | } 1544 | 1545 | if (device_flush()) 1546 | { 1547 | return TEFS_ERR_WRITE; 1548 | } 1549 | #elif defined(USE_DATAFLASH) && defined(USE_FTL) 1550 | /* Reserve page on FTL. */ 1551 | 1552 | if (block_size == 1) 1553 | { 1554 | flare_logical_page_t p; 1555 | flare_GetPage(&ftl, &p); 1556 | } 1557 | else if (block_size == 2) 1558 | { 1559 | 1560 | } 1561 | #endif 1562 | 1563 | return TEFS_ERR_OK; 1564 | } 1565 | 1566 | static int8_t 1567 | tefs_release_device_block( 1568 | uint32_t block_address 1569 | ) 1570 | { 1571 | #if defined(USE_SD) 1572 | /* Start byte for the state section that is correlated to the block 1573 | address. */ 1574 | uint32_t state_bit = DIV_BY_POW_2_EXP(block_address - (1 + state_section_size), block_size_exponent); 1575 | uint8_t byte_buffer = 0; 1576 | 1577 | /* Read in byte. */ 1578 | if (device_read(DIV_BY_POW_2_EXP(DIV_BY_POW_2_EXP(state_bit, 3), page_size_exponent) + 1, &byte_buffer, 1, (uint16_t) MOD_BY_POW_2(DIV_BY_POW_2_EXP(state_bit, 3), page_size))) 1579 | { 1580 | return TEFS_ERR_READ; 1581 | } 1582 | 1583 | /* Check if the block has already been released. */ 1584 | if (byte_buffer & POW_2_TO(7 - MOD_BY_POW_2(state_bit, 8))) 1585 | { 1586 | return TEFS_ERR_OK; 1587 | } 1588 | 1589 | /* Toggle state bit in byte from 0 to 1. */ 1590 | byte_buffer |= (uint8_t) POW_2_TO(7 - MOD_BY_POW_2(state_bit, 8)); 1591 | 1592 | /* Write out the byte. */ 1593 | if (device_write(DIV_BY_POW_2_EXP(DIV_BY_POW_2_EXP(state_bit, 3), page_size_exponent) + 1, &byte_buffer, 1, (uint16_t) MOD_BY_POW_2(DIV_BY_POW_2_EXP(state_bit, 3), page_size))) 1594 | { 1595 | return TEFS_ERR_WRITE; 1596 | } 1597 | 1598 | if (device_flush()) 1599 | { 1600 | return TEFS_ERR_WRITE; 1601 | } 1602 | 1603 | if (state_bit < state_section_bit) 1604 | { 1605 | state_section_bit = state_bit; 1606 | } 1607 | 1608 | is_block_pool_empty = 0; 1609 | #elif defined(USE_DATAFLASH) && defined(USE_FTL) 1610 | /* Release block from FTL. */ 1611 | if (block_size == 1) 1612 | { 1613 | flare_ReturnPage(&ftl, block_address); 1614 | } 1615 | else if (block_size == 8) 1616 | { 1617 | 1618 | } 1619 | #endif 1620 | 1621 | return TEFS_ERR_OK; 1622 | } 1623 | 1624 | static int8_t 1625 | tefs_erase_block( 1626 | uint32_t block_address 1627 | ) 1628 | { 1629 | /* Erase pages in root index block. */ 1630 | uint32_t current_page; 1631 | uint8_t flag = TEFS_EMPTY; 1632 | 1633 | #if defined(USE_SD) 1634 | if (sd_spi_write_continuous_start(block_address, block_size)) 1635 | { 1636 | return TEFS_ERR_WRITE; 1637 | } 1638 | #endif 1639 | 1640 | for (current_page = block_address; 1641 | current_page < block_size + block_address; 1642 | current_page++) 1643 | { 1644 | uint16_t current_byte; 1645 | 1646 | for (current_byte = 0; 1647 | current_byte < page_size; 1648 | current_byte++) 1649 | { 1650 | #if defined(USE_SD) 1651 | if (sd_spi_write_continuous(&flag, 1, current_byte)) 1652 | { 1653 | return TEFS_ERR_WRITE; 1654 | } 1655 | #else 1656 | if (device_write(current_page, &flag, 1, current_byte)) 1657 | { 1658 | return TEFS_ERR_WRITE; 1659 | } 1660 | #endif 1661 | } 1662 | 1663 | #if defined(USE_SD) 1664 | if (sd_spi_write_continuous_next()) 1665 | { 1666 | return TEFS_ERR_WRITE; 1667 | } 1668 | #endif 1669 | } 1670 | 1671 | #if defined(USE_SD) 1672 | if (sd_spi_write_continuous_stop()) 1673 | { 1674 | return TEFS_ERR_WRITE; 1675 | } 1676 | #endif 1677 | 1678 | return TEFS_ERR_OK; 1679 | } 1680 | 1681 | #if defined(USE_SD) 1682 | static int8_t 1683 | tefs_find_next_empty_block( 1684 | uint32_t *state_section_bit 1685 | ) 1686 | { 1687 | uint32_t current_page = DIV_BY_POW_2_EXP(DIV_BY_POW_2_EXP(*state_section_bit, 3), page_size_exponent); 1688 | uint16_t current_byte = (uint16_t) MOD_BY_POW_2(DIV_BY_POW_2_EXP(*state_section_bit, 3), page_size); 1689 | uint8_t byte_buffer = 0; 1690 | 1691 | while (current_page < state_section_size) 1692 | { 1693 | while (current_byte < page_size) 1694 | { 1695 | if (sd_spi_read(current_page + 1, &byte_buffer, 1, current_byte)) 1696 | { 1697 | return TEFS_ERR_READ; 1698 | } 1699 | 1700 | if (byte_buffer) 1701 | { 1702 | uint8_t mask = 0x80; 1703 | uint8_t count = 0; 1704 | 1705 | while (mask != 0 && !(byte_buffer & mask)) 1706 | { 1707 | mask >>= 1; 1708 | count++; 1709 | } 1710 | 1711 | *state_section_bit = MULT_BY_POW_2_EXP(current_page, page_size_exponent + 3) + 1712 | MULT_BY_POW_2_EXP(current_byte, 3) + count; 1713 | 1714 | return TEFS_ERR_OK; 1715 | } 1716 | 1717 | current_byte++; 1718 | } 1719 | 1720 | current_page++; 1721 | current_byte = 0; 1722 | } 1723 | 1724 | is_block_pool_empty = 1; 1725 | return TEFS_ERR_OK; 1726 | } 1727 | #endif 1728 | 1729 | static void 1730 | tefs_map_page_to_root_index_address( 1731 | uint32_t page, 1732 | uint16_t *page_in_root_index, 1733 | uint16_t *byte_in_root_index_page 1734 | ) 1735 | { 1736 | uint32_t child_block_number = DIV_BY_POW_2_EXP(DIV_BY_POW_2_EXP(page, block_size_exponent), addresses_per_block_exponent); 1737 | 1738 | *page_in_root_index = (uint16_t) DIV_BY_POW_2_EXP(child_block_number, page_size_exponent - address_size_exponent); 1739 | 1740 | *byte_in_root_index_page = (uint16_t) MOD_BY_POW_2(MULT_BY_POW_2_EXP(child_block_number, address_size_exponent), addresses_per_block); 1741 | } 1742 | 1743 | static void 1744 | tefs_map_page_to_child_index_address( 1745 | uint32_t page, 1746 | uint16_t *page_in_child_index, 1747 | uint16_t *byte_in_child_index_page 1748 | ) 1749 | { 1750 | uint32_t block_in_child_index = MOD_BY_POW_2(DIV_BY_POW_2_EXP(page, block_size_exponent), addresses_per_block); 1751 | 1752 | *page_in_child_index = (uint16_t) DIV_BY_POW_2_EXP(block_in_child_index, page_size_exponent - address_size_exponent); 1753 | 1754 | *byte_in_child_index_page = (uint16_t) MOD_BY_POW_2(MULT_BY_POW_2_EXP(block_in_child_index, address_size_exponent), page_size); 1755 | } 1756 | 1757 | static int8_t 1758 | tefs_update_file_size( 1759 | file_t *file 1760 | ) 1761 | { 1762 | int8_t response; 1763 | 1764 | if (file->directory_page == 0xFFFFFFFF) 1765 | { 1766 | if (device_write(0, &(file->eof_page), TEFS_DIR_EOF_PAGE_SIZE, file->directory_byte + TEFS_DIR_STATUS_SIZE)) 1767 | { 1768 | return TEFS_ERR_WRITE; 1769 | } 1770 | 1771 | if (device_write(0, &(file->eof_byte), TEFS_DIR_EOF_BYTE_SIZE, file->directory_byte + TEFS_DIR_STATUS_SIZE + TEFS_DIR_EOF_PAGE_SIZE)) 1772 | { 1773 | return TEFS_ERR_WRITE; 1774 | } 1775 | } 1776 | else 1777 | { 1778 | if ((response = tefs_write(&metadata, file->directory_page, &(file->eof_page), TEFS_DIR_EOF_PAGE_SIZE, file->directory_byte + TEFS_DIR_STATUS_SIZE))) 1779 | { 1780 | return response; 1781 | } 1782 | 1783 | if ((response = tefs_write(&metadata, file->directory_page, &(file->eof_byte), TEFS_DIR_EOF_BYTE_SIZE, file->directory_byte + TEFS_DIR_STATUS_SIZE + TEFS_DIR_EOF_PAGE_SIZE))) 1784 | { 1785 | return response; 1786 | } 1787 | } 1788 | 1789 | file->is_file_size_consistent = 1; 1790 | return TEFS_ERR_OK; 1791 | } 1792 | 1793 | static uint8_t 1794 | tefs_power_of_two_exponent( 1795 | uint32_t number 1796 | ) 1797 | { 1798 | uint8_t position = 0; 1799 | 1800 | while (((number & 1) == 0) && number > 1) 1801 | { 1802 | number >>= 1; 1803 | position++; 1804 | } 1805 | 1806 | return position; 1807 | } 1808 | 1809 | static int8_t 1810 | tefs_load_card_data( 1811 | void 1812 | ) 1813 | { 1814 | uint16_t current_byte = 0; 1815 | uint8_t buffer = 0; 1816 | 1817 | /* Read and verify the check flag. */ 1818 | for (current_byte = 0; current_byte < 4; current_byte++) 1819 | { 1820 | if (device_read(0, &buffer, 1, current_byte)) 1821 | { 1822 | return TEFS_ERR_READ; 1823 | } 1824 | 1825 | if (buffer != TEFS_CHECK_FLAG) 1826 | { 1827 | return TEFS_ERR_NOT_FORMATTED; 1828 | } 1829 | } 1830 | 1831 | /* Read the number of pages that the device has. */ 1832 | if (device_read(0, &number_of_pages, 4, current_byte)) 1833 | { 1834 | return TEFS_ERR_READ; 1835 | } 1836 | 1837 | current_byte += 4; 1838 | 1839 | /* Read the physical page size. */ 1840 | if (device_read(0, &page_size_exponent, 1, current_byte)) 1841 | { 1842 | return TEFS_ERR_READ; 1843 | } 1844 | 1845 | current_byte += 1; 1846 | 1847 | /* Read the block size. */ 1848 | if (device_read(0, &block_size_exponent, 1, current_byte)) 1849 | { 1850 | return TEFS_ERR_READ; 1851 | } 1852 | 1853 | current_byte += 1; 1854 | 1855 | /* Read the address size. */ 1856 | if (device_read(0, &address_size_exponent, 1, current_byte)) 1857 | { 1858 | return TEFS_ERR_READ; 1859 | } 1860 | 1861 | current_byte += 1; 1862 | 1863 | /* Read the size of a hash. */ 1864 | if (device_read(0, &hash_size, 1, current_byte)) 1865 | { 1866 | return TEFS_ERR_READ; 1867 | } 1868 | 1869 | current_byte += 1; 1870 | 1871 | /* Read the size of a metadata record. */ 1872 | if (device_read(0, &metadata_size, 2, current_byte)) 1873 | { 1874 | return TEFS_ERR_WRITE; 1875 | } 1876 | 1877 | current_byte += 2; 1878 | 1879 | /* Write the max size for a file name. */ 1880 | if (device_read(0, &max_file_name_size, 2, current_byte)) 1881 | { 1882 | return TEFS_ERR_WRITE; 1883 | } 1884 | 1885 | current_byte += 2; 1886 | 1887 | #if defined(USE_SD) 1888 | /* Read the state section size. */ 1889 | if (device_read(0, &state_section_size, 4, current_byte)) 1890 | { 1891 | return TEFS_ERR_READ; 1892 | } 1893 | 1894 | current_byte += 4; 1895 | #endif 1896 | 1897 | block_size = (uint16_t) POW_2_TO(block_size_exponent); 1898 | page_size = (uint16_t) POW_2_TO(page_size_exponent); 1899 | address_size = (uint8_t) POW_2_TO(address_size_exponent); 1900 | 1901 | addresses_per_block = DIV_BY_POW_2_EXP(MULT_BY_POW_2_EXP(page_size, block_size_exponent), address_size_exponent); 1902 | addresses_per_block_exponent = tefs_power_of_two_exponent(addresses_per_block); 1903 | 1904 | int8_t response; 1905 | int8_t i; 1906 | file_t *temp_file = &hash_entries; 1907 | for (i = 0; i < 2; i++) 1908 | { 1909 | /* Set file size to 0 for hash file directory entry. */ 1910 | if (device_read(0, &(temp_file->eof_page), TEFS_DIR_EOF_PAGE_SIZE, current_byte)) 1911 | { 1912 | return TEFS_ERR_READ; 1913 | } 1914 | 1915 | current_byte += TEFS_DIR_EOF_PAGE_SIZE; 1916 | 1917 | if (device_read(0, &(temp_file->eof_byte), TEFS_DIR_EOF_BYTE_SIZE, current_byte)) 1918 | { 1919 | return TEFS_ERR_READ; 1920 | } 1921 | 1922 | current_byte += TEFS_DIR_EOF_BYTE_SIZE; 1923 | 1924 | /* Read root index block address from the information page. */ 1925 | if (device_read(0, &(temp_file->root_index_block_address), address_size, current_byte)) 1926 | { 1927 | return TEFS_ERR_WRITE; 1928 | } 1929 | 1930 | current_byte += 4; 1931 | 1932 | if (temp_file->eof_page >= MULT_BY_POW_2_EXP(block_size, page_size_exponent - address_size_exponent)) 1933 | { 1934 | /* Read the first child index block address. */ 1935 | if (device_read(temp_file->root_index_block_address, &(temp_file->child_index_block_address), address_size, 0)) 1936 | { 1937 | return TEFS_ERR_READ; 1938 | } 1939 | 1940 | /* Read the first data block address. */ 1941 | if (device_read(temp_file->child_index_block_address, &(temp_file->data_block_address), address_size, 0)) 1942 | { 1943 | return TEFS_ERR_READ; 1944 | } 1945 | } 1946 | else 1947 | { 1948 | temp_file->child_index_block_address = temp_file->root_index_block_address; 1949 | 1950 | /* Read the first data block address. */ 1951 | if (device_read(temp_file->child_index_block_address, &(temp_file->data_block_address), address_size, 0)) 1952 | { 1953 | return TEFS_ERR_READ; 1954 | } 1955 | } 1956 | 1957 | temp_file->directory_page = 0xFFFFFFFF; 1958 | temp_file->directory_byte = current_byte; 1959 | temp_file->current_page_number = 0; 1960 | temp_file->data_block_number = 0; 1961 | temp_file->is_file_size_consistent = 1; 1962 | 1963 | temp_file = &metadata; 1964 | } 1965 | 1966 | #if defined(USE_SD) 1967 | /* Get first byte in state for a free block. */ 1968 | state_section_bit = 0; 1969 | 1970 | if ((response = tefs_find_next_empty_block(&state_section_bit))) 1971 | { 1972 | return response; 1973 | } 1974 | #endif 1975 | 1976 | // #if DEBUG == 1 1977 | // #if defined(USE_SD) 1978 | // printf("State section bit: %u\n", state_section_bit); 1979 | // printf("State section size: %u\n", state_section_size); 1980 | // #endif 1981 | // printf("Directory size: %u\n", directory_size); 1982 | // printf("Number of pages: %u\n", number_of_pages); 1983 | // printf("Page size: %u\n", page_size); 1984 | // printf("Page size exponent: %u\n", page_size_exponent); 1985 | // printf("Addresses per block: %u\n", addresses_per_block); 1986 | // printf("Addresses per block exponent: %u\n", addresses_per_block_exponent); 1987 | // printf("Block size: %u\n", block_size); 1988 | // printf("Block size exponent: %u\n", block_size_exponent); 1989 | // printf("Address size: %u\n", address_size); 1990 | // printf("Address size exponent: %u\n", address_size_exponent); 1991 | // #endif 1992 | 1993 | return TEFS_ERR_OK; 1994 | } 1995 | 1996 | static uint32_t 1997 | hash_string( 1998 | char *str 1999 | ) 2000 | { 2001 | uint32_t hash = 5381; 2002 | int8_t c; 2003 | 2004 | while ((c = *str++)) 2005 | { 2006 | hash = (uint32_t)((hash << 5) + hash) ^ c; /* hash * 33 ^ c */ 2007 | } 2008 | 2009 | if (hash == 0) 2010 | { 2011 | hash = 1; 2012 | } 2013 | 2014 | if (hash_size == 4) 2015 | { 2016 | return hash; 2017 | } 2018 | else 2019 | { 2020 | return hash % 65521; 2021 | } 2022 | } -------------------------------------------------------------------------------- /src/tefs/tefs.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************/ 2 | /** 3 | @file tefs.h 4 | @author Wade Penson 5 | @date July, 2015 6 | @brief TEFS (Tiny Embedded File System) header. 7 | @details TEFS is a file system designed specifically for embedded 8 | devices that have little RAM. It provides an interface to read 9 | and write to pages (the smallest physical unit of addressable 10 | memory); opening, closing, and removing a file; and formatting the 11 | storage device. 12 | 13 | @copyright Copyright 2015 Wade Penson 14 | 15 | Licensed under the Apache License, Version 2.0 (the "License"); 16 | you may not use this file except in compliance with the License. 17 | You may obtain a copy of the License at 18 | 19 | http://www.apache.org/licenses/LICENSE-2.0 20 | 21 | Unless required by applicable law or agreed to in writing, software 22 | distributed under the License is distributed on an "AS IS" BASIS, 23 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 24 | implied. See the License for the specific language governing 25 | permissions and limitations under the License. 26 | */ 27 | /******************************************************************************/ 28 | 29 | #ifndef TEFS_H_ 30 | #define TEFS_H_ 31 | 32 | #ifdef __cplusplus 33 | extern "C" { 34 | #endif 35 | 36 | #include "stdio.h" 37 | #include "string.h" 38 | #include "../tefs_configuration.h" 39 | 40 | /* TODO: Add repository that has dataflash code */ 41 | #if defined(USE_DATAFLASH) && !defined(USE_FTL) 42 | #include "dataflash/dataflash_raw.h" 43 | #elif defined(USE_DATAFLASH) && defined(USE_FTL) 44 | #include "dataflash/ftl/ftl_api.h" 45 | volatile flare_ftl_t ftl; 46 | #endif 47 | 48 | /* Note: SD_BUFFER must be defined in SD SPI. */ 49 | #include "sd_spi/src/sd_spi.h" 50 | 51 | /* Variable to toggle reading before writing to a page. */ 52 | extern uint8_t sd_spi_dirty_write; 53 | 54 | #if defined(USE_DATAFLASH) && defined(USE_FTL) 55 | #define device_write(page, data, length, offset) \ 56 | flare_WriteBytes(&ftl, page + 16, data, offset, length, 1) 57 | #define device_read(page, buffer, length, offset) \ 58 | flare_ReadBytes(&ftl, page + 16, buffer, offset, length) 59 | #define device_flush() 1==0//df_flush() 60 | #elif defined(USE_SD) 61 | #define device_write(page, data, length, offset) \ 62 | sd_spi_write(page, data, length, offset) 63 | #define device_read(page, buffer, length, offset) \ 64 | sd_spi_read(page, buffer, length, offset) 65 | #define device_flush() sd_spi_flush() 66 | #endif 67 | 68 | #define POW_2_TO(exponent) (((uint32_t) 1) << (exponent)) 69 | #define MULT_BY_POW_2_EXP(expression, exponent) ((expression) << (exponent)) 70 | #define DIV_BY_POW_2_EXP(expression, exponent) ((expression) >> (exponent)) 71 | #define MOD_BY_POW_2(expression, constant) ((expression) & ((constant) - 1)) 72 | 73 | // TODO: Finish implementing continuous support 74 | //#define TEFS_CONTINUOUS_SUPPORT 75 | 76 | #define TEFS_INFO_SECTION_SIZE ((uint8_t) 1) 77 | 78 | #define TEFS_DIR_STATUS_SIZE ((uint8_t) 1) 79 | #define TEFS_DIR_EOF_PAGE_SIZE ((uint8_t) 4) 80 | #define TEFS_DIR_EOF_BYTE_SIZE ((uint8_t) 2) 81 | #define TEFS_DIR_ROOT_INDEX_ADDRESS_SIZE ((uint8_t) 4) 82 | #define TEFS_DIR_STATIC_DATA_SIZE ((uint8_t) 11) 83 | 84 | /** Used in information section to verify if the storage device has been formatted. */ 85 | #define TEFS_CHECK_FLAG 0xFC 86 | 87 | /** Indicates if an entry has not been previously allocated. */ 88 | #define TEFS_EMPTY 0x00 89 | 90 | /** Indicates if an entry had been previously allocated but has been 91 | deleted since. */ 92 | #define TEFS_DELETED 0x01 93 | 94 | /** Indicates if an entry is allocated. */ 95 | #define TEFS_IN_USE 0x02 96 | 97 | /** 98 | @defgroup tefs_err_codes Error codes for TEFS. 99 | @{ 100 | */ 101 | #define TEFS_ERR_OK 0 102 | #define TEFS_ERR_READ 1 103 | #define TEFS_ERR_WRITE 2 104 | #define TEFS_ERR_ERASE 3 105 | #define TEFS_ERR_DEVICE_FULL 4 106 | #define TEFS_ERR_FILE_FULL 5 107 | #define TEFS_ERR_FILE_NOT_FOUND 6 108 | #define TEFS_ERR_UNRELEASED_BLOCK 7 109 | #define TEFS_ERR_NOT_FORMATTED 8 110 | #define TEFS_ERR_WRITE_PAST_END 9 111 | #define TEFS_ERR_EOF 10 112 | #define TEFS_ERR_FILE_NAME_TOO_LONG 11 113 | /** @} End of group tefs_err_codes */ 114 | 115 | /* Return code used internally that indicates if a new file has been created. */ 116 | #define TEFS_NEW_FILE 12 117 | 118 | /** File structure. */ 119 | typedef struct file 120 | { 121 | /** Address for the root index block. */ 122 | uint32_t root_index_block_address; 123 | /** Address for the child index block that was previously read from or written to. */ 124 | uint32_t child_index_block_address; 125 | /** Address for the current data block that was previously read from or written to. */ 126 | uint32_t data_block_address; 127 | /** The block in the file that was previously read from or written to. */ 128 | uint32_t data_block_number; 129 | /** The page in the file that was previously read from or written to. */ 130 | uint32_t current_page_number; 131 | /** The page in the metadata file where the metadata is stored for the file. */ 132 | uint32_t directory_page; 133 | /** The byte in the page in the metadata file where the metadata is stored for the file. */ 134 | uint16_t directory_byte; 135 | /** The last page of the file. (For keeping track of the file size) */ 136 | uint32_t eof_page; 137 | /** The last byte in the last page of the file. (For keeping track of the file size) */ 138 | uint16_t eof_byte; 139 | /** Keeps track if the file size has been written out to the directory entry after more data is written. */ 140 | uint8_t is_file_size_consistent; 141 | } file_t; 142 | 143 | /** 144 | @brief Formats the storage device with TEFS. 145 | 146 | @param number_of_pages The number of physical pages that the storage device 147 | has. 148 | @param physical_page_size The size of the pages in bytes. The page size 149 | must be a power of two and it can range from 150 | 2^0 (1) to 2^15 (32768). 151 | @param block_size The size of a block in terms of pages (not bytes). 152 | The block size must be a power of two and it can 153 | range from 2^5 (32) to 2^15 (32768). 154 | @param hash_size The size of a hash in bytes for the directory entries. 155 | The size can be either 2 or 4 bytes. 156 | @param metadata_size The size of each metadata entry associated with a file. 157 | This includes the size of the file name. 158 | @param max_file_name_size This is the max size of a file name for each file 159 | and it is fixed. It must be less than 160 | (metadata entry size - 10) bytes. 161 | @param erase_before_format A 1 if the whole device is to be erased and a 0 162 | to do a quick formatting without pre-erasing the 163 | card. 164 | 165 | @return An error code as defined by one of the TEFS_ERR_* definitions. 166 | */ 167 | int8_t 168 | tefs_format_device( 169 | uint32_t number_of_pages, 170 | uint16_t physical_page_size, 171 | uint16_t block_size, 172 | uint8_t hash_size, 173 | uint16_t metadata_size, 174 | uint16_t max_file_name_size, 175 | uint8_t erase_before_format 176 | ); 177 | 178 | /** 179 | @brief Opens an existing file given the file name. If the file does 180 | not exist, a new file with the given name will be created. 181 | 182 | @param file A file_t structure. 183 | @param file_name File name 184 | 185 | @return An error code as defined by one of the TEFS_ERR_* definitions. 186 | */ 187 | int8_t 188 | tefs_open( 189 | file_t *file, 190 | char *file_name 191 | ); 192 | 193 | /** 194 | @brief Checks if a file exists given the file name. 195 | 196 | @param file_name File name 197 | 198 | @return If the file exists, 1 is returned. If the file does not exist, 0 is 199 | returned. 200 | */ 201 | int8_t 202 | tefs_exists( 203 | char *file_name 204 | ); 205 | 206 | /** 207 | @brief Closes an already opened file. 208 | @details This flushes the buffer out to the card. 209 | 210 | @param file A file_t structure. 211 | 212 | @return An error code as defined by one of the TEFS_ERR_* definitions. 213 | */ 214 | int8_t 215 | tefs_close( 216 | file_t *file 217 | ); 218 | 219 | /** 220 | @brief Deletes the file with the given file name. 221 | 222 | @param file_name File name 223 | 224 | @return An error code as defined by one of the TEFS_ERR_* definitions. 225 | */ 226 | int8_t 227 | tefs_remove( 228 | char *file_name 229 | ); 230 | 231 | /** 232 | @brief Releases a block from the file. 233 | @details The given block address must be the starting address of a 234 | block (or the address of the first page in the block). 235 | 236 | @param file A file_t structure. 237 | @param file_block_address The address of the block in the file. 238 | 239 | @return An error code as defined by one of the TEFS_ERR_* definitions. 240 | */ 241 | int8_t 242 | tefs_release_block( 243 | file_t *file, 244 | uint32_t file_block_address 245 | ); 246 | 247 | /** 248 | @brief Writes data to a page in the file. 249 | @details If the page does not already exist at the end of a file, 250 | a new data block will be allocated. The data will only be 251 | written out to disk when a new page is accessed or 252 | tefs_flush() is called. 253 | 254 | @param file A file_t structure. 255 | @param file_page_address The address of the logical page in the file. 256 | @param[in] data An array of data / an address to the data in 257 | memory. 258 | @param number_of_bytes The size of the data in bytes. 259 | @param byte_offset The byte offset of where to start writing in the 260 | page. 261 | 262 | @return An error code as defined by one of the TEFS_ERR_* definitions. 263 | */ 264 | int8_t 265 | tefs_write( 266 | file_t *file, 267 | uint32_t file_page_address, 268 | void *data, 269 | uint16_t number_of_bytes, 270 | uint16_t byte_offset 271 | ); 272 | 273 | // TODO: Finish implementing continuous writing. 274 | #if defined(TEFS_CONTINUOUS_SUPPORT) 275 | /** 276 | @brief Notifies the card to prepare for sequential writing starting at the 277 | specified page address in the file. 278 | @details A sequential write must be stopped by calling 279 | tefs_write_continuous_stop(). To write from pages, 280 | tefs_write_continuous() in conjunction with tefs_write_next(). 281 | 282 | @param file A file_t structure. 283 | @param start_file_page_address The address of the first page in the 284 | sequence. 285 | 286 | @return An error code as defined by one of the TEFS_ERR_* definitions. 287 | */ 288 | int8_t 289 | tefs_write_continuous_start( 290 | file_t *file, 291 | uint32_t start_file_page_address 292 | ); 293 | 294 | /** 295 | @brief Writes data to the current page in the sequence. 296 | @details The data will be stored in the buffer which has been cleared with 297 | zeros (hence, current data in the page on the card is not 298 | pre-buffered). The data will be only written out to the card 299 | when tefs_write_continuous_next() or tefs_flush() is explicitly 300 | called. 301 | 302 | @param file A file_t structure. 303 | @param[in] data An array of data / an address to the data in 304 | memory. 305 | @param number_of_bytes The size of the data in bytes. 306 | @param byte_offset The byte offset of where to start writing in the 307 | page. 308 | 309 | @return An error code as defined by one of the TEFS_ERR_* definitions. 310 | */ 311 | int8_t 312 | tefs_write_continuous( 313 | file_t *file, 314 | void *data, 315 | uint16_t number_of_bytes, 316 | uint16_t byte_offset 317 | ); 318 | 319 | /** 320 | @brief Writes out the data in the buffer to the card for continuous writing 321 | and advancing to the next page in the sequence. 322 | 323 | @return An error code as defined by one of the TEFS_ERR_* definitions. 324 | */ 325 | int8_t 326 | tefs_write_continuous_next( 327 | file_t *file 328 | ); 329 | 330 | /** 331 | @brief Notifies the card to stop sequential writing and flushes the buffer 332 | to the card. 333 | @details This may take some time since it waits for the card to complete the 334 | write. 335 | 336 | @return An error code as defined by one of the TEFS_ERR_* definitions. 337 | */ 338 | int8_t 339 | tefs_write_continuous_stop( 340 | file_t *file 341 | ); 342 | #endif 343 | 344 | /** 345 | @brief Flushes the data in the buffer out to the device. 346 | @details This will only flush the data if it has not already been flushed. 347 | 348 | @param file A file_t structure. 349 | 350 | @return An error code as defined by one of the TEFS_ERR_* definitions. 351 | */ 352 | int8_t 353 | tefs_flush( 354 | file_t *file 355 | ); 356 | 357 | /** 358 | @brief Reads data from a page in the file. 359 | @details If the location being read from is past the end of the file, 360 | an error will be returned. 361 | 362 | @param file A file_t structure. 363 | @param file_page_address The address of the logical page in the file. 364 | @param[out] data_buffer A location in memory to write the data to. 365 | @param number_of_bytes The number of bytes to read. 366 | @param byte_offset The byte offset of where to start reading in the 367 | page. 368 | 369 | @return An error code as defined by one of the TEFS_ERR_* definitions. 370 | */ 371 | int8_t 372 | tefs_read( 373 | file_t *file, 374 | uint32_t file_page_address, 375 | void *buffer, 376 | uint16_t number_of_bytes, 377 | uint16_t byte_offset 378 | ); 379 | 380 | // TODO: Finish implementing continuous reading. 381 | #if defined(TEFS_CONTINUOUS_SUPPORT) 382 | /** 383 | @brief Notifies the card to prepare for sequential reading starting at the 384 | specified page address in the file. 385 | @details A sequential read must be stopped by calling 386 | tefs_read_continuous_stop(). To read from pages, use 387 | tefs_read_continuous() in conjunction with tefs_read_next(). 388 | 389 | @param file A file_t structure. 390 | @param start_file_page_address The address of the first page in the 391 | sequence. 392 | 393 | @return An error code as defined by one of the TEFS_ERR_* definitions. 394 | */ 395 | int8_t 396 | tefs_read_continuous_start( 397 | file_t *file, 398 | uint32_t start_file_page_address 399 | ); 400 | 401 | /** 402 | @brief Reads in data from the current page in the sequence. 403 | @details To advance to the next page, tefs_read_continuous_next() must 404 | be explicitly called. 405 | 406 | @param file A file_t structure. 407 | @param[out] data_buffer A location in memory to write the data to. 408 | @param number_of_bytes The number of bytes to read. 409 | @param byte_offset The byte offset of where to start reading in the 410 | block. 411 | 412 | @return An error code as defined by one of the TEFS_ERR_* definitions. 413 | */ 414 | int8_t 415 | tefs_read_continuous( 416 | file_t *file, 417 | void *buffer, 418 | uint16_t number_of_bytes, 419 | uint16_t byte_offset 420 | ); 421 | 422 | /** 423 | @brief Advances to the next block in the sequence. 424 | 425 | @return An error code as defined by one of the TEFS_ERR_* definitions. 426 | */ 427 | int8_t 428 | tefs_read_continuous_next( 429 | file_t *file 430 | ); 431 | 432 | /** 433 | @brief Notifies the card to stop sequential reading. 434 | 435 | @return An error code as defined by one of the TEFS_ERR_* definitions. 436 | */ 437 | int8_t 438 | tefs_read_continuous_stop( 439 | file_t *file 440 | ); 441 | #endif 442 | 443 | #ifdef __cplusplus 444 | } 445 | #endif 446 | 447 | #endif /* TEFS_H_ */ -------------------------------------------------------------------------------- /src/tefs_configuration.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************/ 2 | /** 3 | @file tefs_configuration.h 4 | @author Wade Penson 5 | @date June, 2015 6 | @brief Storage Configuration for TEFS. This is where you define the storage 7 | device you want to use for TEFS. 8 | */ 9 | /******************************************************************************/ 10 | 11 | #ifndef TEFS_CONFIGURATION_H_ 12 | #define TEFS_CONFIGURATION_H_ 13 | 14 | /* Uncomment this line if you wish to use an SD card for persistent storage. */ 15 | #define USE_SD 16 | 17 | /* Uncomment this line if you wish to use an Adesto Dataflash card for 18 | persistent storage. A optional FTL (flash transition layer) with 19 | wear leveling is also provided. */ 20 | // #define USE_DATAFLASH 21 | // #define USE_FTL 22 | 23 | #endif /* TEFS_CONFIGURATION_H_ */ -------------------------------------------------------------------------------- /src/tefs_stdio/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | project(tefs_stdio) 3 | 4 | set(SOURCE_FILES 5 | tefs_stdio.c 6 | tefs_stdio.h) 7 | 8 | add_definitions(${tefs_DEFINITIONS}) 9 | 10 | add_library(${PROJECT_NAME} STATIC ${SOURCE_FILES}) 11 | 12 | # Required on Unix OS family to be able to be linked into shared libraries. 13 | set_target_properties(${PROJECT_NAME} PROPERTIES POSITION_INDEPENDENT_CODE ON) 14 | 15 | # Change sd_spi_emulator to sd_spi_device if you want to use TEFS on device 16 | target_link_libraries(${PROJECT_NAME} tefs) -------------------------------------------------------------------------------- /src/tefs_stdio/tefs_stdio.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************/ 2 | /** 3 | @file tefs.c 4 | @author Wade Penson 5 | @date June, 2015 6 | @brief TEFS C file interface. 7 | 8 | @copyright Copyright 2015 Wade Penson 9 | 10 | @license Licensed under the Apache License, Version 2.0 (the "License"); 11 | you may not use this file except in compliance with the License. 12 | You may obtain a copy of the License at 13 | 14 | http://www.apache.org/licenses/LICENSE-2.0 15 | 16 | Unless required by applicable law or agreed to in writing, software 17 | distributed under the License is distributed on an "AS IS" BASIS, 18 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 19 | implied. See the License for the specific language governing 20 | permissions and limitations under the License. 21 | */ 22 | /******************************************************************************/ 23 | 24 | #include "tefs_stdio.h" 25 | 26 | T_FILE * 27 | t_fopen( 28 | char *file_name, 29 | char *mode 30 | ) 31 | { 32 | T_FILE *fp = (T_FILE *) malloc(sizeof(T_FILE)); 33 | 34 | #if DEBUG 35 | printf("Target mode: %.*s\n", 2, mode); 36 | #endif 37 | 38 | /* Open a file for reading. The file must exist. */ 39 | if (strcmp(mode, "r") == 0 || strcmp(mode, "rb") == 0) 40 | { 41 | #if DEBUG 42 | printf("Checking for file\n"); 43 | #endif 44 | 45 | /* Check to see if file exists. */ 46 | if (!tefs_exists(file_name)) 47 | { 48 | #if DEBUG 49 | printf("File does not exist\n"); 50 | #endif 51 | free(fp); 52 | return NULL; 53 | } 54 | 55 | #if DEBUG 56 | printf("File exists\n"); 57 | printf("Attempting file open: %s\n", file_name); 58 | #endif 59 | 60 | if (tefs_open(&(fp->f), file_name)) 61 | { 62 | free(fp); 63 | return NULL; 64 | } 65 | 66 | fp->byte_address = 0; 67 | fp->page_address = 0; 68 | fp->eof = 0; 69 | 70 | return fp; 71 | } 72 | else if (strcmp(mode, "w") == 0 || strcmp(mode, "wb") == 0) 73 | { 74 | /* Create an empty file for writing. If a file with the same name 75 | already exists, its content is erased and the file is considered as 76 | a new empty file. */ 77 | #if DEBUG 78 | printf("Opening file\n"); 79 | #endif 80 | 81 | #if DEBUG 82 | printf("Removing existing file\n"); 83 | #endif 84 | 85 | if (tefs_exists(file_name)) 86 | { 87 | if (tefs_remove(file_name)) 88 | { 89 | free(fp); 90 | return NULL; 91 | } 92 | } 93 | 94 | #if DEBUG 95 | printf("Attempting creating of file: %s\n", file_name); 96 | #endif 97 | 98 | if (tefs_open(&fp->f, file_name)) 99 | { 100 | free(fp); 101 | return NULL; 102 | } 103 | 104 | fp->byte_address = 0; 105 | fp->page_address = 0; 106 | fp->eof = 0; 107 | 108 | return fp; 109 | } 110 | else if (strstr(mode, "r+") != NULL) 111 | { 112 | #if DEBUG 113 | printf("Checking for file\n"); 114 | #endif 115 | 116 | /* Open a file for update both reading and writing. The file must exist. */ 117 | if (!tefs_exists(file_name)) 118 | { 119 | return NULL; 120 | } 121 | 122 | #if DEBUG 123 | printf("File exists\n"); 124 | printf("Attempting file open: %s\n", file_name); 125 | #endif 126 | 127 | if (tefs_open(&fp->f, file_name)) 128 | { 129 | free(fp); 130 | return NULL; 131 | } 132 | 133 | fp->byte_address = 0; 134 | fp->page_address = 0; 135 | fp->eof = 0; 136 | 137 | return fp; 138 | } 139 | else if (strstr(mode, "w+") != NULL) 140 | { 141 | /* Create an empty file for both reading and writing. */ 142 | #if DEBUG 143 | printf("Opening file\n"); 144 | #endif 145 | 146 | if (tefs_exists(file_name)) 147 | { 148 | #if DEBUG 149 | printf("Removing file\n"); 150 | #endif 151 | if (tefs_remove(file_name)) 152 | { 153 | free(fp); 154 | return NULL; 155 | } 156 | } 157 | 158 | #if DEBUG 159 | printf("Attempting creation of file: %s\n", file_name); 160 | #endif 161 | 162 | if (tefs_open(&(fp->f), file_name)) 163 | { 164 | free(fp); 165 | return NULL; 166 | } 167 | 168 | fp->byte_address = 0; 169 | fp->page_address = 0; 170 | fp->eof = 0; 171 | 172 | return fp; 173 | } 174 | else if (strstr(mode, "a+") != NULL) 175 | { 176 | #if DEBUG 177 | printf("Opening file\n"); 178 | #endif 179 | 180 | if (tefs_open(&fp->f, file_name)) 181 | { 182 | free(fp); 183 | return NULL; 184 | } 185 | 186 | /* Set pointers to the end of the file. */ 187 | fp->page_address = fp->f.eof_page; 188 | fp->byte_address = fp->f.eof_byte; 189 | fp->eof = 1; 190 | 191 | return fp; 192 | } 193 | else 194 | { 195 | /* Incorrect arguments. */ 196 | free(fp); 197 | return NULL; 198 | } 199 | 200 | return NULL; 201 | } 202 | 203 | int8_t 204 | t_fclose( 205 | T_FILE *fp 206 | ) 207 | { 208 | tefs_close(&fp->f); 209 | free(fp); 210 | 211 | return 0; 212 | } 213 | 214 | int8_t 215 | t_remove( 216 | char *file_name 217 | ) 218 | { 219 | return tefs_remove(file_name); 220 | } 221 | 222 | size_t 223 | t_fwrite( 224 | void *ptr, 225 | size_t size, 226 | size_t count, 227 | T_FILE *fp 228 | ) 229 | { 230 | uint32_t total_num_bytes = size * count; 231 | uint32_t bytes_read = 0; 232 | 233 | while (total_num_bytes - bytes_read >= 512 - fp->byte_address) 234 | { 235 | if (tefs_write(&fp->f, fp->page_address, (void *) (((char *) ptr) + bytes_read), 512 - fp->byte_address, fp->byte_address)) 236 | { 237 | return bytes_read; 238 | } 239 | 240 | bytes_read += 512 - fp->byte_address; 241 | fp->page_address++; 242 | fp->byte_address = 0; 243 | } 244 | 245 | if (total_num_bytes - bytes_read > 0) 246 | { 247 | if (tefs_write(&fp->f, fp->page_address, (void *) (((char *) ptr) + bytes_read), total_num_bytes - bytes_read, fp->byte_address)) 248 | { 249 | return bytes_read; 250 | } 251 | 252 | fp->byte_address += total_num_bytes - bytes_read; 253 | } 254 | 255 | return total_num_bytes; 256 | } 257 | 258 | size_t 259 | t_fread( 260 | void *ptr, 261 | size_t size, 262 | size_t count, 263 | T_FILE *fp 264 | ) 265 | { 266 | uint32_t total_num_bytes = size * count; 267 | uint32_t bytes_read = 0; 268 | int8_t error; 269 | 270 | while (total_num_bytes - bytes_read >= 512 - fp->byte_address) 271 | { 272 | if ((error = tefs_read(&fp->f, fp->page_address, (void *) (((char *) ptr) + bytes_read), 512 - fp->byte_address, fp->byte_address))) 273 | { 274 | if (error == TEFS_ERR_EOF) 275 | { 276 | fp->eof = 1; 277 | return bytes_read + (512 - fp->byte_address); 278 | } 279 | 280 | return bytes_read; 281 | } 282 | 283 | bytes_read += 512 - fp->byte_address; 284 | fp->page_address++; 285 | fp->byte_address = 0; 286 | } 287 | 288 | if (total_num_bytes - bytes_read > 0) 289 | { 290 | if ((error = tefs_read(&fp->f, fp->page_address, (void *) (((char *) ptr) + bytes_read), total_num_bytes - bytes_read, fp->byte_address))) 291 | { 292 | if (error == TEFS_ERR_EOF) 293 | { 294 | fp->eof = 1; 295 | return bytes_read + (total_num_bytes - bytes_read); 296 | } 297 | 298 | return bytes_read; 299 | } 300 | 301 | fp->byte_address += total_num_bytes - bytes_read; 302 | } 303 | 304 | return total_num_bytes; 305 | } 306 | 307 | int8_t 308 | t_feof( 309 | T_FILE *fp 310 | ) 311 | { 312 | if (fp->eof == 1) 313 | { 314 | #ifdef DEBUG 315 | printf("EOF\n"); 316 | #endif 317 | 318 | /* End of file has been reached. */ 319 | return -1; 320 | }else 321 | { 322 | #ifdef DEBUG 323 | printf("NOT EOF\n"); 324 | #endif 325 | 326 | /* End of file has not been reached. */ 327 | return 0; 328 | } 329 | } 330 | 331 | int8_t 332 | t_fflush( 333 | T_FILE *fp 334 | ) 335 | { 336 | tefs_flush(&fp->f); 337 | 338 | return 0; 339 | } 340 | 341 | int8_t 342 | t_fseek( 343 | T_FILE *fp, 344 | uint32_t offset, 345 | int8_t whence 346 | ) 347 | { 348 | fp->eof = 0; 349 | 350 | if (whence == SEEK_SET || whence == SEEK_CUR) 351 | { 352 | /* Seek from current position. */ 353 | if (whence == SEEK_CUR) 354 | { 355 | offset += (fp->page_address << 9) + fp->byte_address; 356 | } 357 | 358 | uint32_t offset_page = offset >> 9; 359 | uint16_t offset_byte = offset & 511; 360 | 361 | /* Check if position is less than the size of the file. */ 362 | if ((offset_page == fp->f.eof_page && offset_byte > fp->f.eof_byte) || offset_page > fp->f.eof_page) 363 | { 364 | return -1; 365 | } 366 | else if (offset_page == fp->f.eof_page && offset_byte == fp->f.eof_byte) 367 | { 368 | fp->eof = 1; 369 | } 370 | else 371 | { 372 | fp->eof = 0; 373 | } 374 | 375 | fp->page_address = offset_page; 376 | fp->byte_address = offset_byte; 377 | } 378 | else if (whence == SEEK_END) 379 | { 380 | fp->eof = 1; 381 | 382 | if (offset > 0) 383 | { 384 | /* Cannot seek past end of file. */ 385 | return -1; 386 | } 387 | 388 | } 389 | else 390 | { 391 | return -1; 392 | } 393 | 394 | return 0; 395 | } 396 | 397 | int8_t 398 | t_fsetpos( 399 | T_FILE *fp, 400 | fpos_t *pos 401 | ) 402 | { 403 | uint32_t pos_page = *pos >> 9; 404 | uint16_t pos_byte = *pos & 511; 405 | 406 | /* Check if position is less than the size of the file. */ 407 | if (pos_page > fp->f.eof_page) 408 | { 409 | return -1; 410 | } 411 | if (pos_page == fp->f.eof_page && pos_byte > fp->f.eof_byte) 412 | { 413 | return -1; 414 | } 415 | else if (pos_page == fp->f.eof_page && pos_byte == fp->f.eof_byte) 416 | { 417 | fp->eof = 1; 418 | } 419 | else 420 | { 421 | fp->eof = 0; 422 | } 423 | 424 | fp->page_address = pos_page; 425 | fp->byte_address = pos_byte; 426 | 427 | return 0; 428 | } 429 | 430 | int8_t 431 | t_fgetpos( 432 | T_FILE *fp, 433 | fpos_t *pos 434 | ) 435 | { 436 | *pos = (fp->page_address << 9) + fp->byte_address; 437 | 438 | return 0; 439 | } 440 | 441 | uint32_t 442 | t_ftell( 443 | T_FILE *fp 444 | ) 445 | { 446 | return (fp->page_address << 9) + fp->byte_address; 447 | } 448 | 449 | void 450 | t_rewind( 451 | T_FILE *fp 452 | ) 453 | { 454 | fp->eof = 0; 455 | fp->page_address = 0; 456 | fp->byte_address = 0; 457 | } -------------------------------------------------------------------------------- /src/tefs_stdio/tefs_stdio.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************/ 2 | /** 3 | @file tefs_stdio.h 4 | @author Wade Penson 5 | @date June, 2015 6 | @brief TEFS C file interface header. 7 | 8 | @copyright Copyright 2015 Wade Penson 9 | 10 | @license Licensed under the Apache License, Version 2.0 (the "License"); 11 | you may not use this file except in compliance with the License. 12 | You may obtain a copy of the License at 13 | 14 | http://www.apache.org/licenses/LICENSE-2.0 15 | 16 | Unless required by applicable law or agreed to in writing, software 17 | distributed under the License is distributed on an "AS IS" BASIS, 18 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 19 | implied. See the License for the specific language governing 20 | permissions and limitations under the License. 21 | */ 22 | /******************************************************************************/ 23 | 24 | #ifndef TEFS_STDIO_H_ 25 | #define TEFS_STDIO_H_ 26 | 27 | #include "../tefs/tefs.h" 28 | #include "stdlib.h" 29 | 30 | #ifdef __cplusplus 31 | extern "C" { 32 | #endif 33 | 34 | typedef int64_t fpos_t; 35 | 36 | typedef struct _SD_File 37 | { 38 | file_t f; 39 | uint32_t page_address; 40 | uint16_t byte_address; 41 | int8_t eof; 42 | } T_FILE; 43 | 44 | T_FILE* 45 | t_fopen( 46 | char *file_name, 47 | char *mode 48 | ); 49 | 50 | int8_t 51 | t_fclose( 52 | T_FILE *fp 53 | ); 54 | 55 | int8_t 56 | t_remove( 57 | char *file_name 58 | ); 59 | 60 | size_t 61 | t_fwrite( 62 | void *ptr, 63 | size_t size, 64 | size_t count, 65 | T_FILE *fp 66 | ); 67 | 68 | size_t 69 | t_fread( 70 | void *ptr, 71 | size_t size, 72 | size_t count, 73 | T_FILE *fp 74 | ); 75 | 76 | int8_t 77 | t_feof( 78 | T_FILE *fp 79 | ); 80 | 81 | int8_t 82 | t_fflush( 83 | T_FILE *fp 84 | ); 85 | 86 | int8_t 87 | t_fseek( 88 | T_FILE *fp, 89 | uint32_t offset, 90 | int8_t whence 91 | ); 92 | 93 | int8_t 94 | t_fsetpos( 95 | T_FILE *fp, 96 | fpos_t *pos 97 | ); 98 | 99 | int8_t 100 | t_fgetpos( 101 | T_FILE *fp, 102 | fpos_t *pos 103 | ); 104 | 105 | uint32_t 106 | t_ftell( 107 | T_FILE *fp 108 | ); 109 | 110 | void 111 | t_rewind( 112 | T_FILE *fp 113 | ); 114 | 115 | #ifdef __cplusplus 116 | } 117 | #endif 118 | 119 | #endif /* TEFS_STDIO_H_ */ 120 | -------------------------------------------------------------------------------- /unit_tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | project(test_tefs) 3 | 4 | set(SOURCE_FILES 5 | run_tefs.c 6 | test_tefs.c 7 | test_tefs_stdio.c) 8 | 9 | set(PLANCK_UNIT_SOURCE_FILES 10 | planck_unit/src/planckunit.c 11 | planck_unit/src/planckunit.h) 12 | 13 | add_definitions(${tefs_stdio_DEFINITIONS}) 14 | #add_definitions(${planck_unit_DEFINITIONS}) 15 | 16 | include_directories(${tefs_stdio_INCLUDE_DIRS}) 17 | #include_directories(${planck_unit_INCLUDE_DIRS}) 18 | 19 | add_library(planck_unit STATIC ${PLANCK_UNIT_SOURCE_FILES}) 20 | add_executable(${PROJECT_NAME} ${SOURCE_FILES}) 21 | 22 | target_link_libraries(${PROJECT_NAME} tefs_stdio planck_unit) -------------------------------------------------------------------------------- /unit_tests/run_tefs.c: -------------------------------------------------------------------------------- 1 | #define CHIP_SELECT_PIN 4 2 | 3 | #include "../src/tefs/tefs.h" 4 | 5 | #if defined(USE_DATAFLASH) && defined(USE_FTL) 6 | #include "dataflash/ftl/ftl_api.h" 7 | extern volatile flare_ftl_t ftl; 8 | #endif 9 | 10 | void 11 | runalltests_tefs(); 12 | 13 | void 14 | runalltests_tefs_stdio(); 15 | 16 | int 17 | main() 18 | { 19 | #if defined(USE_DATAFLASH) && defined(USE_FTL) 20 | df_jvm_start(); 21 | ftl_Instantiate(&ftl); 22 | #elif defined(USE_DATAFLASH) && !defined(USE_FTL) 23 | int error = 0; 24 | 25 | if ((error = df_Instantiate(CHIP_SELECT_PIN))) 26 | { 27 | printf("Dataflash failed to initialize. Error code: %i\n", error); 28 | return -1; 29 | } 30 | #elif defined(USE_SD) 31 | int error = 0; 32 | 33 | if ((error = sd_spi_init(CHIP_SELECT_PIN))) 34 | { 35 | printf("SD initialization failed. Error code: %i\n", error); 36 | return -1; 37 | } 38 | #endif 39 | 40 | runalltests_tefs(); 41 | runalltests_tefs_stdio(); 42 | return 0; 43 | } 44 | -------------------------------------------------------------------------------- /unit_tests/test_tefs.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************/ 2 | /** 3 | @file test_tefs.c 4 | @author Wade Penson 5 | @date June, 2015 6 | @brief Unit tests for TEFS. 7 | 8 | @copyright Copyright 2015 Wade Penson 9 | 10 | @license Licensed under the Apache License, Version 2.0 (the "License"); 11 | you may not use this file except in compliance with the License. 12 | You may obtain a copy of the License at 13 | 14 | http://www.apache.org/licenses/LICENSE-2.0 15 | 16 | Unless required by applicable law or agreed to in writing, software 17 | distributed under the License is distributed on an "AS IS" BASIS, 18 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 19 | implied. See the License for the specific language governing 20 | permissions and limitations under the License. 21 | */ 22 | /******************************************************************************/ 23 | 24 | #include "planck_unit/src/planckunit.h" 25 | #include "../src/tefs/tefs.h" 26 | 27 | #define CHIP_SELECT_PIN 4 28 | 29 | static uint8_t data[512]; 30 | static uint8_t buffer[512]; 31 | static uint8_t address_size; 32 | static uint32_t state_section_size; 33 | static uint32_t state_section_size_in_bytes; 34 | static uint8_t info_section_size; 35 | static uint32_t i; 36 | static uint32_t j; 37 | static uint32_t four_byte_buffer; 38 | static uint8_t byte_buffer; 39 | static uint16_t current_byte; 40 | static uint32_t current_page; 41 | static char *memory_error = "Ran out of memory"; 42 | 43 | typedef struct { 44 | char *name; 45 | int32_t hash; 46 | file_t *file; 47 | } file_info_t; 48 | 49 | static file_info_t files[] = 50 | { 51 | {"test.aaa", -530280420}, 52 | {"test.bbb", 0} 53 | }; 54 | 55 | typedef struct { 56 | uint32_t num_pages; 57 | uint16_t page_size; 58 | uint16_t block_size; 59 | uint8_t hash_size; 60 | uint16_t meta_data_size; 61 | uint16_t max_file_name_size; 62 | } format_info_t; 63 | 64 | static format_info_t *format_info; 65 | 66 | #if defined(USE_SD) 67 | static format_info_t format_info_arr[] = 68 | { 69 | {62500, 512, 8, 4, 32, 12}, 70 | // {62500, 512, 64, 4, 32, 12}, 71 | // {1000, 512, 1, 4, 16, 10} 72 | }; 73 | #elif defined(USE_DATAFLASH) 74 | static format_info_t format_info_arr[] = 75 | { 76 | {1000, 512, 8, 4, 32, 12} 77 | }; 78 | #endif 79 | 80 | static const int powers_of_two_arr[] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 81 | 2048, 4096, 8192, 16384, 32768, 65536}; 82 | 83 | static uint8_t 84 | find_power_of_2_exp( 85 | uint32_t val 86 | ) 87 | { 88 | for (i = 0; i < 17; i++) 89 | { 90 | if (powers_of_two_arr[i] == val) 91 | { 92 | return (uint8_t) i; 93 | } 94 | } 95 | 96 | return 0; 97 | } 98 | 99 | static uint32_t 100 | hash_string( 101 | char *str 102 | ) 103 | { 104 | uint32_t hash = 5381; 105 | int8_t c; 106 | 107 | while ((c = *str++)) 108 | { 109 | hash = (uint32_t)((hash << 5) + hash) ^ c; /* hash * 33 ^ c */ 110 | } 111 | 112 | if (hash == 0) 113 | { 114 | hash = 1; 115 | } 116 | 117 | if (format_info->hash_size == 4) 118 | { 119 | return hash; 120 | } 121 | else 122 | { 123 | return hash % 65521; 124 | } 125 | } 126 | 127 | static uint32_t 128 | get_block_address( 129 | uint32_t block_number 130 | ) 131 | { 132 | return block_number * format_info->block_size + state_section_size + info_section_size; 133 | } 134 | 135 | static int8_t 136 | check_state_section( 137 | planck_unit_test_t *tc, 138 | uint32_t start_bit, 139 | uint32_t end_bit 140 | ) 141 | { 142 | #if defined(USE_SD) 143 | uint32_t start_byte = start_bit / 8; 144 | uint32_t end_byte = end_bit / 8; 145 | 146 | /* Check state section to see if pages were released */ 147 | uint8_t b = 0; 148 | uint8_t s = 0; 149 | for (current_page = 0; 150 | current_page < state_section_size; 151 | current_page++) 152 | { 153 | for (current_byte = 0; 154 | current_byte < format_info->page_size; 155 | current_byte++) 156 | { 157 | if (start_byte == current_byte + current_page * format_info->page_size && 158 | start_byte / format_info->page_size == current_page) 159 | { 160 | b = 0xFF; 161 | for (i = 1; i <= 1 << (7 - (start_bit % 8)); i <<= 1) 162 | { 163 | b ^= i; 164 | } 165 | 166 | s = 1; 167 | 168 | if (start_byte == end_byte) 169 | { 170 | for (i = 1; i <= 1 << (7 - (end_bit % 8)); i <<= 1) 171 | { 172 | b |= i; 173 | } 174 | 175 | s = 0; 176 | } 177 | } 178 | else if (end_byte == current_byte + current_page * format_info->page_size && 179 | end_byte / format_info->page_size == current_page) 180 | { 181 | b = 0; 182 | for (i = 1; i <= 1 << (7 - (end_bit % 8)); i <<= 1) 183 | { 184 | b |= i; 185 | } 186 | 187 | s = 0; 188 | } 189 | else if (s == 1 || (current_page == state_section_size - 1 && 190 | current_byte >= state_section_size_in_bytes % format_info->page_size)) 191 | { 192 | b = 0; 193 | } 194 | else if (s == 0) 195 | { 196 | b = 0xFF; 197 | } 198 | 199 | device_read(current_page + info_section_size, &byte_buffer, 1, current_byte); 200 | 201 | if (b != byte_buffer) 202 | { 203 | return -1; 204 | } 205 | } 206 | } 207 | #endif 208 | 209 | return 0; 210 | } 211 | 212 | static void 213 | populate_data_array_1( 214 | void 215 | ) 216 | { 217 | for (i = 0; i < 26; i++) 218 | { 219 | data[i] = (uint8_t) ('a' + i); 220 | } 221 | 222 | for (i = 26; i < 512; i++) 223 | { 224 | data[i] = '.'; 225 | } 226 | } 227 | 228 | static void 229 | populate_data_array_2( 230 | void 231 | ) 232 | { 233 | for (i = 0; i < 26; i++) 234 | { 235 | data[i] = (uint8_t) ('A' + i); 236 | } 237 | 238 | for (i = 26; i < 512; i++) 239 | { 240 | data[i] = '!'; 241 | } 242 | } 243 | 244 | static int8_t 245 | format_device( 246 | void 247 | ) 248 | { 249 | #if defined(USE_DATAFLASH) && defined(USE_FTL) 250 | ftl_Instantiate(&ftl); 251 | flare_Createftl(&ftl); 252 | #endif 253 | 254 | return tefs_format_device(format_info->num_pages, 255 | format_info->page_size, 256 | format_info->block_size, 257 | format_info->hash_size, 258 | format_info->meta_data_size, 259 | format_info->max_file_name_size, 260 | 1); 261 | } 262 | 263 | void 264 | test_tefs_format_device_helper( 265 | planck_unit_test_t *tc, 266 | uint8_t pre_erase 267 | ) 268 | { 269 | #if defined(USE_DATAFLASH) && defined(USE_FTL) 270 | ftl_Instantiate(&ftl); 271 | flare_Createftl(&ftl); 272 | #endif 273 | 274 | #if defined(USE_SD) 275 | /* Write out dummy data to help check if format wrote the correct data. */ 276 | byte_buffer = 0xEA; 277 | for (current_page = 0; current_page < 1000; current_page++) 278 | { 279 | for (current_byte = 0; current_byte < format_info->page_size; current_byte++) 280 | { 281 | device_write(current_page, &byte_buffer, 1, current_byte); 282 | } 283 | } 284 | 285 | device_flush(); 286 | #endif 287 | 288 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_format_device(format_info->num_pages, 289 | format_info->page_size, 290 | format_info->block_size, 291 | format_info->hash_size, 292 | format_info->meta_data_size, 293 | format_info->max_file_name_size, 294 | pre_erase)); 295 | 296 | /* Read and verify the check flag */ 297 | for (current_byte = 0; current_byte < 4; current_byte++) 298 | { 299 | device_read(0, &byte_buffer, 1, current_byte); 300 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0xFC, byte_buffer); 301 | } 302 | 303 | /* Read the number of pages that the device has */ 304 | four_byte_buffer = 0; 305 | device_read(0, &four_byte_buffer, 4, current_byte); 306 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, format_info->num_pages, four_byte_buffer); 307 | current_byte += 4; 308 | 309 | /* Read the physical page size */ 310 | device_read(0, &byte_buffer, 1, current_byte); 311 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, find_power_of_2_exp(format_info->page_size), byte_buffer); 312 | current_byte += 1; 313 | 314 | /* Read the block size */ 315 | device_read(0, &byte_buffer, 1, current_byte); 316 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, find_power_of_2_exp(format_info->block_size), byte_buffer); 317 | current_byte += 1; 318 | 319 | /* Read the address size */ 320 | device_read(0, &byte_buffer, 1, current_byte); 321 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, find_power_of_2_exp(address_size), byte_buffer); 322 | current_byte += 1; 323 | 324 | /* Read the hash value size */ 325 | device_read(0, &byte_buffer, 1, current_byte); 326 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, format_info->hash_size, byte_buffer); 327 | current_byte += 1; 328 | 329 | /* Read the meta data record size */ 330 | four_byte_buffer = 0; 331 | device_read(0, &four_byte_buffer, 2, current_byte); 332 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, format_info->meta_data_size, four_byte_buffer); 333 | current_byte += 2; 334 | 335 | /* Read the max name file size */ 336 | four_byte_buffer = 0; 337 | device_read(0, &four_byte_buffer, 2, current_byte); 338 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, format_info->max_file_name_size, four_byte_buffer); 339 | current_byte += 2; 340 | 341 | #if defined(USE_SD) 342 | /* Read the state section size */ 343 | four_byte_buffer = 0; 344 | device_read(0, &four_byte_buffer, 4, current_byte); 345 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, state_section_size, four_byte_buffer); 346 | current_byte += 4; 347 | #endif 348 | 349 | /* Read the meta data for the hash file */ 350 | four_byte_buffer = 0; 351 | device_read(0, &four_byte_buffer, TEFS_DIR_EOF_PAGE_SIZE, current_byte); 352 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, four_byte_buffer); 353 | current_byte += 4; 354 | 355 | four_byte_buffer = 0; 356 | device_read(0, &four_byte_buffer, TEFS_DIR_EOF_BYTE_SIZE, current_byte); 357 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, four_byte_buffer); 358 | current_byte += 2; 359 | 360 | four_byte_buffer = 0; 361 | device_read(0, &four_byte_buffer, 4, current_byte); 362 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, get_block_address(0), four_byte_buffer); 363 | current_byte += 4; 364 | 365 | /* Read the meta data for the meta data file */ 366 | four_byte_buffer = 0; 367 | device_read(0, &four_byte_buffer, TEFS_DIR_EOF_PAGE_SIZE, current_byte); 368 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, four_byte_buffer); 369 | current_byte += 4; 370 | 371 | four_byte_buffer = 0; 372 | device_read(0, &four_byte_buffer, TEFS_DIR_EOF_BYTE_SIZE, current_byte); 373 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, four_byte_buffer); 374 | current_byte += 2; 375 | 376 | four_byte_buffer = 0; 377 | device_read(0, &four_byte_buffer, 4, current_byte); 378 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, get_block_address(2), four_byte_buffer); 379 | current_byte += 4; 380 | 381 | /* Check if the rest of the info section has zeros. */ 382 | while(current_byte < format_info->page_size) 383 | { 384 | device_read(0, &byte_buffer, 1, current_byte); 385 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, byte_buffer); 386 | 387 | current_byte++; 388 | } 389 | 390 | if (check_state_section(tc, 0, 4)) 391 | { 392 | PLANCK_UNIT_ASSERT_FALSE(tc); 393 | } 394 | } 395 | 396 | void 397 | test_tefs_format_device_without_erase( 398 | planck_unit_test_t *tc 399 | ) 400 | { 401 | test_tefs_format_device_helper(tc, 0); 402 | } 403 | 404 | void 405 | test_tefs_format_device_with_erase( 406 | planck_unit_test_t *tc 407 | ) 408 | { 409 | test_tefs_format_device_helper(tc, 1); 410 | } 411 | 412 | void 413 | test_tefs_create_single_file( 414 | planck_unit_test_t *tc 415 | ) 416 | { 417 | files[0].file = malloc(sizeof(file_t)); 418 | 419 | if (files[0].file == NULL) 420 | { 421 | printf("%s\n", memory_error); 422 | exit(-1); 423 | } 424 | 425 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, format_device()); 426 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_open(files[0].file, files[0].name)); 427 | 428 | /* Check the hash value in the hash entries file */ 429 | four_byte_buffer = 0; 430 | device_read(get_block_address(1), &four_byte_buffer, 4, 0); 431 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, files[0].hash, four_byte_buffer); 432 | 433 | /* Check the status byte in the meta data file */ 434 | four_byte_buffer = 0; 435 | device_read(get_block_address(3), &four_byte_buffer, 1, 0); 436 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 2, four_byte_buffer); 437 | 438 | current_byte = TEFS_DIR_STATUS_SIZE; 439 | 440 | /* Check the file size in the directory entry */ 441 | four_byte_buffer = 0; 442 | device_read(get_block_address(3), &four_byte_buffer, 4, current_byte); 443 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, four_byte_buffer); 444 | 445 | current_byte += TEFS_DIR_EOF_PAGE_SIZE; 446 | 447 | four_byte_buffer = 0; 448 | device_read(get_block_address(3), &four_byte_buffer, 2, current_byte); 449 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, four_byte_buffer); 450 | 451 | current_byte += TEFS_DIR_EOF_BYTE_SIZE; 452 | 453 | /* Check the first index block address in directory entry */ 454 | four_byte_buffer = 0; 455 | device_read(get_block_address(3), &four_byte_buffer, 4, current_byte); 456 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, get_block_address(4), four_byte_buffer); 457 | 458 | current_byte += TEFS_DIR_ROOT_INDEX_ADDRESS_SIZE; 459 | 460 | /* Check the file name in the meta data file */ 461 | char name[format_info->max_file_name_size]; 462 | device_read(get_block_address(3), name, format_info->max_file_name_size, current_byte); 463 | 464 | for (i = 0; i < format_info->max_file_name_size; i++) 465 | { 466 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, name[i], files[0].name[i]); 467 | 468 | if (files[0].name[i] == '\0') 469 | { 470 | while (i < format_info->max_file_name_size) 471 | { 472 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, name[i], '\0'); 473 | i++; 474 | } 475 | } 476 | } 477 | 478 | if (check_state_section(tc, 0, 6)) 479 | { 480 | PLANCK_UNIT_ASSERT_FALSE(tc); 481 | } 482 | 483 | /* Check first data block address */ 484 | four_byte_buffer = 0; 485 | device_read(get_block_address(4), &four_byte_buffer, 2, 0); 486 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, get_block_address(5), four_byte_buffer); 487 | 488 | free(files[0].file); 489 | } 490 | 491 | void 492 | test_tefs_create_multiple_files( 493 | planck_unit_test_t *tc 494 | ) 495 | { 496 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, format_device()); 497 | 498 | uint16_t num_hash_blocks = 0; 499 | uint16_t file_num; 500 | for (file_num = 0; file_num < 100; file_num++) 501 | { 502 | file_t *file = malloc(sizeof(file_t)); 503 | 504 | if (file == NULL) 505 | { 506 | printf("%s\n", memory_error); 507 | exit(-1); 508 | } 509 | 510 | char file_name[10]; 511 | sprintf(file_name, "%s%d", "file.", file_num); 512 | 513 | uint32_t file_hash = hash_string(file_name); 514 | 515 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_open(file, file_name)); 516 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_close(file)); 517 | 518 | uint32_t num_hashes_per_block = (format_info->page_size * format_info->block_size / format_info->hash_size); 519 | uint32_t num_meta_entries_per_block = (format_info->page_size * format_info->block_size / format_info->meta_data_size); 520 | 521 | uint32_t hash_entry_page = (file_num * format_info->hash_size) / format_info->page_size; 522 | hash_entry_page += get_block_address(1) + (file_num / num_hashes_per_block) * num_hashes_per_block * 2 * format_info->block_size; 523 | 524 | if (file_num > 0 && (file_num % num_hashes_per_block) == 0) 525 | { 526 | num_hash_blocks += 1; 527 | } 528 | 529 | hash_entry_page += num_hash_blocks * 8 * format_info->block_size; 530 | hash_entry_page += (num_hash_blocks > 0) ? format_info->block_size : 0; 531 | 532 | uint16_t hash_entry_byte = (file_num * format_info->hash_size) % format_info->page_size; 533 | 534 | /* Check the hash value in the hash entries file */ 535 | four_byte_buffer = 0; 536 | device_read(hash_entry_page, &four_byte_buffer, 4, hash_entry_byte); 537 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, file_hash, four_byte_buffer); 538 | 539 | uint32_t meta_data_page = (file_num * format_info->meta_data_size) / format_info->page_size; 540 | meta_data_page += get_block_address(3) + (file_num / num_meta_entries_per_block) * num_meta_entries_per_block * 2 * format_info->block_size; 541 | meta_data_page += (file_num / num_hashes_per_block) * format_info->block_size; 542 | 543 | uint16_t meta_data_byte = (file_num * format_info->meta_data_size) % format_info->page_size; 544 | 545 | /* Check the status byte in the meta data file */ 546 | four_byte_buffer = 0; 547 | device_read(meta_data_page, &four_byte_buffer, 1, meta_data_byte); 548 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 2, four_byte_buffer); 549 | 550 | /* Check the file name in the meta data file */ 551 | char name[format_info->max_file_name_size]; 552 | device_read(meta_data_page, name, format_info->max_file_name_size, meta_data_byte + TEFS_DIR_STATIC_DATA_SIZE); 553 | 554 | for (i = 0; i < format_info->max_file_name_size; i++) 555 | { 556 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, name[i], file_name[i]); 557 | 558 | if (file_name[i] == '\0') 559 | { 560 | while (i < format_info->max_file_name_size) 561 | { 562 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, name[i], '\0'); 563 | i++; 564 | } 565 | } 566 | } 567 | 568 | /* Check the file size in the directory entry */ 569 | four_byte_buffer = 0; 570 | device_read(meta_data_page, &four_byte_buffer, 4, meta_data_byte + TEFS_DIR_STATUS_SIZE); 571 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, four_byte_buffer); 572 | 573 | four_byte_buffer = 0; 574 | device_read(meta_data_page, &four_byte_buffer, 2, meta_data_byte + TEFS_DIR_STATUS_SIZE + TEFS_DIR_EOF_PAGE_SIZE); 575 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, four_byte_buffer); 576 | 577 | uint32_t temp_block = 4 + file_num * 2 + (file_num / num_meta_entries_per_block) + (file_num / num_hashes_per_block); 578 | 579 | /* Check the first index block address in directory entry */ 580 | four_byte_buffer = 0; 581 | device_read(meta_data_page, &four_byte_buffer, TEFS_DIR_ROOT_INDEX_ADDRESS_SIZE, 582 | meta_data_byte + TEFS_DIR_STATUS_SIZE + TEFS_DIR_EOF_PAGE_SIZE + TEFS_DIR_EOF_BYTE_SIZE); 583 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, get_block_address(temp_block), four_byte_buffer); 584 | 585 | if (check_state_section(tc, 0, temp_block + 2)) 586 | { 587 | PLANCK_UNIT_ASSERT_FALSE(tc); 588 | } 589 | 590 | /* Check first data block address */ 591 | four_byte_buffer = 0; 592 | device_read(get_block_address(temp_block), &four_byte_buffer, 2, 0); 593 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, get_block_address(temp_block + 1), four_byte_buffer); 594 | 595 | free(file); 596 | } 597 | } 598 | 599 | void 600 | test_tefs_remove_files_consecutively_helper( 601 | planck_unit_test_t *tc, 602 | uint32_t num_files, 603 | uint32_t num_pages 604 | ) 605 | { 606 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, format_device()); 607 | populate_data_array_1(); 608 | 609 | uint16_t num_hash_blocks = 0; 610 | uint16_t file_num; 611 | for (file_num = 0; file_num < num_files; file_num++) 612 | { 613 | file_t *file = malloc(sizeof(file_t)); 614 | 615 | if (file == NULL) 616 | { 617 | printf("%s\n", memory_error); 618 | exit(-1); 619 | } 620 | 621 | char file_name[10]; 622 | sprintf(file_name, "%s%d", "file.", file_num); 623 | 624 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_open(file, file_name)); 625 | 626 | /* Write num_pages of data to the file */ 627 | for (i = 0; i < num_pages; i++) 628 | { 629 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_write(file, i, data, format_info->page_size, 0)); 630 | } 631 | 632 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_close(file)); 633 | 634 | free(file); 635 | } 636 | 637 | for (file_num = 0; file_num < num_files; file_num++) 638 | { 639 | char file_name[10]; 640 | sprintf(file_name, "%s%d", "file.", file_num); 641 | 642 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_remove(file_name)); 643 | 644 | uint32_t num_hashes_per_block = (format_info->page_size * format_info->block_size / format_info->hash_size); 645 | uint32_t num_meta_entries_per_block = (format_info->page_size * format_info->block_size / format_info->meta_data_size); 646 | 647 | uint32_t hash_entry_page = (file_num * format_info->hash_size) / format_info->page_size; 648 | hash_entry_page += get_block_address(1) + (file_num / num_hashes_per_block) * num_hashes_per_block * 2 * format_info->block_size; 649 | 650 | if (file_num > 0 && (file_num % num_hashes_per_block) == 0) 651 | { 652 | num_hash_blocks += 1; 653 | } 654 | 655 | hash_entry_page += num_hash_blocks * 8 * format_info->block_size; 656 | hash_entry_page += (num_hash_blocks > 0) ? format_info->block_size : 0; 657 | 658 | uint16_t hash_entry_byte = (file_num * format_info->hash_size) % format_info->page_size; 659 | 660 | uint32_t meta_data_page = (file_num * format_info->meta_data_size) / format_info->page_size; 661 | meta_data_page += get_block_address(3) + (file_num / num_meta_entries_per_block) * num_meta_entries_per_block * 2 * format_info->block_size; 662 | meta_data_page += (file_num / num_hashes_per_block) * format_info->block_size; 663 | 664 | uint16_t meta_data_byte = (file_num * format_info->meta_data_size) % format_info->page_size; 665 | 666 | /* Check the hash to see if it has been set to 0. */ 667 | four_byte_buffer = 0; 668 | device_read(hash_entry_page, &four_byte_buffer, 4, hash_entry_byte); 669 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, four_byte_buffer); 670 | 671 | /* Check directory entry to see if file status has been set to deleted. */ 672 | four_byte_buffer = 0; 673 | device_read(meta_data_page, &four_byte_buffer, 1, meta_data_byte); 674 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, TEFS_DELETED, four_byte_buffer); 675 | } 676 | 677 | /* Note: This test will fail if the hash entries or meta data file wrote past a single data block! */ 678 | if (check_state_section(tc, 0, 4)) 679 | { 680 | PLANCK_UNIT_ASSERT_FALSE(tc); 681 | } 682 | } 683 | 684 | void 685 | test_tefs_remove_files_staggered_helper( 686 | planck_unit_test_t *tc, 687 | uint32_t num_files, 688 | uint32_t num_pages 689 | ) 690 | { 691 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, format_device()); 692 | populate_data_array_1(); 693 | 694 | uint16_t file_num; 695 | for (file_num = 0; file_num < num_files; file_num++) 696 | { 697 | file_t *file = malloc(sizeof(file_t)); 698 | 699 | if (file == NULL) 700 | { 701 | printf("%s\n", memory_error); 702 | exit(-1); 703 | } 704 | 705 | char file_name[10]; 706 | sprintf(file_name, "%s%d", "file.", file_num); 707 | 708 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_open(file, file_name)); 709 | 710 | /* Write num_pages of data to the file */ 711 | for (i = 0; i < num_pages; i++) 712 | { 713 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_write(file, i, data, format_info->page_size, 0)); 714 | } 715 | 716 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_close(file)); 717 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_remove(file_name)); 718 | 719 | /* Check the hash to see if it has been set to 0. */ 720 | four_byte_buffer = 0; 721 | device_read(get_block_address(1), &four_byte_buffer, 4, 0); 722 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, four_byte_buffer); 723 | 724 | /* Check directory entry to see if file status has been set to deleted. */ 725 | four_byte_buffer = 0; 726 | device_read(get_block_address(3), &four_byte_buffer, 1, 0); 727 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, TEFS_DELETED, four_byte_buffer); 728 | 729 | free(file); 730 | } 731 | 732 | if (check_state_section(tc, 0, 4)) 733 | { 734 | PLANCK_UNIT_ASSERT_FALSE(tc); 735 | } 736 | } 737 | 738 | void 739 | test_tefs_remove_empty_single_file( 740 | planck_unit_test_t *tc 741 | ) 742 | { 743 | test_tefs_remove_files_consecutively_helper(tc, 1, 0); 744 | } 745 | 746 | void 747 | test_tefs_remove_small_single_file( 748 | planck_unit_test_t *tc 749 | ) 750 | { 751 | test_tefs_remove_files_consecutively_helper(tc, 1, 1); 752 | } 753 | 754 | void 755 | test_tefs_remove_large_single_file( 756 | planck_unit_test_t *tc 757 | ) 758 | { 759 | test_tefs_remove_files_consecutively_helper(tc, 1, 100); 760 | } 761 | 762 | void 763 | test_tefs_remove_multiple_empty_files_consecutively( 764 | planck_unit_test_t *tc 765 | ) 766 | { 767 | test_tefs_remove_files_consecutively_helper(tc, 100, 0); 768 | } 769 | 770 | void 771 | test_tefs_remove_multiple_files_with_data_consecutively( 772 | planck_unit_test_t *tc 773 | ) 774 | { 775 | test_tefs_remove_files_consecutively_helper(tc, 100, 100); 776 | } 777 | 778 | void 779 | test_tefs_remove_multiple_empty_files_staggered( 780 | planck_unit_test_t *tc 781 | ) 782 | { 783 | test_tefs_remove_files_staggered_helper(tc, 100, 0); 784 | } 785 | 786 | void 787 | test_tefs_remove_multiple_files_with_data_staggered( 788 | planck_unit_test_t *tc 789 | ) 790 | { 791 | test_tefs_remove_files_staggered_helper(tc, 100, 100); 792 | } 793 | 794 | void 795 | test_tefs_exists_single_file( 796 | planck_unit_test_t *tc 797 | ) 798 | { 799 | files[0].file = malloc(sizeof(file_t)); 800 | 801 | if (files[0].file == NULL) 802 | { 803 | printf("%s\n", memory_error); 804 | exit(-1); 805 | } 806 | 807 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, format_device()); 808 | 809 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_exists(files[0].name)); 810 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_open(files[0].file, files[0].name)); 811 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 1, tefs_exists(files[0].name)); 812 | 813 | free(files[0].file); 814 | } 815 | 816 | void 817 | test_tefs_write_page_to_single_file( 818 | planck_unit_test_t *tc 819 | ) 820 | { 821 | files[0].file = malloc(sizeof(file_t)); 822 | 823 | if (files[0].file == NULL) 824 | { 825 | printf("%s\n", memory_error); 826 | exit(-1); 827 | } 828 | 829 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, format_device()); 830 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_open(files[0].file, files[0].name)); 831 | 832 | populate_data_array_1(); 833 | 834 | /* Write a single page and check if it has been written */ 835 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_write(files[0].file, 0, data, format_info->page_size, 0)); 836 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, device_read(get_block_address(5), buffer, format_info->page_size, 0)); 837 | 838 | for (i = 0; i < format_info->page_size; i++) 839 | { 840 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, data[i], buffer[i]); 841 | } 842 | 843 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_close(files[0].file)); 844 | 845 | uint32_t size = 0; 846 | device_read(get_block_address(3), &size, 4, TEFS_DIR_STATUS_SIZE); 847 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 1, size); 848 | 849 | size = 0; 850 | device_read(get_block_address(3), &size, 2, TEFS_DIR_STATUS_SIZE + TEFS_DIR_EOF_PAGE_SIZE); 851 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, size); 852 | 853 | if (check_state_section(tc, 0, 6)) 854 | { 855 | PLANCK_UNIT_ASSERT_FALSE(tc); 856 | } 857 | 858 | free(files[0].file); 859 | } 860 | 861 | void 862 | test_tefs_write_data_block_to_single_file( 863 | planck_unit_test_t *tc 864 | ) 865 | { 866 | files[0].file = malloc(sizeof(file_t)); 867 | 868 | if (files[0].file == NULL) 869 | { 870 | printf("%s\n", memory_error); 871 | exit(-1); 872 | } 873 | 874 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, format_device()); 875 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_open(files[0].file, files[0].name)); 876 | 877 | populate_data_array_1(); 878 | 879 | /* Write multiple pages but stay within a single data block */ 880 | for (i = 0; i < format_info->block_size; i++) 881 | { 882 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_write(files[0].file, i, data, format_info->page_size, 0)); 883 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, device_read(get_block_address(5) + i, buffer, format_info->page_size, 0)); 884 | 885 | for (j = 0; j < format_info->page_size; j++) 886 | { 887 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, data[j], buffer[j]); 888 | } 889 | 890 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_flush(files[0].file)); 891 | } 892 | 893 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_close(files[0].file)); 894 | 895 | uint32_t size = 0; 896 | device_read(get_block_address(3), &size, 4, TEFS_DIR_STATUS_SIZE); 897 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, format_info->block_size, size); 898 | 899 | size = 0; 900 | device_read(get_block_address(3), &size, 2, TEFS_DIR_STATUS_SIZE + TEFS_DIR_EOF_PAGE_SIZE); 901 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, size); 902 | 903 | if (check_state_section(tc, 0, 6)) 904 | { 905 | PLANCK_UNIT_ASSERT_FALSE(tc); 906 | } 907 | 908 | free(files[0].file); 909 | } 910 | 911 | void 912 | test_tefs_write_child_block_to_single_file( 913 | planck_unit_test_t *tc 914 | ) 915 | { 916 | files[0].file = malloc(sizeof(file_t)); 917 | 918 | if (files[0].file == NULL) 919 | { 920 | printf("%s\n", memory_error); 921 | exit(-1); 922 | } 923 | 924 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, format_device()); 925 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_open(files[0].file, files[0].name)); 926 | 927 | populate_data_array_1(); 928 | 929 | uint32_t pages_per_child_block = format_info->page_size * format_info->block_size / address_size * format_info->block_size; 930 | uint32_t num_pages = (pages_per_child_block < format_info->num_pages) ? pages_per_child_block : format_info->num_pages; // TODO 931 | 932 | for (i = 0; i < num_pages; i++) 933 | { 934 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_write(files[0].file, i, data, format_info->page_size, 0)); 935 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, device_read(get_block_address(5) + i, buffer, format_info->page_size, 0)); 936 | 937 | for (j = 0; j < format_info->page_size; j++) 938 | { 939 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, data[j], buffer[j]); 940 | } 941 | 942 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_flush(files[0].file)); 943 | } 944 | 945 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_close(files[0].file)); 946 | 947 | uint32_t size = 0; 948 | device_read(get_block_address(3), &size, 4, TEFS_DIR_STATUS_SIZE); 949 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, num_pages, size); 950 | 951 | size = 0; 952 | device_read(get_block_address(3), &size, 2, TEFS_DIR_STATUS_SIZE + TEFS_DIR_EOF_PAGE_SIZE); 953 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, size); 954 | 955 | if (check_state_section(tc, 0, 5 + num_pages / format_info->block_size)) 956 | { 957 | PLANCK_UNIT_ASSERT_FALSE(tc); 958 | } 959 | 960 | free(files[0].file); 961 | } 962 | 963 | void 964 | test_tefs_write_multiple_child_blocks_to_single_file( 965 | planck_unit_test_t *tc 966 | ) 967 | { 968 | files[0].file = malloc(sizeof(file_t)); 969 | 970 | if (files[0].file == NULL) 971 | { 972 | printf("%s\n", memory_error); 973 | exit(-1); 974 | } 975 | 976 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, format_device()); 977 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_open(files[0].file, files[0].name)); 978 | 979 | populate_data_array_1(); 980 | 981 | uint32_t pages_per_child_block = format_info->page_size * format_info->block_size / address_size * format_info->block_size; 982 | uint32_t num_pages = (pages_per_child_block < format_info->num_pages) ? pages_per_child_block : format_info->num_pages; // TODO 983 | 984 | for (i = 0; i < num_pages; i++) 985 | { 986 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_write(files[0].file, i, data, format_info->page_size, 0)); 987 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, device_read(get_block_address(5) + i, buffer, format_info->page_size, 0)); 988 | 989 | for (j = 0; j < format_info->page_size; j++) 990 | { 991 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, data[j], buffer[j]); 992 | } 993 | 994 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_flush(files[0].file)); 995 | } 996 | 997 | for (i = num_pages; i < num_pages * 2; i++) 998 | { 999 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_write(files[0].file, i, data, format_info->page_size, 0)); 1000 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, device_read(get_block_address(5) + i + format_info->block_size * 2, buffer, format_info->page_size, 0)); 1001 | 1002 | for (j = 0; j < format_info->page_size; j++) 1003 | { 1004 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, data[j], buffer[j]); 1005 | } 1006 | 1007 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_flush(files[0].file)); 1008 | } 1009 | 1010 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_close(files[0].file)); 1011 | 1012 | uint32_t size = 0; 1013 | device_read(get_block_address(3), &size, 4, TEFS_DIR_STATUS_SIZE); 1014 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, num_pages * 2, size); 1015 | 1016 | size = 0; 1017 | device_read(get_block_address(3), &size, 2, TEFS_DIR_STATUS_SIZE + TEFS_DIR_EOF_PAGE_SIZE); 1018 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, size); 1019 | 1020 | if (check_state_section(tc, 0, 5 + num_pages * 2 / format_info->block_size + 2)) 1021 | { 1022 | PLANCK_UNIT_ASSERT_FALSE(tc); 1023 | } 1024 | 1025 | free(files[0].file); 1026 | } 1027 | 1028 | void 1029 | test_tefs_read_after_write_to_single_file( 1030 | planck_unit_test_t *tc 1031 | ) 1032 | { 1033 | files[0].file = malloc(sizeof(file_t)); 1034 | 1035 | if (files[0].file == NULL) 1036 | { 1037 | printf("%s\n", memory_error); 1038 | exit(-1); 1039 | } 1040 | 1041 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, format_device()); 1042 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_open(files[0].file, files[0].name)); 1043 | 1044 | populate_data_array_1(); 1045 | 1046 | uint32_t pages_per_child_block = format_info->page_size * format_info->block_size / address_size * format_info->block_size; 1047 | uint32_t num_pages = (pages_per_child_block < format_info->num_pages) ? pages_per_child_block : format_info->num_pages; // TODO 1048 | 1049 | for (i = 0; i < num_pages; i++) 1050 | { 1051 | /* Write a page then read it */ 1052 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_write(files[0].file, i, data, format_info->page_size, 0)); 1053 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_read(files[0].file, i, buffer, format_info->page_size, 0)); 1054 | 1055 | for (j = 0; j < format_info->page_size; j++) 1056 | { 1057 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, data[j], buffer[j]); 1058 | } 1059 | } 1060 | 1061 | free(files[0].file); 1062 | } 1063 | 1064 | void 1065 | test_tefs_read_after_write_to_multiple_files_one_at_a_time( 1066 | planck_unit_test_t *tc 1067 | ) 1068 | { 1069 | files[0].file = malloc(sizeof(file_t)); 1070 | files[1].file = malloc(sizeof(file_t)); 1071 | 1072 | if (files[0].file == NULL || files[1].file == NULL) 1073 | { 1074 | printf("%s\n", memory_error); 1075 | exit(-1); 1076 | } 1077 | 1078 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, format_device()); 1079 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_open(files[0].file, files[0].name)); 1080 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_open(files[1].file, files[1].name)); 1081 | 1082 | populate_data_array_1(); 1083 | 1084 | uint32_t pages_per_child_block = format_info->page_size * format_info->block_size / address_size * format_info->block_size; 1085 | uint32_t num_pages = (pages_per_child_block < format_info->num_pages) ? pages_per_child_block : format_info->num_pages; // TODO 1086 | 1087 | for (i = 0; i < num_pages + 10; i++) 1088 | { 1089 | /* Write a page then read it */ 1090 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_write(files[0].file, i, data, format_info->page_size, 0)); 1091 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_read(files[0].file, i, buffer, format_info->page_size, 0)); 1092 | 1093 | for (j = 0; j < format_info->page_size; j++) 1094 | { 1095 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, data[j], buffer[j]); 1096 | } 1097 | } 1098 | 1099 | for (i = 0; i < num_pages + 10; i++) 1100 | { 1101 | /* Write a page then read it */ 1102 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_write(files[1].file, i, data, format_info->page_size, 0)); 1103 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_read(files[1].file, i, buffer, format_info->page_size, 0)); 1104 | 1105 | for (j = 0; j < format_info->page_size; j++) 1106 | { 1107 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, data[j], buffer[j]); 1108 | } 1109 | } 1110 | 1111 | free(files[0].file); 1112 | free(files[1].file); 1113 | } 1114 | 1115 | void 1116 | test_tefs_read_after_write_to_multiple_files_staggered( 1117 | planck_unit_test_t *tc 1118 | ) 1119 | { 1120 | files[0].file = malloc(sizeof(file_t)); 1121 | files[1].file = malloc(sizeof(file_t)); 1122 | 1123 | if (files[0].file == NULL || files[1].file == NULL) 1124 | { 1125 | printf("%s\n", memory_error); 1126 | exit(-1); 1127 | } 1128 | 1129 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, format_device()); 1130 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_open(files[0].file, files[0].name)); 1131 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_open(files[1].file, files[1].name)); 1132 | 1133 | populate_data_array_1(); 1134 | 1135 | uint32_t pages_per_child_block = format_info->page_size * format_info->block_size / address_size * format_info->block_size; 1136 | uint32_t num_pages = (pages_per_child_block < format_info->num_pages) ? pages_per_child_block : format_info->num_pages; // TODO 1137 | 1138 | for (i = 0; i < num_pages + 10; i++) 1139 | { 1140 | /* Write a page then read it */ 1141 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_write(files[0].file, i, data, format_info->page_size, 0)); 1142 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_read(files[0].file, i, buffer, format_info->page_size, 0)); 1143 | 1144 | for (j = 0; j < format_info->page_size; j++) 1145 | { 1146 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, data[j], buffer[j]); 1147 | } 1148 | 1149 | /* Write a page then read it */ 1150 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_write(files[1].file, i, data, format_info->page_size, 0)); 1151 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_read(files[1].file, i, buffer, format_info->page_size, 0)); 1152 | 1153 | for (j = 0; j < format_info->page_size; j++) 1154 | { 1155 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, data[j], buffer[j]); 1156 | } 1157 | } 1158 | 1159 | free(files[0].file); 1160 | free(files[1].file); 1161 | } 1162 | 1163 | void 1164 | test_tefs_write_to_multiple_files_one_at_a_time( 1165 | planck_unit_test_t *tc 1166 | ) 1167 | { 1168 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, format_device()); 1169 | 1170 | uint16_t file_num; 1171 | for (file_num = 0; file_num < 10; file_num++) 1172 | { 1173 | file_t *file = malloc(sizeof(file_t)); 1174 | 1175 | if (file == NULL) 1176 | { 1177 | printf("%s\n", memory_error); 1178 | exit(-1); 1179 | } 1180 | 1181 | char file_name[10]; 1182 | sprintf(file_name, "%s%d", "file.", file_num); 1183 | 1184 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_open(file, file_name)); 1185 | 1186 | /* Write num_pages of data to the file */ 1187 | for (i = 0; i < 1000; i++) 1188 | { 1189 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_write(file, i, data, format_info->page_size, 0)); 1190 | } 1191 | 1192 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_close(file)); 1193 | 1194 | free(file); 1195 | } 1196 | 1197 | uint16_t num_hash_blocks = 0; 1198 | for (file_num = 0; file_num < 10; file_num++) 1199 | { 1200 | uint32_t num_hashes_per_block = (format_info->page_size * format_info->block_size / format_info->hash_size); 1201 | uint32_t num_meta_entries_per_block = (format_info->page_size * format_info->block_size / 1202 | format_info->meta_data_size); 1203 | 1204 | uint32_t hash_entry_page = (file_num * format_info->hash_size) / format_info->page_size; 1205 | hash_entry_page += get_block_address(1) + 1206 | (file_num / num_hashes_per_block) * num_hashes_per_block * 2 * format_info->block_size; 1207 | 1208 | if (file_num > 0 && (file_num % num_hashes_per_block) == 0) 1209 | { 1210 | num_hash_blocks += 1; 1211 | } 1212 | 1213 | hash_entry_page += num_hash_blocks * 8 * format_info->block_size; 1214 | hash_entry_page += (num_hash_blocks > 0) ? format_info->block_size : 0; 1215 | 1216 | uint16_t hash_entry_byte = (file_num * format_info->hash_size) % format_info->page_size; 1217 | 1218 | uint32_t meta_data_page = (file_num * format_info->meta_data_size) / format_info->page_size; 1219 | meta_data_page += get_block_address(3) + 1220 | (file_num / num_meta_entries_per_block) * num_meta_entries_per_block * 2 * 1221 | format_info->block_size; 1222 | meta_data_page += (file_num / num_hashes_per_block) * format_info->block_size; 1223 | 1224 | uint16_t meta_data_byte = (file_num * format_info->meta_data_size) % format_info->page_size; 1225 | 1226 | /* Check the file size in the directory entry */ 1227 | four_byte_buffer = 0; 1228 | device_read(meta_data_page, &four_byte_buffer, 4, meta_data_byte + TEFS_DIR_STATUS_SIZE); 1229 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, four_byte_buffer); 1230 | 1231 | four_byte_buffer = 0; 1232 | device_read(meta_data_page, &four_byte_buffer, 2, 1233 | meta_data_byte + TEFS_DIR_STATUS_SIZE + TEFS_DIR_EOF_PAGE_SIZE); 1234 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, four_byte_buffer); 1235 | 1236 | uint32_t temp_block = 1237 | 4 + file_num * 2 + (file_num / num_meta_entries_per_block) + (file_num / num_hashes_per_block); 1238 | 1239 | if (check_state_section(tc, 0, temp_block + 2)) 1240 | { 1241 | PLANCK_UNIT_ASSERT_FALSE(tc); 1242 | } 1243 | 1244 | /* Check first data block address */ 1245 | four_byte_buffer = 0; 1246 | device_read(get_block_address(temp_block), &four_byte_buffer, 2, 0); 1247 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, get_block_address(temp_block + 1), four_byte_buffer); 1248 | } 1249 | } 1250 | 1251 | void 1252 | test_tefs_write_to_multiple_files_staggered( 1253 | planck_unit_test_t *tc 1254 | ) 1255 | { 1256 | 1257 | } 1258 | 1259 | void 1260 | test_tefs_write_past_end_of_file( 1261 | planck_unit_test_t *tc 1262 | ) 1263 | { 1264 | 1265 | } 1266 | 1267 | void 1268 | test_tefs_hash_collision( 1269 | planck_unit_test_t *tc 1270 | ) 1271 | { 1272 | file_t *file1 = malloc(sizeof(file_t)); 1273 | file_t *file2 = malloc(sizeof(file_t)); 1274 | 1275 | if (file1 == NULL || file2 == NULL) 1276 | { 1277 | printf("%s\n", memory_error); 1278 | exit(-1); 1279 | } 1280 | 1281 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, format_device()); 1282 | 1283 | /* The words "playwright" and "snush" collide for DJB2a. */ 1284 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_open(file1, "playwright")); 1285 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_open(file2, "snush")); 1286 | 1287 | populate_data_array_1(); 1288 | 1289 | /* Check the hash values in the hash entries file. */ 1290 | four_byte_buffer = 0; 1291 | device_read(get_block_address(1), &four_byte_buffer, 4, 0); 1292 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 195669366, four_byte_buffer); 1293 | 1294 | four_byte_buffer = 0; 1295 | device_read(get_block_address(1), &four_byte_buffer, 4, format_info->hash_size); 1296 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 195669366, four_byte_buffer); 1297 | 1298 | /* Close and open both files. */ 1299 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_close(file1)); 1300 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_close(file2)); 1301 | 1302 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_open(file2, "snush")); 1303 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_open(file1, "playwright")); 1304 | 1305 | /* Write to and from both files. */ 1306 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_write(file1, 0, data, format_info->page_size, 0)); 1307 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, device_read(get_block_address(5), buffer, format_info->page_size, 0)); 1308 | 1309 | for (j = 0; j < format_info->page_size; j++) 1310 | { 1311 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, data[j], buffer[j]); 1312 | } 1313 | 1314 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_write(file2, 0, data, format_info->page_size, 0)); 1315 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, device_read(get_block_address(7), buffer, format_info->page_size, 0)); 1316 | 1317 | for (j = 0; j < format_info->page_size; j++) 1318 | { 1319 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, data[j], buffer[j]); 1320 | } 1321 | 1322 | free(file1); 1323 | free(file2); 1324 | } 1325 | 1326 | //void test_tefs_release_block( 1327 | // planck_unit_test_t *tc 1328 | //) 1329 | //{ 1330 | // file_t file; 1331 | // format_device(); 1332 | // PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_open(&file, "test.aaa")); 1333 | // 1334 | // uint16_t i; 1335 | // populate_data_array_1(); 1336 | // 1337 | // /* Write and read multiple pages */ 1338 | // for (i = 0; i < 100; i++) 1339 | // { 1340 | // PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_write(&file, i, data, 512, 0)); 1341 | // } 1342 | // 1343 | // /* Release the pages */ 1344 | // for (i = 0; i < 2; i++) 1345 | // { 1346 | // PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_release_block(&file, i * 8)); 1347 | // } 1348 | // 1349 | // /* Check if the state section has the right values as well as the root index 1350 | // block */ 1351 | // uint8_t buffer; 1352 | // PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, device_read(1, &buffer, 1, 0)); 1353 | // PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0x30, buffer); 1354 | // PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, device_read(1, &buffer, 1, 1)); 1355 | // PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0x01, buffer); 1356 | // PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, device_read(1, &buffer, 1, 2)); 1357 | // PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0xFF, buffer); 1358 | // 1359 | // uint16_t address; 1360 | // PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, device_read(12, &address, 2, 0)); 1361 | // PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, TEFS_DELETED, address); 1362 | // 1363 | // /* Release the rest of the pages */ 1364 | // for (i = 2; i < (100 / 8) + 1; i++) 1365 | // { 1366 | // PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_release_block(&file, i * 8)); 1367 | // } 1368 | // 1369 | // /* Check if state section, root index block, and child index block are correct */ 1370 | // PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, device_read(1, &buffer, 1, 0)); 1371 | // PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0x7F, buffer); 1372 | // PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, device_read(1, &buffer, 1, 1)); 1373 | // PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0xFF, buffer); 1374 | // PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, device_read(1, &buffer, 1, 2)); 1375 | // PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0xFF, buffer); 1376 | // 1377 | // PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, device_read(4, &address, 2, 0)); 1378 | // PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, TEFS_DELETED, address); 1379 | //} 1380 | 1381 | //#if defined(TEFS_CONTINUOUS_SUPPORT) 1382 | //void test_tefs_sequential_read_and_write( 1383 | // planck_unit_test_t *tc 1384 | //) 1385 | //{ 1386 | // file_t file; 1387 | // format_device(); 1388 | // PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_open(&file, "test.aaa")); 1389 | // 1390 | // populate_data_array_1(); 1391 | // 1392 | // PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_write_continuous_start(&file, 0)); 1393 | // 1394 | // uint8_t buffer[27]; 1395 | // uint16_t i; 1396 | // 1397 | // /* Write and read multiple pages */ 1398 | // for (i = 0; i < 16385 * 2; i++) 1399 | // { 1400 | // PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_write_continuous(&file, data, 512, 0)); 1401 | // PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_write_continuous_next(&file)); 1402 | // } 1403 | // 1404 | // PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_write_continuous_stop(&file)); 1405 | // 1406 | // PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_read_continuous_start(&file, 0)); 1407 | // 1408 | // for (i = 0; i < 16385 * 2; i++) 1409 | // { 1410 | // PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_read_continuous(&file, buffer, 27, 2)); 1411 | // 1412 | // uint8_t j; 1413 | // for (j = 0; j < 27; j++) 1414 | // { 1415 | // PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, data[2 + j], buffer[j]); 1416 | // } 1417 | // 1418 | // PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_read_continuous_next(&file)); 1419 | // } 1420 | // 1421 | // PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, tefs_read_continuous_stop(&file)); 1422 | //} 1423 | //#endif 1424 | 1425 | planck_unit_suite_t* 1426 | tefs_getsuite( 1427 | void 1428 | ) 1429 | { 1430 | planck_unit_suite_t *suite = planck_unit_new_suite(); 1431 | 1432 | planck_unit_add_to_suite(suite, test_tefs_format_device_without_erase); 1433 | planck_unit_add_to_suite(suite, test_tefs_format_device_with_erase); 1434 | planck_unit_add_to_suite(suite, test_tefs_create_single_file); 1435 | 1436 | planck_unit_add_to_suite(suite, test_tefs_create_multiple_files); 1437 | 1438 | planck_unit_add_to_suite(suite, test_tefs_remove_empty_single_file); 1439 | planck_unit_add_to_suite(suite, test_tefs_remove_small_single_file); 1440 | planck_unit_add_to_suite(suite, test_tefs_remove_large_single_file); 1441 | 1442 | planck_unit_add_to_suite(suite, test_tefs_remove_multiple_empty_files_consecutively); 1443 | planck_unit_add_to_suite(suite, test_tefs_remove_multiple_files_with_data_consecutively); 1444 | planck_unit_add_to_suite(suite, test_tefs_remove_multiple_empty_files_staggered); 1445 | planck_unit_add_to_suite(suite, test_tefs_remove_multiple_files_with_data_staggered); 1446 | 1447 | planck_unit_add_to_suite(suite, test_tefs_exists_single_file); 1448 | planck_unit_add_to_suite(suite, test_tefs_write_page_to_single_file); 1449 | planck_unit_add_to_suite(suite, test_tefs_write_data_block_to_single_file); 1450 | planck_unit_add_to_suite(suite, test_tefs_write_child_block_to_single_file); 1451 | planck_unit_add_to_suite(suite, test_tefs_write_multiple_child_blocks_to_single_file); 1452 | 1453 | planck_unit_add_to_suite(suite, test_tefs_read_after_write_to_single_file); 1454 | planck_unit_add_to_suite(suite, test_tefs_read_after_write_to_multiple_files_one_at_a_time); 1455 | planck_unit_add_to_suite(suite, test_tefs_read_after_write_to_multiple_files_staggered); 1456 | // planck_unit_add_to_suite(suite, test_tefs_write_to_multiple_files_one_at_a_time);// 1457 | // planck_unit_add_to_suite(suite, test_tefs_write_to_multiple_files_staggered);// 1458 | 1459 | // 1460 | // planck_unit_add_to_suite(suite, test_tefs_release_block);~ 1461 | 1462 | #if defined(USE_SD) && defined(TEFS_CONTINUOUS_SUPPORT) 1463 | //planck_unit_add_to_suite(suite, test_tefs_sequential_read_and_write);// 1464 | #endif 1465 | 1466 | /* Tests to check if errors are correctly returned. */ 1467 | // planck_unit_add_to_suite(suite, test_tefs_create_files_with_same_name);// 1468 | // planck_unit_add_to_suite(suite, test_tefs_open_file_when_not_formatted);// 1469 | // planck_unit_add_to_suite(suite, test_tefs_open_non_existent_file);// 1470 | // planck_unit_add_to_suite(suite, test_tefs_read_past_end_of_file);// 1471 | // planck_unit_add_to_suite(suite, test_tefs_write_past_end_of_file);// 1472 | // planck_unit_add_to_suite(suite, test_tefs_file_name_too_long);// 1473 | planck_unit_add_to_suite(suite, test_tefs_hash_collision); 1474 | #if !defined(ARDUINO) 1475 | // planck_unit_add_to_suite(suite, test_tefs_fill_device);// 1476 | #endif 1477 | 1478 | if (format_info->block_size == 1) 1479 | { 1480 | // planck_unit_add_to_suite(suite, test_tefs_fill_file);// 1481 | } 1482 | 1483 | return suite; 1484 | } 1485 | 1486 | void 1487 | runalltests_tefs( 1488 | void 1489 | ) 1490 | { 1491 | uint8_t format_run; 1492 | for (format_run = 0; format_run < sizeof(format_info_arr) / sizeof(format_info_t); format_run++) 1493 | { 1494 | format_info = &format_info_arr[format_run]; 1495 | 1496 | #if defined(ARDUINO) 1497 | format_info->num_pages = sd_spi_card_size(); 1498 | #endif 1499 | 1500 | if (format_info->num_pages < 65536) 1501 | { 1502 | address_size = 2; 1503 | } 1504 | else 1505 | { 1506 | address_size = 4; 1507 | } 1508 | 1509 | info_section_size = 1; 1510 | state_section_size_in_bytes = (format_info->num_pages - info_section_size) / (format_info->block_size * 8); 1511 | state_section_size = (state_section_size_in_bytes - 1) / (format_info->page_size) + 1; 1512 | 1513 | planck_unit_suite_t *suite = tefs_getsuite(); 1514 | planck_unit_run_suite(suite); 1515 | planck_unit_destroy_suite(suite); 1516 | } 1517 | } -------------------------------------------------------------------------------- /unit_tests/test_tefs_stdio.c: -------------------------------------------------------------------------------- 1 | #include "planck_unit/src/planckunit.h" 2 | #include "../src/tefs_stdio/tefs_stdio.h" 3 | 4 | #define CHIP_SELECT_PIN 4 5 | 6 | static uint8_t data[530]; 7 | static uint16_t physical_page_size = 512; 8 | static uint16_t block_size = 8; 9 | static uint8_t hash_size = 4; 10 | static uint16_t meta_data_size = 64; 11 | static uint16_t max_file_name_size = 12; 12 | 13 | static void 14 | populate_data_array_1( 15 | void 16 | ) 17 | { 18 | uint16_t i; 19 | 20 | for (i = 0; i < 26; i++) { 21 | data[i] = 'a' + i; 22 | } 23 | 24 | for (i = 26; i < 530; i++) { 25 | data[i] = '.'; 26 | } 27 | } 28 | 29 | // static void 30 | // populate_data_array_2( 31 | // void 32 | // ) 33 | // { 34 | // long int i; 35 | 36 | // for (i = 0; i < 26; i++) { 37 | // data[i] = 'A' + i; 38 | // } 39 | 40 | // for (i = 26; i < 530; i++) { 41 | // data[i] = '!'; 42 | // } 43 | // } 44 | 45 | static void 46 | format_device( 47 | void 48 | ) 49 | { 50 | #if defined(USE_DATAFLASH) && defined(USE_FTL) 51 | ftl_Instantiate(&ftl); 52 | flare_Createftl(&ftl); 53 | #endif 54 | 55 | #if defined(USE_SD) 56 | //int number_of_pages = sd_spi_card_size(); 57 | uint32_t number_of_pages = 62500; 58 | #elif defined(USE_DATAFLASH) && defined(USE_FTL) 59 | uint32_t number_of_pages = 1000; 60 | #elif defined(USE_DATAFLASH) && !defined(USE_FTL) 61 | uint32_t number_of_pages = DF_number_of_pages; 62 | #endif 63 | 64 | tefs_format_device(number_of_pages, physical_page_size, block_size, hash_size, meta_data_size, max_file_name_size, 1); 65 | } 66 | 67 | void 68 | test_tefs_stdio_write_pages( 69 | planck_unit_test_t *tc 70 | ) 71 | { 72 | format_device(); 73 | T_FILE *file = t_fopen("test.aaa", "w+"); 74 | PLANCK_UNIT_ASSERT_TRUE(tc, file != NULL); 75 | 76 | populate_data_array_1(); 77 | 78 | /* Write a single page and check if it has been written */ 79 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 512, t_fwrite(data, 512, 1, file)); 80 | 81 | uint8_t buffer[27]; 82 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, device_read(43, buffer, 27, 2)); 83 | 84 | uint32_t i; 85 | for (i = 0; i < 27; i++) 86 | { 87 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, data[i + 2], buffer[i]); 88 | } 89 | 90 | /* Write multiple pages but stay within a single meta block */ 91 | for (i = 1; i < 50; i++) 92 | { 93 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 512, t_fwrite(data, 512, 1, file)); 94 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, device_read(43 + i, buffer, 27, 2)); 95 | 96 | uint8_t j; 97 | for (j = 0; j < 27; j++) 98 | { 99 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, data[j + 2], buffer[j]); 100 | } 101 | } 102 | 103 | /* Check the file size in the directory entry */ 104 | uint32_t size = 0; 105 | device_read(27, &size, 4, TEFS_DIR_STATUS_SIZE + max_file_name_size); 106 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 25088, size); 107 | 108 | #if defined(USE_SD) 109 | /* Write multiple pages with meta block overflow */ 110 | for (i = 50; i < 16385 * 2; i++) 111 | { 112 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 512, t_fwrite(data, 512, 1, file)); 113 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, device_read(43 + i + (i / (16384)) * 8, 114 | buffer, 27, 2)); 115 | 116 | uint8_t j; 117 | for (j = 0; j < 27; j++) 118 | { 119 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, data[j + 2], buffer[j]); 120 | } 121 | } 122 | 123 | /* Check the file size in the directory entry */ 124 | size = 0; 125 | device_read(27, &size, 4, TEFS_DIR_STATUS_SIZE + max_file_name_size); 126 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 16777728, size); 127 | #endif 128 | } 129 | 130 | void 131 | test_tefs_stdio_write_past_block_boundary( 132 | planck_unit_test_t *tc 133 | ) 134 | { 135 | format_device(); 136 | T_FILE *file = t_fopen("test.aaa", "w+"); 137 | PLANCK_UNIT_ASSERT_TRUE(tc, file != NULL); 138 | 139 | populate_data_array_1(); 140 | uint8_t buffer[27]; 141 | 142 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 530, t_fwrite(data, 530, 1, file)); 143 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 530, t_fwrite(data, 530, 1, file)); 144 | 145 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, device_read(43, buffer, 27, 0)); 146 | 147 | uint8_t j; 148 | for (j = 0; j < 27; j++) 149 | { 150 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, data[j], buffer[j]); 151 | } 152 | 153 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 0, device_read(44, buffer, 27, 18)); 154 | 155 | for (j = 0; j < 27; j++) 156 | { 157 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, data[j], buffer[j]); 158 | } 159 | 160 | /* Check the file size in the directory entry */ 161 | uint32_t size = 0; 162 | device_read(27, &size, 4, TEFS_DIR_STATUS_SIZE + max_file_name_size); 163 | PLANCK_UNIT_ASSERT_INT_ARE_EQUAL(tc, 512, size); 164 | } 165 | 166 | planck_unit_suite_t* 167 | tefs_stdio_getsuite( 168 | void 169 | ) 170 | { 171 | planck_unit_suite_t *suite = planck_unit_new_suite(); 172 | 173 | planck_unit_add_to_suite(suite, test_tefs_stdio_write_pages); 174 | planck_unit_add_to_suite(suite, test_tefs_stdio_write_past_block_boundary); 175 | 176 | return suite; 177 | } 178 | 179 | void 180 | runalltests_tefs_stdio( 181 | void 182 | ) 183 | { 184 | // CuString *output = CuStringNew(); 185 | // CuSuite *suite = tefs_stdio_getsuite(); 186 | 187 | planck_unit_suite_t *suite = tefs_stdio_getsuite(); 188 | planck_unit_run_suite(suite); 189 | 190 | // CuSuiteRun(suite); 191 | // CuSuiteSummary(suite, output); 192 | // CuSuiteDetails(suite, output); 193 | // printf("%s\n", output->buffer); 194 | // 195 | // CuSuiteDelete(suite); 196 | // CuStringDelete(output); 197 | } --------------------------------------------------------------------------------