/*
 * BL25CM1A.c
 *
 *  Created on: 7 сент. 2023 г.
 *      Author: seklyuts
 */
#include "f28x_project.h"
#include "spi_init.h"

#include "BL25CM1A.h"
#include "Arr.h"

#define WREN 0b00000110 //Enable Write Operations
#define WRDI 0b00000100 //Disable Write Operations
#define RDSR 0b00000101 //Read Status Register
#define WRSR 0b00000001 //Write Status Register
#define READ 0b00000011 //Read Data from Memory
#define WRITE 0b00000010 //Write Data to Memory
#define RDID 0b10000011 //Read identification page
#define WRID 0b10000010 //Write identification page
#define RDLS 0b10000011 //Reads the identification page lock status
#define LID 0b10000010 //Locks the identification page in read-only mode





void Bl25cm1a_en(void)
{
    volatile    uint16_t empty;
    Gpio_SPI_CS_BL25CM1A(0);
    transmitData(WREN);
    while(SpiRegs.SPIFFRX.bit.RXFFST != 1)
    {

    }
    Gpio_SPI_CS_BL25CM1A(1);
    empty = SpiRegs.SPIRXBUF;
}

uint16_t Bl25cm1a_ReadStatus(void)
{
    volatile    uint16_t empty;
    Gpio_SPI_CS_BL25CM1A(0);
    transmitData(RDSR);
    transmitData(0xFF);
    while(SpiRegs.SPIFFRX.bit.RXFFST != 2)
    {

    }
    Gpio_SPI_CS_BL25CM1A(1);
    empty = SpiRegs.SPIRXBUF;
    empty = SpiRegs.SPIRXBUF;
    return empty;
}

void Bl25cm1a_read_8_bytes(uint32_t Addr, uint16_t * read_data, uint16_t num_byte)//num_byte <=8
{
    volatile    uint16_t empty, i, j;
    uint16_t Stat = 1;

    Stat = Bl25cm1a_ReadStatus();
    while((Stat&0x1) != 0 )
    {
        Stat = Bl25cm1a_ReadStatus();
    }
    Gpio_SPI_CS_BL25CM1A(0);
    transmitData(READ);
    transmitData(Addr>>16);
    transmitData(Addr>>8);
    transmitData(Addr);
    for(i = 0; i<num_byte; i++) transmitData(0xFF);
    while(SpiRegs.SPIFFRX.bit.RXFFST != (num_byte+4))
    {

    }
    Gpio_SPI_CS_BL25CM1A(1);
    empty = SpiRegs.SPIRXBUF;
    empty = SpiRegs.SPIRXBUF;
    empty = SpiRegs.SPIRXBUF;
    empty = SpiRegs.SPIRXBUF;
    for(j = 0; j<num_byte; j++)
    {
        read_data[j] = SpiRegs.SPIRXBUF;
    }
}

void Bl25cm1a_write_8_bytes(uint32_t Addr, uint16_t * write_data, uint16_t num_byte)//num_byte <=8
{
    volatile    uint16_t empty, i, j;
    uint16_t Stat = 1;

    Stat = Bl25cm1a_ReadStatus();
    while((Stat&0x1) != 0 )
    {
        Stat = Bl25cm1a_ReadStatus();
    }

    Bl25cm1a_en();
    Gpio_SPI_CS_BL25CM1A(0);
    transmitData(WRITE);
    transmitData(Addr>>16);
    transmitData(Addr>>8);
    transmitData(Addr);
    for(i = 0; i<num_byte; i++) transmitData(write_data[i]);
    while(SpiRegs.SPIFFRX.bit.RXFFST != (num_byte+4))
    {

    }
    Gpio_SPI_CS_BL25CM1A(1);
    empty = SpiRegs.SPIRXBUF;
    empty = SpiRegs.SPIRXBUF;
    empty = SpiRegs.SPIRXBUF;
    empty = SpiRegs.SPIRXBUF;
    for(j = 0; j<num_byte; j++)
    {
        empty = SpiRegs.SPIRXBUF;
    }
}

uint16_t  Bl25cm1a_verify_8_bytes(uint32_t Addr, uint16_t * verify_data, uint16_t num_byte)//num_byte <=8
{
    volatile    uint16_t empty, i, j;
    uint16_t Stat = 1;
    uint16_t Err = 0;

    Stat = Bl25cm1a_ReadStatus();
    while((Stat&0x1) != 0 )
    {
        Stat = Bl25cm1a_ReadStatus();
    }
    Gpio_SPI_CS_BL25CM1A(0);
    transmitData(READ);
    transmitData(Addr>>16);
    transmitData(Addr>>8);
    transmitData(Addr);
    for(i = 0; i<num_byte; i++) transmitData(0xFF);
    while(SpiRegs.SPIFFRX.bit.RXFFST != (num_byte+4))
    {

    }
    Gpio_SPI_CS_BL25CM1A(1);
    empty = SpiRegs.SPIRXBUF;
    empty = SpiRegs.SPIRXBUF;
    empty = SpiRegs.SPIRXBUF;
    empty = SpiRegs.SPIRXBUF;
    for(j = 0; j<num_byte; j++)
    {
        if(verify_data[j] != SpiRegs.SPIRXBUF) Err++;
    }
    return Err;
}

void Bl25cm1a_read_data(uint32_t Addr, uint16_t quant8, uint16_t * read_data)
{
    uint32_t i=0;
    uint16_t addr_read_data[8];

    if(quant8 > 8)
    {
        for(i = 0; i < (quant8-8); i += 8)
        {                                                                       //в этом цикле только полные посылки по 8 байт
            Bl25cm1a_read_8_bytes(Addr+i, addr_read_data, 8);
            copy8_to_16(addr_read_data, read_data, 4);
            read_data+=4;
        }
    }
    if(i < quant8)
    {                                                                           //тут м.б. от 1 до 8 байт
        Bl25cm1a_read_8_bytes(Addr+i, addr_read_data, (quant8 - i));            //читаем оставшиеся байты
        if((quant8 - i) & 1) {addr_read_data[quant8] = 0; quant8++; }           //если байт нечётное число, то дополняем до чётного нулём чтобы записать 16-битными словами в буфер
        copy8_to_16(addr_read_data, read_data, (quant8 - i)/2);
    }
}



uint16_t Bl25cm1a_verify_data(uint32_t Addr, uint16_t quant8, uint16_t * verify_data)
{
    uint32_t i=0;
    uint16_t addr_vfy_data[8];
    uint16_t quant16;

    if(quant8 > 8)
    {
        for(i = 0; i < (quant8-8); i += 8)
        {                                                                    //в этом цикле только полные посылки по 8 байт
            copy16_to_8(verify_data, addr_vfy_data, 4);
            if(Bl25cm1a_verify_8_bytes(Addr+i, addr_vfy_data, 8)) return 1;
            verify_data+=4;
        }
    }
    if(i < quant8)
    {                                                               //тут м.б. от 1 до 8 байт
        quant16 = quant16bitWords(quant8-i);
        copy16_to_8(verify_data, addr_vfy_data, quant16);
        if(Bl25cm1a_verify_8_bytes(Addr+i, addr_vfy_data, (quant8 - i))) return 1;
    }
    return 0;
}

void Bl25cm1a_write_1_page(uint32_t Addr, uint16_t quant8, uint16_t * write_data)
{
    uint32_t i=0;
    uint16_t addr_write_data[8];
    uint16_t quant16;

    if(quant8 > 8)
    {
        for(i = 0; i < (quant8-8); i += 8)
        {                                                   //в этом цикле только полные посылки по 8 байт
            copy16_to_8(write_data, addr_write_data, 4);
            Bl25cm1a_write_8_bytes(Addr+i, addr_write_data, 8);
            write_data += 4;
        }
    }
    if(i < quant8)
    {                                                       //тут м.б. от 1 до 8 байт
        quant16 = quant16bitWords(quant8-i);
        copy16_to_8(write_data, addr_write_data, quant16);
        Bl25cm1a_write_8_bytes(Addr+i, addr_write_data, (quant8 - i));
    }
}

void Bl25cm1a_write_data(uint32_t Addr_8bit, uint16_t quant_8bit, uint16_t * write_data)
{
    uint16_t * addr_write_data = write_data;
    uint16_t page_quant_8bit = 0;

    while( (Addr_8bit&0xFF)+(quant_8bit) > BL25CM1A0_PAGE)           //если данные выходят за границу текущей страницы
    {
        page_quant_8bit = BL25CM1A0_PAGE - (Addr_8bit&0xFF);       //вычисляем кол-во байт данных до конца текущей страницы
        Bl25cm1a_write_1_page(Addr_8bit,  page_quant_8bit, addr_write_data); //записываем эти данные на текущую страницу
        Addr_8bit += page_quant_8bit;                                             //перелистываем страницу внешней памяти
        addr_write_data += page_quant_8bit/2;                                  //шагаем на следующие незаписанные данные в буфере
        quant_8bit -= page_quant_8bit;                                            //уменьшаем кол-во данных на величину которую уже записали
    }
    if(quant_8bit > 0)
    {
        Bl25cm1a_write_1_page(Addr_8bit,  quant_8bit, addr_write_data); //если данные для записи остались, то записываем их
    }
}
