1
0
Fork 0
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:
bertrand 2015-08-10 22:42:04 +02:00
parent 70d77fd851
commit 2b312fdbb4
26 changed files with 970 additions and 653 deletions

315
radio/src/cli.cpp Normal file
View 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);
}