#include "stm32f1xx_hal.h"

// Array to store the GPIO banks and pins for each LED in the sequential order
const GPIO_TypeDef* gpioBanks[] = {
    GPIOB, GPIOB, GPIOB, GPIOB, GPIOA, GPIOA, GPIOA, GPIOA,
    GPIOA, GPIOA, GPIOA, GPIOA, GPIOA, GPIOA, GPIOB, GPIOB,
    GPIOB, GPIOB, GPIOB, GPIOB, GPIOB
};

const uint16_t ledPins[] = {
    GPIO_PIN_11, GPIO_PIN_10, GPIO_PIN_1, GPIO_PIN_0, GPIO_PIN_7, GPIO_PIN_6, GPIO_PIN_5, GPIO_PIN_4,
    GPIO_PIN_3, GPIO_PIN_2, GPIO_PIN_1, GPIO_PIN_0, GPIO_PIN_11, GPIO_PIN_12, GPIO_PIN_13, GPIO_PIN_14,
    GPIO_PIN_15, GPIO_PIN_5, GPIO_PIN_6, GPIO_PIN_7, GPIO_PIN_3,
};

// Define a constant for the ground pin
#define GROUND_PIN GPIO_PIN_3

// Define the input pin for signal detection
#define INPUT_PIN_B3 GPIO_PIN_15

// Function to initialize GPIO pins
static void MX_GPIO_Init(void)
{
    // Enable GPIOA and GPIOB clocks
    __HAL_RCC_GPIOA_CLK_ENABLE();
    __HAL_RCC_GPIOB_CLK_ENABLE();

    GPIO_InitTypeDef GPIO_InitStruct;

    // Configure all the LED pins as output
    for (int i = 0; i < sizeof(ledPins) / sizeof(ledPins[0]); i++)
    {
        GPIO_InitStruct.Pin = ledPins[i];
        GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; // Output push-pull mode
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; // Higher GPIO speed
        HAL_GPIO_Init((GPIO_TypeDef*)gpioBanks[i], &GPIO_InitStruct);
    }

    // Configure the ground pin as input with a pull-up resistor
    GPIO_InitStruct.Pin = GROUND_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    // Configure B3 as input with a pull-up resistor
    GPIO_InitStruct.Pin = INPUT_PIN_B3;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}


// Function to perform the sequential lighting effect
void sequentialEffect(int repeatCount)
{
    int ledCount = sizeof(ledPins) / sizeof(ledPins[0]);

    for (int repeat = 0; repeat < repeatCount; repeat++)
    {
        // Forward sequence
        for (int i = 0; i < ledCount - 2; i++)
        {
            // Turn on the three LEDs together
            HAL_GPIO_WritePin((GPIO_TypeDef*)gpioBanks[i], ledPins[i], GPIO_PIN_RESET);
            HAL_GPIO_WritePin((GPIO_TypeDef*)gpioBanks[i + 1], ledPins[i + 1], GPIO_PIN_RESET);
            HAL_GPIO_WritePin((GPIO_TypeDef*)gpioBanks[i + 2], ledPins[i + 2], GPIO_PIN_RESET);

            HAL_Delay(20); // LEDs will be OFF for 20 milliseconds

            // Turn off the three LEDs together
            HAL_GPIO_WritePin((GPIO_TypeDef*)gpioBanks[i], ledPins[i], GPIO_PIN_SET);
            HAL_GPIO_WritePin((GPIO_TypeDef*)gpioBanks[i + 1], ledPins[i + 1], GPIO_PIN_SET);
            HAL_GPIO_WritePin((GPIO_TypeDef*)gpioBanks[i + 2], ledPins[i + 2], GPIO_PIN_SET);
        }

        // Backward sequence
        for (int i = ledCount - 3; i >= 0; i--)
        {
            // Turn on the three LEDs together
            HAL_GPIO_WritePin((GPIO_TypeDef*)gpioBanks[i], ledPins[i], GPIO_PIN_RESET);
            HAL_GPIO_WritePin((GPIO_TypeDef*)gpioBanks[i + 1], ledPins[i + 1], GPIO_PIN_RESET);
            HAL_GPIO_WritePin((GPIO_TypeDef*)gpioBanks[i + 2], ledPins[i + 2], GPIO_PIN_RESET);

            HAL_Delay(20); // LEDs will be OFF for 20 milliseconds

            // Turn off the three LEDs together
            HAL_GPIO_WritePin((GPIO_TypeDef*)gpioBanks[i], ledPins[i], GPIO_PIN_SET);
            HAL_GPIO_WritePin((GPIO_TypeDef*)gpioBanks[i + 1], ledPins[i + 1], GPIO_PIN_SET);
            HAL_GPIO_WritePin((GPIO_TypeDef*)gpioBanks[i + 2], ledPins[i + 2], GPIO_PIN_SET);
        }

        HAL_Delay(5); // Wait for 5 milliseconds before repeating the effect
    }
}

// Function to perform the Tetris effect
void tetrisEffect(int repeatCount)
{
    int ledCount = sizeof(ledPins) / sizeof(ledPins[0]);

    for (int repeat = 0; repeat < repeatCount; repeat++)
    {
        int startIndex = 0;
        int endIndex = ledCount - 1;
        int direction = 1; // Direction of the stack movement (1 = left, -1 = right)

        while (1)
        {
            // Turn on both the start and end LEDs together
            HAL_GPIO_WritePin((GPIO_TypeDef*)gpioBanks[startIndex], ledPins[startIndex], GPIO_PIN_RESET);
            HAL_GPIO_WritePin((GPIO_TypeDef*)gpioBanks[endIndex], ledPins[endIndex], GPIO_PIN_RESET);
            HAL_Delay(15); // LEDs will be ON for 10 milliseconds

            startIndex += direction;
            endIndex -= direction;

            // Check if the stack has reached the middle
            if (startIndex == endIndex || startIndex - 1 == endIndex)
            {
                HAL_Delay(0); // Delay when the stack reaches the middle
                direction = -direction; // Change the direction to move back

                // Move the start index back to include the middle LED in the turn-off process
                startIndex += direction;
            }

            // Check if the stack has reached the ends
            if (startIndex < 0 || endIndex >= ledCount)
            {
                break; // Exit the loop when the stack reaches the ends
            }
        }

        // Turn off the remaining LEDs from both sides
        for (int i = 0; i < ledCount; i++)
        {
            HAL_GPIO_WritePin((GPIO_TypeDef*)gpioBanks[i], ledPins[i], GPIO_PIN_SET);
            HAL_GPIO_WritePin((GPIO_TypeDef*)gpioBanks[ledCount - 1 - i], ledPins[ledCount - 1 - i], GPIO_PIN_SET);
            HAL_Delay(15); // LEDs will be OFF for 20 milliseconds
        }

        HAL_Delay(0); // Wait for 100 milliseconds before repeating the effect
    }
}

// Function to perform the Line Move effect
void lineMoveEffect(int repeatCount)
{
    int ledCount = sizeof(ledPins) / sizeof(ledPins[0]);

    // Repeat the effect for the specified number of times
    for (int repeat = 0; repeat < repeatCount; repeat++)
    {
        // Move the lines back to their original positions
        for (int startIndexLeft = ledCount - 3, startIndexRight = 0; startIndexLeft >= 0; startIndexLeft--, startIndexRight++)
        {
            // Turn on the LEDs in the lines
            for (int i = 0; i < ledCount; i++)
            {
                if (i >= startIndexLeft && i < startIndexLeft + 3) // Choose the number of LEDs in the line (3 in this case)
                {
                    //HAL_GPIO_WritePin((GPIO_TypeDef*)gpioBanks[i], ledPins[i], GPIO_PIN_RESET); // Set the pin high
                    HAL_GPIO_WritePin((GPIO_TypeDef*)gpioBanks[i], ledPins[i], GPIO_PIN_SET); // Set the pin high
                }
                else if (i >= startIndexRight && i < startIndexRight + 3)
                {
                    //HAL_GPIO_WritePin((GPIO_TypeDef*)gpioBanks[i], ledPins[i], GPIO_PIN_RESET); // Set the pin high
                    HAL_GPIO_WritePin((GPIO_TypeDef*)gpioBanks[i], ledPins[i], GPIO_PIN_SET); // Set the pin high
                }
                else
                {
                    //HAL_GPIO_WritePin((GPIO_TypeDef*)gpioBanks[i], ledPins[i], GPIO_PIN_SET); // Set the pin low
                    HAL_GPIO_WritePin((GPIO_TypeDef*)gpioBanks[i], ledPins[i], GPIO_PIN_RESET); // Set the pin low
                }
            }

            HAL_Delay(20); // LEDs in the lines will be ON for 20 milliseconds

            // Turn off the LEDs in the lines
            for (int i = 0; i < ledCount; i++)
            {
                HAL_GPIO_WritePin((GPIO_TypeDef*)gpioBanks[i], ledPins[i], GPIO_PIN_RESET); // Set the pin low
            }
        }

        HAL_Delay(5); // Wait for 100 milliseconds before repeating the effect
    }
}

// Function to perform the Rotation effect
void rotationEffect(int repeatCount)
{
    int ledCount = sizeof(ledPins) / sizeof(ledPins[0]);

    for (int repeat = 0; repeat < repeatCount; repeat++)
    {
        for (int i = 0; i < ledCount; i++)
        {
            HAL_GPIO_WritePin((GPIO_TypeDef*)gpioBanks[i], ledPins[i], GPIO_PIN_SET);
            HAL_Delay(20); // LED will be ON for 20 milliseconds

            HAL_GPIO_WritePin((GPIO_TypeDef*)gpioBanks[i], ledPins[i], GPIO_PIN_RESET);
        }

        HAL_Delay(10); // Wait for 100 milliseconds before repeating the effect
    }
}

// Function to perform the Alternating Effect
void alternatingEffect(int repeatCount)
{
    int ledCount = sizeof(ledPins) / sizeof(ledPins[0]);

    for (int repeat = 0; repeat < repeatCount; repeat++)
    {
        for (int i = 0; i < ledCount; i++)
        {
            if (i % 2 == 0)
            {
                HAL_GPIO_WritePin((GPIO_TypeDef*)gpioBanks[i], ledPins[i], GPIO_PIN_RESET); // Turn on the LED
            }
            else
            {
                HAL_GPIO_WritePin((GPIO_TypeDef*)gpioBanks[i], ledPins[i], GPIO_PIN_SET); // Turn off the LED
            }
        }

        HAL_Delay(50);

        for (int i = 0; i < ledCount; i++)
        {
            if (i % 2 == 0)
            {
                HAL_GPIO_WritePin((GPIO_TypeDef*)gpioBanks[i], ledPins[i], GPIO_PIN_SET); // Turn off the LED
            }
            else
            {
                HAL_GPIO_WritePin((GPIO_TypeDef*)gpioBanks[i], ledPins[i], GPIO_PIN_RESET); // Turn on the LED
            }
        }

        HAL_Delay(50);
    }
}

// Function to perform a sequential blinking effect
void sequentialBlink(int repeatCount)
{
    for (int repeat = 0; repeat < repeatCount; repeat++)
    {
        // Light up the LEDs from the bottom to the top
        for (int i = 0; i < sizeof(ledPins) / sizeof(ledPins[0]); i++)
        {
            HAL_GPIO_WritePin((GPIO_TypeDef*)gpioBanks[i], ledPins[i], GPIO_PIN_SET);
            HAL_Delay(0); // LED will be ON for 50 milliseconds
        }

        // Turn off the LEDs from the top to the bottom
        for (int i = sizeof(ledPins) / sizeof(ledPins[0]) - 1; i >= 0; i--)
        {
            HAL_GPIO_WritePin((GPIO_TypeDef*)gpioBanks[i], ledPins[i], GPIO_PIN_RESET);
            HAL_Delay(20); // LED will be OFF for 50 milliseconds
        }

        HAL_Delay(10); // Wait for 100 milliseconds before repeating the effect
    }
}

// Function to read the state of PA15 multiple times and filter noise
int readPA15WithNoiseFilter(void)
{
    int numReadings = 5; // Number of readings to take
    int noiseThreshold = 3; // Threshold for noise (adjust as needed)
    int readings = 0;

    // Read PA15 multiple times and count the number of HIGH readings
    for (int i = 0; i < numReadings; i++)
    {
        if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_3) == GPIO_PIN_SET)
        {
            readings++;
        }
    }

    // If most readings are HIGH, consider it HIGH, else LOW
    if (readings >= (numReadings - noiseThreshold))
    {
        return GPIO_PIN_RESET;
    }
    else
    {
        return GPIO_PIN_SET;
    }
}

// Function to read the state of pin B3 multiple times and filter noise
int readB3WithNoiseFilter(void)
{
    int numReadings = 5; // Number of readings to take
    int noiseThreshold = 3; // Threshold for noise (adjust as needed)
    int readings = 0;

    // Read pin B3 multiple times and count the number of HIGH readings
    for (int i = 0; i < numReadings; i++)
    {
        if (HAL_GPIO_ReadPin(GPIOA, INPUT_PIN_B3) == GPIO_PIN_SET)
        {
            readings++;
        }
    }

    // If most readings are LOW, consider it LOW, else HIGH
    if (readings >= (numReadings - noiseThreshold))
    {
        return GPIO_PIN_RESET;
    }
    else
    {
        return GPIO_PIN_SET;
    }
}

// Function to detect and perform an action when the ground pin is grounded
void detectGround(void)
{
    // Use the filtered reading of PA15
    if (readPA15WithNoiseFilter() == GPIO_PIN_SET)
    {
        // Ground pin is connected to ground, perform your action here
        // For example, you can call the sequentialEffect function:

        lineMoveEffect(5);
        alternatingEffect(10);
        sequentialEffect(3);
        tetrisEffect(3);
        sequentialBlink(0);

        // Call the sequentialBlink function when B3 is high
        if (HAL_GPIO_ReadPin(GPIOA, INPUT_PIN_B3) == GPIO_PIN_RESET)
        {
            sequentialBlink(1); // Adjust the delay as needed
        }
    }
}

int main(void)
{
    // Initialize HAL library and system
    HAL_Init();

    // Initialize GPIO pins, including B3
    MX_GPIO_Init();

    int repeatCount = 1; // Set the number of times you want to repeat each effect

    while (1)
    {
        //lineMoveEffect(5);
        //alternatingEffect(10);
        //sequentialEffect(3);
        //tetrisEffect(3);
        //sequentialBlink(0);
    //}
//}
///*
        // Check the state of pin B3 with noise filtering
        if (readB3WithNoiseFilter() == GPIO_PIN_SET)
        {
            // Pin B3 is grounded or LOW, call the sequentialBlink function
            sequentialBlink(1); // Adjust the delay as needed
        }
        else
        {
            // Pin B3 is high, continue with other effects

            // Call the Line Move effect multiple times
            for (int i = 0; i < repeatCount; i++)
            {
                detectGround(); // Check if the ground pin is grounded and perform the action
            }

            // ... (other effects and their respective function calls)

            // Call the Tetris effect multiple times
            for (int i = 0; i < repeatCount; i++)
            {
                detectGround(); // Check if the ground pin is grounded and perform the action
            }
        }
    }
}
//*/
Loading
stm32-bluepill