mirror of
https://github.com/opentx/opentx.git
synced 2025-07-19 22:35:12 +03:00
Fixes #2595 - Cli added
Based on projectkk2glider work, with a lot of bugs I am sure. Still not tested, this is why I preferred working on my own branch. I push it now so that Jenkins do the first tests and you can review if I am on the right track. I am really wondering if a merge with the Lua api would be possible / nice, what do you think?
This commit is contained in:
parent
70d77fd851
commit
2b312fdbb4
26 changed files with 970 additions and 653 deletions
315
radio/src/cli.cpp
Normal file
315
radio/src/cli.cpp
Normal file
|
@ -0,0 +1,315 @@
|
|||
/*
|
||||
* Authors (alphabetical order)
|
||||
* - Andre Bernet <bernet.andre@gmail.com>
|
||||
* - Andreas Weitl
|
||||
* - Bertrand Songis <bsongis@gmail.com>
|
||||
* - Bryan J. Rentoul (Gruvin) <gruvin@gmail.com>
|
||||
* - Cameron Weeks <th9xer@gmail.com>
|
||||
* - Erez Raviv
|
||||
* - Gabriel Birkus
|
||||
* - Jean-Pierre Parisy
|
||||
* - Karl Szmutny
|
||||
* - Michael Blandford
|
||||
* - Michal Hlavinka
|
||||
* - Pat Mackenzie
|
||||
* - Philip Moss
|
||||
* - Rob Thomson
|
||||
* - Romolo Manfredini <romolo.manfredini@gmail.com>
|
||||
* - Thomas Husterer
|
||||
*
|
||||
* opentx is based on code named
|
||||
* gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/,
|
||||
* er9x by Erez Raviv: http://code.google.com/p/er9x/,
|
||||
* and the original (and ongoing) project by
|
||||
* Thomas Husterer, th9x: http://code.google.com/p/th9x/
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "opentx.h"
|
||||
#include <ctype.h>
|
||||
|
||||
#define CLI_STACK_SIZE 500
|
||||
#define CLI_MAX_ARGS 8
|
||||
|
||||
extern Fifo<512> uart3TxFifo;
|
||||
OS_TID cliTaskId;
|
||||
OS_STK cliStack[CLI_STACK_SIZE];
|
||||
Fifo<256> cliRxFifo;
|
||||
uint8_t cliTracesEnabled = false;
|
||||
|
||||
typedef int (* CliFunction) (const char ** args);
|
||||
|
||||
struct CliCommand
|
||||
{
|
||||
const char * name;
|
||||
CliFunction func;
|
||||
const char * args;
|
||||
};
|
||||
|
||||
struct MemArea
|
||||
{
|
||||
const char * name;
|
||||
void * start;
|
||||
int size;
|
||||
};
|
||||
|
||||
void cliPrompt()
|
||||
{
|
||||
serialPutc('>');
|
||||
}
|
||||
|
||||
int toInt(const char ** argv, int index, int * val)
|
||||
{
|
||||
if (*argv[index] == '\0') {
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
int base = 10;
|
||||
const char * s = argv[index];
|
||||
if (strlen(s) > 2 && s[0] == '0' && s[1] == 'x') {
|
||||
base = 16;
|
||||
s = &argv[index][2];
|
||||
}
|
||||
char * endptr = NULL;
|
||||
*val = strtol(s, &endptr, base);
|
||||
if (*endptr == '\0')
|
||||
return 1;
|
||||
else {
|
||||
serialPrint("%s: Invalid argument \"%s\"", argv[0], argv[index]);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int cliBeep(const char ** argv)
|
||||
{
|
||||
int freq = BEEP_DEFAULT_FREQ;
|
||||
int duration = 100;
|
||||
if (toInt(argv, 1, &freq) >= 0 && toInt(argv, 2, &duration) >= 0) {
|
||||
audioQueue.playTone(freq, duration, 20, PLAY_NOW);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cliPlay(const char ** argv)
|
||||
{
|
||||
audioQueue.playFile(argv[1], PLAY_NOW);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cliLs(const char ** argv)
|
||||
{
|
||||
FILINFO fno;
|
||||
DIR dir;
|
||||
char *fn; /* This function is assuming non-Unicode cfg. */
|
||||
#if _USE_LFN
|
||||
TCHAR lfn[_MAX_LFN + 1];
|
||||
fno.lfname = lfn;
|
||||
fno.lfsize = sizeof(lfn);
|
||||
#endif
|
||||
|
||||
FRESULT res = f_opendir(&dir, argv[1]); /* Open the directory */
|
||||
if (res == FR_OK) {
|
||||
for (;;) {
|
||||
res = f_readdir(&dir, &fno); /* Read a directory item */
|
||||
if (res != FR_OK || fno.fname[0] == 0) break; /* Break on error or end of dir */
|
||||
|
||||
#if _USE_LFN
|
||||
fn = *fno.lfname ? fno.lfname : fno.fname;
|
||||
#else
|
||||
fn = fno.fname;
|
||||
#endif
|
||||
serialPrint(fn);
|
||||
}
|
||||
}
|
||||
else {
|
||||
serialPrint("%s: Invalid directory \"%s\"", argv[0], argv[1]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cliTrace(const char ** argv)
|
||||
{
|
||||
if (!strcmp(argv[1], "on")) {
|
||||
cliTracesEnabled = true;
|
||||
}
|
||||
else if (!strcmp(argv[1], "off")) {
|
||||
cliTracesEnabled = false;
|
||||
}
|
||||
else {
|
||||
serialPrint("%s: Invalid argument \"%s\"", argv[0], argv[1]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cliVolume(const char ** argv)
|
||||
{
|
||||
int level = 0;
|
||||
if (toInt(argv, 1, &level) > 0) {
|
||||
setVolume(level);
|
||||
}
|
||||
else {
|
||||
serialPrint("%s: Invalid argument \"%s\"", argv[0], argv[1]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const MemArea memAreas[] = {
|
||||
{ "RCC", RCC, sizeof(RCC_TypeDef) },
|
||||
{ "GPIOA", GPIOA, sizeof(GPIO_TypeDef) },
|
||||
{ "GPIOB", GPIOB, sizeof(GPIO_TypeDef) },
|
||||
{ "GPIOC", GPIOC, sizeof(GPIO_TypeDef) },
|
||||
{ "GPIOD", GPIOD, sizeof(GPIO_TypeDef) },
|
||||
{ "GPIOE", GPIOE, sizeof(GPIO_TypeDef) },
|
||||
{ "GPIOF", GPIOF, sizeof(GPIO_TypeDef) },
|
||||
{ "GPIOG", GPIOG, sizeof(GPIO_TypeDef) },
|
||||
{ "USART1", USART1, sizeof(USART_TypeDef) },
|
||||
{ "USART3", USART3, sizeof(USART_TypeDef) },
|
||||
{ NULL, NULL, 0 },
|
||||
};
|
||||
|
||||
int cliDisplay(const char ** argv)
|
||||
{
|
||||
int address = 0;
|
||||
|
||||
for (const MemArea * area = memAreas; area->name != NULL; area++) {
|
||||
if (!strcmp(area->name, argv[1])) {
|
||||
dump((uint8_t *)area->start, area->size);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!strcmp(argv[1], "adc")) {
|
||||
for (int i=0; i<NUMBER_ANALOG; i++) {
|
||||
serialPrint("adc[%d] = %04X", i, Analog_values[i]);
|
||||
}
|
||||
}
|
||||
else if (!strcmp(argv[1], "outputs")) {
|
||||
for (int i=0; i<NUM_CHNOUT; i++) {
|
||||
serialPrint("outputs[%d] = %04X", i, channelOutputs[i]);
|
||||
}
|
||||
}
|
||||
else if (toInt(argv, 1, &address) > 0) {
|
||||
int size = 256;
|
||||
if (toInt(argv, 2, &size) >= 0) {
|
||||
dump((uint8_t *)address, size);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cliHelp(const char ** argv);
|
||||
|
||||
const CliCommand cliCommands[] = {
|
||||
{ "beep", cliBeep, "[<frequency>] [<duration>]" },
|
||||
{ "ls", cliLs, "<directory>" },
|
||||
{ "play", cliPlay, "<filename>" },
|
||||
{ "print", cliDisplay, "<address> [<size>] | <what>" },
|
||||
{ "trace", cliTrace, "on | off" },
|
||||
{ "volume", cliVolume, "<level>" },
|
||||
{ "help", cliHelp, "[<command>]" },
|
||||
{ NULL, NULL, NULL } /* sentinel */
|
||||
};
|
||||
|
||||
int cliHelp(const char ** argv)
|
||||
{
|
||||
for (const CliCommand * command = cliCommands; command->name != NULL; command++) {
|
||||
if (argv[1][0] == '\0' || !strcmp(command->name, argv[0])) {
|
||||
serialPrint("%s %s", command->name, command->args);
|
||||
if (argv[1][0] != '\0') {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (argv[1][0] != '\0') {
|
||||
serialPrint("Invalid command \"%s\"", argv[0]);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int cliExecCommand(const char ** argv)
|
||||
{
|
||||
if (argv[0][0] == '\0')
|
||||
return 0;
|
||||
|
||||
for (const CliCommand * command = cliCommands; command->name != NULL; command++) {
|
||||
if (!strcmp(command->name, argv[0])) {
|
||||
return command->func(argv);
|
||||
}
|
||||
}
|
||||
serialPrint("Invalid command \"%s\"", argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int cliExecLine(char * line)
|
||||
{
|
||||
int len = strlen(line);
|
||||
const char * argv[CLI_MAX_ARGS];
|
||||
memset(argv, 0, sizeof(argv));
|
||||
int argc = 1;
|
||||
argv[0] = line;
|
||||
for (int i=0; i<len; i++) {
|
||||
if (line[i] == ' ') {
|
||||
line[i] = '\0';
|
||||
if (argc < CLI_MAX_ARGS) {
|
||||
argv[argc++] = &line[i+1];
|
||||
}
|
||||
}
|
||||
}
|
||||
return cliExecCommand(argv);
|
||||
}
|
||||
|
||||
void cliTask(void * pdata)
|
||||
{
|
||||
char line[256];
|
||||
uint8_t pos = 0;
|
||||
|
||||
cliPrompt();
|
||||
|
||||
for (;;) {
|
||||
uint8_t c;
|
||||
|
||||
while (!cliRxFifo.pop(c)) {
|
||||
CoTickDelay(5); // 10ms
|
||||
}
|
||||
|
||||
if (c == 12) {
|
||||
// clear screen
|
||||
serialPrint("\033[2J\033[1;1H");
|
||||
cliPrompt();
|
||||
}
|
||||
else if (c == 127) {
|
||||
// backspace
|
||||
if (pos) {
|
||||
line[--pos] = '\0';
|
||||
serialPutc(c);
|
||||
}
|
||||
}
|
||||
else if (c == '\r' || c == '\n') {
|
||||
// enter
|
||||
serialCrlf();
|
||||
line[pos] = '\0';
|
||||
cliExecLine(line);
|
||||
pos = 0;
|
||||
cliPrompt();
|
||||
}
|
||||
else if (isascii(c)) {
|
||||
line[pos++] = c;
|
||||
serialPutc(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cliStart()
|
||||
{
|
||||
cliTaskId = CoCreateTaskEx(cliTask, NULL, 10, &cliStack[CLI_STACK_SIZE-1], CLI_STACK_SIZE, 1, false);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue