--- /dev/null
+/**
+ * \file
+ * <!--
+ * This file is part of BeRTOS.
+ *
+ * Bertos is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * As a special exception, you may use this file as part of a free software
+ * library without restriction. Specifically, if other files instantiate
+ * templates or use macros or inline functions from this file, or you compile
+ * this file and link it with other files to produce an executable, this
+ * file does not by itself cause the resulting executable to be covered by
+ * the GNU General Public License. This exception does not however
+ * invalidate any other reasons why the executable file might be covered by
+ * the GNU General Public License.
+ *
+ * Copyright 2010 Develer S.r.l. (http://www.develer.com/)
+ *
+ * -->
+ *
+ * \brief Configuration file for the Eeprom module.
+ *
+ * \author Daniele Basile <asterix@develer.com>
+ */
+
+#ifndef CFG_EEPROM_H
+#define CFG_EEPROM_H
+
+/**
+ * Module logging level.
+ *
+ * $WIZ$ type = "enum"
+ * $WIZ$ value_list = "log_level"
+ */
+#define EEPROM_LOG_LEVEL LOG_LVL_INFO
+
+/**
+ * Module logging format.
+ *
+ * $WIZ$ type = "enum"
+ * $WIZ$ value_list = "log_format"
+ */
+#define EEPROM_LOG_FORMAT LOG_FMT_TERSE
+
+/**
+ * Check this to disable Eeprom deprecated API support.
+ *
+ * $WIZ$ type = "boolean"
+ */
+#define CONFIG_EEPROM_DISABLE_OLD_API 0
+
+#endif /* CFG_EEPROM_H */
#include "eeprom.h"
#include "cfg/cfg_i2c.h"
+#include "cfg/cfg_eeprom.h"
-#include <cfg/macros.h> // MIN()
+/* Define logging setting (for cfg/log.h module). */
+#define LOG_LEVEL EEPROM_LOG_LEVEL
+#define LOG_FORMAT EEPROM_LOG_FORMAT
+#include <cfg/log.h>
#include <cfg/debug.h>
-#include <cfg/module.h> // MOD_CHECK()
+#include <cfg/macros.h> // MIN()
#include <cpu/attr.h>
-#include <drv/i2c.h>
-
-#include <drv/wdt.h>
-#include <cpu/byteorder.h> // cpu_to_be16()
+#include <drv/i2c.h>
#include <string.h> // memset()
STATIC_ASSERT(countof(mem_info) == EEPROM_CNT);
-/**
- * Check that the contents of an EEPROM range
- * match with a provided data buffer.
- *
- * \return true on success.
- * \note Seek position of \a fd will not change.
- */
-bool eeprom_verify(Eeprom *fd, const void *buf, size_t count)
-{
- uint8_t verify_buf[16];
- bool result = true;
+#define CHUNCK_SIZE 16
- /* Save seek position */
- kfile_off_t prev_seek = fd->fd.seek_pos;
+bool eeprom_erase(Eeprom *eep, e2addr_t addr, e2_size_t size)
+{
+ uint8_t tmp[CHUNCK_SIZE] = { [0 ... (CHUNCK_SIZE - 1)] = 0xFF };
- while (count && result)
+ while (size)
{
- /* Split read in smaller pieces */
- size_t size = MIN(count, sizeof verify_buf);
-
- /* Read back buffer */
- if (eeprom_read(&fd->fd, verify_buf, size))
- {
- if (memcmp(buf, verify_buf, size) != 0)
- {
- TRACEMSG("Data mismatch!");
- result = false;
- }
- }
- else
- {
- TRACEMSG("Read error!");
- result = false;
- }
-
- /* Update count and addr for next operation */
- count -= size;
- buf = ((const char *)buf) + size;
+ block_idx_t idx = addr / eep->blk.blk_size;
+ size_t offset = addr % eep->blk.blk_size;
+ size_t count = MIN(size, (e2_size_t)CHUNCK_SIZE);
+ size_t ret_len = eep->blk.priv.vt->writeDirect((KBlock *)eep, idx, tmp, offset, count);
+ size -= ret_len;
+ addr += ret_len;
+
+ if (ret_len != count)
+ return false;
}
-
- /* Restore previous seek position */
- fd->fd.seek_pos = prev_seek;
- return result;
+ return true;
}
-/**
- * Erase specified part of eeprom, writing 0xFF.
- *
- * \a addr starting address
- * \a count length of block to erase
- * \note Seek position is unchanged.
- * \return true if ok, false otherwise.
- */
-bool eeprom_erase(Eeprom *fd, e2addr_t addr, e2_size_t count)
+bool eeprom_verify(Eeprom *eep, e2addr_t addr, const void *buf, size_t size)
{
- e2blk_size_t blk_size = mem_info[fd->type].blk_size;
- uint8_t buf[blk_size];
- kfile_off_t prev_off = fd->fd.seek_pos;
- bool res = true;
- size_t size;
-
- memset(buf, 0xFF, blk_size);
-
-
- kfile_seek(&fd->fd, addr, KSM_SEEK_SET);
-
- /*
- * Optimization: this first write id used to realign
- * current address to block boundaries.
- */
-
- wdt_reset();
- size = MIN(count, (e2_size_t)(blk_size - (addr & (blk_size - 1))));
- if (kfile_write(&fd->fd, buf, size) != size)
+ uint8_t verify_buf[CHUNCK_SIZE];
+ while (size)
{
- fd->fd.seek_pos = prev_off;
- return false;
- }
- count -= size;
+ block_idx_t idx = addr / eep->blk.blk_size;
+ size_t offset = addr % eep->blk.blk_size;
+ size_t count = MIN(size, (size_t)CHUNCK_SIZE);
- /* Clear all */
- while (count)
- {
- /* Long operation, reset watchdog */
- wdt_reset();
+ size_t ret_len = eep->blk.priv.vt->readDirect((KBlock *)eep, idx, verify_buf, offset, count);
- size = MIN(count, (e2_size_t)sizeof buf);
- if (kfile_write(&fd->fd, buf, size) != size)
+ if (ret_len != count)
{
- res = false;
- break;
+ LOG_ERR("Verify read fail.\n");
+ return false;
}
- count -= size;
- }
- fd->fd.seek_pos = prev_off;
- return res;
-}
-
-
-/**
- * Initialize EEPROM module.
- * \a fd is the Kfile context.
- * \a type is the eeprom device we want to initialize (\see EepromType)
- * \a addr is the i2c devide address (usually pins A0, A1, A2).
- * \a verify is true if you want that every write operation will be verified.
- */
-void eeprom_init(Eeprom *fd, EepromType type, e2dev_addr_t addr, bool verify)
-{
- MOD_CHECK(i2c);
- ASSERT(type < EEPROM_CNT);
-
- memset(fd, 0, sizeof(*fd));
- DB(fd->fd._type = KFT_EEPROM);
-
- fd->type = type;
- fd->addr = addr;
- fd->fd.size = mem_info[fd->type].e2_size;
-
- // Setup eeprom programming functions.
- fd->fd.read = eeprom_read;
- if (verify)
- fd->fd.write = eeprom_writeVerify;
- else
- fd->fd.write = eeprom_writeRaw;
- fd->fd.close = kfile_genericClose;
+ if (memcmp(buf, verify_buf, ret_len) != 0)
+ {
+ LOG_ERR("Data mismatch!\n");
+ return false;
+ }
- fd->fd.seek = kfile_genericSeek;
+ size -= ret_len;
+ addr += ret_len;
+ buf = ((const char *)buf) + ret_len;
+ }
+ return true;
}
-static size_t eeprom_writeDirect(KBlock *blk, block_idx_t idx, const void *buf, size_t offset, size_t size)
+static size_t eeprom_write(KBlock *blk, block_idx_t idx, const void *buf, size_t offset, size_t size)
{
- Eeprom *fd = EEPROM_CAST_KBLOCK(blk);
+ Eeprom *eep = EEPROM_CAST_KBLOCK(blk);
e2dev_addr_t dev_addr;
uint8_t addr_buf[2];
uint8_t addr_len;
ASSERT(idx <= blk->blk_cnt);
size = MIN(size, blk->blk_size - offset);
- if (mem_info[fd->type].has_dev_addr)
+ if (mem_info[eep->type].has_dev_addr)
{
- dev_addr = fd->addr;
+ dev_addr = eep->addr;
addr_len = 2;
}
else
addr_len = 1;
}
- if (mem_info[fd->type].has_dev_addr)
+ if (mem_info[eep->type].has_dev_addr)
{
addr_buf[0] = (abs_addr >> 8) & 0xFF;
addr_buf[1] = (abs_addr & 0xFF);
addr_buf[0] = (abs_addr & 0xFF);
}
- i2c_start_w(fd->i2c, EEPROM_ADDR(dev_addr), addr_len + size, I2C_STOP);
- i2c_write(fd->i2c, addr_buf, addr_len);
- i2c_write(fd->i2c, buf, size);
+ i2c_start_w(eep->i2c, EEPROM_ADDR(dev_addr), addr_len + size, I2C_STOP);
+ i2c_write(eep->i2c, addr_buf, addr_len);
+ i2c_write(eep->i2c, buf, size);
- if (i2c_error(fd->i2c))
+ if (i2c_error(eep->i2c))
return 0;
return size;
}
-
static size_t eeprom_readDirect(struct KBlock *_blk, block_idx_t idx, void *_buf, size_t offset, size_t size)
{
Eeprom *blk = EEPROM_CAST_KBLOCK(_blk);
return rd_len;
}
+static size_t eeprom_writeDirect(KBlock *blk, block_idx_t idx, const void *buf, size_t offset, size_t size)
+{
+ Eeprom *eep = EEPROM_CAST_KBLOCK(blk);
+ if (!eep->verify)
+ return eeprom_write(blk, idx, buf, offset, size);
+ else
+ {
+ int retries = 5;
+ while (retries--)
+ {
+ uint8_t verify_buf[CHUNCK_SIZE];
+ size_t wr_len = 0;
+ size_t len = 0;
+ while (size)
+ {
+ /* Split read in smaller pieces */
+ size_t count = MIN(size, (size_t)CHUNCK_SIZE);
+ if ((wr_len = eeprom_write(blk, idx, buf, offset, count)) != 0)
+ {
+ if (eeprom_readDirect(blk, idx, verify_buf, offset, count) != wr_len)
+ {
+ LOG_ERR("Verify read fail.\n");
+ return 0;
+ }
+ else if (memcmp(buf, verify_buf, wr_len) != 0)
+ {
+ LOG_ERR("Data mismatch!\n");
+ continue;
+ }
+ }
+ else
+ {
+ LOG_ERR("Write fail.\n");
+ return 0;
+ }
+ size -= wr_len;
+ len += wr_len;
+ buf = ((const char *)buf) + wr_len;
+ }
+ return len;
+ }
+ }
+
+ return 0;
+}
+
static int kblockEeprom_dummy(UNUSED_ARG(struct KBlock *,b))
{
return 0;
* \param i2c context for i2c channel
* \param addr is the i2c devide address (usually pins A0, A1, A2).
*/
-void eeprom_init_5(Eeprom *blk, I2c *i2c, EepromType type, e2dev_addr_t addr, bool verify)
+void eeprom_init_5(Eeprom *eep, I2c *i2c, EepromType type, e2dev_addr_t addr, bool verify)
{
ASSERT(type < EEPROM_CNT);
- memset(blk, 0, sizeof(*blk));
- DB(blk->blk.priv.type = KBT_EEPROM);
+ memset(eep, 0, sizeof(*eep));
+ DB(eep->blk.priv.type = KBT_EEPROM);
- blk->type = type;
- blk->addr = addr;
- blk->i2c = i2c;
+ eep->type = type;
+ eep->addr = addr;
+ eep->i2c = i2c;
+ eep->verify = verify;
- blk->blk.blk_size = mem_info[type].blk_size;
- blk->blk.blk_cnt = mem_info[type].e2_size / mem_info[type].blk_size;
- blk->blk.priv.flags |= KB_PARTIAL_WRITE;
- blk->blk.priv.vt = &eeprom_unbuffered_vt;
+ eep->blk.blk_size = mem_info[type].blk_size;
+ eep->blk.blk_cnt = mem_info[type].e2_size / mem_info[type].blk_size;
+ eep->blk.priv.flags |= KB_PARTIAL_WRITE;
+ eep->blk.priv.vt = &eeprom_unbuffered_vt;
}
#ifndef DRV_EEPROM_H
#define DRV_EEPROM_H
-#define EEPROM_OLD_API 1
+#include "cfg/cfg_eeprom.h"
#include <cfg/compiler.h>
#include <cfg/debug.h>
#include <cpu/attr.h>
#if COMPILER_C99
- #define eeprom_init(...) PP_CAT(eeprom_init ## _, COUNT_PARMS(__VA_ARGS__)) (__VA_ARGS__)
+ #define eeprom_init(...) PP_CAT(eeprom_init ## _, COUNT_PARMS(__VA_ARGS__)) (__VA_ARGS__)
+ #define eeprom_verify(...) PP_CAT(eeprom_verify ## _, COUNT_PARMS(__VA_ARGS__)) (__VA_ARGS__)
#else
- #define eeprom_init(args...) PP_CAT(eeprom_init ## _, COUNT_PARMS(args)) (args)
+ #define eeprom_init(args...) PP_CAT(eeprom_init ## _, COUNT_PARMS(args)) (args)
+ #define eeprom_verify(args...) PP_CAT(eeprom_verify ## _, COUNT_PARMS(args)) (args)
#endif
EepromType type; ///< EEPROM type
e2dev_addr_t addr; ///< Device address.
bool verify;
-#if EEPROM_OLD_API
+#if !CONFIG_EEPROM_DISABLE_OLD_API
union {
KFile fd;
KFileBlock fdblk;
} DEPRECATED;
-#endif
+#endif /* !CONFIG_EEPROM_DISABLE_OLD_API */
} Eeprom;
-#if EEPROM_OLD_API
+#if !CONFIG_EEPROM_DISABLE_OLD_API
STATIC_ASSERT(offsetof(Eeprom, fd) == offsetof(Eeprom, fdblk.fd));
-#endif
+#endif /* !CONFIG_EEPROM_DISABLE_OLD_API */
/**
* ID for eeproms.
e2_size_t e2_size; ///< eeprom size
} EepromInfo;
-void eeprom_init_5(Eeprom *blk, I2c *i2c, EepromType type, e2dev_addr_t addr, bool verify);
+bool eeprom_erase(Eeprom *eep, e2addr_t addr, e2_size_t count);
+bool eeprom_verify_4(Eeprom *eep, e2addr_t addr, const void *buf, size_t count);
+void eeprom_init_5(Eeprom *eep, I2c *i2c, EepromType type, e2dev_addr_t addr, bool verify);
-#if EEPROM_OLD_API
-DEPRECATED bool eeprom_erase(Eeprom *fd, e2addr_t addr, e2_size_t count);
-DEPRECATED bool eeprom_verify(Eeprom *fd, const void *buf, size_t count);
+#if !CONFIG_EEPROM_DISABLE_OLD_API
-
-DEPRECATED INLINE void eeprom_init_4(Eeprom *ee, EepromType type, e2dev_addr_t addr, bool verify)
+DEPRECATED INLINE bool eeprom_verify_3(Eeprom *eep, const void *buf, size_t count)
{
- eeprom_init_5(ee, &local_i2c_old_api, type, addr, verify);
- kfileblock_init(&ee->fdblk, &ee->blk);
+ return eeprom_verify_4(eep, (e2addr_t)eep->fdblk.fd.seek_pos, buf, count);
}
-
-#endif
+DEPRECATED INLINE void eeprom_init_4(Eeprom *eep, EepromType type, e2dev_addr_t addr, bool verify)
+{
+ eeprom_init_5(eep, &local_i2c_old_api, type, addr, verify);
+ kfileblock_init(&eep->fdblk, &eep->blk);
+}
+#endif /* !CONFIG_EEPROM_DISABLE_OLD_API */
#endif /* DRV_EEPROM_H */