/**
  ******************************************************************************
  * File Name          : main.c
  * Description        : Main program body
  ******************************************************************************
  *
  * COPYRIGHT(c) 2016 STMicroelectronics
  *
  * Redistribution and use in source and binary forms, with or without modification,
  * are permitted provided that the following conditions are met:
  *   1. Redistributions of source code must retain the above copyright notice,
  *      this list of conditions and the following disclaimer.
  *   2. 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.
  *   3. Neither the name of STMicroelectronics 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 HOLDER 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.
  *
  ******************************************************************************
  */
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"
#include "usb_device.h"
#include "stdlib.h"

/* USER CODE BEGIN Includes */
#include "spi_sd.h"
#include "drawing.h"
#include "global.h"
/* USER CODE END Includes */

/* Private variables ---------------------------------------------------------*/
SPI_HandleTypeDef hspi1;

TIM_HandleTypeDef htim2;
DMA_HandleTypeDef hdma_tim2_ch1;
DMA_HandleTypeDef hdma_tim2_ch2_ch4;
DMA_HandleTypeDef hdma_tim2_up;

UART_HandleTypeDef huart2;

/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/
extern uint8_t eightbit[766][3];
volatile uint64_t lifeClock = 0;
volatile uint32_t instrNum = 0;
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
void Error_Handler(void);
static void MX_GPIO_Init(void);
static void MX_DMA_Init(void);
static void MX_SPI1_Init(void);
static void MX_USART2_UART_Init(void);
static void MX_TIM2_Init(void);

void HAL_TIM_MspPostInit(TIM_HandleTypeDef *htim);
        


/* USER CODE BEGIN PFP */
/* Private function prototypes -----------------------------------------------*/
//uint8_t brightness[21] = {1, 3, 5, 10, 15, 20, 25, 35, 50, 55, 255, 55, 50, 35, 25, 20, 15, 10, 5, 3, 1};
uint8_t brightness[21] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 150, 255, 150, 0, 0, 0, 0, 0, 0, 0, 0, 0};

    uint32_t script[30] = { 
        12870, // heart beating start 0
        13205,
        13530,
        13925,
        14255,
        14600,
        14980,
        15310,
        15640,
        16030,
        16360,
        16720,
        17085,
        17415,
        17755,
        18135,
        18465,
        18775, // heart beating end 17
        24310, // turn off the heart
        
        32275, // blue chest
        
        33300, // start to draw the question mark
        33785, // end to draw the question mark
        
        35295, // invert the question
        35470, // normal quetion mark
        
        35620, // invert the question
        35795, // normal quetion mark
                
        35957, // invert the question
        36127,  // normal quetion mark
        
        36290, // boom!
        37280  // clear the screen
        
        
    };
/* USER CODE END PFP */

/* USER CODE BEGIN 0 */

//#define TIM3_CCR1_Address 0x40000434 // physical memory address of Timer 3 CCR1 register
//#define TIM3_CCR2_Address 0x40000438 // physical memory address of Timer 3 CCR1 register
//#define TIM3_CCR3_Address 0x4000043C // physical memory address of Timer 3 CCR1 register
//#define TIM3_CCR4_Address 0x40000440 // physical memory address of Timer 3 CCR1 register

#define GPIOB_Address     0x40010C00 // physical memory address of GPIOB ODR register


//uint16_t    LED_BYTE_Buffer[BUF_SIZE]; 

__align(32) uint16_t WS2812_IO_High = 0xFFFF;
__align(32) uint16_t WS2812_IO_Low = 0x0000;

volatile uint8_t WS2812_TX = 1;
volatile uint8_t TIM2_overflows = 0;
static uint8_t color[3] = {0xAA, 0x11, 0x33};
__align(32) uint16_t WS2812_IO_framedata[BUF_SIZE_IN_BYTES/2];

/* simple delay counter to waste time, don't rely on for accurate timing */
void Delay(__IO uint32_t nCount)
{ 
  while(nCount--)
  { 
  }
}

/*******************************************************************************
* Function Name  : sendchar
* Description    : Retargets the C library printf function to the USART.
*******************************************************************************/
void sendchar(uint8_t ch){
    HAL_UART_Transmit(&huart2, &ch, 1, 100);
}
/******************************************************************************/
/* This function sets the color of a single pixel in the framebuffer 
 * 
 * Arguments:
 * row = the channel number/LED strip the pixel is in from 0 to 15
 * column = the column/LED position in the LED string from 0 to number of LEDs per strip
 * red, green, blue = the RGB color triplet that the pixel should display 
 */
void WS2812_framedata_setPixel(uint8_t row, uint16_t column, uint8_t red, uint8_t green, uint8_t blue)
{
	uint8_t i;
	for (i = 0; i < 8; i++)
	{
		// clear the data for pixel 
		WS2812_IO_framedata[((column*24)+i)] &= ~(0x01<<row);
		WS2812_IO_framedata[((column*24)+8+i)] &= ~(0x01<<row);
		WS2812_IO_framedata[((column*24)+16+i)] &= ~(0x01<<row);
		// write new data for pixel
		WS2812_IO_framedata[((column*24)+i)] |= ((((green<<i) & 0x80)>>7)<<row);
		WS2812_IO_framedata[((column*24)+8+i)] |= ((((red<<i) & 0x80)>>7)<<row);
		WS2812_IO_framedata[((column*24)+16+i)] |= ((((blue<<i) & 0x80)>>7)<<row);
	}
}

/* This function is a wrapper function to set all LEDs in the complete row to the specified color
 * 
 * Arguments:
 * row = the channel number/LED strip to set the color of from 0 to 15
 * columns = the number of LEDs in the strip to set to the color from 0 to number of LEDs per strip
 * red, green, blue = the RGB color triplet that the pixels should display 
 */
void WS2812_framedata_setRow(uint8_t row, uint16_t columns, uint8_t red, uint8_t green, uint8_t blue)
{
	uint8_t i;
	for (i = 0; i <= columns; i++)
	{
		WS2812_framedata_setPixel(row, i, red, green, blue);
	}
}

/* This function is a wrapper function to set all the LEDs in the column to the specified color
 * 
 * Arguments:
 * rows = the number of channels/LED strips to set the row in from 0 to 15
 * column = the column/LED position in the LED string from 0 to number of LEDs per strip
 * red, green, blue = the RGB color triplet that the pixels should display 
 */
void WS2812_framedata_setColumn(uint8_t rows, uint16_t column, uint8_t red, uint8_t green, uint8_t blue)
{
	uint8_t i;
	for (i = 0; i <= rows; i++)
	{
		WS2812_framedata_setPixel(i, column, red, green, blue);
	}
}

/* Transmit the frambuffer with buffersize number of bytes to the LEDs 
 * buffersize = (#LEDs / 16) * 24 */
void WS2812_sendbuf(uint32_t buffersize)
{		
    HAL_StatusTypeDef result;
	// transmission complete flag, indicate that transmission is taking place
	WS2812_TX = 0;
    
	// configure the number of bytes to be transferred by the DMA controller
    // !!! DO NOT FORGET TO DISABLE HT DMA INTERRUPT !!!
    if ((result = HAL_DMA_Start_IT(&hdma_tim2_up, (uint32_t)&WS2812_IO_High, (uint32_t)&GPIOB->ODR, buffersize)) != HAL_OK)
    {
        dprintf_text("Error 1");
    }
    
    if ((result = HAL_DMA_Start_IT(&hdma_tim2_ch2_ch4, (uint32_t)&WS2812_IO_Low, (uint32_t)&GPIOB->ODR, buffersize)) != HAL_OK)
    {
        dprintf_text("Error 2");
    }
    
    if ((result = HAL_DMA_Start_IT(&hdma_tim2_ch1, (uint32_t)&WS2812_IO_framedata, (uint32_t)&GPIOB->ODR, buffersize)) != HAL_OK)
    {
        dprintf_text("Error 3");
    }
	
	// clear all TIM2 flags
 	TIM2->SR = 0;
    
    // IMPORTANT: enable the TIM2 DMA requests AFTER enabling the DMA channels!
    TIM2->DIER |= TIM_DMA_CC1;
    TIM2->DIER |= TIM_DMA_CC2;
    TIM2->DIER |= TIM_DMA_UPDATE;

	// preload counter with 89 so TIM2 generates UEV directly to start DMA transfer
    TIM2->CNT = 29;
	// start TIM2
    HAL_NVIC_DisableIRQ(TIM2_IRQn);
    __HAL_TIM_DISABLE_IT(&htim2, TIM_IT_UPDATE);
	__HAL_TIM_ENABLE(&htim2);  
}


void drawSquare (uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) 
{
    uint16_t x, y = 0;
    while(!WS2812_TX);                  // wait until the last frame was transmitted
    for (x = 0; x < NUMBER_OF_COLUMNS; x++)
    {
         for(y = 0; y < NUMBER_OF_ROWS; y++) 
         {
            if (x >= x1 && x < x2 && y >= y1 && y < y2 ) {
                WS2812_framedata_setPixel(y, x, color[0], color[1], color[2]);
            } else {
                WS2812_framedata_setPixel(y, x, 0x00, 0x00, 0x00);
            }
         }
    }
    WS2812_sendbuf(BUF_SIZE_IN_BYTES);  // flush buffer to the screen         
}

void drawVerLine (uint8_t column, uint16_t y1, uint16_t y2) 
{
    uint16_t y;
    while(!WS2812_TX);                  // wait until the last frame was transmitted
    for(y = 0; y < NUMBER_OF_ROWS; y++) 
    {
        if (y >= y1 && y <= y2) {
                WS2812_framedata_setPixel(y, column, 0x33, 0x00, 0x00);
            } else {
                WS2812_framedata_setPixel(y, column, 0x00, 0x00, 0x00);
            }
    }
    WS2812_sendbuf(BUF_SIZE_IN_BYTES);  // flush buffer to the screen         
}

void drawHorLine (uint8_t row, uint16_t x1, uint16_t x2) 
{
    uint16_t x;
    while(!WS2812_TX);                  // wait until the last frame was transmitted
    for(x = 0; x < NUMBER_OF_COLUMNS; x++) 
    {
        if (x >= x1 && x <= x2) {
                WS2812_framedata_setPixel(row, x, 0x33, 0x00, 0x00);
            } else {
                WS2812_framedata_setPixel(row, x, 0x00, 0x00, 0x00);
            }
    }
    WS2812_sendbuf(BUF_SIZE_IN_BYTES);  // flush buffer to the screen         
}


void clearScreen(void){
    for(uint8_t i = 0; i < NUMBER_OF_COLUMNS; i++)
    {
        while(!WS2812_TX);
        for(uint8_t j = 0; j < NUMBER_OF_ROWS; j++) 
        {
            WS2812_framedata_setRow(j, i, 0x00, 0x00, 0x00);
        }
        WS2812_sendbuf(BUF_SIZE_IN_BYTES);           
    }
}

void drawBigHeart(int y) {
    drawHorLine (0, 14+y, 16+y);
    drawHorLine (1, 13+y, 17+y);
    drawHorLine (2, 12+y, 18+y);
    drawHorLine (3, 11+y, 19+y);
    drawHorLine (4, 10+y, 19+y);
    drawHorLine (5, 9+y, 19+y);
    drawHorLine (6, 8+y, 18+y);
    drawHorLine (7, 7+y, 17+y);
    drawHorLine (8, 7+y, 17+y);
    drawHorLine (9, 8+y, 18+y);
    drawHorLine (10, 9+y, 19+y);
    drawHorLine (11, 10+y, 19+y);
    drawHorLine (12, 11+y, 19+y);
    drawHorLine (13, 12+y, 18+y);
    drawHorLine (14, 13+y, 17+y);
    drawHorLine (15, 14+y, 16+y);
}

void drawMiddleHeart(int y) {
    drawHorLine (0, 22+y, 0+y); // don't draw 
    drawHorLine (1, 14+y, 15+y);
    drawHorLine (2, 13+y, 16+y);
    drawHorLine (3, 12+y, 17+y);
    drawHorLine (4, 11+y, 17+y);
    drawHorLine (5, 10+y, 17+y);
    drawHorLine (6, 9+y, 16+y);
    drawHorLine (7, 8+y, 15+y);
    drawHorLine (8, 8+y, 15+y);
    drawHorLine (9, 9+y, 16+y);
    drawHorLine (10, 10+y, 17+y);
    drawHorLine (11, 11+y, 17+y);
    drawHorLine (12, 12+y, 17+y);
    drawHorLine (13, 13+y, 16+y);
    drawHorLine (14, 14+y, 15+y);   
    drawHorLine (15, 22+y, 0+y); // don't draw
}

void drawSmallHeart(int y) {
    drawHorLine (0, 22+y, 0+y); // don't draw 
    drawHorLine (1, 22+y, 0+y); // don't draw
    drawHorLine (2, 14+y, 15+y);
    drawHorLine (3, 13+y, 16+y);
    drawHorLine (4, 12+y, 17+y);
    drawHorLine (5, 11+y, 17+y);
    drawHorLine (6, 10+y, 16+y);
    drawHorLine (7, 9+y, 15+y);
    drawHorLine (8, 9+y, 15+y);
    drawHorLine (9, 10+y, 16+y);
    drawHorLine (10, 11+y, 17+y);
    drawHorLine (11, 12+y, 17+y);
    drawHorLine (12, 13+y, 16+y);
    drawHorLine (13, 14+y, 15+y);
    drawHorLine (14, 22+y, 0+y); // don't draw 
    drawHorLine (15, 22+y, 0+y); // don't draw
}


void openHeart(void){
    
}
/* USER CODE END 0 */

int main(void)
{
  /* USER CODE BEGIN 1 */
//    uint8_t i, j;
//    uint8_t LED_IN_STRIP = 15;

  /* USER CODE END 1 */

  /* MCU Configuration----------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* Configure the system clock */
  SystemClock_Config();

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_SPI1_Init();
//  MX_USB_DEVICE_Init();
  MX_USART2_UART_Init();
  MX_TIM2_Init();

  /* USER CODE BEGIN 2 */

//    for(int8_t i = NUMBER_OF_COLUMNS; i >= 0; i--) 
//    {
//        while(!WS2812_TX);
//        WS2812_framedata_setPixel(8, i, 0x0A, 0x0A, 0x0A);
//        WS2812_framedata_setPixel(7, i, 0x0A, 0x0A, 0x0A);
//        WS2812_sendbuf(BUF_SIZE_IN_BYTES);           
//        Delay( 500000L );
//    }
//    
//    
//    WS2812_framedata_setRow(9, NUMBER_OF_COLUMNS, 0x0A, 0x0A, 0x0A);
//    WS2812_framedata_setRow(6, NUMBER_OF_COLUMNS, 0x0A, 0x0A, 0x0A); 
//    drawHorLine (7, 7, 17);
//    drawHorLine (8, 7, 17);
//    Delay( 500000L );
//    WS2812_framedata_setRow(10, NUMBER_OF_COLUMNS, 0x0A, 0x0A, 0x0A);
//    WS2812_framedata_setRow(5, NUMBER_OF_COLUMNS, 0x0A, 0x0A, 0x0A); 
//    drawHorLine (6, 8, 18);
//    drawHorLine (9, 8, 18);
//    Delay( 500000L );
//    WS2812_framedata_setRow(11, NUMBER_OF_COLUMNS, 0x0A, 0x0A, 0x0A);
//    WS2812_framedata_setRow(4, NUMBER_OF_COLUMNS, 0x0A, 0x0A, 0x0A); 
//    drawHorLine (5, 9, 19);
//    drawHorLine (10, 9, 19);
//    Delay( 500000L );
//    WS2812_framedata_setRow(12, NUMBER_OF_COLUMNS, 0x0A, 0x0A, 0x0A);
//    WS2812_framedata_setRow(3, NUMBER_OF_COLUMNS, 0x0A, 0x0A, 0x0A); 
//    drawHorLine (4, 10, 19);
//    drawHorLine (11, 10, 19);
//    Delay( 500000L );
//    WS2812_framedata_setRow(13, NUMBER_OF_COLUMNS, 0x0A, 0x0A, 0x0A);
//    WS2812_framedata_setRow(2, NUMBER_OF_COLUMNS, 0x0A, 0x0A, 0x0A); 
//    drawHorLine (3, 11, 19);
//    drawHorLine (12, 11, 19);
//    Delay( 500000L );
//    WS2812_framedata_setRow(14, NUMBER_OF_COLUMNS, 0x0A, 0x0A, 0x0A);
//    WS2812_framedata_setRow(1, NUMBER_OF_COLUMNS, 0x0A, 0x0A, 0x0A); 
//    drawHorLine (2, 12, 18);
//    drawHorLine (13, 12, 18);
//    Delay( 500000L );
//    WS2812_framedata_setRow(15, NUMBER_OF_COLUMNS, 0x0A, 0x0A, 0x0A);
//    WS2812_framedata_setRow(0, NUMBER_OF_COLUMNS, 0x0A, 0x0A, 0x0A); 
//    drawHorLine (1, 13, 17);
//    drawHorLine (14, 13, 17);
//    Delay( 500000L );
//    WS2812_framedata_setRow(0, NUMBER_OF_COLUMNS, 0x0A, 0x0A, 0x0A);
//    WS2812_framedata_setRow(0, NUMBER_OF_COLUMNS, 0x0A, 0x0A, 0x0A); 
//    drawHorLine (0, 14, 16);
//    drawHorLine (15, 14, 16);
//    Delay( 5000000L );
    
    for(uint8_t i = 0, y = 0; i < 6; i++)
    {
        instrNum = i * 3;
        while(lifeClock < script[instrNum]);
        drawMiddleHeart(y);   
        instrNum ++;
        while(lifeClock < script[instrNum]);
        drawBigHeart(y);     
        instrNum ++;
        while(lifeClock < script[instrNum]);
        drawSmallHeart(y);
    }
    
    ++instrNum;
    while(lifeClock < script[instrNum]); // go to the next instruction
    clearScreen();
    ++instrNum;
    while(lifeClock < script[instrNum]); // go to the next instruction
    /****** SET THE SCREEN TO THE BLUE *********/
    while(!WS2812_TX); 
    for(uint16_t j = 0; j < NUMBER_OF_ROWS; j++) 
    {
        WS2812_framedata_setRow(j, NUMBER_OF_COLUMNS, 0x00, 0x00, 0x22);
    }
    WS2812_sendbuf(BUF_SIZE_IN_BYTES); 
    /*******************************************/
    ++instrNum;
    while(lifeClock < script[instrNum]); // go to the next instruction
    drawQuestionMark();
    
    ++instrNum;
    while(lifeClock < script[instrNum]); // go to the next instruction
    drawInvertedQuestion(0x11, 0x16, 0x52);
    
    ++instrNum;
    while(lifeClock < script[instrNum]); // go to the next instruction
    drawNormalQuestion();
    
    ++instrNum;
    while(lifeClock < script[instrNum]); // go to the next instruction
    drawInvertedQuestion(0x56, 0x01, 0x07);
    
    ++instrNum;
    while(lifeClock < script[instrNum]); // go to the next instruction
    drawNormalQuestion();
    
    ++instrNum;
    while(lifeClock < script[instrNum]); // go to the next instruction
    drawInvertedQuestion(0x04, 0x65, 0x11);
        
    ++instrNum;
    while(lifeClock < script[instrNum]); // go to the next instruction
    drawNormalQuestion();
    
    ++instrNum;
    while(lifeClock < script[instrNum]); // go to the next instruction
    clearScreen();
    boom();
    
    while(1);
    
    uint8_t squareSide = 4;
//    uint8_t startPosition = 0;
    uint8_t step = 1;
    uint8_t currentY;
    int8_t x, y, x1, x2, y1, y2;
    uint32_t breaking;
    uint32_t acceleration;
    
    
    // MOVING SQUARES EXAMPLE
    while(1)
    {   
        for (y = 0; y <= (NUMBER_OF_ROWS - squareSide);) {
            breaking = 0;
            for (x = 0; (x + squareSide) <= NUMBER_OF_COLUMNS; x++) {  // move left
                x1 = x;
                y1 = y;
                x2 = x1 + squareSide;
                y2 = y1 + squareSide;
                drawSquare(x1, y1, x2, y2);
                Delay( 300000L + breaking);
                breaking += 10000;
            }
            x--;
            currentY = y;
            for (; y < currentY + squareSide; y++) {
                x1 = x + squareSide;
                y1 = y;
                x2 = x1 - squareSide;
                y2 = y1 + squareSide;
                color[0] = color[0] + rand() % 10;
                color[1] = color[1] + rand() % 10;
                color[2] = color[2] + rand() % 10;
                drawSquare(x2, y1, x1, y2); // swap x1 and x2
                Delay( 500000L );
            }
            //y = y + squareSide;
            acceleration = 0;
            for (; x >= 0; x--) {      // move right
                x1 = x + squareSide;
                y1 = y;
                x2 = x1 - squareSide;
                y2 = y1 + squareSide;
                drawSquare(x2, y1, x1, y2); // swap x1 and x2
                Delay( 100000L - acceleration);
                acceleration -= 10000;
            }
            x++;
            currentY = y;
            for (; y < currentY + squareSide; y++) {
                x1 = x + squareSide;
                y1 = y;
                x2 = x1 - squareSide;
                y2 = y1 + squareSide;
                color[0] = color[0] + rand() % 10;
                color[1] = color[1] + rand() % 10;
                color[2] = color[2] + rand() % 10;
                drawSquare(x2, y1, x1, y2); // swap x1 and x2
                Delay( 500000L );
            }
        }          
        if (squareSide  < 8) {
            squareSide+=2;
        } else {
            break;
        }
    }
    
    clearScreen();
    
    while(1)
    {
//        uint16_t i, j, cikle;
        for (uint16_t i = 0; i < NUMBER_OF_ROWS; i++)
        {
             for(uint16_t j = 0; j < NUMBER_OF_COLUMNS; j++) 
             {
                // wait until the last frame was transmitted
                while(!WS2812_TX);
                // this funtion is a wrapper and achieved the same thing, tidies up the code
                WS2812_framedata_setRow(i, j, 0x0A, 0x0A, 0x0A);
                // send the framebuffer out to the LEDs
                WS2812_sendbuf(BUF_SIZE_IN_BYTES);           
                // wait some amount of time
                Delay( 100000L );
             }
        }
        break;
    }


    while (1){
        uint16_t i, j, cikle;
		// set pixels (columns) in the defined row (channel 0) to the
		// color values defined in the colors array
        for (cikle = 0; cikle < 3; cikle++) {
            for (i = 0; i < NUMBER_OF_COLUMNS; i++)
            {
                // wait until the last frame was transmitted
                while(!WS2812_TX);
                // this funtion is a wrapper and achieved the same thing, tidies up the code
                WS2812_framedata_setRow(0, i, 0x55, 0xAA, 0x37);
                WS2812_framedata_setRow(1, i, 0xAA, 0x55, 0x0F);
                WS2812_framedata_setRow(2, i, 0x3F, 0x1F, 0x0F);
                WS2812_framedata_setRow(3, i, 0x1F, 0x5F, 0x2F);
                WS2812_framedata_setRow(4, i, 0x0F, 0x0F, 0x0F);
                WS2812_framedata_setRow(5, i, 0x00, 0x56, 0x78);
                WS2812_framedata_setRow(6, i, 0x55, 0x4A, 0x44);
                WS2812_framedata_setRow(7, i, 0x5A, 0x35, 0x1F);
                WS2812_framedata_setRow(8, i, 0x7F, 0x0F, 0x29);
                WS2812_framedata_setRow(9, i, 0x1F, 0x2F, 0x7F);
                WS2812_framedata_setRow(10, i, 0x0F, 0x3F, 0xAF);
                WS2812_framedata_setRow(11, i, 0x12, 0x16, 0x18);
                WS2812_framedata_setRow(12, i, 0x15, 0x1A, 0xF7);
                WS2812_framedata_setRow(13, i, 0x00, 0x55, 0x2F);
                WS2812_framedata_setRow(14, i, 0x0F, 0x4F, 0x5F);
                WS2812_framedata_setRow(15, i, 0x9F, 0x0F, 0x00);
                // send the framebuffer out to the LEDs
                WS2812_sendbuf(BUF_SIZE_IN_BYTES);           
                // wait some amount of time
                Delay( 100000L );
            }
            
            // all the pixels set to zero here, row by row
            for(i = 0; i < NUMBER_OF_COLUMNS; i++)
            {
                // wait until the last frame was transmitted
                while(!WS2812_TX);
                for(j = 0; j < NUMBER_OF_ROWS; j++) 
                {
                    WS2812_framedata_setRow(j, i, 0x00, 0x00, 0x00);
                }
                // send the framebuffer out to the LEDs
                WS2812_sendbuf(BUF_SIZE_IN_BYTES);           
                // wait some amount of time
                Delay( 100000L );
            }
        }
        // set all pixels to the value from the color table (in crc.c file)
        for (i = 0; i < sizeof(eightbit)/3; i++) 
            {
                while(!WS2812_TX);
                for(j = 0; j < NUMBER_OF_ROWS; j++) 
                {
                    WS2812_framedata_setRow(j, NUMBER_OF_COLUMNS, eightbit[i][0], eightbit[i][1], eightbit[i][2]);
                }
                WS2812_sendbuf(BUF_SIZE_IN_BYTES);           
                Delay( 500L );
            }
        break;
	}   

    for (uint16_t count = 0; count < 70; count++) 
    {
        uint16_t i, j;
        while(!WS2812_TX);
        for(i = 0; i < NUMBER_OF_ROWS; i++) {
            for(j = 0; j < NUMBER_OF_COLUMNS; j++) { 
                WS2812_framedata_setPixel(i, j, brightness[rand() % 21], brightness[rand() % 21], brightness[rand() % 21]);
            } 
        }
        WS2812_sendbuf(BUF_SIZE_IN_BYTES);           
        HAL_Delay(50);
    }
    
    clearScreen();

   // while(1);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
    while (1)
    {
        //	while (1){  
//        int16_t i;
//		/* first cycle through the colors on 2 LEDs chained together
//		 * last LED in the chain will receive first sent triplet
//		 * --> last LED in the chain will 'lead' 
//		 */
//		for (i = 0; i < 766; i += 5)
//		{
//			WS2812_send(&eightbit[i], 5);
//			HAL_Delay(1);
//		}
//		
//		/* cycle through the colors on only one LED
//		 * this time only the first LED that data is 
//		 * fed into will update
//		 */
////		for (i = 0; i < 766; i += 1)
////		{
////			WS2812_send(&eightbit[i], 1);
////			HAL_Delay(1);
////		}
//    }
    
//    uint8_t ledBuffer[BUF_SIZE];
//    memset(ledBuffer, 0xFF, sizeof(ledBuffer));
//    uint8_t value;
//    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_All, GPIO_PIN_RESET);
//    HAL_Delay(1);
//    __disable_irq();
//    //for (;;/*uint16_t i = 0; i < 4; i++*/){
//        for (uint16_t x = 0; x < sizeof(ledBuffer); x++) {
//            value = ledBuffer[x];
//            WRITE_START(); 
//            if (value & 0x80) {
//                WRITE1();
//            } else {
//                WRITE0();
//            }
//            WRITE_START();
//            if (value & 0x40) {
//                WRITE1();
//            } else {
//                WRITE0();
//            }
//            WRITE_START();
//            if (value & 0x20){
//                WRITE1();
//            } else {
//                WRITE0();
//            }
//            WRITE_START();
//            if (value & 0x10){
//                WRITE1();
//            } else {
//                WRITE0();
//            }
//            WRITE_START();
//            if (value & 0x08){
//                WRITE1();
//            } else {
//                WRITE0();
//            }
//            WRITE_START();
//            if (value & 0x04){
//                WRITE1();
//            } else {
//                WRITE0();
//            }
//            WRITE_START();
//            if (value & 0x02){
//                WRITE1();
//            } else {
//                WRITE0();
//            }
//            WRITE_START();
//            if (value & 0x01){
//                WRITE1();
//            } else {
//                WRITE0();
//            }
//        }
//    //}
//    __enable_irq();

//void WS2812_send(uint8_t (*color)[3], uint16_t len)
//{
//	uint8_t j;
//	uint8_t led;
//	uint16_t memaddr;
//	uint16_t buffersize;

//	buffersize = (len*24)+42;	// number of bytes needed is #LEDs * 24 bytes + 42 trailing bytes
//	memaddr = 0;				// reset buffer memory index
//	led = 0;					// reset led index

//	// fill transmit buffer with correct compare values to achieve
//	// correct pulse widths according to color values
//	while (len)
//	{	
//		for (j = 0; j < 8; j++)					// GREEN data
//		{
//			if ( (color[led][1]<<j) & 0x80 )	// data sent MSB first, j = 0 is MSB j = 7 is LSB
//			{
//				LED_BYTE_Buffer[memaddr] = 64; 	// compare value for logical 1
//			}
//			else
//			{
//				LED_BYTE_Buffer[memaddr] = 24;	// compare value for logical 0
//			}
//			memaddr++;
//		}
//		
//		for (j = 0; j < 8; j++)					// RED data
//		{
//			if ( (color[led][0]<<j) & 0x80 )	// data sent MSB first, j = 0 is MSB j = 7 is LSB
//			{
//				LED_BYTE_Buffer[memaddr] = 64; 	// compare value for logical 1
//			}
//			else
//			{
//				LED_BYTE_Buffer[memaddr] = 24;	// compare value for logical 0
//			}
//			memaddr++;
//		}
//		
//		for (j = 0; j < 8; j++)					// BLUE data
//		{
//			if ( (color[led][2]<<j) & 0x80 )	// data sent MSB first, j = 0 is MSB j = 7 is LSB
//			{
//				LED_BYTE_Buffer[memaddr] = 64; 	// compare value for logical 1
//			}
//			else
//			{
//				LED_BYTE_Buffer[memaddr] = 24;	// compare value for logical 0
//			}
//			memaddr++;
//		}
//		
//		led++;
//		len--;
//	}
//	
//	// add needed delay at end of byte cycle, pulsewidth = 0
//	while(memaddr < buffersize)
//	{
//		LED_BYTE_Buffer[memaddr] = 0;
//		memaddr++;
//	}
//    //HAL_DMA_Start_IT(&hdma_tim3_ch4_up, (uint32_t)&LED_BYTE_Buffer, TIM3_CCR4_Address, buffersize);

//    
////	DMA_SetCurrDataCounter(DMA1_Channel6, buffersize); 	// load number of bytes to be transferred
////	DMA_Cmd(DMA1_Channel6, ENABLE); 			// enable DMA channel 6
////	TIM_Cmd(TIM3, ENABLE); 						// enable Timer 3
////	while(!DMA_GetFlagStatus(DMA1_FLAG_TC6)); 	// wait until transfer complete
////	TIM_Cmd(TIM3, DISABLE); 					// disable Timer 3
////	DMA_Cmd(DMA1_Channel6, DISABLE); 			// disable DMA channel 6
////	DMA_ClearFlag(DMA1_FLAG_TC6); 				// clear DMA1 Channel 6 transfer complete flag
//}

  /* USER CODE END WHILE */

  /* USER CODE BEGIN 3 */

    }
  /* USER CODE END 3 */

}

/** System Clock Configuration
*/
void SystemClock_Config(void)
{

  RCC_OscInitTypeDef RCC_OscInitStruct;
  RCC_ClkInitTypeDef RCC_ClkInitStruct;
  RCC_PeriphCLKInitTypeDef PeriphClkInit;

  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }

  PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USB;
  PeriphClkInit.UsbClockSelection = RCC_USBCLKSOURCE_PLL_DIV1_5;
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
  {
    Error_Handler();
  }

  HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);

  HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);

  /* SysTick_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(SysTick_IRQn, 1, 0);
}

/* SPI1 init function */
static void MX_SPI1_Init(void)
{

  hspi1.Instance = SPI1;
  hspi1.Init.Mode = SPI_MODE_MASTER;
  hspi1.Init.Direction = SPI_DIRECTION_2LINES;
  hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi1.Init.NSS = SPI_NSS_HARD_OUTPUT;
  hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;
  hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi1.Init.CRCPolynomial = 10;
  if (HAL_SPI_Init(&hspi1) != HAL_OK)
  {
    Error_Handler();
  }

}

/* TIM2 init function */
static void MX_TIM2_Init(void)
{

  TIM_ClockConfigTypeDef sClockSourceConfig;
  TIM_MasterConfigTypeDef sMasterConfig;
  TIM_OC_InitTypeDef sConfigOC;

  htim2.Instance = TIM2;
  htim2.Init.Prescaler = 2;
  htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim2.Init.Period = 29; //89;
  htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
  {
    Error_Handler();
  }

  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }

  if (HAL_TIM_OC_Init(&htim2) != HAL_OK)
  {
    Error_Handler();
  }

  if (HAL_TIM_PWM_Init(&htim2) != HAL_OK)
  {
    Error_Handler();
  }

  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }

  sConfigOC.OCMode = TIM_OCMODE_TIMING;
  sConfigOC.Pulse = 8;//25;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  if (HAL_TIM_OC_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
  {
    Error_Handler();
  }

  sConfigOC.OCMode = TIM_OCMODE_PWM1;
  sConfigOC.Pulse = 17;//65;
  if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
  {
    Error_Handler();
  }

  HAL_TIM_MspPostInit(&htim2);

}

/* USART2 init function */
static void MX_USART2_UART_Init(void)
{

  huart2.Instance = USART2;
  huart2.Init.BaudRate = 115200;
  huart2.Init.WordLength = UART_WORDLENGTH_8B;
  huart2.Init.StopBits = UART_STOPBITS_1;
  huart2.Init.Parity = UART_PARITY_NONE;
  huart2.Init.Mode = UART_MODE_TX_RX;
  huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart2.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart2) != HAL_OK)
  {
    Error_Handler();
  }

}

/** 
  * Enable DMA controller clock
  */
static void MX_DMA_Init(void) 
{
  /* DMA controller clock enable */
  __HAL_RCC_DMA1_CLK_ENABLE();

  /* DMA interrupt init */
  /* DMA1_Channel2_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Channel2_IRQn, 1, 0);
  HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn);
  /* DMA1_Channel5_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Channel5_IRQn, 2, 0);
  HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn);
  /* DMA1_Channel7_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Channel7_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Channel7_IRQn);

}

/** Configure pins as 
        * Analog 
        * Input 
        * Output
        * EVENT_OUT
        * EXTI
*/
static void MX_GPIO_Init(void)
{

  GPIO_InitTypeDef GPIO_InitStruct;

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOD_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_RESET);

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_10 
                          |GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14 
                          |GPIO_PIN_15|GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5 
                          |GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9, GPIO_PIN_RESET);

  /*Configure GPIO pins : PC14 PC15 */
  GPIO_InitStruct.Pin = GPIO_PIN_14|GPIO_PIN_15;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

  /*Configure GPIO pins : PB0 PB1 PB2 PB10 
                           PB11 PB12 PB13 PB14 
                           PB15 PB3 PB4 PB5 
                           PB6 PB7 PB8 PB9 */
  GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_10 
                          |GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14 
                          |GPIO_PIN_15|GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5 
                          |GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /*Configure GPIO pin : PA15 */
  GPIO_InitStruct.Pin = GPIO_PIN_15;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @param  None
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler */
  /* User can add his own implementation to report the HAL error return state */
  while(1) 
  {
  }
  /* USER CODE END Error_Handler */ 
}

#ifdef USE_FULL_ASSERT

/**
   * @brief Reports the name of the source file and the source line number
   * where the assert_param error has occurred.
   * @param file: pointer to the source file name
   * @param line: assert_param error line source number
   * @retval None
   */
void assert_failed(uint8_t* file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
    ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */

}

#endif

/**
  * @}
  */ 

/**
  * @}
*/ 

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
