精华内容
下载资源
问答
  • ftl

    2013-11-15 11:31:05
    1.在ftl中调用服务 2.在ftl中查询实体 3.在groovy中如何获取应用中的某个文件 fileUrl=new ComponentLocationResolver().resolveLocation("component://应用名/目录/"); file=new...
    1.在ftl中调用服务 

    <#assign result=dispatcher.runSync("服务名",Static["org.ofbiz.base.util.UtilMisc"].toMap(key,value))>


    2.在ftl中查询实体
    <#assign statusItemGen=delegator.findByPrimaryKey("StatusItem",Static["org.ofbiz.base.util.UtilMisc"].toMap("statusId",facc.statusId?if_exists))>


    3.在groovy中如何获取应用中的某个文件
    fileUrl=new ComponentLocationResolver().resolveLocation("component://应用名/目录/");
    file=new File(fileUrl.getPath()+文件名);


    或者
    String fileName="文件名";
    String location="component:应用名/目录/";
    URL locationUrl=FlexibleLocation.resolveLocation(location+fileName);


    4.jdbc查询
    public BigDecimal getOrderReceivedPaymentTotal(String orderId) {
    // String helperName = delegator.getGroupHelperName("org.ofbiz");
    // Connection conn =null;
    // Statement statement = null;
    // ResultSet rs = null;
    // BigDecimal db = null;
    // try {
    // conn = ConnectionFactory.getConnection(helperName);
    // statement = conn.createStatement();
    // statement.execute("SELECT sum(MAX_AMOUNT) FROM ORDER_PAYMENT_PREF_AND_PAYMENT where order_id='"+
    // orderId+"' and status_Id='PAYMENT_RECEIVED' and paymentStatusId='PMNT_RECEIVED'");
    // rs = statement.getResultSet();
    // if(rs.next()) {
    // db = rs.getBigDecimal(1);
    // }
    // } catch(Exception e) {
    // System.out.println(e);
    // } finally {
    // try {
    // if(rs != null) {
    // rs.close();
    // }
    // if(statement != null) {
    // statement.close();
    // }
    // if(conn != null) {
    // conn.close();
    // }
    // } catch(Exception e) {
    // System.out.println(e);
    // }
    // }
    // return db;
    // }


    5.条件查询
    exprList = [EntityCondition.makeCondition("partyId", EntityOperator.EQUALS, userLogin.partyId),
    EntityCondition.makeCondition("shoppingListTypeId", EntityOperator.EQUALS, "SLT_WISH_LIST"),
    EntityCondition.makeCondition("listName", EntityOperator.NOT_EQUAL, "Auto Suggestions")];
    condition = EntityCondition.makeCondition(exprList, EntityOperator.AND);
    allShoppingLists = delegator.findList("ShoppingList", condition, null, ["createdStamp DESC"], null, false);

    例如查询一个时间段
    exprList = [EntityCondition.makeCondition("createdByUserLogin", EntityOperator.EQUALS, userLogin.userLoginId),
    EntityCondition.makeCondition("createdDate", EntityOperator.BETWEEN, [UtilDateTime.getDayStart(UtilDateTime.nowTimestamp()),UtilDateTime.getDayEnd(UtilDateTime.nowTimestamp())])];
    condition = EntityCondition.makeCondition(exprList, EntityOperator.AND);
    productPromoCodes=delegator.findByCondition("ProductPromoCode",condition,null,null);

    多种条件的组合
    exprList = [EntityCondition.makeCondition("statusId", EntityOperator.NOT_EQUAL, "PARTY_DISABLED")
    , EntityCondition.makeCondition("statusId", EntityOperator.NOT_EQUAL, null)];
    CondList = EntityCondition.makeCondition(exprList, EntityOperator.AND);
    CondList1 = EntityCondition.makeCondition("statusId", EntityOperator.EQUALS, null);
    statusPartyDisable = EntityCondition.makeCondition([CondList1, CondList], EntityOperator.OR);
    entityConditionList = null;
    if (prepareResult.entityConditionList != null) {
    ConditionList = [ prepareResult.entityConditionList, statusPartyDisable ];
    entityConditionList = EntityCondition.makeCondition(ConditionList);
    } else if (context.noConditionFind == "Y") {
    entityConditionList = statusPartyDisable;
    }

    6.读取配置文件
    currencyUom = UtilProperties.getPropertyValue("general.properties", "currency.uom.id.default", "CNY");

    7.对查询的结果过滤
    supProduct = EntityUtil.filterByDate(supProduct, UtilDateTime.nowTimestamp(), "availableFromDate", "availableThruDate", true);

    8.更新记录
    GenericValue pref = delegator.findByPrimaryKey("OrderPaymentPreference", UtilMisc.toMap("orderPaymentPreferenceId", prefId));
    pref.set("securityCode", securityCode);
    pref.store();

    9.distinct语句的查询
    List<EntityCondition> conditionList = UtilMisc.toList(
    EntityCondition.makeCondition("contactListId", EntityOperator.EQUALS, contactList.get("contactListId")),
    EntityCondition.makeCondition("statusId", EntityOperator.EQUALS, "CLPT_ACCEPTED"),
    EntityCondition.makeCondition("preferredContactMechId", EntityOperator.NOT_EQUAL, null),
    EntityUtil.getFilterByDateExpr(), EntityUtil.getFilterByDateExpr("contactFromDate", "contactThruDate")
    );
    List<String> fieldsToSelect = UtilMisc.toList("infoString");

    EntityCondition conditions = EntityCondition.makeCondition(conditionList, EntityOperator.AND);
    List<GenericValue> sendToEmails = delegator.findByCondition("ContactListPartyAndContactMech", conditions, null, fieldsToSelect, null,
    new EntityFindOptions(true, EntityFindOptions.TYPE_SCROLL_INSENSITIVE, EntityFindOptions.CONCUR_READ_ONLY, true));
    展开全文
  • FTL crashed

    2020-12-28 01:16:28
    <ul><li>Pi-hole: v5.2.1</li><li>AdminLTE: v5.2.1</li><li>FTL: v5.3.2</li></ul> <h3>Platform <ul><li>OS and version: ubuntu server Ubuntu 20.04.1 LTS</li></ul> <ul><li>Platform: Raspberry Pi</li></ul...
  • ftl crash

    2021-01-03 05:04:52
    FTL failed. We woke in the morning and had access to the local network but not the internet. the router had a good connectetion to the wan, Pihole web was also operating but had no DNS. <p>On initial ...
  • FTL Crash

    2020-12-26 17:28:23
    <ul><li>FTL Crashed randomly...</li></ul> <p><strong>Log file output [if available]</strong></p> <p><strong>FTL Log: [2020-05-13 13:59:23.202 27621] Note: FTL forked to handle TCP requests [2020-05-13...
  • FTL Crashed

    2020-12-26 03:48:36
    <div><p>*[2020-05-05 10:33:29.285 17042] !!!!!!!!!!... FTL crashed!...[2020-05-05 10:33:29.286 17042] Please report a bug at https://github.com/pi-hole/FTL/issues ...[2020-05-05 10:33:29....pi-hole/FTL</p></div>
  • FTL crash

    2020-12-26 03:56:20
    /FTL-queries" from 17203200 to 17432576 [2019-07-18 08:43:36.066 28732] Resizing "/FTL-queries" from 17432576 to 17661952 [2019-07-18 08:51:52.100 28732] Resizing "/FTL-queries" ...
  • Restart FTL

    2021-01-05 05:45:51
    <div><p>There should be away to restart it via web ui like you can whit DNS, FTL is always offline after like 12h for me.</p><p>该提问来源于开源项目:pi-hole/FTL</p></div>
  • FTL crashed!

    2021-01-02 11:36:17
    [2020-08-19 09:00:08.016 13657/F1955] B[0007]: /usr/bin/pihole-FTL(_FTL_new_query+0x69b) [0x564d3be4348b] [2020-08-19 09:00:08.023 13657/F1955] L[0007]: /root/project/src/dnsmasq_interface.c:435 ...
  • FTLDNS ( pihole-FTL )提供了一个交互式的API,并生成丕Kong统计的Web界面。 快速:通过将我们的代码库与dnsmasq紧密耦合,可以直接从内存中读取统计信息 用途广泛: dnsmasq上游更改可以快速合并,而不会造成太...
  • FTL version is v5.3.2 (Latest: v5.3.2) <h3>Platform <p>Armbian 20.11 Bionic (Linux npik2 5.9.12-meson64 #20.11.1 SMP PREEMPT Fri Dec 4 00:23:48 CET 2020 aarch64 aarch64 aarch64 GNU/Linux) NanoPi K2 ...
  • FTL crashing

    2020-12-30 10:15:29
    Well, pihole does not as FTL crashes once in a while and by this I mean once in 2-3 days. <p><strong>[BUG | ISSUE] Steps to reproduce:</strong></p> <ul><li>Install pihole via an official script.</li>...
  • ftl crashes

    2020-12-26 03:48:27
    <div><p><strong>In raising this issue, I confirm the following (please check boxes, eg [X]) Failure to fill the template will close your issue:</strong></p> <ul><li>[X] I have ...pi-hole/FTL</p></div>
  • FTL Trainer

    2014-08-07 16:51:40
    FTL trainer for v 1.5.13 +27 options
  • NAND FTL

    2021-04-17 22:06:20
    工作测试板用了H750核心板模块,模块上有一块512MB NAND Flash,提供的FTL参考比较混乱,使用中也不稳定,网上有一堆阐述FTL的文章,都没有可以直接使用的源代码,还是自己写一个吧,自己的比较香! 提示:有时间,...

    NAND FTL


    前言

    工作测试板用了H750核心板模块,模块上有一块512MB NAND Flash,提供的FTL参考比较混乱,使用中也不稳定,网上有一堆阐述FTL的文章,都没有可以直接使用的源代码,还是自己写一个吧,自己的比较香!


    成熟的FTL都是商用收费的,免费的uffs又不兼容window fat,这样就不能模拟U盘,所以都促使了写一个适合自己使用的。

    一、FTL是什么?

    FTL是平台文件系统到NAND之间的中间层,因为NAND是页读取,块写入(如果写入区非FF),块的编程和擦除过程中,还会发生坏块,块本身的擦除次数还有寿命限制

    所以,文件系统读写NAND时候,FTL在中间做地址转换,坏块管理等转换

    完整的FTL功能通常包括如下:

    1 - 坏块管理
    nand block都有一定擦写次数,到达一定次数后,读写会不稳定,当发现写入或擦除失败时,应该标记为坏块,不再使用这些块

    2 - 擦写平衡
    原因同上,不能一直在固定块擦除写入,例如逻辑sector0数据,写入block0 page0,下一次sector再写入时,不是擦除block0后重新写入,而是在block2 page0写入,block0标记为垃圾块,block2标记为新的逻辑块,当找不到空闲块时,进行垃圾块擦除回收

    3 - 掉电保护
    只要在新块写入成功之后,再把原有块标记为垃圾块,一定程度上,防止了数据丢失

    4 - 冷热数据
    有些数据是频繁读取和写入的,例如系统LOG,称为热数据,有些数据是写入之后,很少变动的,例如UI图片等,称为冷数据,为了避免频繁擦写寻找空闲块,应该尽可能把热数据和冷数据,分别存在不同区块

    二、功能实现

    FTL整个流程还是有点复杂的,写了满满的注释,和LOG打印,目前测试下来基本可以用了。
    没有做冷热数据,因为一方面主要做静态存储,另一方面能力有限,不知道怎么下手。

    NAND CHIP是h27u4g8f,4096个block,每个block 64page,每个page main 2048byte,spare 64byte

    spare byte0~15,存储ECC
    spare byte16~17,正常FFFF,如果是坏块,则不为FFFF
    spare byte18~19,正常FFFF,如果是垃圾块,则不为FFFF
    spare byte20~21,如果FFFF,是空闲块,如果0 ~ 4095,是使用中逻辑块

    上电初始化NAND,读取ID,然后读取block 0 ~ 4095的PAGE0的SPARE,判断块状态,生成LUT

    写扇区:
    逻辑转到物理,查找物理块,找到了,如果写入区都是FF,则直接写入,如果写入区有数据,重新查找一个空闲块,把之前块数据复制到新块,并写入新数据,新块标记为当前逻辑块,之前块标记为垃圾块

    读扇区:
    逻辑转到物理,查找物理块,找到了,读取扇区数据,如果没找到,找一块空闲块,标记为当前逻辑块,然后读取扇区数据,理论上返回应该全都是FF

    以上两个动作,都会查找物理块,如果找不到需要的物理块,就查找全部的垃圾块,然后擦除垃圾块,重新标记为空闲块,达到了垃圾块回收的效果。垃圾块回收完成后,读写动作重新查找物理块,如果还没找到,返回NO FREE ERROR

    二、相关代码

    
    #include "stdint.h"
    #include "rtthread.h"
    #include "sram.h"
    #include "vopftl.h"
    
    #define DBG
    #define DBG_TAG             "ftl"
    #include "log.h"
    
    #ifndef NULL
    #define NULL        (0)
    #endif
    
    #define FTL_EOK                 0
    #define FTL_ERROR               1
    #define FTL_NO_LIFE             2
    #define FTL_NO_FREE             3
    #define FTL_WRITE_ERR           4
    #define FTL_COPY_ERR            5
    
    #define PAGE_SIZE               (2048)
    #define PAGE_NUM                (64)
    #define BLOCK_NUM               (4096)
    
    #define OOB_SIZE                16
    
    #define OOB_BAD_POS             0
    #define OOB_GARBAGE_POS         2
    #define OOB_LOGICAL_POS         4
    
    #define OOB_GET_BAD             (*(uint16_t *)&p_oobbuf[OOB_BAD_POS])
    #define OOB_GET_GARBAGE         (*(uint16_t *)&p_oobbuf[OOB_GARBAGE_POS])
    #define OOB_GET_LOGICAL         (*(uint16_t *)&p_oobbuf[OOB_LOGICAL_POS])
    
    #define BLOCK_FREE              0xffff
    #define BLOCK_BAD               0xfffe
    #define BLOCK_GARBAGE           0xfffd
    #define BLOCK_ACTIVE            0xfffc
    #define BLOCK_ABNORMAL          0xfffb
    
    static nand_drv_t *pdrv = NULL;
    
    ALIGN(4)
    static uint8_t  oob_buf[OOB_SIZE];
    static uint8_t *p_oobbuf = (uint8_t *)oob_buf;
    
    ALIGN(4)
    static uint8_t  page_buf[PAGE_SIZE];
    static uint8_t *p_pagebuf = (uint8_t *)page_buf;
    
    ALIGN(4)
    static uint16_t  lut_buf[BLOCK_NUM];
    static uint16_t *p_lutbuf = (uint16_t *)lut_buf;
    
    static uint16_t cur_logical;
    static uint16_t cur_physical;
    static uint16_t cur_page;
    
    static uint32_t sector_max = 0;
    
    //标记坏块
    static uint8_t block_mask_bad(uint16_t phyblock)
    {
        uint8_t buf[2] = {0x00, 0x00};
        //写入坏块标记    
        LOG_D("block %d mask bad\r\n", phyblock);
        if (pdrv->write_page(phyblock, 0, NULL, OOB_BAD_POS, buf, 2))
        {
            return FTL_ERROR;
        }
        //更新表格
        p_lutbuf[phyblock] = BLOCK_BAD;
        return FTL_EOK;
    }
    
    //标记垃圾块
    static uint8_t block_mask_garbage(uint16_t phyblock)
    {
        uint8_t buf[2] = {0x00, 0x00};
        //写入垃圾块标记
        LOG_D("block %d mask garbage\r\n", phyblock);
        if (pdrv->write_page(phyblock, 0, NULL, OOB_GARBAGE_POS, buf, 2))
        {
            return FTL_ERROR;
        }
        //更新表格
        p_lutbuf[phyblock] = BLOCK_GARBAGE;
        return FTL_EOK;
    }
    
    //标记逻辑块
    static uint8_t block_mask_logical(uint16_t phyblock, uint16_t logblock)
    {
        uint8_t buf[2] = {0x00, 0x00};
        buf[0] = logblock & 0xff;
        buf[1] = logblock >> 8;    
        LOG_D("block %d mask logical %d\r\n", phyblock, logblock);
        //写入逻辑块
        if (pdrv->write_page(phyblock, 0, NULL, OOB_LOGICAL_POS, buf, 2))
        {
            return FTL_ERROR;
        }
        //更新表格
        p_lutbuf[phyblock] = logblock;
        return FTL_EOK;
    }
    
    //逻辑块转物理块地址
    static uint8_t block_log2phy(uint16_t *phyblock, uint16_t logblock)
    {   //搜寻表格
        for (uint16_t i = 0; i < BLOCK_NUM; i++)
        {
            if (p_lutbuf[i] == logblock) 
            {   //返回实际物理块
                *phyblock = i;
                LOG_D("block logical %d to physical %d\r\n", logblock, i);
                return FTL_EOK;
            }
        }
        LOG_D("block logical %d to physical fail\r\n", logblock);
        return FTL_ERROR;
    }
    
    //释放垃圾块
    static uint8_t collect_garbage_block(uint16_t phyblock, uint8_t odd_even)
    {
        uint16_t odd,even;
        odd = 0; even = 0;
        for (uint16_t block = 0; block < BLOCK_NUM; block++)
        {
            if (p_lutbuf[block] == BLOCK_GARBAGE)
            {   //找到垃圾块
                if (pdrv->erase_block(block))
                {   //擦除失败,标记坏块
                    block_mask_bad(block);
                }
                else
                {   //擦除成功
                    if (block & 0x1){odd++;}else{even++;}
                    //更新表格
                    p_lutbuf[block] = BLOCK_FREE;
                    LOG_D("collect garbage block - %d\r\n", block);
                }
            }
        }
        LOG_D("collect garbage block number - odd %d, even %d\r\n", odd, even);
        //需要判断奇偶
        if (odd_even)
        {
            if (((phyblock & 0x1) == 1)&&(odd )){return FTL_EOK;}
            if (((phyblock & 0x1) == 0)&&(even)){return FTL_EOK;}
        }
        else
        {
            if ((odd)||(even)){return FTL_EOK;}
        }
        return (FTL_NO_FREE);
    }
    
    //选址一个空闲块,选择是否需要奇偶判断
    static uint8_t select_free_block(uint16_t *phyblock, uint16_t logblock, uint8_t odd_even)
    {
        LOG_D("select free block fot logic %d\r\n", logblock);
    aa: //查找可用块
        for (uint16_t block = 0; block < BLOCK_NUM; block++)
        {   //块空闲,不判断奇偶或者判断奇偶
            if ((p_lutbuf[block] == BLOCK_FREE)&&
                ((odd_even == 0)||((odd_even > 0)&&((block & 0x1)==(*phyblock & 0x1)))))
            {   //找到一个可用的空闲块,并且在同一PLANE
    bb:         //先做一遍擦除测试
                LOG_D("select free block - %d\r\n", block);
                LOG_D("erase physical block %d\r\n", block);
                if (pdrv->erase_block(block))
                {   //擦除失败,标记坏块,更新表格,重新查找
                    block_mask_bad(block);
                    goto aa;
                }
                //是一个好块,标记逻辑块
                if (block_mask_logical(block, logblock))
                {   //标记失败,进行擦除测试
                    goto bb;
                }
                //返回新的物理块
                *phyblock = block;            
                LOG_D("select free block - %d, pass\r\n", block);
                return FTL_EOK;
            }
        }
        //释放垃圾块
        LOG_D("select free block fail, so collect garbage block\r\n");
        if (collect_garbage_block(*phyblock, odd_even))
        {   //释放失败
            LOG_D("not any garbage block can be free\r\n");
            return FTL_NO_FREE;
        }
        //释放成功,重新开始
        goto aa;
    }
    
    //数据复制到新块并写入新的数据
    static uint8_t writecopy_block(uint16_t *phyblock, uint16_t logblock, uint16_t page, uint8_t *buf)
    {
        uint8_t rst = FTL_EOK;    
        uint16_t sblock = *phyblock;
        uint16_t tblock = *phyblock;
        
    aa:
        //找一块可用的复制块, 判断奇偶
        if (select_free_block(&tblock, logblock, 1))
        {   
            return FTL_NO_FREE;
        }
        //复制块数据
        for (uint16_t i = 0; i < PAGE_NUM; i++)
        {
            rst = FTL_EOK;
            if (i == page)
            {   //写入数据
                if (pdrv->write_page(tblock, i, buf, 0, NULL, 0)){rst = FTL_WRITE_ERR;}
            }
            else
            {   //复制数据
                if (pdrv->copyback_page(sblock, i, tblock, i)){rst = FTL_COPY_ERR;}
            }
            if (rst != FTL_EOK)
            {   //写入失败,标记当前块为垃圾块,重新开始查找空闲块
                block_mask_garbage(tblock);
                goto aa;
            }
        }
        //操作成功,标记之前块为垃圾块
        block_mask_garbage(sblock);
        //更新当前物理块
        *phyblock = tblock;
        return FTL_EOK;
    }
    
    //读写打开
    uint8_t ftl_open(uint32_t sector)
    {   
        //超出操作范围
        if (sector >= sector_max)
        {
            LOG_D("ftl open sector fail, %d / %d\r\n", sector, sector_max);
            return FTL_ERROR;
        }
    
        //逻辑块位置
        cur_logical  = sector / PAGE_NUM;
        cur_page     = sector % PAGE_NUM;    
        cur_physical = 0xffff;
        //转成实际物理块
        if (block_log2phy(&cur_physical, cur_logical))
        {   //没有找到,申请一个新块
            if (select_free_block(&cur_physical, cur_logical, 0))
            {   //申请失败
                return FTL_ERROR;
            }
        }
        LOG_D("ftl open sector pass, logical %d, physical %d, page %d\r\n", cur_logical, cur_physical, cur_page);
        return FTL_EOK;
    }
    
    //读写关闭
    uint8_t ftl_close(void)
    {
        LOG_D("ftl close, logical %d, physical %d, page %d\r\n", cur_logical, cur_physical, cur_page);
        cur_logical  = 0xffff;
        cur_page     = 0;    
        cur_physical = 0xffff;
        return FTL_EOK;
    }
    
    //写入一个扇区
    uint8_t ftl_write_sector(uint8_t *buf, uint32_t count)
    {   
        uint16_t i;    
        uint8_t *pdat = buf;
        while (count > 0)
        {
            //参数异常
            if (cur_physical >= BLOCK_NUM){return FTL_ERROR;}
            //先读出写入区域的数据
            pdrv->read_page(cur_physical, cur_page, p_pagebuf, NULL);
            for (i = 0; i < PAGE_SIZE; i++)
            {
                if (p_pagebuf[i] != 0xff){break;}
            }    
            //数据写入
            if (i == PAGE_SIZE)
            {   //区域全空,可以直接写入
                if (pdrv->write_page(cur_physical, cur_page, pdat, 0, NULL, 0))
                {   //写入失败, 复制写入到新的物理块
                    if (writecopy_block(&cur_physical, cur_logical, cur_page, pdat))
                    {   //复制失败
                        return FTL_ERROR;
                    }
                }
            }
            else
            {   //区域非空,写入到新的块
                if (writecopy_block(&cur_physical, cur_logical, cur_page, pdat))
                {   //复制失败
                   return FTL_ERROR;
                }
            }
            LOG_D("ftl write pass, logical %d, physical %d, page %d\r\n", cur_logical, cur_physical, cur_page);
            count--;
            //还有后续数据需要写入
            if (count > 0)
            {   //已经是物理块最后一页
                if ((cur_page + 1) >= PAGE_NUM)
                {   //逻辑块+1, 转成实际物理块
                    cur_logical++;
                    if (block_log2phy(&cur_physical, cur_logical))
                    {   //没有找到,申请一个新块
                        if (select_free_block(&cur_physical, cur_logical, 0))
                        {   //申请失败
                            return FTL_NO_FREE;
                        }
                    }
                }
                else
                {   //到下一页
                    cur_page++;
                }
                //数据地址增加
                pdat += PAGE_SIZE;
            }
        }
        return FTL_EOK;
    
    }
    
    //读出一个扇区
    uint8_t ftl_read_sector(uint8_t *buf, uint32_t count)
    {   
        uint8_t *pdat = buf;
        while (count > 0)
        {
            //参数异常
            if (cur_physical >= BLOCK_NUM){return FTL_ERROR;}
            //读出区域数据
            pdrv->read_page(cur_physical, cur_page, pdat, NULL);        
            LOG_D("ftl read pass, logical %d, physical %d, page %d\r\n", cur_logical, cur_physical, cur_page);
            count--;
            //还有后续数据需要读出
            if (count > 0)
            {   //已经是物理块最后一页
                if ((cur_page + 1) >= PAGE_NUM)
                {   //逻辑块+1, 转成实际物理块
                    cur_logical++;
                    if (block_log2phy(&cur_physical, cur_logical))
                    {   //没有找到,申请一个新块
                        if (select_free_block(&cur_physical, cur_logical, 0))
                        {   //申请失败
                            return FTL_ERROR;
                        }
                    }
                }
                else
                {   //到下一页
                    cur_page++;
                }
                //数据地址增加
                pdat += PAGE_SIZE;
            }
        }
        return FTL_EOK;
    }
    
    uint32_t ftl_get_sector_count(void)
    {
        return (sector_max);
    }
    
    uint32_t ftl_get_sector_size(void)
    {
        return (PAGE_SIZE);
    }
    
    uint32_t ftl_is_init(void)
    {
        return 0;
    }
    
    #if 0
    uint32_t fatfs_ftl_lock(void)
    {
    
    }
    
    uint32_t fatfs_ftl_unlock(void)
    {
    
    }
    
    uint32_t fatfs_ftl_ready(void)
    {
    
    }
    
    uint32_t udisk_ftl_lock(void)
    {
    
    }
    
    uint32_t udisk_ftl_unlock(void)
    {
    
    }
    
    uint32_t udisk_ftl_ready(void)
    {
    
    }
    #endif
    
    //扫描全部物理块
    static void scan_block(void)
    {
        uint16_t v_bad, v_garbage, v_free, v_active, v_abnormal;
        uint32_t readerr = 0;
        
        //扫描全部BLOCK,产生转换表
        v_bad      = 0;
        v_garbage  = 0;
        v_free     = 0;
        v_active   = 0;
        v_abnormal = 0;
        for (uint16_t i = 0; i < BLOCK_NUM; i++)
        {   //读取OOB信息
            if (pdrv->read_page(i, 0, NULL, p_oobbuf))
            {   //读取错误
                readerr++;
            }
            if (OOB_GET_BAD != 0xffff)
            {   //损坏块
                p_lutbuf[i] = BLOCK_BAD;  
                v_bad++;
            }
            else if (OOB_GET_GARBAGE != 0xffff)
            {   //垃圾块
                p_lutbuf[i] = BLOCK_GARBAGE;
                v_garbage++;
            }
            else if (OOB_GET_LOGICAL == 0xffff)
            {   //空闲块
                p_lutbuf[i] = BLOCK_FREE;
                v_free++;
            }
            else if (OOB_GET_LOGICAL < BLOCK_NUM)
            {   //活动块
                p_lutbuf[i] = OOB_GET_LOGICAL;
                v_active++;
            }
            else
            {   //异常块
                p_lutbuf[i] = BLOCK_ABNORMAL;
                v_abnormal++;
            }
        }
    
        LOG_D("ftl nand scan complete, read error - %d\r\n", readerr);
        LOG_D("block bad:      %d\r\n", v_bad);
        LOG_D("block garbage:  %d\r\n", v_garbage);
        LOG_D("block free:     %d\r\n", v_free);
        LOG_D("block active:   %d\r\n", v_active);
        LOG_D("block abnormal: %d\r\n", v_abnormal);
    
        sector_max = (v_garbage + v_free + v_active) * PAGE_NUM;
    
        uint32_t tmp1 = (v_garbage + v_free) * PAGE_NUM * PAGE_SIZE / (1024 * 1024);
        uint32_t tmp2 = (v_garbage + v_free + v_active) * PAGE_NUM * PAGE_SIZE / (1024 * 1024);
        
        LOG_D("ftl total sector %d, free %dMByte, capacity %dMByte\r\n", sector_max, tmp1, tmp2);
    }
    
    //擦除全部物理块
    static void format_block(void)
    {
        uint16_t i;
        LOG_D("ftl format:\r\n");
        for (i = 0; i < BLOCK_NUM; i++)
        { 
            if (pdrv->erase_block(i))
            {
                LOG_D("ftl format block %d fail\r\n", i);
                block_mask_bad(i);
            }
        }
    }
    
    uint8_t ftl_init(void)
    {
        pdrv = (nand_drv_t *)&nand_h27u4g8f;
    
        //芯片初始化
        if (pdrv->chip_init()){return 1;}
        LOG_D("chip init pass - %08x\r\n", pdrv->id);
    
        scan_block();
        
        return FTL_EOK;    
    }
    
    #ifdef FINSH_USING_MSH
    #include "stdlib.h"
    #include "ll_random.h"
    
    static void ftl_msh_function(int argc, char **argv)
    {
        uint16_t i,j;
        uint8_t *buf;
        if ((argc == 2)&&(rt_strcmp(argv[1], "lut") == 0))
        {
            rt_kprintf("ftl lut:\r\n");
            for (i = 0; i < BLOCK_NUM / 32; i++)
            {
                for (j = 0; j < 32; j++)
                {
                    rt_kprintf("%04x ", lut_buf[i * 32 + j]);
                }
                rt_kprintf("\r\n");
            }
        }
    
        if ((argc == 2)&&(rt_strcmp(argv[1], "format") == 0))
        {
            format_block();
        }
    
        if ((argc == 2)&&(rt_strcmp(argv[1], "scan") == 0))
        {
            scan_block();
        }
    
        if ((argc == 2)&&(rt_strcmp(argv[1], "garbage") == 0))
        {
            collect_garbage_block(0, 0);
        }
    
        if ((argc == 3)&&(rt_strcmp(argv[1], "read") == 0))
        {
            buf = rt_malloc_align(PAGE_SIZE, 4);
            rt_memset(buf, 0xff, PAGE_SIZE);
                    
            if (ftl_open(atoi(argv[2])) == FTL_EOK)
            {
                ftl_read_sector(buf, 1);
                ftl_close();
            }
    
            for (i = 0; i < PAGE_SIZE / 64; i++)
            {
                for (j = 0; j < 64; j++)
                {
                    rt_kprintf("%02x ", buf[i * 64 + j]);
                }
                rt_kprintf("\r\n");
            }
            rt_free_align(buf);
        }
    
        if ((argc == 3)&&(rt_strcmp(argv[1], "write") == 0))
        {
            buf = rt_malloc_align(PAGE_SIZE, 4);
            rt_memset(buf, 0xff, PAGE_SIZE);
            
            ll_random_generate((uint32_t *)buf, PAGE_SIZE / 4);
            
            if (ftl_open(atoi(argv[2])) == FTL_EOK)
            {
                ftl_write_sector(buf, 1);
                ftl_close();
            }
            rt_free_align(buf);
        }
    }
    
    MSH_CMD_EXPORT_ALIAS(ftl_msh_function, ftl, ftl msh function);
    
    #endif
    

    测试

    在这里插入图片描述


    总结

    很多时候,除非你找到的是,商用的很成熟的代码和工具。

    如果是不知名到第三方,总是比较被动,或者到处都是坑,一旦发现问题的时候,也很难去解决

    所以,要学会耐心啃一些协议,多看一些芯片资料,搞懂里面的原理和机制,有了自己的理解之后,就可以写出一个适合需求,又放心使用的驱动了。

    展开全文
  • FTL简介

    千次阅读 2020-03-28 20:57:00
    SSD-FTL简介 参考资料《深入浅出SSD》 FTL 1.全称 Flash Translation Layer,闪存转换层 2.作用 完成Host逻辑地址空间到闪存(Flash)物理地址空间的映射; FTL算法的优劣,决定了SSD的性能,可靠性,耐用性等,它是...

    SSD-FTL简介

    参考资料《深入浅出SSD》

    FTL

    1.全称

    Flash Translation Layer,闪存转换层

     

    2.作用

    完成Host逻辑地址空间到闪存(Flash)物理地址空间的映射;

    FTL算法的优劣,决定了SSD的性能,可靠性,耐用性等,它是SSD固件的核心。

     

    说明:

    1)SSD会把每一笔用户逻辑数据写入闪存地址空间,便记录下该逻辑地址到物理地址的映射关系

    2)当host读取数据时,SSD会根据这个映射,从闪存读取这笔数据,然后返回给用户

     

    3.FTL的种类

    1)基于主机(Host Based)

    FTL在主机端实现,用自己计算机的CPU和内存资源,如图

     

     

    2)基于设备(Device Based,主流)

    FTL在设备端实现,用的是SSD上的控制器和RAM资源,如图

     

     

    闪存的重要特性

    1.闪存块需要先擦除才能写入,不能覆盖写

    2.闪存都是有一定寿命的,每擦除一次闪存块,都会对其造成磨损,一般用PE(Program/EraseCount)数来衡量

    3.每个闪存块的读是有限的,读的太多,上面的数据就会出错,造成读干扰问题

    4.闪存的数据保持问题,由于电荷的流失,存储在闪存上的数据是会丢失的

    5.闪存天生就有坏块

    6.对MLC和TLC来说,存在Lower Page corruption的问题

     说明:在对Upper Page/Extra Page写入时,如果发生异常掉电,可能会把Lower Page上成功写入的数据破坏掉,

     好的FTL应该尽量避免这种情况

    7.MLC和TLC的读写速度不如SLC,但它们都可以配成SLC模式来使用,好的FTL应该会利用这个特性来改善SSD的性能和可靠性

     

    展开全文
  • FreeMarker教程 ftl

    2018-02-22 14:12:13
    FreeMarker教程 ftl,web前端 web开发 FreeMarkerFreeMarker教程 ftl,web前端 web开发 FreeMarker
  • FTL支持文档: 用“ FTL”诊断故障并不像用“ RTMP”诊断故障那样容易。 您要记住的第一件事是,FTL通过UDP而不是TCP传输数据,因此它不受束缚,并且依赖于您的Internet连接是100%稳定的。 FTL最容易引起的第一个...
  • FTL考虑

    2019-06-11 09:55:00
    不要在FTL中实现复杂的逻辑,因为FTL无法调试。FTL是一种模版技术,ftl文件作为输入传输到模版引擎进行转换。JSP相对来说会好一些,因为JSP会编译为Servlet。 转载于:...

        不要在FTL中实现复杂的逻辑,因为FTL无法调试。FTL是一种模版技术,ftl文件作为输入传输到模版引擎进行转换。JSP相对来说会好一些,因为JSP会编译为Servlet。

    转载于:https://www.cnblogs.com/cbkun/p/11002012.html

    展开全文
  • public.ftl

    2019-09-02 16:33:46
    ftl文件,用于在博客中引入该文件,博客名称为“java导出word使用FreeMarker方式导出”
  • msst2015-ftl 包含 MSST 2015 论文中描述的 FTL:Margaglia 和 Brinkmann,“通过延长 P/E 周期提高 MLC 闪存性能和耐久性”
  • FTL 入门

    万次阅读 多人点赞 2017-10-20 01:13:01
    最近的项目中用的是ftl文件而不是传统的jsp,于是上网查了一下,感觉这是个好东西,于是准备记录下来。 以下摘自百度百科。 1.概念 FreeMarker是一款模板引擎: 即一种基于模板和要改变...
  • FTL敌人武器计时计算器 该工具计算敌方武器何时开火。 这些时间可以通过其他因素来更改。 例如,如果敌人隐身,他们可能会在隐身时拿着武器。
  • FTL入门

    2020-09-16 10:38:07
    FTL入门 一、概念 FreeMarker 是一款 模板引擎: 即一种基于模板和要改变的数据, 并用来生成输出文本(HTML网页,电子邮件,配置文件,源代码等)的通用工具。 它不是面向最终用户的,而是一个Java类库,是一款程序员...
  • :rocket: FTL Mixer的FTL流协议的客户端和服务器实现 :red_question_mark: 用法 和均可作为Docker映像使用。 您应该至少对和有一定的了解。 提供了一个示例Docker Compose文件以帮助您入门。 请注意,这仅是示例,...
  • FTL笔记

    2021-05-17 10:52:10
    FTL是一套网页模板引擎, 基于模板和数据动态地生成网页。 它不面向最终用户, 而是通过java加载网页后再进行展示。 与jsp(JavaServer Page)的区别 J 可以编写java代码, 功能强大 + F 不能编写java代码, 但实现了...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 5,966
精华内容 2,386
关键字:

ftl