//#############################################################################
//
// FILE:   ipc_ex2_msgqueue_cm.c
//
// TITLE:  IPC example with interrupt and message queue
//
//! \addtogroup driver_cm_c28x_dual_example_list
//! <h1> IPC message passing example with interrupt and message queue </h1>
//!
//! This example demonstrates how to configure IPC and pass information from
//! C28x to CM core with message queues.
//! It is recommended to run the C28x1 core first, followed by the CM core.
//!
//! \b External \b Connections \n
//!  - None.
//!
//! \b Watch \b Variables \n
//!  - None.
//!
//
//#############################################################################
// $Copyright:
// Copyright (C) 2022 Texas Instruments Incorporated - http://www.ti.com
//
// Redistribution and use in source and binary forms, with or without 
// modification, are permitted provided that the following conditions 
// are met:
// 
//   Redistributions of source code must retain the above copyright 
//   notice, this list of conditions and the following disclaimer.
// 
//   Redistributions in binary form must reproduce the above copyright
//   notice, this list of conditions and the following disclaimer in the 
//   documentation and/or other materials provided with the   
//   distribution.
// 
//   Neither the name of Texas Instruments Incorporated nor the names of
//   its contributors may be used to endorse or promote products derived
//   from this software without specific prior written permission.
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// $
//###########################################################################
/*
 * Команды бывают следующих типов:

    0x00 - чтение
    0x01 - запись
    0x02 - verify
    0x03 - перезагрузка устройства
    0xFF - конец передачи (Flush)

Передаваемый по IPC адрес является относительным.
 *

ID устройства:

Flash - A0
EMIF - A1
BL25CM1A 1M bits - A2
GD25Q16E 16M-bit (2M*8) - A3
ZD24C02A, 2K - A4

Command = 000100A3 = запись в GD25Q16E
 *
 */
//
// Included Files
//
#include "cm.h"
#include "ipc.h"

//
// Defines
//
#define IPC_CMD_READ_MEM   0x1001
#define IPC_CMD_RESP       0x2001

#define TEST_PASS          0x5555
#define TEST_FAIL          0xAAAA

#define WRONG_COMMAND       0x10
#define ERROR_VERIFY        0x11
#define FLASH_ERR           0x12
#define FLASH_FAIL          0x13
#define FLASH_ECC_FAIL      0x14
#define WRONG_LENGHT        0x15
#define WRONG_ADDR          0x16
#define WRONG_ID            0x17
#define BUSY                0x18

#define COMMAND_ACCEPTED    0x20
#define DONE_SUCCESS        0x21

IPC_MessageQueue_t messageQueue;

uint16_t WriteToCpu1, ReadFromCpu1;
uint16_t WriteToCpu2, ReadFromCpu2;
uint16_t copyBuf1,copyBuf2,fillBuf1,ErraseBuff,Fiil0Buff,TheEndGD25Q16E;
IPC_Message_t TxMsg, RxMsg;
//uint16_t IntNum = 1;
uint16_t GetMes[16];
uint16_t PutMes[16];
uint16_t offset;

uint16_t  TempConst = 2;
//uint16_t CounterCPU1Blocks = 0;

uint32_t Command=0x0100A3,StartAddr=0x1E7040,Data=160;
uint32_t InCommand,InAddr,InData;
uint16_t Fill_num = 0x0;

uint16_t Array[256]=
{
0x27, 0x17, 0x00, 0x02, 0x00, 0x07, 0x00, 0x0A,
0x27, 0x18, 0x00, 0x02, 0x00, 0x08, 0x00, 0x0A,
0x27, 0x19, 0x00, 0x02, 0x00, 0x09, 0x00, 0x0A,
0x27, 0x1A, 0x00, 0x02, 0x00, 0x0A, 0x00, 0x0A,
0x27, 0x1B, 0x00, 0x02, 0x00, 0x0B, 0x00, 0x0A,
0x27, 0x1C, 0x00, 0x02, 0x00, 0x0C, 0x00, 0x0A,
0x27, 0x1D, 0x00, 0x02, 0x00, 0x0D, 0x00, 0x0A,
0x27, 0x1E, 0x00, 0x02, 0x00, 0x0E, 0x00, 0x0A,
0x27, 0x1F, 0x00, 0x02, 0x00, 0x0F, 0x00, 0x0A,
0x27, 0x20, 0x00, 0x02, 0x00, 0x10, 0x00, 0x0A,
0x27, 0x21, 0x00, 0x02, 0x27, 0x22, 0x00, 0x02,
0x00, 0x11, 0x00, 0x0A, 0x27, 0x23, 0x00, 0x02,
0x00, 0x12, 0x00, 0x0A, 0x27, 0x24, 0x00, 0x02,
0x00, 0x13, 0x00, 0x0A, 0x27, 0x25, 0x00, 0x02,
0x00, 0x14, 0x00, 0x0A, 0x27, 0x26, 0x00, 0x02,
0x00, 0x15, 0x00, 0x0A, 0x27, 0x27, 0x00, 0x02,
0x00, 0x16, 0x00, 0x0A, 0x27, 0x28, 0x00, 0x02,
0x00, 0x17, 0x00, 0x0A, 0x27, 0x29, 0x00, 0x02,
0x00, 0x18, 0x00, 0x0A, 0x27, 0x2A, 0x00, 0x02,
0x00, 0x19, 0x00, 0x0A, 0x27, 0x2B, 0x00, 0x02,
0x27, 0x1F, 0x00, 0x02, 0x00, 0x0F, 0x00, 0x0A,
0x27, 0x20, 0x00, 0x02, 0x00, 0x10, 0x00, 0x0A,
0x27, 0x21, 0x00, 0x02, 0x27, 0x22, 0x00, 0x02,
0x00, 0x11, 0x00, 0x0A, 0x27, 0x23, 0x00, 0x02,
0x00, 0x12, 0x00, 0x0A, 0x27, 0x24, 0x00, 0x02,
0x00, 0x13, 0x00, 0x0A, 0x27, 0x25, 0x00, 0x02,
0x00, 0x14, 0x00, 0x0A, 0x27, 0x26, 0x00, 0x02,
0x00, 0x15, 0x00, 0x0A, 0x27, 0x27, 0x00, 0x02,
0x00, 0x16, 0x00, 0x0A, 0x27, 0x28, 0x00, 0x02,
0x00, 0x17, 0x00, 0x0A, 0x27, 0x29, 0x00, 0x02,
0x00, 0x18, 0x00, 0x0A, 0x27, 0x2A, 0x00, 0x02,
0x00, 0x19, 0x00, 0x0A, 0x27, 0x2B, 0x00, 0x02
};





// IPC ISR for Flag 1
// C28x core sends data with message queue using Flag 0
//

void FillBuff1_num(uint16_t num)
{
    uint16_t  i;
    uint16_t   * Buffer = (uint16_t *)CMTOCPU1MSGRAM0_BASE;

    for(i=0; i < 2048; i++)
    {
        Buffer[i] = num;
    }
}





void FillBuff1Array(void)
{
    uint16_t  i,j,a,b;
    uint16_t   * Buffer = (uint16_t *)CMTOCPU1MSGRAM0_BASE;
    for(j=0; j< 16; j++)
    {
        for(i=0; i < 256; i++)
        {
            a = Array[i*2];
            b = Array[i*2+1];
            Buffer[i+256*j] = b+(a<<8);
        }
    }
}

uint16_t ErrVerify;


void verifyArray(void)
{
    uint16_t  i,j,a,b,r1,r2;
    uint16_t   * Buffer = (uint16_t *)CPU1TOCMMSGRAM0_BASE;
    for(j=0; j< 16; j++)
    {
        for(i=0; i < 256; i++)
        {
            a = Array[i*2];
            b = Array[i*2+1];

            r1 = Buffer[i+80*j];
            r2 = b+(a<<8);

            if(r1 != r2)
            {
                ErrVerify++;
            }
        }
    }
}





void FillBuff1(void)
{
    uint16_t  i,j,a,b;
    uint16_t   * Buffer = (uint16_t *)CMTOCPU1MSGRAM0_BASE;

    for(i=0; i < 2048; i++)
    {
        j = i+offset & 0x7F;
        a = (2*j<<8);
        b = (2*j+1);
        //Buffer = (uint16_t *)(CMTOCPU1MSGRAM0_BASE+2*i);
        Buffer[i] = a+b;
    }
}


void buffCopy1(void)
{
    uint16_t  i;
    uint16_t   * Buffer = (uint16_t *)CMTOCPU1MSGRAM0_BASE;
    uint16_t   * GetFromCmBuff = (uint16_t *)CPU1TOCMMSGRAM0_BASE;
    for(i=0; i < 2048; i++)
    {
        Buffer[i] = GetFromCmBuff[i];
    }
}

void buffCopy2(void)
{
    uint16_t  i;
    uint16_t   * Buffer = (uint16_t *)CMTOCPU2MSGRAM0_BASE;
    uint16_t   * GetFromCmBuff = (uint16_t *)CPU2TOCMMSGRAM0_BASE;
    for(i=0; i < 2048; i++)
    {
        Buffer[i] = GetFromCmBuff[i];
    }
}

void putMessage_to_CPU1(uint16_t  IntNum)
{
//    uint16_t  i;
//    uint16_t   * Buffer = (uint16_t *)CMTOCPU1MSGRAM0_BASE;
//    for(i=0; i < 2048; i++)
//    {
//        Buffer[i] = i*TempConst;
//    }
    IPC_setFlagLtoR(IPC_CM_L_CPU1_R, (1<<IntNum));
}

void putMessage_to_CPU2(uint16_t  IntNum)
{
//    uint16_t  i;
//    uint16_t   * Buffer = (uint16_t *)CMTOCPU2MSGRAM0_BASE;
//    for(i=0; i < 2048; i++)
//    {
//        Buffer[i] = i*TempConst;
//    }
    IPC_setFlagLtoR(IPC_CM_L_CPU2_R, (1<<IntNum));
}



void getMessage_from_CPU1(uint16_t * Addr, uint16_t IntNum)
{
    uint16_t * GetFromCmBuff;
    uint16_t i;
    GetFromCmBuff = (uint16_t *)CPU1TOCMMSGRAM0_BASE;
    for(i=0; i < 16; i++)
    {
        Addr[i] = GetFromCmBuff[i];
    }
    IPC_readCommand(IPC_CM_L_CPU1_R, 0, 0, &InCommand, &InAddr, &InData );
}

void getMessage_from_CPU2(uint16_t * Addr, uint16_t IntNum)
{
    uint16_t * GetFromCmBuff;
    uint16_t i;
    GetFromCmBuff = (uint16_t *)CPU2TOCMMSGRAM0_BASE;
    for(i=0; i < 16; i++)
    {
        Addr[i] = GetFromCmBuff[i];
    }
    IPC_readCommand(IPC_CM_L_CPU2_R, 0, 0, &InCommand, &InAddr, &InData );
}

uint16_t CounterISR[4] = {0,0,0,0};

__interrupt void IPC1_ISR1()
{


    getMessage_from_CPU1(GetMes,16);

    if(WriteToCpu1 != 2 )
    {
        putMessage_to_CPU1(0);
    }
    else WriteToCpu1 = 0;

    //
    // Acknowledge the flag
    //
    CounterISR[0]++;
    IPC_ackFlagRtoL(IPC_CM_L_CPU1_R, IPC_FLAG1);
}






uint16_t ErrStage = 0, TestErrCommand = 0;
uint16_t stage=0, read_now = 1;
uint16_t CountErr[257];



__interrupt void IPC2_ISR1()
{


    getMessage_from_CPU2(GetMes,16);

    if(WriteToCpu2 != 2 )
    {
        putMessage_to_CPU2(0);
    }
    else WriteToCpu2 = 0;

    //
    // Acknowledge the flag
    //
    CounterISR[2]++;
    IPC_ackFlagRtoL(IPC_CM_L_CPU2_R, IPC_FLAG1);
}


__interrupt void IPC2_ISR0()
{

    IPC_readCommand(IPC_CM_L_CPU2_R, 0, 0, &InCommand, &InAddr, &InData );
    getMessage_from_CPU1(GetMes,16);

    if(WriteToCpu2 != 2 )
    {
        putMessage_to_CPU2(0);
    }
    else WriteToCpu2 = 0;

    //
    // Acknowledge the flag
    //
    CounterISR[3]++;
    IPC_ackFlagRtoL(IPC_CM_L_CPU2_R, IPC_FLAG0);
}
//
// Main
//


void DoItCPU1(void)
{
    if(WriteToCpu1 == 1)
    {
        WriteToCpu1 = 2;
        IPC_sendCommand(IPC_CM_L_CPU1_R, 0, 0, Command, StartAddr, Data);
        IPC_setFlagLtoR(IPC_CM_L_CPU1_R, (1<<0));
    }
//    if(ReadFromCpu1 == 1)
//    {
//        ReadFromCpu1 = 0;
//        getMessage_from_CPU1(GetMes,16);
//        IPC_readCommand(IPC_CM_L_CPU1_R, 0, 0, &InCommand, &InAddr, &InData );
//    }
//    if(TheEndGD25Q16E == 1)
//    {
//        TheEndGD25Q16E = 0;
//        IPC_sendCommand(IPC_CM_L_CPU1_R, 0, 0, 0xFF00A3, 0, 0);
//        IPC_setFlagLtoR(IPC_CM_L_CPU1_R, (1<<0));
//    }
}


//void SendStopToGD25Q16E(void)
//{
//    IPC_sendCommand(IPC_CM_L_CPU1_R, 0, 0, 0xFF00A3, 0, 0);
//    IPC_setFlagLtoR(IPC_CM_L_CPU1_R, (1<<0));
//}



void DoItCPU2(void)
{
    if(WriteToCpu2 == 1)
    {
        WriteToCpu2 = 2;
        IPC_sendCommand(IPC_CM_L_CPU2_R, 0, 0, Command, StartAddr, Data);
        IPC_setFlagLtoR(IPC_CM_L_CPU2_R, (1<<0));
    }
//    if(ReadFromCpu2 == 1)
//    {
//        ReadFromCpu2 = 0;
//        getMessage_from_CPU2(GetMes,16);
//        IPC_readCommand(IPC_CM_L_CPU2_R, 0, 0, &InCommand, &InAddr, &InData );
//    }
}

void DoItBoof(void)
{
    if(copyBuf1 == 1)
    {
        copyBuf1 = 0;
        buffCopy1();
    }
    if(copyBuf2 == 1)
    {
        copyBuf2 = 0;
        buffCopy2();
    }
    if(fillBuf1 == 1)
    {
        fillBuf1 = 0;
        FillBuff1Array();
    }

    if(Fiil0Buff == 1)
    {
        Fiil0Buff = 0;
        FillBuff1_num(Fill_num);
    }
}

uint16_t stageStart = 145;
uint16_t stageEnd = 145;
uint16_t Size = 0x1000;
uint16_t OffsetAdr = 0;

void writeAndVerifyAllGD25Q16E(void)
{
    if(stage == 0)
    {
        Command = 0xFF00A3;
        StartAddr = 0;
        WriteToCpu1 = 1;
    }
    else
    {
        if(stage <= 256 )
        {
            if(stageStart == 0) stageStart++;
            if(stage <= 1)stage = stageStart;

            if(read_now) Command = 0x0000A3;
            else Command = 0x0100A3;
            StartAddr = (stage - 1)*0x1000 + OffsetAdr;
            Data = Size;
            WriteToCpu1 = 1;

            if(stage == stageEnd) stage = 256;
        }
    }
}

uint16_t AdrErr[2048];

void verify_num(uint16_t num)
{
    uint16_t  i,r1,r2;
    uint16_t   * Buffer = (uint16_t *)CPU1TOCMMSGRAM0_BASE;
        for(i=0; i < (Size/2); i++)
        {
            r1 = Buffer[i];
            r2 = num;

            if(r1 != r2)
            {
                AdrErr[ErrVerify] = i*2;
                ErrVerify++;
            }
        }

}


__interrupt void IPC1_ISR0()
{

    IPC_readCommand(IPC_CM_L_CPU1_R, 0, 0, &InCommand, &InAddr, &InData );
    getMessage_from_CPU1(GetMes,16);

    WriteToCpu1 = 0;
    TestErrCommand = InCommand>>16;

    if((TestErrCommand != COMMAND_ACCEPTED) && (TestErrCommand != DONE_SUCCESS) )
    {
        ErrStage++;
    }

    if(Command == 0x0000A3)
    {
        verify_num(Fill_num);
    }

    CountErr[stage] = ErrVerify;
    ErrVerify = 0;
    stage++;

    //
    // Acknowledge the flag
    //
    CounterISR[1]++;
    IPC_ackFlagRtoL(IPC_CM_L_CPU1_R, IPC_FLAG0);
}

void main(void)
{
    //
    // Initialize device clock and peripherals
    //
    CM_init();

    //
    // Clear any IPC flags if set already
    //
    IPC_clearFlagLtoR(IPC_CM_L_CPU1_R, IPC_FLAG_ALL);

    //
    // Enable IPC interrupts
    //
    IPC_registerInterrupt(IPC_CM_L_CPU1_R, IPC_INT1, IPC1_ISR1);
    IPC_registerInterrupt(IPC_CM_L_CPU1_R, IPC_INT0, IPC1_ISR0);

    IPC_registerInterrupt(IPC_CM_L_CPU2_R, IPC_INT1, IPC2_ISR1);
    IPC_registerInterrupt(IPC_CM_L_CPU2_R, IPC_INT0, IPC2_ISR0);
    //
    // Initialize message queue
    //
    //IPC_initMessageQueue(IPC_CM_L_CPU1_R, &messageQueue, IPC_INT1, IPC_INT1);

    //
    // Synchronize both the cores.
    //
    //IPC_sync(IPC_CM_L_CPU1_R, IPC_FLAG31);

    //
    // Loop forever. Wait for IPC interrupt
    //

    //FillBuff1Array();
    FillBuff1_num(Fill_num);
    stage = 257;

    while(1)
    {
        DoItCPU1();
        DoItCPU2();
        DoItBoof();

        if(WriteToCpu1 == 0) writeAndVerifyAllGD25Q16E();
    }
}


//
// End of File
//
