Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
BufferedBlockDevice.cpp
00001 /* mbed Microcontroller Library 00002 * Copyright (c) 2018 ARM Limited 00003 * 00004 * Licensed under the Apache License, Version 2.0 (the "License"); 00005 * you may not use this file except in compliance with the License. 00006 * You may obtain a copy of the License at 00007 * 00008 * http://www.apache.org/licenses/LICENSE-2.0 00009 * 00010 * Unless required by applicable law or agreed to in writing, software 00011 * distributed under the License is distributed on an "AS IS" BASIS, 00012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 * See the License for the specific language governing permissions and 00014 * limitations under the License. 00015 */ 00016 00017 #include "BufferedBlockDevice.h" 00018 #include "mbed_assert.h" 00019 #include <algorithm> 00020 #include <string.h> 00021 00022 static inline uint32_t align_down(bd_size_t val, bd_size_t size) 00023 { 00024 return val / size * size; 00025 } 00026 00027 BufferedBlockDevice::BufferedBlockDevice(BlockDevice *bd) 00028 : _bd(bd), _bd_program_size(0), _curr_aligned_addr(0), _flushed(true), _cache(0) 00029 { 00030 } 00031 00032 BufferedBlockDevice::~BufferedBlockDevice() 00033 { 00034 deinit(); 00035 } 00036 00037 int BufferedBlockDevice::init() 00038 { 00039 int err = _bd->init(); 00040 if (err) { 00041 return err; 00042 } 00043 00044 _bd_program_size = _bd->get_program_size(); 00045 00046 if (!_cache) { 00047 _cache = new uint8_t[_bd_program_size]; 00048 } 00049 00050 _curr_aligned_addr = _bd->size(); 00051 _flushed = true; 00052 00053 return 0; 00054 } 00055 00056 int BufferedBlockDevice::deinit() 00057 { 00058 delete[] _cache; 00059 _cache = 0; 00060 return _bd->deinit(); 00061 } 00062 00063 int BufferedBlockDevice::flush() 00064 { 00065 if (!_flushed) { 00066 int ret = _bd->program(_cache, _curr_aligned_addr, _bd_program_size); 00067 if (ret) { 00068 return ret; 00069 } 00070 _flushed = true; 00071 } 00072 return 0; 00073 } 00074 00075 int BufferedBlockDevice::sync() 00076 { 00077 int ret = flush(); 00078 if (ret) { 00079 return ret; 00080 } 00081 return _bd->sync(); 00082 } 00083 00084 int BufferedBlockDevice::read(void *b, bd_addr_t addr, bd_size_t size) 00085 { 00086 MBED_ASSERT(_cache); 00087 bool moved_unit = false; 00088 00089 bd_addr_t aligned_addr = align_down(addr, _bd_program_size); 00090 00091 uint8_t *buf = static_cast<uint8_t *> (b); 00092 00093 if (aligned_addr != _curr_aligned_addr) { 00094 // Need to flush if moved to another program unit 00095 flush(); 00096 _curr_aligned_addr = aligned_addr; 00097 moved_unit = true; 00098 } 00099 00100 while (size) { 00101 _curr_aligned_addr = align_down(addr, _bd_program_size); 00102 if (moved_unit) { 00103 int ret = _bd->read(_cache, _curr_aligned_addr, _bd_program_size); 00104 if (ret) { 00105 return ret; 00106 } 00107 } 00108 bd_addr_t offs_in_buf = addr - _curr_aligned_addr; 00109 bd_size_t chunk = std::min(_bd_program_size - offs_in_buf, size); 00110 memcpy(buf, _cache + offs_in_buf, chunk); 00111 moved_unit = true; 00112 buf += chunk; 00113 addr += chunk; 00114 size -= chunk; 00115 } 00116 00117 return 0; 00118 } 00119 00120 int BufferedBlockDevice::program(const void *b, bd_addr_t addr, bd_size_t size) 00121 { 00122 MBED_ASSERT(_cache); 00123 int ret; 00124 bool moved_unit = false; 00125 00126 bd_addr_t aligned_addr = align_down(addr, _bd_program_size); 00127 00128 const uint8_t *buf = static_cast <const uint8_t *> (b); 00129 00130 // Need to flush if moved to another program unit 00131 if (aligned_addr != _curr_aligned_addr) { 00132 flush(); 00133 _curr_aligned_addr = aligned_addr; 00134 moved_unit = true; 00135 } 00136 00137 while (size) { 00138 _curr_aligned_addr = align_down(addr, _bd_program_size); 00139 bd_addr_t offs_in_buf = addr - _curr_aligned_addr; 00140 bd_size_t chunk = std::min(_bd_program_size - offs_in_buf, size); 00141 const uint8_t *prog_buf; 00142 if (chunk < _bd_program_size) { 00143 // If moved a unit, and program doesn't cover entire unit, it means we don't have the entire 00144 // program unit cached - need to complete it from underlying BD 00145 if (moved_unit) { 00146 ret = _bd->read(_cache, _curr_aligned_addr, _bd_program_size); 00147 if (ret) { 00148 return ret; 00149 } 00150 } 00151 memcpy(_cache + offs_in_buf, buf, chunk); 00152 prog_buf = _cache; 00153 } else { 00154 // No need to copy data to our cache on each iteration. Just make sure it's updated 00155 // on the last iteration, when size is not greater than program size (can't be smaller, as 00156 // this is covered in the previous condition). 00157 prog_buf = buf; 00158 if (size == _bd_program_size) { 00159 memcpy(_cache, buf, _bd_program_size); 00160 } 00161 } 00162 00163 // Don't flush on the last iteration, just on all preceding ones. 00164 if (size > chunk) { 00165 ret = _bd->program(prog_buf, _curr_aligned_addr, _bd_program_size); 00166 if (ret) { 00167 return ret; 00168 } 00169 _bd->sync(); 00170 } else { 00171 _flushed = false; 00172 } 00173 00174 moved_unit = true; 00175 buf += chunk; 00176 addr += chunk; 00177 size -= chunk; 00178 } 00179 00180 return 0; 00181 } 00182 00183 int BufferedBlockDevice::erase(bd_addr_t addr, bd_size_t size) 00184 { 00185 MBED_ASSERT(is_valid_erase(addr, size)); 00186 return _bd->erase(addr, size); 00187 } 00188 00189 int BufferedBlockDevice::trim(bd_addr_t addr, bd_size_t size) 00190 { 00191 MBED_ASSERT(is_valid_erase(addr, size)); 00192 00193 if ((_curr_aligned_addr >= addr) && (_curr_aligned_addr <= addr + size)) { 00194 _flushed = true; 00195 _curr_aligned_addr = _bd->size(); 00196 } 00197 return _bd->trim(addr, size); 00198 } 00199 00200 bd_size_t BufferedBlockDevice::get_read_size() const 00201 { 00202 return 1; 00203 } 00204 00205 bd_size_t BufferedBlockDevice::get_program_size() const 00206 { 00207 return 1; 00208 } 00209 00210 bd_size_t BufferedBlockDevice::get_erase_size() const 00211 { 00212 return _bd->get_erase_size(); 00213 } 00214 00215 bd_size_t BufferedBlockDevice::get_erase_size(bd_addr_t addr) const 00216 { 00217 return _bd->get_erase_size(addr); 00218 } 00219 00220 int BufferedBlockDevice::get_erase_value() const 00221 { 00222 return _bd->get_erase_value(); 00223 } 00224 00225 bd_size_t BufferedBlockDevice::size() const 00226 { 00227 return _bd->size(); 00228 }
Generated on Tue Jul 12 2022 12:43:36 by
1.7.2