Astralixi Pico OS Megathread

Update:

I am trying to fix my history cycling thing, but even if I do shift + up/down it does nothing, so I need to figure out how to fix this.

Update:

No luck in trying to fix it. I may post parts of my code here tommorow (the parts in relation to the issues I have been having) for any chance of fixing this. Astrox Radio/Podcast Episode 2 2025 Releasing on Sunday!!!

Help Needed Urgently for History Cycling

History Cycling is when your on the command line, and you use the up and down arrow to cycle through your most recently used commands, but in my os’s case, you have to use shift with the up/down arrow.

add_to_history function

// Stores used commands in history so they can be used for command_history
void add_to_history(const char *command) {
    if (command[0] == '\0') return; // Don't log empty commands

    size_t len = strlen(command);
    if (len >= MAX_COMMAND_LENGTH) len = MAX_COMMAND_LENGTH - 1;

    // Add at current history_index position
    strncpy(commandHistory[history_index], command, len);
    commandHistory[history_index][len] = '\0';

    history_index = (history_index + 1) % MAX_HISTORY; // Circular buffer advance
    history_cycle_index = -1; // reset cycling on new command
}

command_history_cycle_up function

// Cycles up through command history (older entries)
void command_history_cycle_up(char *buffer, int *idx) {
    bool any = false;
    for (int i = 0; i < MAX_HISTORY; ++i) if (commandHistory[i][0] != '\0') { any = true; break; }
    if (!any) return;

    if (history_cycle_index == -1) {
        history_cycle_index = (history_index - 1 + MAX_HISTORY) % MAX_HISTORY; // Most recent command
    } else {
        history_cycle_index = (history_cycle_index - 1 + MAX_HISTORY) % MAX_HISTORY; // older command
    }

    int start = history_cycle_index;
    while (commandHistory[history_cycle_index][0] == '\0') {
        history_cycle_index = (history_cycle_index - 1 + MAX_HISTORY) % MAX_HISTORY;
        if (history_cycle_index == start) { // no commands found
            history_cycle_index = -1;
            return;
        }
    }

    // Clear current line
    while (*idx > 0) {
        display_emit('\b');
        display_emit(' ');
        display_emit('\b');
        (*idx)--;
    }

    // Copy selected command to buffer and display
    strncpy(buffer, commandHistory[history_cycle_index], MAX_COMMAND_LENGTH - 1);
    buffer[MAX_COMMAND_LENGTH - 1] = '\0';

    *idx = strlen(buffer);

    for (int i = 0; i < *idx; i++) display_emit(buffer[i]);
}

command_history_cycle_down function

void command_history_cycle_down(char *buffer, int *idx) {
    if (history_cycle_index == -1) return; // Not cycling

    history_cycle_index = (history_cycle_index + 1) % MAX_HISTORY;

    if (history_cycle_index == history_index) { // means clear line
        while (*idx > 0) {
            display_emit('\b');
            display_emit(' ');
            display_emit('\b');
            (*idx)--;
        }
        buffer[0] = '\0';
        history_cycle_index = -1;
        return;
    }

    int start = history_cycle_index;
    while (commandHistory[history_cycle_index][0] == '\0') {
        history_cycle_index = (history_cycle_index + 1) % MAX_HISTORY;
        if (history_cycle_index == start) {
            history_cycle_index = -1;
            while (*idx > 0) {
                display_emit('\b');
                display_emit(' ');
                display_emit('\b');
                (*idx)--;
            }
            buffer[0] = '\0';
            return;
        }
    }

    while (*idx > 0) {
        display_emit('\b');
        display_emit(' ');
        display_emit('\b');
        (*idx)--;
    }

    strncpy(buffer, commandHistory[history_cycle_index], MAX_COMMAND_LENGTH - 1);
    buffer[MAX_COMMAND_LENGTH - 1] = '\0';

    *idx = strlen(buffer);

    for (int i = 0; i < *idx; i++) display_emit(buffer[i]);
}

related parts from read_line function

    int idx = 0;
    history_cycle_index = -1; // Reset history position at start
    
// Detect Shift key (0xA2 or 0xA3), then wait for follow-up arrow key
        if (c == 0xA2 || c == 0xA3) {
            // Wait for next key (arrow key)
            while (!keyboard_key_available()) {
                if (user_interrupt) {
                    display_emit('\r');
                    display_emit('\n');
                    printf("^C\n");
                    user_interrupt = false;
                    buffer[0] = '\0';
                    return;
                }
                tight_loop_contents();
            }
            int next_raw = keyboard_get_key();
            if (next_raw < 0) continue;
            unsigned char next_c = (unsigned char)next_raw;

            if (next_c == 0x48) {          // Shift + Up arrow
                command_history_cycle_up(buffer, &idx);
                continue;
            } else if (next_c == 0xB6) {   // Shift + Down arrow
                command_history_cycle_down(buffer, &idx);
                continue;
            }
            // If not recognized, ignore and continue input
            continue;
        }

Please feel free to help, and spot any mistakes I have made.
Thanks!

Accroding to the source code of the keyboard firmware

https://github.com/clockworkpi/PicoCalc/blob/master/Code/picocalc_keyboard/keyboard.ino

The firmware deal with modify keys like alt and shift itself and the capslock status as well.

It will send you a page up/down scan code when you press shift + up/down.

If your are not going to modify the keyboard firmware to adapt your “OS”

you need to workaround with this FEATURE

I am using Blair’s picocalc-text-starter drivers, and I am using the keyboard.c driver in there.

HELP NEEDED (2)

Here are some updated parts of my code in relation to the history cycling thing I am trying to implement, but it won’t work.

read_line

// Reads a line from keyboard into 'buffer', echoing to display, up to maxLength-1 chars
void read_line(char *buffer, int maxLength) {
    int idx = 0;
    history_cycle_index = -1; // Reset history position at start
    bool shift_pressed = false;
    
    while (idx < maxLength - 1) {
        if (!keyboard_key_available()) {
            if (user_interrupt) {
                display_emit('\r');
                display_emit('\n');
                printf("^C\n");
                user_interrupt = false;
                buffer[0] = '\0';
                return;
            }
            tight_loop_contents();
            continue;
        }
        
        int raw = keyboard_get_key();
        if (raw < 0) continue;
        
        unsigned char c = (unsigned char)raw;
        
        // Debug: Uncomment this line to see what scan codes you're getting
        // printf("[DEBUG: Got key 0x%02X]\n", c);
        
        // Check for Page Up (0x21) - this is what the keyboard sends for Shift+Up
        if (c == 0x21) {
            command_history_cycle_up(buffer, &idx);
            continue;
        }
        
        // Check for Page Down (0x22) - this is what the keyboard sends for Shift+Down
        if (c == 0x22) {
            command_history_cycle_down(buffer, &idx);
            continue;
        }
        
        // Alternative: Check for uppercase versions of arrow keys if shift is applied
        // Some keyboards send different codes
        if (c == 0x48 || c == 0x26) { // Possible Up arrow or shifted Up arrow codes
            command_history_cycle_up(buffer, &idx);
            continue;
        }
        
        if (c == 0x50 || c == 0x28) { // Possible Down arrow or shifted Down arrow codes  
            command_history_cycle_down(buffer, &idx);
            continue;
        }
        
        // Handle Enter key - end input
        if (c == '\r' || c == '\n') break;
        
        // Handle backspace
        if (c == 0x7F || c == 0x08) {
            if (idx > 0) {
                idx--;
                display_emit('\b');
                display_emit(' ');
                display_emit('\b');
            }
            continue;
        }
        
        // Ignore unprintable characters (but not the special keys we're looking for)
        if (c < 32 || c > 126) {
            // Skip other unprintable characters
            continue;
        }
        
        // Regular printable input
        buffer[idx++] = (char)c;
        display_emit((char)c);
    }
    
    buffer[idx] = '\0';
    display_emit('\r');
    display_emit('\n');
}

command cycle up

// Cycles up through command history (older entries)
void command_history_cycle_up(char *buffer, int *idx) {
    bool any = false;
    for (int i = 0; i < MAX_HISTORY; ++i) if (commandHistory[i][0] != '\0') { any = true; break; }
    if (!any) return;

    if (history_cycle_index == -1) {
        history_cycle_index = (history_index - 1 + MAX_HISTORY) % MAX_HISTORY; // Most recent command
    } else {
        history_cycle_index = (history_cycle_index - 1 + MAX_HISTORY) % MAX_HISTORY; // older command
    }

    int start = history_cycle_index;
    while (commandHistory[history_cycle_index][0] == '\0') {
        history_cycle_index = (history_cycle_index - 1 + MAX_HISTORY) % MAX_HISTORY;
        if (history_cycle_index == start) { // no commands found
            history_cycle_index = -1;
            return;
        }
    }

    // Clear current line
    while (*idx > 0) {
        display_emit('\b');
        display_emit(' ');
        display_emit('\b');
        (*idx)--;
    }

    // Copy selected command to buffer and display
    strncpy(buffer, commandHistory[history_cycle_index], MAX_COMMAND_LENGTH - 1);
    buffer[MAX_COMMAND_LENGTH - 1] = '\0';

    *idx = strlen(buffer);

    for (int i = 0; i < *idx; i++) display_emit(buffer[i]);
}

command cycle down

void command_history_cycle_down(char *buffer, int *idx) {
    if (history_cycle_index == -1) return; // Not currently cycling through history
    
    // Move forward in history (toward newer commands)
    int next_index = (history_cycle_index + 1) % MAX_HISTORY;
    
    // Check if we've cycled back to the current position
    if (next_index == history_index) {
        // We've reached the end - clear the line
        while (*idx > 0) {
            display_emit('\b');
            display_emit(' ');
            display_emit('\b');
            (*idx)--;
        }
        buffer[0] = '\0';
        history_cycle_index = -1;
        return;
    }
    
    // Find the next non-empty command
    int start = next_index;
    while (commandHistory[next_index][0] == '\0') {
        next_index = (next_index + 1) % MAX_HISTORY;
        if (next_index == start || next_index == history_index) {
            // No more commands found - clear line
            history_cycle_index = -1;
            while (*idx > 0) {
                display_emit('\b');
                display_emit(' ');
                display_emit('\b');
                (*idx)--;
            }
            buffer[0] = '\0';
            return;
        }
    }
    
    history_cycle_index = next_index;
    
    // Clear current line
    while (*idx > 0) {
        display_emit('\b');
        display_emit(' ');
        display_emit('\b');
        (*idx)--;
    }
    
    // Display the command from history
    strncpy(buffer, commandHistory[history_cycle_index], MAX_COMMAND_LENGTH - 1);
    buffer[MAX_COMMAND_LENGTH - 1] = '\0';
    *idx = strlen(buffer);
    for (int i = 0; i < *idx; i++) display_emit(buffer[i]);
}

** add to history**

// Stores used commands in history so they can be used for command_history
void add_to_history(const char *command) {
    if (command[0] == '\0') return; // Don't log empty commands
    
    // Copy the command to the history buffer safely
    strncpy(commandHistory[history_index], command, MAX_COMMAND_LENGTH - 1);
    commandHistory[history_index][MAX_COMMAND_LENGTH - 1] = '\0'; // Ensure null termination
    
    history_index = (history_index + 1) % MAX_HISTORY; // Circular buffer advance
    history_cycle_index = -1; // reset cycling on new command
}

Please help :expressionless:
@jblanked @BlairLeduc (sorry for tagging, but you two are the most experienced with the drivers)

I don’t understand why you are having trouble here with your code? With six months of experience, surely you can read C code that you depend upon to use it correctly?

3 Likes

Ya, with more then six months under his belt, he’s apparently at masters level by now… puzzling… :thinking:

I’ve tried my best, I just can’t find a fix. I have tested it, and I know the read_line function is working, but I can guarantee that the command_history_cycle_up, and command_history_cycle_down functions aren’t working as indented and the add_to_history function might be working, but I don’t know.

Here is some of my code, I desprately need help :pleading_face:

function command_history_cycle_up

// Moves backward (up) through the command history
void command_history_cycle_up(char *buffer, int *idx) {
    if (!history_has_entries()) return;
    int original = history_cycle_idx;
    if (history_cycle_idx == -1) {
        // Start from most recent
        history_cycle_idx = (history_next_idx - 1 + MAX_HISTORY) % MAX_HISTORY;
    } else {
        // Move one entry earlier
        history_cycle_idx = (history_cycle_idx - 1 + MAX_HISTORY) % MAX_HISTORY;
    }
    // Skip over empty entries
    while (history[history_cycle_idx][0] == '\0' &&
           history_cycle_idx != original) {
        history_cycle_idx = (history_cycle_idx - 1 + MAX_HISTORY) % MAX_HISTORY;
    }
    // If we went all the way around and found nothing, stop cycling
    if (history[history_cycle_idx][0] == '\0') {
        history_cycle_idx = original;
        return;
    }
    // Clear current line
    while (*idx > 0) {
        display_emit('\b');
        display_emit(' ');
        display_emit('\b');
        (*idx)--;
    }
    strncpy(buffer, history[history_cycle_idx], MAX_COMMAND_LENGTH - 1);
    buffer[MAX_COMMAND_LENGTH - 1] = '\0';
    *idx = strlen(buffer);
    for (int i = 0; i < *idx; i++) {
        display_emit(buffer[i]);
    }
}

function command_history_cycle_down

// Moves forward (down) through the command history or clears the line at newest
void command_history_cycle_down(char *buffer, int *idx) {
    if (!history_has_entries() || history_cycle_idx == -1) return;
    int original = history_cycle_idx;
    int next_idx = (history_cycle_idx + 1) % MAX_HISTORY;
    // If at or past newest command, clear line
    if (next_idx == history_next_idx || history[next_idx][0] == '\0') {
        while (*idx > 0) {
            display_emit('\b');
            display_emit(' ');
            display_emit('\b');
            (*idx)--;
        }
        buffer[0] = '\0';
        history_cycle_idx = -1;
        return;
    }
    history_cycle_idx = next_idx;
    // Skip empty entries
    while (history[history_cycle_idx][0] == '\0' &&
           history_cycle_idx != original) {
        history_cycle_idx = (history_cycle_idx + 1) % MAX_HISTORY;
        if (history_cycle_idx == history_next_idx) {
            history_cycle_idx = -1;
            buffer[0] = '\0';
            while (*idx > 0) {
                display_emit('\b');
                display_emit(' ');
                display_emit('\b');
                (*idx)--;
            }
            return;
        }
    }
    // Clear current line
    while (*idx > 0) {
        display_emit('\b');
        display_emit(' ');
        display_emit('\b');
        (*idx)--;
    }
    strncpy(buffer, history[history_cycle_idx], MAX_COMMAND_LENGTH - 1);
    buffer[MAX_COMMAND_LENGTH - 1] = '\0';
    *idx = strlen(buffer);
    for (int i = 0; i < *idx; i++) {
        display_emit(buffer[i]);
    }
}

function add_to_history

// Add command to history; overwrites oldest if buffer full
void add_to_history(const char *command) {
    if (command[0] == '\0') return; // Do not store empty commands

    strncpy(history[history_next_idx], command, MAX_COMMAND_LENGTH - 1);
    history[history_next_idx][MAX_COMMAND_LENGTH - 1] = '\0'; // Ensure null terminated

    history_next_idx = (history_next_idx + 1) % MAX_HISTORY;
    history_cycle_idx = -1; // Reset cycling position when new command added
}

Please help, i’ve been working on this same issue for the last 5 days…

Listen @Astrox, when you wrote me with this text and snippets of code:

I interpreted this as not asking for help, it is expecting, no, telling me to help you. I am no longer going to be to be part of this circus.

8 Likes

No, no more, I’m tired of it too.

5 Likes

tumblr_b942e2909ae9e4630c098cd288227448_647f1a87_250

2 Likes

3 Likes

Astralixi OS Version Beta Released!

Thanks to Blair Leduc for the drivers, and this whole community for any contributions.

AstralixiOS Version BETA Release Devlog

Update:

I have made the time actually count! This may seem confusing, so let me explain. Before, time was just a static string, which wouldn’t update every minute, hour, etc. So I fixed that, and now, the time actually accurately updates.

Insane Opportunity

As many of you know, Astralixi OS has already seen its Alpha and Beta releases — and now, I’m looking to create a “team”! I’m currently searching for around 3 contributors to join me in pushing Astralixi even further. Whether you’re into systems programming, UI/UX (future of Astralixi OS), or just passionate about OS development, this is a great chance to get involved. If you’re interested in contributing, please fill out the application form here:
:backhand_index_pointing_right: https://take.supersurvey.com/QB50PAFU4

Disclaimer: These contributors will be on a 6 month “contract”, they can get kicked at any time, for open sourcing code, not contributing, etc.

GUIs will be added to Astralixi OS in version two or three and onwards. Version one will have more commands, and improvements.

The taskbar will show battery percentage, time, and will have a quick access menu button.

Opinions needed on designs: