RTC auf true

Committer:
kevman
Date:
Wed Mar 13 11:03:24 2019 +0000
Revision:
2:7aab896b1a3b
Parent:
0:38ceb79fef03
2019-03-13

Who changed what in which revision?

UserRevisionLine numberNew contents of line
kevman 0:38ceb79fef03 1 /* mbed Microcontroller Library
kevman 0:38ceb79fef03 2 * Copyright (c) 2018 ARM Limited
kevman 0:38ceb79fef03 3 *
kevman 0:38ceb79fef03 4 * Licensed under the Apache License, Version 2.0 (the "License");
kevman 0:38ceb79fef03 5 * you may not use this file except in compliance with the License.
kevman 0:38ceb79fef03 6 * You may obtain a copy of the License at
kevman 0:38ceb79fef03 7 *
kevman 0:38ceb79fef03 8 * http://www.apache.org/licenses/LICENSE-2.0
kevman 0:38ceb79fef03 9 *
kevman 0:38ceb79fef03 10 * Unless required by applicable law or agreed to in writing, software
kevman 0:38ceb79fef03 11 * distributed under the License is distributed on an "AS IS" BASIS,
kevman 0:38ceb79fef03 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
kevman 0:38ceb79fef03 13 * See the License for the specific language governing permissions and
kevman 0:38ceb79fef03 14 * limitations under the License.
kevman 0:38ceb79fef03 15 */
kevman 0:38ceb79fef03 16
kevman 0:38ceb79fef03 17 #include "BufferedBlockDevice.h"
kevman 0:38ceb79fef03 18 #include "platform/mbed_assert.h"
kevman 0:38ceb79fef03 19 #include "platform/mbed_critical.h"
kevman 0:38ceb79fef03 20 #include <algorithm>
kevman 0:38ceb79fef03 21 #include <string.h>
kevman 0:38ceb79fef03 22
kevman 0:38ceb79fef03 23 static inline uint32_t align_down(bd_size_t val, bd_size_t size)
kevman 0:38ceb79fef03 24 {
kevman 0:38ceb79fef03 25 return val / size * size;
kevman 0:38ceb79fef03 26 }
kevman 0:38ceb79fef03 27
kevman 0:38ceb79fef03 28 BufferedBlockDevice::BufferedBlockDevice(BlockDevice *bd)
kevman 0:38ceb79fef03 29 : _bd(bd), _bd_program_size(0), _curr_aligned_addr(0), _flushed(true), _cache(0), _init_ref_count(0), _is_initialized(false)
kevman 0:38ceb79fef03 30 {
kevman 0:38ceb79fef03 31 }
kevman 0:38ceb79fef03 32
kevman 0:38ceb79fef03 33 BufferedBlockDevice::~BufferedBlockDevice()
kevman 0:38ceb79fef03 34 {
kevman 0:38ceb79fef03 35 deinit();
kevman 0:38ceb79fef03 36 }
kevman 0:38ceb79fef03 37
kevman 0:38ceb79fef03 38 int BufferedBlockDevice::init()
kevman 0:38ceb79fef03 39 {
kevman 0:38ceb79fef03 40 uint32_t val = core_util_atomic_incr_u32(&_init_ref_count, 1);
kevman 0:38ceb79fef03 41
kevman 0:38ceb79fef03 42 if (val != 1) {
kevman 0:38ceb79fef03 43 return BD_ERROR_OK;
kevman 0:38ceb79fef03 44 }
kevman 0:38ceb79fef03 45
kevman 0:38ceb79fef03 46 int err = _bd->init();
kevman 0:38ceb79fef03 47 if (err) {
kevman 0:38ceb79fef03 48 return err;
kevman 0:38ceb79fef03 49 }
kevman 0:38ceb79fef03 50
kevman 0:38ceb79fef03 51 _bd_program_size = _bd->get_program_size();
kevman 0:38ceb79fef03 52
kevman 0:38ceb79fef03 53 if (!_cache) {
kevman 0:38ceb79fef03 54 _cache = new uint8_t[_bd_program_size];
kevman 0:38ceb79fef03 55 }
kevman 0:38ceb79fef03 56
kevman 0:38ceb79fef03 57 _curr_aligned_addr = _bd->size();
kevman 0:38ceb79fef03 58 _flushed = true;
kevman 0:38ceb79fef03 59
kevman 0:38ceb79fef03 60 _is_initialized = true;
kevman 0:38ceb79fef03 61 return BD_ERROR_OK;
kevman 0:38ceb79fef03 62 }
kevman 0:38ceb79fef03 63
kevman 0:38ceb79fef03 64 int BufferedBlockDevice::deinit()
kevman 0:38ceb79fef03 65 {
kevman 0:38ceb79fef03 66 if (!_is_initialized) {
kevman 0:38ceb79fef03 67 return BD_ERROR_OK;
kevman 0:38ceb79fef03 68 }
kevman 0:38ceb79fef03 69
kevman 0:38ceb79fef03 70 uint32_t val = core_util_atomic_decr_u32(&_init_ref_count, 1);
kevman 0:38ceb79fef03 71
kevman 0:38ceb79fef03 72 if (val) {
kevman 0:38ceb79fef03 73 return BD_ERROR_OK;
kevman 0:38ceb79fef03 74 }
kevman 0:38ceb79fef03 75
kevman 0:38ceb79fef03 76 delete[] _cache;
kevman 0:38ceb79fef03 77 _cache = 0;
kevman 0:38ceb79fef03 78 _is_initialized = false;
kevman 0:38ceb79fef03 79 return _bd->deinit();
kevman 0:38ceb79fef03 80 }
kevman 0:38ceb79fef03 81
kevman 0:38ceb79fef03 82 int BufferedBlockDevice::flush()
kevman 0:38ceb79fef03 83 {
kevman 0:38ceb79fef03 84 if (!_is_initialized) {
kevman 0:38ceb79fef03 85 return BD_ERROR_DEVICE_ERROR;
kevman 0:38ceb79fef03 86 }
kevman 0:38ceb79fef03 87
kevman 0:38ceb79fef03 88 if (!_flushed) {
kevman 0:38ceb79fef03 89 int ret = _bd->program(_cache, _curr_aligned_addr, _bd_program_size);
kevman 0:38ceb79fef03 90 if (ret) {
kevman 0:38ceb79fef03 91 return ret;
kevman 0:38ceb79fef03 92 }
kevman 0:38ceb79fef03 93 _flushed = true;
kevman 0:38ceb79fef03 94 }
kevman 0:38ceb79fef03 95 return 0;
kevman 0:38ceb79fef03 96 }
kevman 0:38ceb79fef03 97
kevman 0:38ceb79fef03 98 int BufferedBlockDevice::sync()
kevman 0:38ceb79fef03 99 {
kevman 0:38ceb79fef03 100 if (!_is_initialized) {
kevman 0:38ceb79fef03 101 return BD_ERROR_DEVICE_ERROR;
kevman 0:38ceb79fef03 102 }
kevman 0:38ceb79fef03 103
kevman 0:38ceb79fef03 104 int ret = flush();
kevman 0:38ceb79fef03 105 if (ret) {
kevman 0:38ceb79fef03 106 return ret;
kevman 0:38ceb79fef03 107 }
kevman 0:38ceb79fef03 108 return _bd->sync();
kevman 0:38ceb79fef03 109 }
kevman 0:38ceb79fef03 110
kevman 0:38ceb79fef03 111 int BufferedBlockDevice::read(void *b, bd_addr_t addr, bd_size_t size)
kevman 0:38ceb79fef03 112 {
kevman 0:38ceb79fef03 113 MBED_ASSERT(_cache);
kevman 0:38ceb79fef03 114 if (!_is_initialized) {
kevman 0:38ceb79fef03 115 return BD_ERROR_DEVICE_ERROR;
kevman 0:38ceb79fef03 116 }
kevman 0:38ceb79fef03 117
kevman 0:38ceb79fef03 118 bool moved_unit = false;
kevman 0:38ceb79fef03 119
kevman 0:38ceb79fef03 120 bd_addr_t aligned_addr = align_down(addr, _bd_program_size);
kevman 0:38ceb79fef03 121
kevman 0:38ceb79fef03 122 uint8_t *buf = static_cast<uint8_t *> (b);
kevman 0:38ceb79fef03 123
kevman 0:38ceb79fef03 124 if (aligned_addr != _curr_aligned_addr) {
kevman 0:38ceb79fef03 125 // Need to flush if moved to another program unit
kevman 0:38ceb79fef03 126 flush();
kevman 0:38ceb79fef03 127 _curr_aligned_addr = aligned_addr;
kevman 0:38ceb79fef03 128 moved_unit = true;
kevman 0:38ceb79fef03 129 }
kevman 0:38ceb79fef03 130
kevman 0:38ceb79fef03 131 while (size) {
kevman 0:38ceb79fef03 132 _curr_aligned_addr = align_down(addr, _bd_program_size);
kevman 0:38ceb79fef03 133 if (moved_unit) {
kevman 0:38ceb79fef03 134 int ret = _bd->read(_cache, _curr_aligned_addr, _bd_program_size);
kevman 0:38ceb79fef03 135 if (ret) {
kevman 0:38ceb79fef03 136 return ret;
kevman 0:38ceb79fef03 137 }
kevman 0:38ceb79fef03 138 }
kevman 0:38ceb79fef03 139 bd_addr_t offs_in_buf = addr - _curr_aligned_addr;
kevman 0:38ceb79fef03 140 bd_size_t chunk = std::min(_bd_program_size - offs_in_buf, size);
kevman 0:38ceb79fef03 141 memcpy(buf, _cache + offs_in_buf, chunk);
kevman 0:38ceb79fef03 142 moved_unit = true;
kevman 0:38ceb79fef03 143 buf += chunk;
kevman 0:38ceb79fef03 144 addr += chunk;
kevman 0:38ceb79fef03 145 size -= chunk;
kevman 0:38ceb79fef03 146 }
kevman 0:38ceb79fef03 147
kevman 0:38ceb79fef03 148 return 0;
kevman 0:38ceb79fef03 149 }
kevman 0:38ceb79fef03 150
kevman 0:38ceb79fef03 151 int BufferedBlockDevice::program(const void *b, bd_addr_t addr, bd_size_t size)
kevman 0:38ceb79fef03 152 {
kevman 0:38ceb79fef03 153 if (!_is_initialized) {
kevman 0:38ceb79fef03 154 return BD_ERROR_DEVICE_ERROR;
kevman 0:38ceb79fef03 155 }
kevman 0:38ceb79fef03 156
kevman 0:38ceb79fef03 157 int ret;
kevman 0:38ceb79fef03 158 bool moved_unit = false;
kevman 0:38ceb79fef03 159
kevman 0:38ceb79fef03 160 bd_addr_t aligned_addr = align_down(addr, _bd_program_size);
kevman 0:38ceb79fef03 161
kevman 0:38ceb79fef03 162 const uint8_t *buf = static_cast <const uint8_t *> (b);
kevman 0:38ceb79fef03 163
kevman 0:38ceb79fef03 164 // Need to flush if moved to another program unit
kevman 0:38ceb79fef03 165 if (aligned_addr != _curr_aligned_addr) {
kevman 0:38ceb79fef03 166 flush();
kevman 0:38ceb79fef03 167 _curr_aligned_addr = aligned_addr;
kevman 0:38ceb79fef03 168 moved_unit = true;
kevman 0:38ceb79fef03 169 }
kevman 0:38ceb79fef03 170
kevman 0:38ceb79fef03 171 while (size) {
kevman 0:38ceb79fef03 172 _curr_aligned_addr = align_down(addr, _bd_program_size);
kevman 0:38ceb79fef03 173 bd_addr_t offs_in_buf = addr - _curr_aligned_addr;
kevman 0:38ceb79fef03 174 bd_size_t chunk = std::min(_bd_program_size - offs_in_buf, size);
kevman 0:38ceb79fef03 175 const uint8_t *prog_buf;
kevman 0:38ceb79fef03 176 if (chunk < _bd_program_size) {
kevman 0:38ceb79fef03 177 // If moved a unit, and program doesn't cover entire unit, it means we don't have the entire
kevman 0:38ceb79fef03 178 // program unit cached - need to complete it from underlying BD
kevman 0:38ceb79fef03 179 if (moved_unit) {
kevman 0:38ceb79fef03 180 ret = _bd->read(_cache, _curr_aligned_addr, _bd_program_size);
kevman 0:38ceb79fef03 181 if (ret) {
kevman 0:38ceb79fef03 182 return ret;
kevman 0:38ceb79fef03 183 }
kevman 0:38ceb79fef03 184 }
kevman 0:38ceb79fef03 185 memcpy(_cache + offs_in_buf, buf, chunk);
kevman 0:38ceb79fef03 186 prog_buf = _cache;
kevman 0:38ceb79fef03 187 } else {
kevman 0:38ceb79fef03 188 // No need to copy data to our cache on each iteration. Just make sure it's updated
kevman 0:38ceb79fef03 189 // on the last iteration, when size is not greater than program size (can't be smaller, as
kevman 0:38ceb79fef03 190 // this is covered in the previous condition).
kevman 0:38ceb79fef03 191 prog_buf = buf;
kevman 0:38ceb79fef03 192 if (size == _bd_program_size) {
kevman 0:38ceb79fef03 193 memcpy(_cache, buf, _bd_program_size);
kevman 0:38ceb79fef03 194 }
kevman 0:38ceb79fef03 195 }
kevman 0:38ceb79fef03 196
kevman 0:38ceb79fef03 197 // Don't flush on the last iteration, just on all preceding ones.
kevman 0:38ceb79fef03 198 if (size > chunk) {
kevman 0:38ceb79fef03 199 ret = _bd->program(prog_buf, _curr_aligned_addr, _bd_program_size);
kevman 0:38ceb79fef03 200 if (ret) {
kevman 0:38ceb79fef03 201 return ret;
kevman 0:38ceb79fef03 202 }
kevman 0:38ceb79fef03 203 _bd->sync();
kevman 0:38ceb79fef03 204 } else {
kevman 0:38ceb79fef03 205 _flushed = false;
kevman 0:38ceb79fef03 206 }
kevman 0:38ceb79fef03 207
kevman 0:38ceb79fef03 208 moved_unit = true;
kevman 0:38ceb79fef03 209 buf += chunk;
kevman 0:38ceb79fef03 210 addr += chunk;
kevman 0:38ceb79fef03 211 size -= chunk;
kevman 0:38ceb79fef03 212 }
kevman 0:38ceb79fef03 213
kevman 0:38ceb79fef03 214 return 0;
kevman 0:38ceb79fef03 215 }
kevman 0:38ceb79fef03 216
kevman 0:38ceb79fef03 217 int BufferedBlockDevice::erase(bd_addr_t addr, bd_size_t size)
kevman 0:38ceb79fef03 218 {
kevman 0:38ceb79fef03 219 MBED_ASSERT(is_valid_erase(addr, size));
kevman 0:38ceb79fef03 220 if (!_is_initialized) {
kevman 0:38ceb79fef03 221 return BD_ERROR_DEVICE_ERROR;
kevman 0:38ceb79fef03 222 }
kevman 0:38ceb79fef03 223
kevman 0:38ceb79fef03 224 return _bd->erase(addr, size);
kevman 0:38ceb79fef03 225 }
kevman 0:38ceb79fef03 226
kevman 0:38ceb79fef03 227 int BufferedBlockDevice::trim(bd_addr_t addr, bd_size_t size)
kevman 0:38ceb79fef03 228 {
kevman 0:38ceb79fef03 229 MBED_ASSERT(is_valid_erase(addr, size));
kevman 0:38ceb79fef03 230 if (!_is_initialized) {
kevman 0:38ceb79fef03 231 return BD_ERROR_DEVICE_ERROR;
kevman 0:38ceb79fef03 232 }
kevman 0:38ceb79fef03 233
kevman 0:38ceb79fef03 234 if ((_curr_aligned_addr >= addr) && (_curr_aligned_addr <= addr + size)) {
kevman 0:38ceb79fef03 235 _flushed = true;
kevman 0:38ceb79fef03 236 _curr_aligned_addr = _bd->size();
kevman 0:38ceb79fef03 237 }
kevman 0:38ceb79fef03 238 return _bd->trim(addr, size);
kevman 0:38ceb79fef03 239 }
kevman 0:38ceb79fef03 240
kevman 0:38ceb79fef03 241 bd_size_t BufferedBlockDevice::get_read_size() const
kevman 0:38ceb79fef03 242 {
kevman 0:38ceb79fef03 243 return 1;
kevman 0:38ceb79fef03 244 }
kevman 0:38ceb79fef03 245
kevman 0:38ceb79fef03 246 bd_size_t BufferedBlockDevice::get_program_size() const
kevman 0:38ceb79fef03 247 {
kevman 0:38ceb79fef03 248 return 1;
kevman 0:38ceb79fef03 249 }
kevman 0:38ceb79fef03 250
kevman 0:38ceb79fef03 251 bd_size_t BufferedBlockDevice::get_erase_size() const
kevman 0:38ceb79fef03 252 {
kevman 0:38ceb79fef03 253 if (!_is_initialized) {
kevman 0:38ceb79fef03 254 return 0;
kevman 0:38ceb79fef03 255 }
kevman 0:38ceb79fef03 256
kevman 0:38ceb79fef03 257 return _bd->get_erase_size();
kevman 0:38ceb79fef03 258 }
kevman 0:38ceb79fef03 259
kevman 0:38ceb79fef03 260 bd_size_t BufferedBlockDevice::get_erase_size(bd_addr_t addr) const
kevman 0:38ceb79fef03 261 {
kevman 0:38ceb79fef03 262 if (!_is_initialized) {
kevman 0:38ceb79fef03 263 return 0;
kevman 0:38ceb79fef03 264 }
kevman 0:38ceb79fef03 265
kevman 0:38ceb79fef03 266 return _bd->get_erase_size(addr);
kevman 0:38ceb79fef03 267 }
kevman 0:38ceb79fef03 268
kevman 0:38ceb79fef03 269 int BufferedBlockDevice::get_erase_value() const
kevman 0:38ceb79fef03 270 {
kevman 0:38ceb79fef03 271 if (!_is_initialized) {
kevman 0:38ceb79fef03 272 return BD_ERROR_DEVICE_ERROR;
kevman 0:38ceb79fef03 273 }
kevman 0:38ceb79fef03 274
kevman 0:38ceb79fef03 275 return _bd->get_erase_value();
kevman 0:38ceb79fef03 276 }
kevman 0:38ceb79fef03 277
kevman 0:38ceb79fef03 278 bd_size_t BufferedBlockDevice::size() const
kevman 0:38ceb79fef03 279 {
kevman 0:38ceb79fef03 280 if (!_is_initialized) {
kevman 0:38ceb79fef03 281 return 0;
kevman 0:38ceb79fef03 282 }
kevman 0:38ceb79fef03 283
kevman 0:38ceb79fef03 284 return _bd->size();
kevman 0:38ceb79fef03 285 }