takashi kadono / Mbed OS Nucleo_446

Dependencies:   ssd1331

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ExhaustibleBlockDevice.cpp Source File

ExhaustibleBlockDevice.cpp

00001 /* mbed Microcontroller Library
00002  * Copyright (c) 2017 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 "ExhaustibleBlockDevice.h"
00018 #include "mbed.h"
00019 #include "mbed_critical.h"
00020 
00021 
00022 ExhaustibleBlockDevice::ExhaustibleBlockDevice(BlockDevice *bd, uint32_t erase_cycles)
00023     : _bd(bd), _erase_array(NULL), _erase_cycles(erase_cycles), _init_ref_count(0), _is_initialized(false)
00024 {
00025 }
00026 
00027 ExhaustibleBlockDevice::~ExhaustibleBlockDevice()
00028 {
00029     delete[] _erase_array;
00030 }
00031 
00032 int ExhaustibleBlockDevice::init()
00033 {
00034     int err;
00035     uint32_t val = core_util_atomic_incr_u32(&_init_ref_count, 1);
00036 
00037     if (val != 1) {
00038         return BD_ERROR_OK;
00039     }
00040 
00041     err = _bd->init();
00042     if (err) {
00043         goto fail;
00044     }
00045 
00046     if (!_erase_array) {
00047         // can only be allocated after initialization
00048         _erase_array = new uint32_t[_bd->size() / _bd->get_erase_size()];
00049         for (size_t i = 0; i < _bd->size() / _bd->get_erase_size(); i++) {
00050             _erase_array[i] = _erase_cycles;
00051         }
00052     }
00053 
00054     _is_initialized = true;
00055     return BD_ERROR_OK;
00056 
00057 fail:
00058     _is_initialized = false;
00059     _init_ref_count = 0;
00060     return err;
00061 }
00062 
00063 int ExhaustibleBlockDevice::deinit()
00064 {
00065     if (!_is_initialized) {
00066         return BD_ERROR_OK;
00067     }
00068 
00069     core_util_atomic_decr_u32(&_init_ref_count, 1);
00070 
00071     if (_init_ref_count) {
00072         return BD_ERROR_OK;
00073     }
00074 
00075     // _erase_array is lazily cleaned up in destructor to allow
00076     // data to live across de/reinitialization
00077     _is_initialized = false;
00078     return _bd->deinit();
00079 }
00080 
00081 int ExhaustibleBlockDevice::sync()
00082 {
00083     if (!_is_initialized) {
00084         return BD_ERROR_DEVICE_ERROR;
00085     }
00086 
00087     return _bd->sync();
00088 }
00089 
00090 int ExhaustibleBlockDevice::read(void *buffer, bd_addr_t addr, bd_size_t size)
00091 {
00092     if (!_is_initialized) {
00093         return BD_ERROR_DEVICE_ERROR;
00094     }
00095 
00096     return _bd->read(buffer, addr, size);
00097 }
00098 
00099 int ExhaustibleBlockDevice::program(const void *buffer, bd_addr_t addr, bd_size_t size)
00100 {
00101     MBED_ASSERT(is_valid_program(addr, size));
00102 
00103     if (!_is_initialized) {
00104         return BD_ERROR_DEVICE_ERROR;
00105     }
00106 
00107     if (_erase_array[addr / get_erase_size()] == 0) {
00108         return 0;
00109     }
00110 
00111     return _bd->program(buffer, addr, size);
00112 }
00113 
00114 int ExhaustibleBlockDevice::erase(bd_addr_t addr, bd_size_t size)
00115 {
00116     MBED_ASSERT(is_valid_erase(addr, size));
00117     if (!_is_initialized) {
00118         return BD_ERROR_DEVICE_ERROR;
00119     }
00120 
00121     bd_size_t eu_size = get_erase_size();
00122     while (size) {
00123         // use an erase cycle
00124         if (_erase_array[addr / eu_size] > 0) {
00125             _erase_array[addr / eu_size] -= 1;
00126         }
00127 
00128         if (_erase_array[addr / eu_size] > 0) {
00129             int  err = _bd->erase(addr, eu_size);
00130             if (err) {
00131                 return err;
00132             }
00133         }
00134 
00135         addr += eu_size;
00136         size -= eu_size;
00137     }
00138 
00139     return 0;
00140 }
00141 
00142 bd_size_t ExhaustibleBlockDevice::get_read_size() const
00143 {
00144     if (!_is_initialized) {
00145         return BD_ERROR_DEVICE_ERROR;
00146     }
00147 
00148     return _bd->get_read_size();
00149 }
00150 
00151 bd_size_t ExhaustibleBlockDevice::get_program_size() const
00152 {
00153     if (!_is_initialized) {
00154         return BD_ERROR_DEVICE_ERROR;
00155     }
00156 
00157     return _bd->get_program_size();
00158 }
00159 
00160 bd_size_t ExhaustibleBlockDevice::get_erase_size() const
00161 {
00162     if (!_is_initialized) {
00163         return BD_ERROR_DEVICE_ERROR;
00164     }
00165 
00166     return _bd->get_erase_size();
00167 }
00168 
00169 bd_size_t ExhaustibleBlockDevice::get_erase_size(bd_addr_t addr) const
00170 {
00171     if (!_is_initialized) {
00172         return BD_ERROR_DEVICE_ERROR;
00173     }
00174 
00175     return _bd->get_erase_size(addr);
00176 }
00177 
00178 int ExhaustibleBlockDevice::get_erase_value() const
00179 {
00180     if (!_is_initialized) {
00181         return BD_ERROR_DEVICE_ERROR;
00182     }
00183 
00184     return _bd->get_erase_value();
00185 }
00186 
00187 bd_size_t ExhaustibleBlockDevice::size() const
00188 {
00189     if (!_is_initialized) {
00190         return BD_ERROR_DEVICE_ERROR;
00191     }
00192 
00193     return _bd->size();
00194 }