<commit_before>#include "stm32f4xx.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include "serial.h"
#include "menu.h"
#include "timer.h"
#include "microphone.h"

char* Menu_Commands_Text[MENU_NUM_ITEMS] = {
    "Turn all off",
    "Turn on (mask)",
    "Random (0 - steady, 1 - change on beat)",
    "Equalizer",
    "Turn all outputs on",
    "Walking Ones",
    "Walking Zeros",
};

char command[RXBUFFERSIZE + 1];
uint8_t command_len = 0;
static void handle_command();
static void equalizer(int16_t *data);
static void random(int16_t *data);
static void turnOnNum(uint8_t num);
static void turnOnMask(uint16_t mask);
static void walking_ones(void);
static void walking_zeros(void);
extern volatile uint32_t Num_Ticks;

void display_menu()
{
    for(int i = 0; i < MENU_NUM_ITEMS; i++)
    {
        printf("%d - %s\r\n", i, Menu_Commands_Text[i]);
    }
    printf("\r\n");
}

void process_menu()
{
    uint8_t read_len = read(0, &command[command_len], RXBUFFERSIZE - command_len);
    command_len += read_len;

    /* Wait to receive entire command */
    if((command_len > 0) && (command[command_len-1] == '\r'))
    {
        command[command_len] = '\0';
        printf("Command: %s\r\n", command);
        display_menu();

        handle_command();

        command_len = 0;
    }

    /* Prevent overflow */
    if(command_len >= RXBUFFERSIZE)
        command_len = 0;
}

static void handle_command()
{
    char *endptr;
    long int command_num = strtol(command, &endptr, 0);
    sample_collected_fp = NULL; /* Stop collecting samples */
    timer_callback_handler = NULL;
    timer_stopInterval();

    switch(command_num)
    {
        case MENU_OFF:
            turnOnNum(0);
            break;
        case MENU_ON:
            /* Get the turn on mask */
            {
                long int mask = strtol(endptr, NULL, 0);
                turnOnMask(mask);
                break;
            }
        case MENU_RANDOM:
            {
                long int submenu = strtol(endptr, NULL, 0);

                if(submenu == 0)
                {
                    uint32_t randnum = RNG_GetRandomNumber();
                    turnOnMask((uint16_t)(randnum & 0xFFFF));
                }
                else if(submenu == 1)
                {
                    sample_collected_fp = random;
                }
                else
                {
                    printf("Invalid submenu");
                }
                break;
            }
        case MENU_EQ:
            sample_collected_fp = equalizer;
            break;
        case MENU_ALL_ON:
            turnOnMask(0xFFFF);
            break;
        case MENU_WALKING_ONES:
            /* Get the interval */
            {
                long int mask = strtol(endptr, NULL, 0);
                if(mask == 0) /* Default to 1 second */
                    mask = 1000;
                timer_callback_handler = walking_ones;
                timer_startInterval((mask * 2) - 1);
            }
            break;
        case MENU_WALKING_ZEROS:
            /* Get the interval */
            {
                long int mask = strtol(endptr, NULL, 0);
                if(mask == 0) /* Default to 1 second */
                    mask = 1000;
                timer_callback_handler = walking_zeros;
                timer_startInterval((mask * 2) - 1);
            }
            break;
        default:
            printf("No such command\r\n");
            break;
        
    }
}

static void equalizer(int16_t *data)
{
    const uint16_t num_instant_energy_samples = 1600;
    const uint16_t num_historic_energy_samples = 50;

    static double historic_energy_samples[50];
    static int8_t historic_energy_sample_idx = 0;
    static double instant_energy_avg = 0;
    static int16_t instant_energy_avg_cnt = 0;

    /* Keep a running sum of each sample. */
    for(int i = 0; i < 16; i++)
        instant_energy_avg += data[i] * data[i];
    instant_energy_avg_cnt += 16;

    if(instant_energy_avg_cnt == num_instant_energy_samples) // We have 800 samples (1/20th of a second)
    {
        /* Find current min and max */
        double min = historic_energy_samples[0];
        double max = historic_energy_samples[0];
        for(int i = 1; i < num_historic_energy_samples; i++)
        {
            if(historic_energy_samples[i] < min)
                min = historic_energy_samples[i];
            else if(historic_energy_samples[i] > max)
                max = historic_energy_samples[i];
        }
        historic_energy_samples[historic_energy_sample_idx++] = instant_energy_avg;
        if(historic_energy_sample_idx >= num_historic_energy_samples)
            historic_energy_sample_idx = 0;

        double step = (max - min) / 8;
        uint16_t turn_on = (uint16_t)((instant_energy_avg - min) / step) + 0.5;
        turnOnNum(turn_on);

        instant_energy_avg = 0;
        instant_energy_avg_cnt = 0;
    }
}

/* Algorithm comes from http://archive.gamedev.net/archive/reference/programming/features/beatdetection/index.html */
static void random(int16_t *data)
{
    const uint16_t num_instant_energy_samples = 800;
    const uint16_t num_historic_energy_samples = 20;

    static double historic_energy_samples[20];
    static int8_t historic_energy_sample_idx = 0;
    static double instant_energy_avg = 0;<commit_msg>Quick change to oscillator, will only turn off one line at a time<commit_after>#include "stm32f4xx.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include "serial.h"
#include "menu.h"
#include "timer.h"
#include "microphone.h"

char* Menu_Commands_Text[MENU_NUM_ITEMS] = {
    "Turn all off",
    "Turn on (mask)",
    "Random (0 - steady, 1 - change on beat)",
    "Equalizer",
    "Turn all outputs on",
    "Walking Ones",
    "Walking Zeros",
};

char command[RXBUFFERSIZE + 1];
uint8_t command_len = 0;
static void handle_command();
static void equalizer(int16_t *data);
static void random(int16_t *data);
static void turnOnNum(uint8_t num);
static void turnOnMask(uint16_t mask);
static void walking_ones(void);
static void walking_zeros(void);
extern volatile uint32_t Num_Ticks;

void display_menu()
{
    for(int i = 0; i < MENU_NUM_ITEMS; i++)
    {
        printf("%d - %s\r\n", i, Menu_Commands_Text[i]);
    }
    printf("\r\n");
}

void process_menu()
{
    uint8_t read_len = read(0, &command[command_len], RXBUFFERSIZE - command_len);
    command_len += read_len;

    /* Wait to receive entire command */
    if((command_len > 0) && (command[command_len-1] == '\r'))
    {
        command[command_len] = '\0';
        printf("Command: %s\r\n", command);
        display_menu();

        handle_command();

        command_len = 0;
    }

    /* Prevent overflow */
    if(command_len >= RXBUFFERSIZE)
        command_len = 0;
}

static void handle_command()
{
    char *endptr;
    long int command_num = strtol(command, &endptr, 0);
    sample_collected_fp = NULL; /* Stop collecting samples */
    timer_callback_handler = NULL;
    timer_stopInterval();

    switch(command_num)
    {
        case MENU_OFF:
            turnOnNum(0);
            break;
        case MENU_ON:
            /* Get the turn on mask */
            {
                long int mask = strtol(endptr, NULL, 0);
                turnOnMask(mask);
                break;
            }
        case MENU_RANDOM:
            {
                long int submenu = strtol(endptr, NULL, 0);

                if(submenu == 0)
                {
                    uint32_t randnum = RNG_GetRandomNumber();
                    turnOnMask((uint16_t)(randnum & 0xFFFF));
                }
                else if(submenu == 1)
                {
                    sample_collected_fp = random;
                }
                else
                {
                    printf("Invalid submenu");
                }
                break;
            }
        case MENU_EQ:
            sample_collected_fp = equalizer;
            break;
        case MENU_ALL_ON:
            turnOnMask(0xFFFF);
            break;
        case MENU_WALKING_ONES:
            /* Get the interval */
            {
                long int mask = strtol(endptr, NULL, 0);
                if(mask == 0) /* Default to 1 second */
                    mask = 1000;
                timer_callback_handler = walking_ones;
                timer_startInterval((mask * 2) - 1);
            }
            break;
        case MENU_WALKING_ZEROS:
            /* Get the interval */
            {
                long int mask = strtol(endptr, NULL, 0);
                if(mask == 0) /* Default to 1 second */
                    mask = 1000;
                timer_callback_handler = walking_zeros;
                timer_startInterval((mask * 2) - 1);
            }
            break;
        default:
            printf("No such command\r\n");
            break;
        
    }
}

static void equalizer(int16_t *data)
{
    const uint16_t num_instant_energy_samples = 1600;
    const uint16_t num_historic_energy_samples = 50;

    static double historic_energy_samples[50];
    static int8_t historic_energy_sample_idx = 0;
    static double instant_energy_avg = 0;
    static int16_t instant_energy_avg_cnt = 0;
    static uint16_t num_on = 0;

    /* Keep a running sum of each sample. */
    for(int i = 0; i < 16; i++)
        instant_energy_avg += data[i] * data[i];
    instant_energy_avg_cnt += 16;

    if(instant_energy_avg_cnt == num_instant_energy_samples) // We have 800 samples (1/20th of a second)
    {
        /* Find current min and max */
        double min = historic_energy_samples[0];
        double max = historic_energy_samples[0];
        for(int i = 1; i < num_historic_energy_samples; i++)
        {
            if(historic_energy_samples[i] < min)
                min = historic_energy_samples[i];
            else if(historic_energy_samples[i] > max)
                max = historic_energy_samples[i];
        }
        historic_energy_samples[historic_energy_sample_idx++] = instant_energy_avg;
        if(historic_energy_sample_idx >= num_historic_energy_samples)
            historic_energy_sample_idx = 0;

        double step = (max - min) / 8;
        uint16_t turn_on = (uint16_t)((instant_energy_avg - min) / step) + 0.5;

        /* If it is louder than before, set to the proper value */
        if(turn_on >= num_on)
        {
            num_on = turn_on;
            turnOnNum(num_on);
        }
        else /* Decrement just by one if quieter */
        {
            turnOnNum(--num_on);
        }

        instant_energy_avg = 0;
        instant_energy_avg_cnt = 0;
    }
}

/* Algorithm comes from http://archive.gamedev.net/archive/reference/programming/features/beatdetection/index.html */
static void random(int16_t *data)
{
    const uint16_t num_instant_energy_samples = 800;
    const uint16_t num_historic_energy_samples = 20;

    static double historic_energy_samples[20];
    static int8_t historic_energy_sample_idx = 0;
    static double instant_energy_avg = 0;
{'fraction_non_alphanumeric': 0.10213111793389923, 'fraction_numerical': 0.0210402745168864, 'mean_word_length': 1.9407859798194371, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 20, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7501329', 'n_tokens_mistral': 3677, 'n_tokens_neox': 3381, 'n_words': 800}