#include "flash_dev_at45db.h"

#define AT45DB_TIME_PROGR           12 /* в спецификации указано 6, но по какой-то причине может выполняться и 8-8.3 */
#define AT45DB_TIME_PROGR_ERASE     40


#define AT45DB642_TIME_ERASE_PAGE      35
#define AT45DB642_TIME_ERASE_BLOCK     100
#define AT45DB642_TIME_ERASE_SECTOR    1300


#define AT45DB641_TIME_ERASE_PAGE      35
#define AT45DB641_TIME_ERASE_BLOCK     50
#define AT45DB641_TIME_ERASE_SECTOR    6500


#define AT45DB041_TIME_ERASE_PAGE      25
#define AT45DB041_TIME_ERASE_BLOCK     35
#define AT45DB041_TIME_ERASE_SECTOR    1100

#define AT45DB161E_TIME_ERASE_PAGE      35
#define AT45DB161E_TIME_ERASE_BLOCK     100
#define AT45DB161E_TIME_ERASE_SECTOR    2000

#define AT45DB161D_TIME_ERASE_PAGE      35
#define AT45DB161D_TIME_ERASE_BLOCK     100
#define AT45DB161D_TIME_ERASE_SECTOR    5000



#define SET_PAGE_POW_TOUT   3000
#define SET_PROTECTION_TOUT 2000




#define AT45DB_CMD_READ_ARRAY                   0x03
#define AT45DB_CMD_RD_STATUS                    0xD7

#define AT45DB_CMD_ERASE_PAGE                   FLASH_CMD_CODE_ERASE_PAGE
#define AT45DB_CMD_ERASE_BLOCK                  0x50
#define AT45DB_CMD_ERASE_SECTOR                 0x7C

#define AT45DB_CMD_BUF_WR(buf)                  (!buf ? 0x84 : 0x87)
#define AT45DB_CMD_MEM_TO_BUF(buf)              (!buf ? 0x53 : 0x55)
#define AT45DB_CMD_BUF_TO_MEM_WITH_ERASE(buf)   (!buf ? 0x83 : 0x86)
#define AT45DB_CMD_BUF_TO_MEM_WITHOUT_ERASE(buf)(!buf ? 0x88 : 0x89)


#define AT45DB_PROT_MSK_SECTOR0_A   0xC0
#define AT45DB_PROT_MSK_SECTOR0_B   0x30
#define AT45DB_PROT_MSK_SECTORS     0xFF


typedef struct {
    unsigned sectors_cnt;
    unsigned sector_size;
    unsigned sector_0a_size;
    unsigned block_size;
    unsigned page_size;
} t_flash_at45db_specinfo;


#define AT45DB_ERASE_POS_SECTOR 0
#define AT45DB_ERASE_POS_BLOCK  1
#define AT45DB_ERASE_POS_PAGE   2



static const t_flash_erase_cmd f_erase_cmds_at45db642[] = {
    {AT45DB_CMD_ERASE_SECTOR, AT45DB642_SECTOR_SIZE, AT45DB642_TIME_ERASE_SECTOR, 0},
    {AT45DB_CMD_ERASE_BLOCK,  AT45DB642_BLOCK_SIZE,  AT45DB642_TIME_ERASE_BLOCK,  0},
    {AT45DB_CMD_ERASE_PAGE,   AT45DB642_PAGE_SIZE,   AT45DB642_TIME_ERASE_PAGE,   0},
    {0,0,0,0}
};

static const t_flash_erase_cmd f_erase_cmds_at45db641[] = {
    {AT45DB_CMD_ERASE_SECTOR, AT45DB641_SECTOR_SIZE, AT45DB641_TIME_ERASE_SECTOR, 0},
    {AT45DB_CMD_ERASE_BLOCK,  AT45DB641_BLOCK_SIZE,  AT45DB641_TIME_ERASE_BLOCK,  0},
    {AT45DB_CMD_ERASE_PAGE,   AT45DB641_PAGE_SIZE,   AT45DB641_TIME_ERASE_PAGE,   0},
    {0,0,0,0}
};


static const t_flash_erase_cmd f_erase_cmds_at45db041[] = {
    {AT45DB_CMD_ERASE_SECTOR, AT45DB041_SECTOR_SIZE, AT45DB041_TIME_ERASE_SECTOR, 0},
    {AT45DB_CMD_ERASE_BLOCK,  AT45DB041_BLOCK_SIZE,  AT45DB041_TIME_ERASE_BLOCK,  0},
    {AT45DB_CMD_ERASE_PAGE,   AT45DB041_PAGE_SIZE,   AT45DB041_TIME_ERASE_PAGE,   0},
    {0,0,0,0}
};

static const t_flash_erase_cmd f_erase_cmds_at45db161e[] = {
    {AT45DB_CMD_ERASE_SECTOR, AT45DB161_SECTOR_SIZE, AT45DB161E_TIME_ERASE_SECTOR, 0},
    {AT45DB_CMD_ERASE_BLOCK,  AT45DB161_BLOCK_SIZE,  AT45DB161E_TIME_ERASE_BLOCK,  0},
    {AT45DB_CMD_ERASE_PAGE,   AT45DB161_PAGE_SIZE,   AT45DB161E_TIME_ERASE_PAGE,   0},
    {0,0,0,0}
};

static const t_flash_erase_cmd f_erase_cmds_at45db161d[] = {
    {AT45DB_CMD_ERASE_SECTOR, AT45DB161_SECTOR_SIZE, AT45DB161D_TIME_ERASE_SECTOR, 0},
    {AT45DB_CMD_ERASE_BLOCK,  AT45DB161_BLOCK_SIZE,  AT45DB161D_TIME_ERASE_BLOCK,  0},
    {AT45DB_CMD_ERASE_PAGE,   AT45DB161_PAGE_SIZE,   AT45DB161D_TIME_ERASE_PAGE,   0},
    {0,0,0,0}
};



static const t_flash_at45db_specinfo flash_specinfo_at45db641 = {
    AT45DB64X_SECTORS_CNT,
    AT45DB64X_SECTOR_SIZE,
    AT45DB641_SECTOR_0A_SIZE,
    AT45DB641_BLOCK_SIZE,
    AT45DB641_PAGE_SIZE,
};

const t_flash_info flash_info_at45db641 =  {
    {AT45DB64X_ID_MANUFACTURER, AT45DB64X_ID_DEVICE, AT45DB64X_ID_CAPACITY, 1},
    AT45DB64X_FLASH_SIZE,
    {AT45DB_CMD_RD_STATUS, AT45DB_STATUS_RDY, AT45DB_STATUS_RDY,0x0},
    {FLASH_CMD_CODE_READ, 0},
    {f_erase_cmds_at45db641, FLASH_CMD_CODE_WRITE_ENABLE},
    {0, 0, 0},
    {0},
    {0, 0, 0},
    {   NULL,
        flash_at45db_get_status,
        flash_at45db_read,
        flash_at45db_erase,
        flash_at45db_get_erase_cmd,
        flash_at45db_write,
        flash_at45db_write_enable,
        flash_at45db_lock_enable,
        flash_at45db_lock,
        flash_at45db_unlock,
        flash_at45db_lock_check,
        NULL,
        NULL,
        flash_at45db_erase_cb,
        NULL,
        NULL,
        NULL
    },
    &flash_specinfo_at45db641
};


static const t_flash_at45db_specinfo flash_specinfo_at45db642 = {
    AT45DB64X_SECTORS_CNT,
    AT45DB64X_SECTOR_SIZE,
    AT45DB642_SECTOR_0A_SIZE,
    AT45DB642_BLOCK_SIZE,
    AT45DB642_PAGE_SIZE,
};


const t_flash_info flash_info_at45db642 =  {
    {AT45DB64X_ID_MANUFACTURER, AT45DB64X_ID_DEVICE, AT45DB64X_ID_CAPACITY, 0},
    AT45DB64X_FLASH_SIZE,
    {AT45DB_CMD_RD_STATUS, AT45DB_STATUS_RDY, AT45DB_STATUS_RDY,0x0},
    {FLASH_CMD_CODE_READ, 0},
    {f_erase_cmds_at45db642, FLASH_CMD_CODE_WRITE_ENABLE},
    {0, 0, 0},
    {0},
    {0, 0, 0},
    {   NULL,
        flash_at45db_get_status,
        flash_at45db_read,
        flash_at45db_erase,
        flash_at45db_get_erase_cmd,
        flash_at45db_write,
        flash_at45db_write_enable,
        flash_at45db_lock_enable,
        flash_at45db_lock,
        flash_at45db_unlock,
        flash_at45db_lock_check,
        NULL,
        NULL,
        flash_at45db_erase_cb,
        NULL,
        NULL,
        NULL
    },
    &flash_specinfo_at45db642
};


static const t_flash_at45db_specinfo flash_specinfo_at45db6041 = {
    AT45DB041_SECTORS_CNT,
    AT45DB041_SECTOR_SIZE,
    AT45DB041_SECTOR_0A_SIZE,
    AT45DB041_BLOCK_SIZE,
    AT45DB041_PAGE_SIZE,
};

const t_flash_info flash_info_at45db041 =  {
    {AT45DB041_ID_MANUFACTURER, AT45DB041_ID_DEVICE, AT45DB041_ID_CAPACITY, 1},
    AT45DB041_FLASH_SIZE,
    {AT45DB_CMD_RD_STATUS, AT45DB_STATUS_RDY, AT45DB_STATUS_RDY,0x0},
    {FLASH_CMD_CODE_READ, 0},
    {f_erase_cmds_at45db041, FLASH_CMD_CODE_WRITE_ENABLE},
    {0, 0, 0},
    {0},
    {0, 0, 0},
    {   NULL,
        flash_at45db_get_status,
        flash_at45db_read,
        flash_at45db_erase,
        flash_at45db_get_erase_cmd,
        flash_at45db_write,
        flash_at45db_write_enable,
        flash_at45db_lock_enable,
        flash_at45db_lock,
        flash_at45db_unlock,
        flash_at45db_lock_check,
        NULL,
        NULL,
        flash_at45db_erase_cb,
        NULL,
        NULL,
        NULL
    },
    &flash_specinfo_at45db6041
};


static const t_flash_at45db_specinfo flash_specinfo_at45db161 = {
    AT45DB161_SECTORS_CNT,
    AT45DB161_SECTOR_SIZE,
    AT45DB161_SECTOR_0A_SIZE,
    AT45DB161_BLOCK_SIZE,
    AT45DB161_PAGE_SIZE,

};

const t_flash_info flash_info_at45db161e =  {
    {AT45DB161_ID_MANUFACTURER, AT45DB161_ID_DEVICE, AT45DB161_ID_CAPACITY, 1},
    AT45DB161_FLASH_SIZE,
    {AT45DB_CMD_RD_STATUS, AT45DB_STATUS_RDY, AT45DB_STATUS_RDY,0x0},
    {FLASH_CMD_CODE_READ, 0},
    {f_erase_cmds_at45db161e, FLASH_CMD_CODE_WRITE_ENABLE},
    {0, 0, 0},
    {0},
    {0, 0, 0},
    {   NULL,
        flash_at45db_get_status,
        flash_at45db_read,
        flash_at45db_erase,
        flash_at45db_get_erase_cmd,
        flash_at45db_write,
        flash_at45db_write_enable,
        flash_at45db_lock_enable,
        flash_at45db_lock,
        flash_at45db_unlock,
        flash_at45db_lock_check,
        NULL,
        NULL,
        flash_at45db_erase_cb,
        NULL,
        NULL,
        NULL,
    },
    &flash_specinfo_at45db161
};

const t_flash_info flash_info_at45db161d =  {
    {AT45DB161_ID_MANUFACTURER, AT45DB161_ID_DEVICE, AT45DB161_ID_CAPACITY, 0},
    AT45DB161_FLASH_SIZE,
    {AT45DB_CMD_RD_STATUS, AT45DB_STATUS_RDY, AT45DB_STATUS_RDY,0x0},
    {FLASH_CMD_CODE_READ, 0},
    {f_erase_cmds_at45db161d, FLASH_CMD_CODE_WRITE_ENABLE},
    {0, 0, 0},
    {0},
    {0, 0, 0},
    {   NULL,
        flash_at45db_get_status,
        flash_at45db_read,
        flash_at45db_erase,
        flash_at45db_get_erase_cmd,
        flash_at45db_write,
        flash_at45db_write_enable,
        flash_at45db_lock_enable,
        flash_at45db_lock,
        flash_at45db_unlock,
        flash_at45db_lock_check,
        NULL,
        NULL,
        flash_at45db_erase_cb,
        NULL,
        NULL,
        NULL,
    },
    &flash_specinfo_at45db161
};


t_flash_errs flash_at45db_set(t_flash_iface *iface) {    
    const t_flash_info *flash_infos[] = {
        &flash_info_at45db642,
        &flash_info_at45db641,
        &flash_info_at45db041,
        &flash_info_at45db161e,
        &flash_info_at45db161d
    };
    return flash_set_from_list(iface, flash_infos, sizeof(flash_infos)/sizeof(flash_infos[0]), NULL);
}


t_flash_errs flash_at45db_set_page_size_pow2(t_flash_iface *iface) {
    unsigned char cmd[4] = {0x3D, 0x2A, 0x80, 0xA6};
    t_flash_errs err;

    err = flash_exec_cmd_only(iface, cmd, 4, 0);
    if (!err) {
        err = flash_wait_ready(iface, SET_PAGE_POW_TOUT, NULL);
    }

    flash_iface_flush(iface, err);

    return err;
}


t_flash_errs flash_at45db_set_sector_protection(t_flash_iface *iface,
                                                unsigned sect0, unsigned sectors) {
    unsigned char cmd[4+AT45DB_MAX_SECTORS_CNT];
    t_flash_errs err;

    /* Стирание регистра защиты (после команды все сектора защищены) */
    cmd[0] = 0x3D;
    cmd[1] = 0x2A;
    cmd[2] = 0x7F;
    cmd[3] = 0xCF;

    err = flash_exec_cmd_only(iface, cmd, 4, 0);
    if (!err)
        err = flash_wait_ready(iface, SET_PROTECTION_TOUT, NULL);

    /* Запись регистров защиты */
    if (!err) {
        size_t sect_idx;
        const t_flash_at45db_specinfo *specinfo = (const t_flash_at45db_specinfo *)iface->flash_info->devspec;

        cmd[0] = 0x3D;
        cmd[1] = 0x2A;
        cmd[2] = 0x7F;
        cmd[3] = 0xFC;


        cmd[4] = 0;
        if (sect0 & AT45DB_PROT_SECT0_A)
            cmd[4] |= AT45DB_PROT_MSK_SECTOR0_A;
        if (sect0 & AT45DB_PROT_SECT0_B)
            cmd[4] |= AT45DB_PROT_MSK_SECTOR0_B;

        for (sect_idx = 1; sect_idx < specinfo->sectors_cnt; sect_idx++)
            cmd[4+sect_idx] = sectors & AT45DB_PROT_SECTOR(sect_idx) ? 0xFF : 0x00;

        err = flash_exec_cmd_only(iface, cmd, 4 + specinfo->sectors_cnt, 0);
    }

    if (!err)
        err = flash_wait_ready(iface, SET_PROTECTION_TOUT, NULL);


    flash_iface_flush(iface, err);
    return err;
}

t_flash_errs flash_at45db_get_sector_protection(t_flash_iface *iface,
                                                unsigned *sect0, unsigned *sectors) {
   unsigned char cmd = 0x32;
   unsigned char data[AT45DB_MAX_SECTORS_CNT];
   const t_flash_at45db_specinfo *specinfo = (const t_flash_at45db_specinfo *)iface->flash_info->devspec;
   t_flash_errs err;

   err = flash_exec_cmd(iface, &cmd, 1, NULL, 3, data, specinfo->sectors_cnt, 0);
   if (!err) {

       unsigned cur_sect0 = 0, cur_sectors = 0;
       size_t sect_idx;

       if ((data[0] & AT45DB_PROT_MSK_SECTOR0_A) == AT45DB_PROT_MSK_SECTOR0_A)
           cur_sect0 |= AT45DB_PROT_SECT0_A;

       if ((data[0] & AT45DB_PROT_MSK_SECTOR0_B) == AT45DB_PROT_MSK_SECTOR0_B)
            cur_sect0 |= AT45DB_PROT_SECT0_B;


       for (sect_idx = 1; sect_idx < specinfo->sectors_cnt; ++sect_idx) {
           if ((data[sect_idx] & AT45DB_PROT_MSK_SECTORS) == AT45DB_PROT_MSK_SECTORS)
               cur_sectors |= AT45DB_PROT_SECTOR(sect_idx);
       }

       if (sect0!=NULL)
           *sect0 = cur_sect0;
       if (sectors!=NULL)
           *sectors = cur_sectors;
   }
   flash_iface_flush(iface, err);
   return err;
}

t_flash_errs flash_at45db_write(t_flash_iface *iface, unsigned addr,
                                const unsigned char *data, size_t len,
                                unsigned flags) {
    t_flash_errs err = FLASH_ADDR_CHECK(iface, addr, len);
    int buf = 0;
    unsigned page_size=0;
    unsigned wt_time = flags & FLASH_WR_FLAGS_WITH_ERASE ? AT45DB_TIME_PROGR_ERASE : AT45DB_TIME_PROGR;
    if (!err) {
        const t_flash_at45db_specinfo *specinfo = (const t_flash_at45db_specinfo *)iface->flash_info->devspec;
        page_size = specinfo->page_size;
    }

    while (len && !err) {
        int page_update = 0;
        unsigned page_offs = addr & (page_size-1);
        size_t page_len  = page_size - page_offs;
        if (page_len > len)
            page_len = len;
        if (page_len != page_size) {
            err = flash_wait_ready(iface, wt_time, NULL);
            if (!err) {
                err = flash_exec_cmd_addr_only(iface, AT45DB_CMD_MEM_TO_BUF(buf), addr, 0);
            }
            if (!err) {
                err = flash_wait_ready(iface, wt_time, NULL);
            }
            page_update = 1;
        }

        if (!err) {
            err = flash_exec_cmd_addr(iface, AT45DB_CMD_BUF_WR(buf), page_offs, 0,
                                      data, NULL, page_len, 0);
        }

        if (!err) {
            /* ожидание готовности к памяти к записи */
            err = flash_wait_ready(iface, wt_time, NULL);
        }

        if (!err) {
            err = flash_exec_cmd_addr_only(iface, page_update || (flags & FLASH_WR_FLAGS_WITH_ERASE) ?
                                          AT45DB_CMD_BUF_TO_MEM_WITH_ERASE(buf) :
                                          AT45DB_CMD_BUF_TO_MEM_WITHOUT_ERASE(buf),
                                          addr,  0);
        }

        if (!err) {
            buf  ^= 1;
            addr += (unsigned)page_len;
            data += page_len;
            len  -= page_len;
        }
    }


    if (!err) {
        err = flash_wait_ready(iface, wt_time, NULL);
    }

    flash_iface_flush(iface, err);

    return err;
}



t_flash_errs flash_at45db_erase_cb(t_flash_iface *iface, unsigned addr, size_t len, void (*cb)(void)) {
    t_flash_errs err = FLASH_ADDR_CHECK(iface, addr, len);
    if (!err) {
        const t_flash_at45db_specinfo *specinfo = (const t_flash_at45db_specinfo *)iface->flash_info->devspec;
        /* Сектора 0A и 0B проверяем отдельно, так как они нестандартного размера
         * и не стандартных адресов */
        if ((addr == 0) && (len >= specinfo->sector_0a_size)) {
            err = flash_exec_cmd_addr_only(iface, AT45DB_CMD_ERASE_SECTOR, addr, 0);
            if (!err) {
                err = flash_wait_ready_cb(iface, iface->flash_info->erase.cmds[AT45DB_ERASE_POS_SECTOR].time, NULL, cb);
            }
            if (!err) {
                addr += specinfo->sector_0a_size;
                len -= specinfo->sector_0a_size;
            }
        }

        if (!err && (addr == specinfo->sector_0a_size) && (len >= (specinfo->sector_size - specinfo->sector_0a_size))) {
            err = flash_exec_cmd_addr_only(iface, AT45DB_CMD_ERASE_SECTOR, addr, 0);
            if (!err) {
                err = flash_wait_ready_cb(iface, iface->flash_info->erase.cmds[AT45DB_ERASE_POS_SECTOR].time, NULL, cb);
            }
            if (!err) {
                addr += (specinfo->sector_size - specinfo->sector_0a_size);
                len -= (specinfo->sector_size - specinfo->sector_0a_size);
            }
        }
    }

    /* если есть область для стирания, креме сектаров 0A и 0B =>
     * стираем их */
    if (!err && (len!=0)) {
        err = flash_generic_erase(iface, addr, len);
    } else {
        flash_iface_flush(iface, err);
    }


    return err;
}

t_flash_errs flash_at45db_erase(t_flash_iface *iface, unsigned addr, size_t len) {
    return flash_at45db_erase_cb(iface, addr, len, NULL);
}

t_flash_errs flash_at45db_protection_enable(t_flash_iface *iface) {
    unsigned char cmd[4] = {0x3D, 0x2A, 0x7F, 0xA9};
    t_flash_errs err;

    err = flash_exec_cmd_only(iface, cmd, 4, 0);
    if (!err) {
        err = flash_wait_ready(iface, SET_PROTECTION_TOUT, NULL);
    }

    flash_iface_flush(iface, err);
    return err;
}

t_flash_errs flash_at45db_protection_disable(t_flash_iface *iface) {
    unsigned char cmd[4] = {0x3D, 0x2A, 0x7F, 0x9A};
    t_flash_errs err;

    err = flash_exec_cmd_only(iface, cmd, 4, 0);
    if (!err) {
        err = flash_wait_ready(iface, SET_PROTECTION_TOUT, NULL);
    }

    flash_iface_flush(iface, err);
    return err;
}


static int sect_check(unsigned addr, unsigned size, unsigned sect_addr, unsigned sect_size) {
    return (addr < (sect_addr + sect_size)) && ((addr + size) > sect_addr);

}

void flash_at45db_region_sectors_mask(t_flash_iface *iface, unsigned addr, unsigned size, unsigned *psect0, unsigned *psectors) {
    const t_flash_at45db_specinfo *specinfo = (const t_flash_at45db_specinfo *)iface->flash_info->devspec;
    unsigned sect0 = 0, sectors = 0;
    unsigned sect_num;

    if (sect_check(addr, size, 0, specinfo->sector_0a_size))
        sect0 |= AT45DB_PROT_SECT0_A;
    if (sect_check(addr, size, specinfo->sector_0a_size, specinfo->sector_size - specinfo->sector_0a_size))
        sect0 |= AT45DB_PROT_SECT0_B;
    for (sect_num = 1; sect_num < AT45DB_MAX_SECTORS_CNT; sect_num++) {
        if (sect_check(addr, size, sect_num*specinfo->sector_size, specinfo->sector_size))
            sectors |= AT45DB_PROT_SECTOR(sect_num);
    }
    if (psect0 != NULL)
        *psect0 = sect0;
    if (psectors != NULL)
        *psectors = sectors;
}

t_flash_errs flash_at45db_lock(t_flash_iface *iface, unsigned addr, unsigned size) {
    t_flash_errs err;
    unsigned cur_sect0 = 0, cur_sectors = 0, change_sect0 = 0, change_sectors = 0;

    err = flash_at45db_get_sector_protection(iface, &cur_sect0, &cur_sectors);
    if (!err) {
        flash_at45db_region_sectors_mask(iface, addr, size, &change_sect0, &change_sectors);
        change_sect0 = cur_sect0 | change_sect0;
        change_sectors = cur_sectors | change_sectors;

        if ((cur_sect0 != change_sect0) || (cur_sectors != change_sectors))
            err = flash_at45db_set_sector_protection(iface, change_sect0, change_sectors);

        if (!err) {
            err = flash_at45db_get_sector_protection(iface, &cur_sect0, &cur_sectors);
            if (!err && ((cur_sect0 != change_sect0) || (cur_sectors != change_sectors)))
                err = FLASH_ERR_OP_FAILED;
        }
    }
    return err;
}

t_flash_errs flash_at45db_unlock(t_flash_iface *iface, unsigned addr, unsigned size) {
    t_flash_errs err;
    unsigned cur_sect0 = 0, cur_sectors = 0, change_sect0 = 0, change_sectors = 0;

    err = flash_at45db_get_sector_protection(iface, &cur_sect0, &cur_sectors);
    if (!err) {
        flash_at45db_region_sectors_mask(iface, addr, size, &change_sect0, &change_sectors);
        change_sect0 = cur_sect0 & ~change_sect0;
        change_sectors = cur_sectors & ~change_sectors;

        if ((cur_sect0 != change_sect0) || (cur_sectors != change_sectors))
            err = flash_at45db_set_sector_protection(iface, change_sect0, change_sectors);

        if (!err) {
            err = flash_at45db_get_sector_protection(iface, &cur_sect0, &cur_sectors);
            if (!err && ((cur_sect0 != change_sect0) || (cur_sectors != change_sectors))) {
                err = FLASH_ERR_OP_FAILED;
            }
        }
    }
    return err;
}



t_flash_errs flash_at45db_lock_enable(t_flash_iface *iface) {
    unsigned char flash_status;
    t_flash_errs err = flash_at45db_get_status(iface, &flash_status);
    if (!(flash_status & AT45DB_STATUS_PROTECT)) {
        err = flash_at45db_protection_enable(iface);
        if (!err) {
            err = flash_at45db_get_status(iface, &flash_status);
            if (!err && !(flash_status & AT45DB_STATUS_PROTECT))
                err = FLASH_ERR_OP_FAILED;
        }
    }
    return err;
}




t_flash_errs flash_at45db_lock_check(t_flash_iface *iface, unsigned addr, unsigned size, int locked, int *check_ok) {
    t_flash_errs err;
    unsigned cur_sect0 = 0, cur_sectors = 0;

    err = flash_at45db_get_sector_protection(iface, &cur_sect0, &cur_sectors);
    if (!err) {
        unsigned req_sect0, req_sectors;
        flash_at45db_region_sectors_mask(iface, addr, size, &req_sect0, &req_sectors);
        cur_sect0 &= req_sect0;
        cur_sectors &= req_sectors;

        if (locked) {
            *check_ok = (cur_sect0  == req_sect0) &&
                    (cur_sectors == req_sectors);
        } else {
            *check_ok = (cur_sect0  == 0) &&
                    (cur_sectors == 0);
        }
    }
    return err;

}

