#include <stdint.h>
#include <string.h>

#include "omw_flash.h"

#define   CMD_ONLY          0
#define   CMD_READ          1
#define   CMD_WRITE         2
#define   CMD_ADDR          3
#define   CMD_ADDR_READ     4
#define   CMD_ADDR_WRITE    5
#define   CMD_ADDR_R2       6
#define   CMD_ADDR_R4       7
#define   CMD_ADDR_W2       8
#define   CMD_ADDR_W4       9

#define  REG_CMD_TYPE 0x1F000000
#define  REG_CMD_CODE 0x1F000004
#define  REG_CMD_ADDR 0x1F000008
#define  REG_CMD_LEN  0x1F00000C
#define  REG_CMD_DATA 0x1F000010
#define  REG_CMD_REQ  0x1F00001C

#define WORD_ALIGN_BUF_LEN_BITS  3

#ifndef OMW_EN_OTA
#undef __FLASH_OTA_OP_CODE_SECTION
#define __FLASH_OTA_OP_CODE_SECTION

#undef __FLASH_RAM_CODE_SECTION
#define __FLASH_RAM_CODE_SECTION  __RAM_CODE_SECTION
#endif

typedef volatile unsigned int  reg32_t;

static uint8_t wt_cmd  = CMD_ADDR_WRITE;
static uint8_t wt_code = 0x02;
static uint8_t rd_cmd  = CMD_ADDR_R2;
static uint8_t rd_code = 0x3B;

int wdalignbuf[1 << WORD_ALIGN_BUF_LEN_BITS] = {0};

//__FLASH_RAM_CODE_SECTION, inline will compile to RAM auto,
static inline void flash_write_enable()
{
    *(reg32_t*)(REG_CMD_TYPE) = CMD_ONLY;
    *(reg32_t*)(REG_CMD_CODE) = 6;
    *(reg32_t*)(REG_CMD_REQ ) = 1;
}

__FLASH_RAM_CODE_SECTION
int flash_read_status()
{
    int status;
    *(reg32_t*)(REG_CMD_TYPE) = CMD_READ;
    *(reg32_t*)(REG_CMD_CODE) = 5;
    *(reg32_t*)(REG_CMD_LEN ) = 1;
    *(reg32_t*)(REG_CMD_REQ ) = 1;

    status = *(reg32_t*)(REG_CMD_REQ);
    return status;
}

__FLASH_RAM_CODE_SECTION
void flash_section_erase(int addr)
{
    ATOMIC_SECTION_BEGIN();

    flash_write_enable();

    *(reg32_t*)(REG_CMD_TYPE) = CMD_ADDR;
    *(reg32_t*)(REG_CMD_CODE) = 0x20;
    *(reg32_t*)(REG_CMD_ADDR) = addr;
    *(reg32_t*)(REG_CMD_REQ ) = 1;

    while(1 == (0x1 & flash_read_status()));

    ATOMIC_SECTION_END();
}

__FLASH_OTA_OP_CODE_SECTION
//len: bytes, must be 4, 16, 32
static void flash_page_read(int addr, int * data, int len)
{
    int len_word;
    int i;
	ATOMIC_SECTION_BEGIN();
    *(reg32_t*)(REG_CMD_TYPE) = rd_cmd;
    *(reg32_t*)(REG_CMD_CODE) = rd_code;

    *(reg32_t*)(REG_CMD_ADDR) = addr;
    *(reg32_t*)(REG_CMD_LEN ) = len; // byte

    *(reg32_t*)(REG_CMD_REQ ) = 1;

    len_word = (len >> 2);

    for(i=0;i<len_word;i++)
    {
        data[i] = *(reg32_t*)(REG_CMD_DATA);
    }
	ATOMIC_SECTION_END();
}

__FLASH_OTA_OP_CODE_SECTION
static void flash_read_less_one_word(int addr, int off, char * pbuf, int len)
{
    char * ptmp = (char *)wdalignbuf;
    flash_page_read(addr, wdalignbuf, 4);
    for (int i = 0; i < len; i++)
    {
        pbuf[i] = ptmp[off + i];
    }
}

__FLASH_OTA_OP_CODE_SECTION
static int flashRead(char* dst, char *src, int length){
    int rm_len;
    int cur_len_bits;
    int dst_addr, src_addr, ua_off, ua_len;

    dst_addr = (int)dst;
    src_addr = (int)src;
    rm_len = length;
    cur_len_bits = 5;
    ua_off = src_addr & 0x3;
    ua_len = 4 - ua_off;
    ua_len = (ua_len > rm_len) ? rm_len:ua_len;

    if (ua_off > 0)
    {
        src_addr = src_addr & (~0x3);
        flash_read_less_one_word(src_addr, ua_off, dst, ua_len);
        rm_len -= ua_len;
        src_addr += 4;  //word aligned
        dst_addr += ua_len;
    }

    while(rm_len >= 4)
    {
        int cur_tms = (rm_len >> cur_len_bits);
        for (int i = 0; i < cur_tms; i++)
        {
            int cur_dst = dst_addr;
            if (0 != (cur_dst & 0x3))
            {//not word aligned
                cur_dst = (int)wdalignbuf;
            }

            flash_page_read(src_addr, (int *)cur_dst, (1 << cur_len_bits));
            src_addr += (1 << cur_len_bits);
            if (cur_dst != dst_addr)
            {
                memcpy((void *)dst_addr, (void *)cur_dst, (1 << cur_len_bits));
            }
            dst_addr += (1 << cur_len_bits);
        }
        rm_len = (rm_len & ((1 << cur_len_bits) - 1));
        if (5 == cur_len_bits)
        {
            cur_len_bits = 4;
        }
        else if (4 == cur_len_bits)
        {
            cur_len_bits = 2;
        }
        else
        {
            break;
        }
    }

    if (rm_len > 0)
    {
        flash_read_less_one_word(src_addr, 0, (char *)dst_addr, rm_len);
    }

    return 0;
}

//len: bytes, must <= 32, will write 4, 32 bytes
__FLASH_RAM_CODE_SECTION
void flash_page_program(int addr, int * data, int len)
{
    int len_word;
    int i;

    ATOMIC_SECTION_BEGIN();

    flash_write_enable();

    *(reg32_t*)(REG_CMD_TYPE) = wt_cmd;
    *(reg32_t*)(REG_CMD_CODE) = wt_code;

    *(reg32_t*)(REG_CMD_ADDR) = addr;
    *(reg32_t*)(REG_CMD_LEN ) = len; // byte

    len_word = (len >> 2);

    for(i=0;i<len_word;i++)
    {
        *(volatile reg32_t*)(REG_CMD_DATA) = data[i];
    }

    *(reg32_t*)(REG_CMD_REQ) = 1;

    while(1 == (0x1 & flash_read_status()));

    ATOMIC_SECTION_END();
}

__FLASH_OTA_OP_CODE_SECTION
static void flash_write_less_one_word(int addr, int off, char * pdata, int len)
{
    char * ptmp = (char *)wdalignbuf;
    flash_page_read(addr, wdalignbuf, 4);

    for (int i = 0; i < len; i++)
    {
        ptmp[off + i] = pdata[i];
    }

    flash_page_program(addr, wdalignbuf, 4);
}

__FLASH_OTA_OP_CODE_SECTION
static int flashProgram(char* dst, char *src, int length)
{
    int rm_len;
    int cur_len_bits;
    int dst_addr, src_addr, ua_off, ua_len;

    cur_len_bits = 5;
    rm_len = length;
    dst_addr = (int)dst;
    src_addr = (int)src;
    ua_off = dst_addr & 0x3;
    ua_len = 4 - ua_off;
    ua_len = (ua_len > rm_len) ? rm_len:ua_len;

    if (ua_off > 0)
    {
        dst_addr = dst_addr & (~0x3);
        flash_write_less_one_word(dst_addr, ua_off, src, ua_len);
        rm_len -= ua_len;
        dst_addr += 4; //word aligned
        src_addr += ua_len;
    }

    while(rm_len >= 4)
    {
        int cur_tms = (rm_len >> cur_len_bits);
        for (int i = 0; i < cur_tms; i++)
        {
            int cur_src = src_addr;
            if (0 != (cur_src & 0x3))
            {//not word aligned
				OMW_MEMCPY(wdalignbuf, (void *)src_addr, (1 << cur_len_bits));
                cur_src = (int)wdalignbuf;
            }

            flash_page_program(dst_addr, (int *)cur_src, (1 << cur_len_bits));

            src_addr += (1 << cur_len_bits);
            dst_addr += (1 << cur_len_bits);
        }
        rm_len = (rm_len & ((1 << cur_len_bits) - 1));
        if (5 == cur_len_bits)
        {
            cur_len_bits = 2;
        }
        else
        {
            break;
        }
    }

    if (rm_len > 0)
    {
        flash_write_less_one_word(dst_addr, 0, (char *)src_addr, rm_len);
    }

    return 0;
}

__FLASH_OTA_OP_CODE_SECTION
void omw_flash_sector_erase(uint32_t dst, uint16_t sec_nr)
{
    int cur_addr = (int)dst;

    for (int i = 0; i < sec_nr; i++)
    {
        flash_section_erase(cur_addr);
        cur_addr += OMW_FLASH_SECTOR_SIZE;
    }
}


__FLASH_OTA_OP_CODE_SECTION
void omw_flash_read(uint32_t addr, uint8_t * buf, uint32_t len)
{
    #ifndef FAKE_FLASH
    flashRead((char *)buf, (char *)addr, len);
    #else
    memcpy(buf, (void *)addr, len);
    #endif
}

__FLASH_OTA_OP_CODE_SECTION
void omw_flash_write(uint32_t addr, uint8_t * buf, uint32_t len)
{
    #ifndef FAKE_FLASH
    flashProgram((char *)addr, (char *)buf,  len);
    #else
    memcpy((char *)addr, buf,  len);
    #endif
}



#define FLASH_PER_CPY_SZ_BITS   8
#define FLASH_PER_CPY_SZ        (1 << FLASH_PER_CPY_SZ_BITS)
static void flash_move_cache_data_to_buf(uint32_t buf_addr, uint8_t * tmp_buf, uint32_t sec_valid_max_offset)
{
    uint16_t cache_ofst = 0;
	uint16_t cp_nr = ((sec_valid_max_offset + FLASH_PER_CPY_SZ - 1) >> FLASH_PER_CPY_SZ_BITS);

    flash_section_erase(buf_addr);

    for (int i = 0; i < cp_nr; i++)
    {
		uint16_t cp_l = sec_valid_max_offset > FLASH_PER_CPY_SZ ? FLASH_PER_CPY_SZ : sec_valid_max_offset;

        flashRead((char *)tmp_buf, (char *)(OMW_FLASH_OVWT_CACHE_ADDR + cache_ofst), cp_l);
        flashProgram((char *)(buf_addr + cache_ofst), (char *)tmp_buf,  cp_l);

        cache_ofst += FLASH_PER_CPY_SZ;  //if cp_l < FLASH_PER_CPY_SZ, that is ok, will not go into loop again
		sec_valid_max_offset -= FLASH_PER_CPY_SZ; //if cp_l < FLASH_PER_CPY_SZ, that is ok, will not go into loop again
    }

    flash_section_erase(OMW_FLASH_OVWT_CACHE_ADDR);
}

//only support one sector overwrite, sec_valid_max_offset fasten work
//4k sector erase
#if 1
void omw_flash_overwrite(struct omw_flash_ovwrt_tag * ovwrt_info, uint32_t ovwrt_info_sz, uint32_t sec_valid_max_offset)
{
    uint32_t addr = ovwrt_info[0].addr;
    uint32_t len  = ovwrt_info[0].len;
    uint8_t * buf = ovwrt_info[0].data;
    uint32_t sec_s_idx = (addr >> OMW_FLASH_SS_BITS);
    uint32_t addr_st   = (sec_s_idx << OMW_FLASH_SS_BITS);
    uint16_t first_o   = addr - addr_st;
    uint16_t cache_ofst = 0;
    uint32_t cur_ovwrt_idx = 0;
    uint16_t ua_l;
    uint16_t cpd_l;
	uint16_t cp_nr;

    uint8_t  tmp_buf[FLASH_PER_CPY_SZ]; //!!!!!!!!STACK MAYBE OVERFLOW

__MULTI_OVWRT_LOOP:
    ua_l  = first_o & (FLASH_PER_CPY_SZ - 1);
    cpd_l = 0;

    //first sector copy: FLASH_PER_CPY_SZ aligned 
    for (int i = 0; i < (first_o >> FLASH_PER_CPY_SZ_BITS); i++)
    {
        flashRead((char *)tmp_buf, (char *)(addr_st + cache_ofst), FLASH_PER_CPY_SZ);
        flashProgram((char *)(OMW_FLASH_OVWT_CACHE_ADDR + cache_ofst), (char *)tmp_buf,  FLASH_PER_CPY_SZ);
        cache_ofst += FLASH_PER_CPY_SZ;
    }

    //first sector copy: less FLASH_PER_CPY_SZ copy
    if (ua_l || sec_valid_max_offset <= FLASH_PER_CPY_SZ)
    {
        uint32_t rd_l = sec_valid_max_offset - cache_ofst;
        uint32_t cp_l;

        if (rd_l > FLASH_PER_CPY_SZ) rd_l = FLASH_PER_CPY_SZ;
        cp_l = len > (rd_l - ua_l) ? (rd_l - ua_l) : len;

        flashRead((char *)tmp_buf, (char *)(addr_st + cache_ofst), rd_l);
        memcpy(tmp_buf + ua_l, buf, cp_l);

        if (sec_valid_max_offset <= FLASH_PER_CPY_SZ)
        {
            flash_section_erase(addr_st);
            flashProgram((char *)addr_st, (char *)tmp_buf,  sec_valid_max_offset);
            return;
        }

        flashProgram((char *)(OMW_FLASH_OVWT_CACHE_ADDR + cache_ofst), (char *)tmp_buf,  rd_l);
        cache_ofst += rd_l; //if not algined FLASH_PER_CPY_SZ, that is ok, cp_nr will be 0

        len -= cp_l;
        cpd_l += cp_l;
    }

    cp_nr = ((sec_valid_max_offset - cache_ofst  + FLASH_PER_CPY_SZ - 1) >> FLASH_PER_CPY_SZ_BITS);

    //first sector copy: tail FLASH_PER_CPY_SZs copy
    for (int i = 0; i < cp_nr; i++)
    {
        if (len)
        {
            uint32_t cp_l = len > FLASH_PER_CPY_SZ ? FLASH_PER_CPY_SZ : len;

            flashProgram((char *)(OMW_FLASH_OVWT_CACHE_ADDR + cache_ofst), (char *)(buf + cpd_l), cp_l); // + pd_l

            len -= cp_l;
            cpd_l += cp_l;

            if (!len) // + pd_l
            {
                if (cache_ofst + cp_l < sec_valid_max_offset)
                {
                    uint16_t al_l = FLASH_PER_CPY_SZ - cp_l; // - pd_l
                    uint16_t rm_l = sec_valid_max_offset - cp_l - cache_ofst; // - pd_l

                    if (rm_l > al_l)  rm_l = al_l;
                    if (rm_l)
                    {
                        flashRead((char *)tmp_buf, (char *)(addr_st + cache_ofst + cp_l), rm_l);  // + pd_l
                        flashProgram((char *)(OMW_FLASH_OVWT_CACHE_ADDR + cache_ofst + cp_l), (char *)tmp_buf, rm_l); // + pd_l
                    }
                }

                cur_ovwrt_idx++;

                if (cur_ovwrt_idx < ovwrt_info_sz)
                {
                    cache_ofst += FLASH_PER_CPY_SZ;

                    len = ovwrt_info[cur_ovwrt_idx].len;
                    buf = ovwrt_info[cur_ovwrt_idx].data;

                    first_o = ovwrt_info[cur_ovwrt_idx].addr - addr_st - cache_ofst;

                    goto __MULTI_OVWRT_LOOP;
                }
            }
        }
        else
        {
            uint16_t rm_l = sec_valid_max_offset - cache_ofst;
            if (rm_l > FLASH_PER_CPY_SZ) rm_l = FLASH_PER_CPY_SZ;

            flashRead((char *)tmp_buf, (char *)(addr_st + cache_ofst), rm_l);
            flashProgram((char *)(OMW_FLASH_OVWT_CACHE_ADDR + cache_ofst), (char *)tmp_buf, rm_l);
        }

        cache_ofst += FLASH_PER_CPY_SZ; //if last one is not FLASH_PER_CPY_SZ aligned, that is ok, will not go into loop again
    }

    flash_move_cache_data_to_buf(addr_st, tmp_buf, sec_valid_max_offset);
}
#else
void omw_flash_overwrite(uint32_t addr, uint8_t * buf, uint32_t len, uint32_t sec_valid_max_offset)
{
    uint32_t sec_s_idx = (addr >> OMW_FLASH_SS_BITS);
    // uint32_t sec_e_idx = ((addr + len) >> OMW_FLASH_SS_BITS);
    // uint16_t last_l    = (addr + len) & (OMW_FLASH_SS - 1);
    uint32_t addr_st   = (sec_s_idx << OMW_FLASH_SS_BITS);
    uint16_t first_o   = addr - addr_st;
    uint16_t cache_ofst = 0;

    uint16_t ua_l = first_o & (FLASH_PER_CPY_SZ - 1);
    uint16_t cpd_l = 0;
	uint16_t cp_nr;

    uint8_t  tmp_buf[FLASH_PER_CPY_SZ]; //!!!!!!!!STACK MAYBE OVERFLOW

    // if (sec_s_idx == sec_e_idx) last_l = 0;  //last one not across sector

    //first sector copy: FLASH_PER_CPY_SZ aligned
    for (int i = 0; i < (first_o >> FLASH_PER_CPY_SZ_BITS); i++)
    {
        flashRead((char *)tmp_buf, (char *)(addr_st + cache_ofst), FLASH_PER_CPY_SZ);
        flashProgram((char *)(OMW_FLASH_OVWT_CACHE_ADDR + cache_ofst), (char *)tmp_buf,  FLASH_PER_CPY_SZ);
        cache_ofst += FLASH_PER_CPY_SZ;
    }

    //first sector copy: less FLASH_PER_CPY_SZ copy
    if (ua_l)
    {
        uint32_t rd_l = sec_valid_max_offset - cache_ofst;
        uint32_t cp_l;

        if (rd_l > FLASH_PER_CPY_SZ) rd_l = FLASH_PER_CPY_SZ;
        cp_l = len > (rd_l - ua_l) ? (rd_l - ua_l) : len;

        flashRead((char *)tmp_buf, (char *)(addr_st + cache_ofst), rd_l);
        memcpy(tmp_buf + ua_l, buf, cp_l);

        if (sec_valid_max_offset <= FLASH_PER_CPY_SZ)
        {
            flash_section_erase(addr_st);
            flashProgram((char *)addr_st, (char *)tmp_buf,  sec_valid_max_offset);
            return;
        }

        flashProgram((char *)(OMW_FLASH_OVWT_CACHE_ADDR + cache_ofst), (char *)tmp_buf,  rd_l);
        cache_ofst += rd_l; //if not algined FLASH_PER_CPY_SZ, that is ok, cp_nr will be 0

        len -= cp_l;
        cpd_l += cp_l;
    }

    cp_nr = ((sec_valid_max_offset - cache_ofst  + FLASH_PER_CPY_SZ - 1) >> FLASH_PER_CPY_SZ_BITS);

    //first sector copy: tail FLASH_PER_CPY_SZs copy
    for (int i = 0; i < cp_nr; i++)
    {
        if (len)
        {
            uint32_t cp_l = len > FLASH_PER_CPY_SZ ? FLASH_PER_CPY_SZ : len;

            // uint32_t pd_l = 0;

            // if ((cp_l & 0x3) && (cache_ofst + cp_l < sec_valid_max_offset))
            // {//not 4 bytes aligned
            //     pd_l = sec_valid_max_offset - cache_ofst - cp_l;
            //     if (pd_l > (4 - (cp_l & 0x3))) pd_l = (4 - (cp_l & 0x3));

            //     flashRead((char *)(buf + cpd_l), (char *)(addr_st + cache_ofst + cp_l), pd_l);
            // }

            flashProgram((char *)(OMW_FLASH_OVWT_CACHE_ADDR + cache_ofst), (char *)(buf + cpd_l), cp_l); // + pd_l

            len -= cp_l;
            cpd_l += cp_l;

            if (!len && cache_ofst + cp_l < sec_valid_max_offset) // + pd_l
            {
                uint16_t al_l = FLASH_PER_CPY_SZ - cp_l; // - pd_l
                uint16_t rm_l = sec_valid_max_offset - cp_l - cache_ofst; // - pd_l

                if (rm_l > al_l)  rm_l = al_l;
                if (rm_l)
                {
                    flashRead((char *)tmp_buf, (char *)(addr_st + cache_ofst + cp_l), rm_l);  // + pd_l
                    flashProgram((char *)(OMW_FLASH_OVWT_CACHE_ADDR + cache_ofst + cp_l), (char *)tmp_buf, rm_l); // + pd_l
                }
            }
        }
        else
        {
            uint16_t rm_l = sec_valid_max_offset - cache_ofst;
            if (rm_l > FLASH_PER_CPY_SZ) rm_l = FLASH_PER_CPY_SZ;

            flashRead((char *)tmp_buf, (char *)(addr_st + cache_ofst), rm_l);
            flashProgram((char *)(OMW_FLASH_OVWT_CACHE_ADDR + cache_ofst), (char *)tmp_buf, rm_l);
        }

        cache_ofst += FLASH_PER_CPY_SZ; //if last one is not FLASH_PER_CPY_SZ aligned, that is ok, will not go into loop again
    }

    flash_move_cache_data_to_buf(addr_st, tmp_buf, sec_valid_max_offset);

	//only support one sector(4K bytes) overwrite, not need the next code
	#if 0
    addr_st += OMW_FLASH_SS;
    //mid sector aligned copy
    for (int i = 0; i < (len >> OMW_FLASH_SS_BITS); i++)
    {
        flash_section_erase(addr_st);
        flashProgram((char *)addr_st, (char *)(buf + cpd_l),  OMW_FLASH_SS);
        addr_st += OMW_FLASH_SS;
        cpd_l += OMW_FLASH_SS;
    }

    //last sector copy
    if (last_l)
    {
        cache_ofst = 0;
        for (int i = 0; i < (last_l >> FLASH_PER_CPY_SZ_BITS); i++)
        {
            flashProgram((char *)(OMW_FLASH_OVWT_CACHE_ADDR + cache_ofst), (char *)(buf + cpd_l),  FLASH_PER_CPY_SZ);
            cache_ofst += FLASH_PER_CPY_SZ;
            cpd_l += FLASH_PER_CPY_SZ;
        }

        ua_l = last_l & (FLASH_PER_CPY_SZ - 1);
        if (ua_l)
        {
            flashProgram((char *)(OMW_FLASH_OVWT_CACHE_ADDR + cache_ofst), (char *)(buf + cpd_l),  ua_l);
            flashRead((char *)tmp_buf, (char *)(addr_st + cache_ofst + ua_l), FLASH_PER_CPY_SZ - ua_l);
            flashProgram((char *)(OMW_FLASH_OVWT_CACHE_ADDR + cache_ofst + ua_l), (char *)tmp_buf, FLASH_PER_CPY_SZ - ua_l);

            cache_ofst += FLASH_PER_CPY_SZ;

            for (int i = 0; i < ((OMW_FLASH_SS - cache_ofst) >> FLASH_PER_CPY_SZ_BITS); i++)
            {
                flashRead((char *)tmp_buf, (char *)(addr_st + cache_ofst), FLASH_PER_CPY_SZ);
                flashProgram((char *)(OMW_FLASH_OVWT_CACHE_ADDR + cache_ofst), (char *)tmp_buf, FLASH_PER_CPY_SZ);

                cache_ofst += FLASH_PER_CPY_SZ;
            }
        }

        flash_move_cache_data_to_buf(addr_st, tmp_buf);
    }
	#endif
}
#endif

void omw_flash_get_uid( uint32_t * data)
{
    int i=0;
    *(reg32_t*)(REG_CMD_TYPE) = CMD_ADDR_READ;
    *(reg32_t*)(REG_CMD_CODE) = 0x4B;
    *(reg32_t*)(REG_CMD_LEN)  = 16;
    *(reg32_t*)(REG_CMD_ADDR) = 0x00000000;
    *(reg32_t*)(REG_CMD_REQ)  = 1;

    for(i=0;i<4;i++)
    {
        data[i] = *(reg32_t*)(REG_CMD_DATA);
    }
}

uint32_t omw_flash_get_device_address( uint32_t * data)
{
  omw_flash_get_uid(data);
  uint32_t addr_1 = data[0]^data[2]^data[3];
  uint16_t  addr_2 =(uint16_t) (data[1]>>16)^(data[1]);
  uint32_t addr = (uint32_t) (addr_1<<8)  | addr_2 ;
  return addr;
}

#define ADDR_SZ  6
void omw_flash_get_device_addr(uint8_t *dev_addr)
{
   uint32_t data[5];
   uint8_t * psrc = (uint8_t *)data;

   omw_flash_get_uid(data);

    psrc[16] = psrc[0];
    psrc[17] = psrc[1];

    for (int i = 0; i < ADDR_SZ; i++)
    {
       dev_addr[i] = psrc[i] ^ psrc[i + 6] ^ psrc[i + 12];
    }
}
