Personalizando o Letter Shell com comandos, variáveis e atalhos

Em projetos embarcados, ter um shell interativo é um grande facilitador para depuração e testes. O Letter Shell oferece uma base sólida, mas muitas vezes precisamos ir além do básico: registrar nossas próprias funções como comandos, criar atalhos de teclado ou expor variáveis para leitura e escrita direatmente pelo terminal. A boa notícia é que a arquitetura do Letter Shell foi projetada com extensibilidade em mente, tratando funções, variáveis e teclas de maneira unificada como "itens de comando".

Este artigo mostra como personalizar o shell usando os mecanismos de exportação fornecidos, tomando cuidado com a retenção no linker e fornecendo exemplos práticos.

Configuração do linker

Para que os comandos registrados não sejam removidos pelo linker durante a otimização, é necessário preservar a seção .shellCommand. As configurações variam conforme o compilador:

  • Keil MDK: adicione --keep shellCommand* nas opções de compilação.
  • GCC: insira no script de linker: ``` _shell_command_start = .; KEEP (*(shellCommand)) _shell_command_end = .;
    
    

Exportando funções como comandos

A macro SHELL_EXPORT_CMD permite transformar uma função C em um comando invocável pelo terminal. A função é registrada na seção shellCommand por meio de uma estrutura de atributos. O exemplo a seguir cria um comando saudar que imprime uma mensagem:

void exibirSaudacao(void) {
    Shell* sh = shellGetCurrent();
    if (sh) {
        shellWriteString(sh, "Ola, shell customizado!");
    }
}

SHELL_EXPORT_CMD(
    SHELL_CMD_PERMISSION(0) |
    SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC) |
    SHELL_CMD_DISABLE_RETURN,
    saudar, exibirSaudacao, "Exibe uma saudacao"
);

Note que a função exportada é convertida para (int (*)()) internamente, o que sacrifica a verificação de tipos. Em aplicações críticas, pode-se envolver a função original em uma função de assinatura compatível para maior segurança.

Variáveis acessíveis pelo terminal

Além de funções, o Letter Shell permite exportar variáveis para leitura e escrita. Os tipos suportados incluem inteiros, strings e ponteiros. A macro SHELL_EXPORT_VAR recebe o endereço da variável (exceto para strings, onde o próprio array já é um ponteiro).

int contador = 0;
SHELL_EXPORT_VAR(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_VAR_INT),
                 contador, &contador, "Contador de eventos");

char mensagem[] = "teste shell";
SHELL_EXPORT_VAR(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_VAR_STRING),
                 mensagem, mensagem, "Mensagem de status");

struct Dispositivo disp;
SHELL_EXPORT_VAR(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_VAR_POINT),
                 disp, &disp, "Estrutura de dispositivo");

Com isso, digitar contador no terminal mostra seu valor atual, e atribuições como contador = 10 atualizam a variável em tempo real. Para variáveis somente leitura, adicione o atributo SHELL_CMD_READ_ONLY.

Atalhos de teclado

Também é possível associar ações a teclas específicas (como Tab, Ctrl+C, ou setas). A macro SHELL_EXPORT_KEY registra um callback para uma sequência de bytes representada em big-endian.

Por exemplo, a tecla Ctrl+C envia o byte 0x03. Para registrá-la:

uint8_t flagInterrupcao = 0;

void aoPressionarCtrlC(Shell* shell) {
    flagInterrupcao = 1;
    // Reexibe o prompt e reativa a análise de comandos
    extern void escreverPrompt(Shell* shell, unsigned char novaLinha);
    escreverPrompt(shell, 1);
    extern void executarShell(Shell* shell);
    executarShell(shell);
}

SHELL_EXPORT_KEY(SHELL_CMD_PERMISSION(0), 0x03000000, aoPressionarCtrlC, "Ctrl+C");

Para desocbrir a sequência de bytes de outras teclas, utilize um terminal com modo hexadecimal (como o SecureCRT) e pressione a tecla desejada enquanto observa os dados recebidos. Lembre-se de completar com zeros à direita até 4 bytes, pois o valor é tratado como big‑endian de 32 bits.

O mecanismo de exportação unificado, baseado na seção shellCommand e nas macros fornecidas, torna o Letter Shell uma ferramenta de depuração extremamente flexível. Basta garantir que a seção não seja removida pelo linker e você poderá rapidamente transformar suas funções, variáveis e atalhos em comandos de terminal.

Tags: Letter Shell shell embarcado Depuração comandos personalizados variaveis

Publicado em 9-2 07:47