Simple Shell

實作一個 shell,支援以下指令:

  • help
  • hello
  • timestamp
  • reboot

main.c

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
#include "shell.h"

#define CMD_LEN 128

int main() {
    shell_init();

    while (1) {
        char cmd[CMD_LEN];
        shell_input(cmd);
        shell_controller(cmd);
    }
}

shell.c

shell_input 基本上就是在 read_newline,然後處理一下 ANSI Escape。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
void shell_input(char* cmd) {
    uart_printf("\r# ");

    int idx = 0, end = 0, i;
    cmd[0] = '\0';
    char c;
    while ((c = uart_read()) != '\n') {
        // Decode CSI key sequences
        if (c == 27) {
            enum ANSI_ESC key = decode_ansi_escape();
            switch (key) {
                case CursorForward:
                    if (idx < end) idx++;
                    break;

                case CursorBackward:
                    if (idx > 0) idx--;
                    break;

                case Delete:
                    // left shift command
                    for (i = idx; i < end; i++) {
                        cmd[i] = cmd[i + 1];
                    }
                    cmd[--end] = '\0';
                    break;

                case Unknown:
                    uart_flush();
                    break;
            }
        }
        // CTRL-C
        else if (c == 3) {
            cmd[0] = '\0';
            break;
        }
        // Backspace
        else if (c == 8 || c == 127) {
            if (idx > 0) {
                idx--;
                // left shift command
                for (i = idx; i < end; i++) {
                    cmd[i] = cmd[i + 1];
                }
                cmd[--end] = '\0';
            }
        }
        else {
            // right shift command
            if (idx < end) {
                for (i = end; i > idx; i--) {
                    cmd[i] = cmd[i - 1];
                }
            }
            cmd[idx++] = c;
            cmd[++end] = '\0';
        }
        uart_printf("\r# %s \r\e[%dC", cmd, idx + 2);
    }

    uart_printf("\n");
}

shell_controller 根據 input 決定要執行什麼 function。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
void shell_controller(char* cmd) {
    if (!strcmp(cmd, "")) {
        return;
    }
    else if (!strcmp(cmd, "help")) {
        uart_printf("help: print all available commands\n");
        uart_printf("hello: print Hello World!\n");
        uart_printf("timestamp: get current timestamp\n");
        uart_printf("reboot: reboot pi\n");
    }
    else if (!strcmp(cmd, "hello")) {
        uart_printf("Hello World!\n");
    }
    else if (!strcmp(cmd, "timestamp")) {
        uart_printf("%f\n", get_timestamp());
    }
    else if (!strcmp(cmd, "reboot")) {
        uart_printf("Rebooting...");
        reset();
        while (1); // hang until reboot
    }
    else {
        uart_printf("shell: command not found: %s\n", cmd);
    }
}

Registers

CNTFRQ_EL0

This register is provided so that software can discover the frequency of the system counter. It must be programmed with this value as part of system initialization. The value of the register is not interpreted by hardware.

https://developer.arm.com/docs/ddi0595/c/aarch64-system-registers/cntfrq_el0

CNTPCT_EL0

Holds the 64-bit physical count value.

https://developer.arm.com/docs/ddi0595/b/aarch64-system-registers/cntpct_el0

PMPASSWORD, PM_RSTC, PM_WDOG

https://elinux.org/BCM2835_registers#PM

comments powered by Disqus