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.
Dependencies: nRF51_Vdd TextLCD BME280
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 "platform/mbed_assert.h" 00019 #include "platform/mbed_critical.h" 00020 #include <algorithm> 00021 #include <string.h> 00022 00023 static inline uint32_t align_down(bd_size_t val, bd_size_t size) 00024 { 00025 return val / size * size; 00026 } 00027 00028 BufferedBlockDevice::BufferedBlockDevice(BlockDevice *bd) 00029 : _bd(bd), _bd_program_size(0), _curr_aligned_addr(0), _flushed(true), _cache(0), _init_ref_count(0), _is_initialized(false) 00030 { 00031 } 00032 00033 BufferedBlockDevice::~BufferedBlockDevice() 00034 { 00035 deinit(); 00036 } 00037 00038 int BufferedBlockDevice::init() 00039 { 00040 uint32_t val = core_util_atomic_incr_u32(&_init_ref_count, 1); 00041 00042 if (val != 1) { 00043 return BD_ERROR_OK; 00044 } 00045 00046 int err = _bd->init(); 00047 if (err) { 00048 return err; 00049 } 00050 00051 _bd_program_size = _bd->get_program_size(); 00052 00053 if (!_cache) { 00054 _cache = new uint8_t[_bd_program_size]; 00055 } 00056 00057 _curr_aligned_addr = _bd->size(); 00058 _flushed = true; 00059 00060 _is_initialized = true; 00061 return BD_ERROR_OK; 00062 } 00063 00064 int BufferedBlockDevice::deinit() 00065 { 00066 if (!_is_initialized) { 00067 return BD_ERROR_OK; 00068 } 00069 00070 uint32_t val = core_util_atomic_decr_u32(&_init_ref_count, 1); 00071 00072 if (val) { 00073 return BD_ERROR_OK; 00074 } 00075 00076 delete[] _cache; 00077 _cache = 0; 00078 _is_initialized = false; 00079 return _bd->deinit(); 00080 } 00081 00082 int BufferedBlockDevice::flush() 00083 { 00084 if (!_is_initialized) { 00085 return BD_ERROR_DEVICE_ERROR; 00086 } 00087 00088 if (!_flushed) { 00089 int ret = _bd->program(_cache, _curr_aligned_addr, _bd_program_size); 00090 if (ret) { 00091 return ret; 00092 } 00093 _flushed = true; 00094 } 00095 return 0; 00096 } 00097 00098 int BufferedBlockDevice::sync() 00099 { 00100 if (!_is_initialized) { 00101 return BD_ERROR_DEVICE_ERROR; 00102 } 00103 00104 int ret = flush(); 00105 if (ret) { 00106 return ret; 00107 } 00108 return _bd->sync(); 00109 } 00110 00111 int BufferedBlockDevice::read(void *b, bd_addr_t addr, bd_size_t size) 00112 { 00113 MBED_ASSERT(_cache); 00114 if (!_is_initialized) { 00115 return BD_ERROR_DEVICE_ERROR; 00116 } 00117 00118 bool moved_unit = false; 00119 00120 bd_addr_t aligned_addr = align_down(addr, _bd_program_size); 00121 00122 uint8_t *buf = static_cast<uint8_t *> (b); 00123 00124 if (aligned_addr != _curr_aligned_addr) { 00125 // Need to flush if moved to another program unit 00126 flush(); 00127 _curr_aligned_addr = aligned_addr; 00128 moved_unit = true; 00129 } 00130 00131 while (size) { 00132 _curr_aligned_addr = align_down(addr, _bd_program_size); 00133 if (moved_unit) { 00134 int ret = _bd->read(_cache, _curr_aligned_addr, _bd_program_size); 00135 if (ret) { 00136 return ret; 00137 } 00138 } 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 memcpy(buf, _cache + offs_in_buf, chunk); 00142 moved_unit = true; 00143 buf += chunk; 00144 addr += chunk; 00145 size -= chunk; 00146 } 00147 00148 return 0; 00149 } 00150 00151 int BufferedBlockDevice::program(const void *b, bd_addr_t addr, bd_size_t size) 00152 { 00153 if (!_is_initialized) { 00154 return BD_ERROR_DEVICE_ERROR; 00155 } 00156 00157 int ret; 00158 bool moved_unit = false; 00159 00160 bd_addr_t aligned_addr = align_down(addr, _bd_program_size); 00161 00162 const uint8_t *buf = static_cast <const uint8_t *> (b); 00163 00164 // Need to flush if moved to another program unit 00165 if (aligned_addr != _curr_aligned_addr) { 00166 flush(); 00167 _curr_aligned_addr = aligned_addr; 00168 moved_unit = true; 00169 } 00170 00171 while (size) { 00172 _curr_aligned_addr = align_down(addr, _bd_program_size); 00173 bd_addr_t offs_in_buf = addr - _curr_aligned_addr; 00174 bd_size_t chunk = std::min(_bd_program_size - offs_in_buf, size); 00175 const uint8_t *prog_buf; 00176 if (chunk < _bd_program_size) { 00177 // If moved a unit, and program doesn't cover entire unit, it means we don't have the entire 00178 // program unit cached - need to complete it from underlying BD 00179 if (moved_unit) { 00180 ret = _bd->read(_cache, _curr_aligned_addr, _bd_program_size); 00181 if (ret) { 00182 return ret; 00183 } 00184 } 00185 memcpy(_cache + offs_in_buf, buf, chunk); 00186 prog_buf = _cache; 00187 } else { 00188 // No need to copy data to our cache on each iteration. Just make sure it's updated 00189 // on the last iteration, when size is not greater than program size (can't be smaller, as 00190 // this is covered in the previous condition). 00191 prog_buf = buf; 00192 if (size == _bd_program_size) { 00193 memcpy(_cache, buf, _bd_program_size); 00194 } 00195 } 00196 00197 // Don't flush on the last iteration, just on all preceding ones. 00198 if (size > chunk) { 00199 ret = _bd->program(prog_buf, _curr_aligned_addr, _bd_program_size); 00200 if (ret) { 00201 return ret; 00202 } 00203 _bd->sync(); 00204 } else { 00205 _flushed = false; 00206 } 00207 00208 moved_unit = true; 00209 buf += chunk; 00210 addr += chunk; 00211 size -= chunk; 00212 } 00213 00214 return 0; 00215 } 00216 00217 int BufferedBlockDevice::erase(bd_addr_t addr, bd_size_t size) 00218 { 00219 MBED_ASSERT(is_valid_erase(addr, size)); 00220 if (!_is_initialized) { 00221 return BD_ERROR_DEVICE_ERROR; 00222 } 00223 00224 return _bd->erase(addr, size); 00225 } 00226 00227 int BufferedBlockDevice::trim(bd_addr_t addr, bd_size_t size) 00228 { 00229 MBED_ASSERT(is_valid_erase(addr, size)); 00230 if (!_is_initialized) { 00231 return BD_ERROR_DEVICE_ERROR; 00232 } 00233 00234 if ((_curr_aligned_addr >= addr) && (_curr_aligned_addr <= addr + size)) { 00235 _flushed = true; 00236 _curr_aligned_addr = _bd->size(); 00237 } 00238 return _bd->trim(addr, size); 00239 } 00240 00241 bd_size_t BufferedBlockDevice::get_read_size() const 00242 { 00243 return 1; 00244 } 00245 00246 bd_size_t BufferedBlockDevice::get_program_size() const 00247 { 00248 return 1; 00249 } 00250 00251 bd_size_t BufferedBlockDevice::get_erase_size() const 00252 { 00253 if (!_is_initialized) { 00254 return 0; 00255 } 00256 00257 return _bd->get_erase_size(); 00258 } 00259 00260 bd_size_t BufferedBlockDevice::get_erase_size(bd_addr_t addr) const 00261 { 00262 if (!_is_initialized) { 00263 return 0; 00264 } 00265 00266 return _bd->get_erase_size(addr); 00267 } 00268 00269 int BufferedBlockDevice::get_erase_value() const 00270 { 00271 if (!_is_initialized) { 00272 return BD_ERROR_DEVICE_ERROR; 00273 } 00274 00275 return _bd->get_erase_value(); 00276 } 00277 00278 bd_size_t BufferedBlockDevice::size() const 00279 { 00280 if (!_is_initialized) { 00281 return 0; 00282 } 00283 00284 return _bd->size(); 00285 }
Generated on Tue Jul 12 2022 15:15:40 by
