kopia lustrzana https://github.com/OpenRTX/OpenRTX
just the emulator shell broken out
rodzic
efb549731c
commit
45228e226e
|
@ -50,6 +50,14 @@ build_*
|
|||
# gutentags
|
||||
tags
|
||||
|
||||
|
||||
# subprojects
|
||||
subprojects/radio_tool
|
||||
subprojects/codec2
|
||||
|
||||
#ignore log files
|
||||
*.log
|
||||
|
||||
#ignore linux openrtx emulator history file
|
||||
.emulatorsh_history
|
||||
|
||||
|
|
|
@ -309,7 +309,7 @@ dm1801_def = def + mk22fn512_def + {'PLATFORM_DM1801': ''}
|
|||
|
||||
linux_c_args = ['-DPLATFORM_LINUX']
|
||||
linux_cpp_args = ['-std=c++14', '-DPLATFORM_LINUX']
|
||||
linux_l_args = ['-lm']
|
||||
linux_l_args = ['-lm', '-lreadline']
|
||||
|
||||
# Add AddressSanitizer if required
|
||||
if get_option('asan')
|
||||
|
|
|
@ -0,0 +1,124 @@
|
|||
p
|
||||
p
|
||||
p
|
||||
p
|
||||
r 12
|
||||
key 1 2 3 4 5 6 enter
|
||||
key esc
|
||||
key 1 2 3 4 5 6 enter
|
||||
key 4 5 1 8 enter
|
||||
key 4 5 1 8 enter
|
||||
key 4 6 9 enter
|
||||
key esc
|
||||
key enter
|
||||
key down down down
|
||||
key down
|
||||
key enter
|
||||
key esc
|
||||
key down down down down down
|
||||
key enter
|
||||
key esc
|
||||
p
|
||||
p
|
||||
key enter
|
||||
key esc
|
||||
key 4 5 1 8 enter
|
||||
key 1 4 6 5 2 enter
|
||||
p
|
||||
p
|
||||
key enter down down down down down enter
|
||||
key esc
|
||||
key down down down down
|
||||
key enter
|
||||
key esc
|
||||
key esc
|
||||
key enter up up enter
|
||||
key up
|
||||
key esc
|
||||
key esc
|
||||
r 12
|
||||
r 15
|
||||
s
|
||||
vb 7.6
|
||||
key enter
|
||||
key esc
|
||||
s
|
||||
channel 1
|
||||
channel 2
|
||||
ch 3
|
||||
ch 5
|
||||
ch 15
|
||||
key esc
|
||||
ch 2
|
||||
key esc
|
||||
key esc
|
||||
key esc
|
||||
key enter
|
||||
key esc
|
||||
key esc
|
||||
key enter
|
||||
key down down down
|
||||
key enter
|
||||
key enter
|
||||
key down
|
||||
key enter
|
||||
key up
|
||||
key up
|
||||
key up
|
||||
key up
|
||||
key up
|
||||
key up
|
||||
key down
|
||||
key down
|
||||
key esc
|
||||
|
||||
p
|
||||
p
|
||||
key esc
|
||||
key esc
|
||||
key esc
|
||||
key up
|
||||
key esc
|
||||
key up
|
||||
key up
|
||||
key 4 5 1 8 enter enter
|
||||
p
|
||||
p
|
||||
key 1 4 6 5 2 enter 4 5 1 8 enter
|
||||
p
|
||||
p
|
||||
p
|
||||
p
|
||||
key enter up up enter
|
||||
key up
|
||||
key esc
|
||||
key down down down down enter
|
||||
key esc
|
||||
key down down down down down enter
|
||||
key esc
|
||||
key esc
|
||||
|
||||
key esc
|
||||
key esc
|
||||
key esc
|
||||
key up
|
||||
key esc
|
||||
key up
|
||||
key up
|
||||
key 4 5 1 8 enter enter
|
||||
p
|
||||
p
|
||||
key 1 4 6 5 2 enter 4 5 1 8 enter
|
||||
ready
|
||||
p
|
||||
p
|
||||
p
|
||||
p
|
||||
key enter up up enter
|
||||
key up
|
||||
key esc
|
||||
key down down down down enter
|
||||
key esc
|
||||
key down down down down down enter
|
||||
key esc
|
||||
key esc
|
|
@ -0,0 +1,9 @@
|
|||
sleep 4000
|
||||
nop SAT menu
|
||||
key enter DOWN down down down down enter
|
||||
ready
|
||||
screenshot sat.bmp
|
||||
nop GPS menu
|
||||
key esc DOWN down down down enter
|
||||
ready
|
||||
screenshot gps.bmp
|
|
@ -0,0 +1,6 @@
|
|||
sleep 3000
|
||||
screenshot noptt.bmp
|
||||
key 1 2 3
|
||||
ptt
|
||||
sleep 1000
|
||||
screenshot ptt.bmp
|
|
@ -0,0 +1,16 @@
|
|||
|
||||
|
||||
|
||||
uidev:
|
||||
meson compile -C build_linux openrtx_linux
|
||||
cat sat_menu_dev.txt | build_linux/openrtx_linux
|
||||
convert SAT.bmp -resize 600% SAT.jpg
|
||||
|
||||
|
||||
valgrind:
|
||||
meson compile -C build_linux openrtx_linux
|
||||
cat leak_check.txt | valgrind --leak-check=full --log-file=valgrind.log build_linux/openrtx_linux
|
||||
record:
|
||||
meson compile -C build_linux openrtx_linux
|
||||
cat record_demo.txt | build_linux/openrtx_linux
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
key enter down down down down down enter
|
||||
sleep 5000
|
||||
screenshot SAT.bmp
|
|
@ -0,0 +1,9 @@
|
|||
key enter down down down down down enter
|
||||
sleep 1000
|
||||
key down enter
|
||||
sleep 5000
|
||||
nop sleep 1000
|
||||
nop key enter
|
||||
nop sleep 1000
|
||||
nop screenshot delta.bmp
|
||||
|
|
@ -57,6 +57,100 @@ SDL_Texture *displayTexture; /* SDL rendering surface */
|
|||
void *frameBuffer; /* Pointer to framebuffer */
|
||||
bool inProgress; /* Flag to signal when rendering is in progress */
|
||||
|
||||
|
||||
int screenshot_display(const char *filename)
|
||||
{
|
||||
//https://stackoverflow.com/a/48176678
|
||||
//user1902824
|
||||
//modified to keep renderer and display texture references in the body rather than as a parameter
|
||||
SDL_Renderer * ren = renderer;
|
||||
SDL_Texture * tex = displayTexture;
|
||||
int err = 0;
|
||||
|
||||
|
||||
SDL_Texture *ren_tex;
|
||||
SDL_Surface *surf;
|
||||
int st;
|
||||
int w;
|
||||
int h;
|
||||
int format;
|
||||
void *pixels;
|
||||
|
||||
pixels = NULL;
|
||||
surf = NULL;
|
||||
ren_tex = NULL;
|
||||
format = SDL_PIXELFORMAT_RGBA32;
|
||||
|
||||
/* Get information about texture we want to save */
|
||||
st = SDL_QueryTexture(tex, NULL, NULL, &w, &h);
|
||||
if (st != 0) {
|
||||
SDL_Log("Failed querying texture: %s\n", SDL_GetError());
|
||||
err++;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ren_tex = SDL_CreateTexture(ren, format, SDL_TEXTUREACCESS_TARGET, w, h);
|
||||
if (!ren_tex) {
|
||||
SDL_Log("Failed creating render texture: %s\n", SDL_GetError());
|
||||
err++;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize our canvas, then copy texture to a target whose pixel data we
|
||||
* can access
|
||||
*/
|
||||
st = SDL_SetRenderTarget(ren, ren_tex);
|
||||
if (st != 0) {
|
||||
SDL_Log("Failed setting render target: %s\n", SDL_GetError());
|
||||
err++;
|
||||
goto cleanup;
|
||||
}
|
||||
SDL_SetRenderDrawColor(ren, 0x00, 0x00, 0x00, 0x00);
|
||||
SDL_RenderClear(ren);
|
||||
st = SDL_RenderCopy(ren, tex, NULL, NULL);
|
||||
if (st != 0) {
|
||||
SDL_Log("Failed copying texture data: %s\n", SDL_GetError());
|
||||
err++;
|
||||
goto cleanup;
|
||||
}
|
||||
/* Create buffer to hold texture data and load it */
|
||||
pixels = malloc(w * h * SDL_BYTESPERPIXEL(format));
|
||||
if (!pixels) {
|
||||
SDL_Log("Failed allocating memory\n");
|
||||
err++;
|
||||
goto cleanup;
|
||||
}
|
||||
st = SDL_RenderReadPixels(ren, NULL, format, pixels, w * SDL_BYTESPERPIXEL(format));
|
||||
if (st != 0) {
|
||||
SDL_Log("Failed reading pixel data: %s\n", SDL_GetError());
|
||||
err++;
|
||||
goto cleanup;
|
||||
}
|
||||
/* Copy pixel data over to surface */
|
||||
surf = SDL_CreateRGBSurfaceWithFormatFrom(pixels, w, h, SDL_BITSPERPIXEL(format), w * SDL_BYTESPERPIXEL(format), format);
|
||||
if (!surf) {
|
||||
SDL_Log("Failed creating new surface: %s\n", SDL_GetError());
|
||||
err++;
|
||||
goto cleanup;
|
||||
}
|
||||
/* Save result to an image */
|
||||
st = SDL_SaveBMP(surf, filename);
|
||||
if (st != 0) {
|
||||
SDL_Log("Failed saving image: %s\n", SDL_GetError());
|
||||
err++;
|
||||
goto cleanup;
|
||||
}
|
||||
SDL_Log("Saved texture as BMP to \"%s\"\n", filename);
|
||||
|
||||
cleanup:
|
||||
SDL_FreeSurface(surf);
|
||||
free(pixels);
|
||||
SDL_DestroyTexture(ren_tex);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* Internal helper function which fetches pixel at position (x, y) from framebuffer
|
||||
|
@ -105,7 +199,8 @@ void display_init()
|
|||
SDL_WINDOWPOS_UNDEFINED,
|
||||
SDL_WINDOWPOS_UNDEFINED,
|
||||
SCREEN_WIDTH * 3, SCREEN_HEIGHT * 3,
|
||||
SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE);
|
||||
SDL_WINDOW_SHOWN );
|
||||
//removed RESIZABLE flag so automatic screen recording is a little easier
|
||||
|
||||
renderer = SDL_CreateRenderer(window, -1, 0);
|
||||
SDL_RenderSetLogicalSize(renderer, SCREEN_WIDTH, SCREEN_HEIGHT);
|
||||
|
|
|
@ -23,13 +23,17 @@
|
|||
#include <interfaces/keyboard.h>
|
||||
#include <SDL2/SDL.h>
|
||||
|
||||
extern keyboard_t shellkeyq_get();
|
||||
|
||||
void kbd_init()
|
||||
{
|
||||
}
|
||||
|
||||
keyboard_t kbd_getKeys() {
|
||||
keyboard_t keys = 0;
|
||||
SDL_PumpEvents();
|
||||
|
||||
//this pulls in emulated keypresses from the command shell
|
||||
keys |= shellkeyq_get();
|
||||
|
||||
const uint8_t *state = SDL_GetKeyboardState(NULL);
|
||||
if (state[SDL_SCANCODE_0]) keys |= KEY_0;
|
||||
|
|
|
@ -20,42 +20,261 @@
|
|||
|
||||
|
||||
#include "emulator.h"
|
||||
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <interfaces/keyboard.h>
|
||||
#include <SDL2/SDL.h>
|
||||
|
||||
#include <readline/readline.h>
|
||||
#include <readline/history.h>
|
||||
|
||||
|
||||
radio_state Radio_State = {12, 8.2f, 3, 4, 1, false};
|
||||
|
||||
int CLIMenu()
|
||||
{
|
||||
int choice = 0;
|
||||
printf("Select the value to change:\n");
|
||||
printf("1 -> RSSI\n");
|
||||
printf("2 -> Vbat\n");
|
||||
printf("3 -> Mic Level\n");
|
||||
printf("4 -> Volume Level\n");
|
||||
printf("5 -> Channel selector\n");
|
||||
printf("6 -> Toggle PTT\n");
|
||||
printf("7 -> Print current state\n");
|
||||
printf("8 -> Exit\n");
|
||||
printf("> ");
|
||||
do
|
||||
{
|
||||
scanf("%d", &choice);
|
||||
} while (choice < 1 || choice > 8);
|
||||
printf("\033[1;1H\033[2J");
|
||||
return choice;
|
||||
extern int screenshot_display(const char *filename);
|
||||
|
||||
typedef int (*_climenu_fn)(void* self, int argc, char ** argv );
|
||||
|
||||
typedef struct {
|
||||
char * name;
|
||||
char * description;
|
||||
void * var;
|
||||
_climenu_fn fn;
|
||||
} _climenu_option;
|
||||
|
||||
enum shell_retvals {
|
||||
SH_ERR=-1,
|
||||
SH_CONTINUE=0,
|
||||
SH_WHAT=1,
|
||||
SH_EXIT_OK=2,
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
keyboard_t _shellkeyq[25] = {0};
|
||||
int _skq_cap = 25;
|
||||
int _skq_head;
|
||||
int _skq_tail;
|
||||
int _skq_in;
|
||||
int _skq_out;
|
||||
void _dump_skq(){
|
||||
for( int i = 0; i < _skq_cap; i++){
|
||||
printf("skq[%d] == %d\n", i, _shellkeyq[i]);
|
||||
}
|
||||
}
|
||||
void shellkeyq_put(keyboard_t keys){
|
||||
//note - we must allow keys == 0 to be inserted because otherwise a queue full of
|
||||
// [1,1,1,1,1] is simulating HOLDING 1, and we sometimes (well, often) want
|
||||
// [1,0,1,0,1,0] to simulate separate keypresses
|
||||
// this, of course, relies on the kbd_thread getting just one element off the queue
|
||||
// for every kbd_getKeys().
|
||||
if( _skq_in > _skq_out + _skq_cap ){
|
||||
printf("too many keys!\n");
|
||||
return;
|
||||
}
|
||||
_shellkeyq[ _skq_tail ] = keys;
|
||||
_skq_in++;
|
||||
_skq_tail = (_skq_tail + 1 ) % _skq_cap;
|
||||
/*printf("head: %d tail: %d in %d out %d\n", _skq_head, _skq_tail, _skq_in, _skq_out);*/
|
||||
}
|
||||
keyboard_t shellkeyq_get(){
|
||||
if( _skq_in > _skq_out ){
|
||||
//only if we've fallen behind and there's data in there:
|
||||
keyboard_t out = _shellkeyq[ _skq_head ];
|
||||
_shellkeyq[ _skq_head ] = 0;
|
||||
_skq_out++;
|
||||
_skq_head = (_skq_head + 1 ) % _skq_cap;
|
||||
/*printf("head: %d tail: %d in %d out %d\n", _skq_head, _skq_tail, _skq_in, _skq_out);*/
|
||||
/*_dump_skq();*/
|
||||
return out;
|
||||
} else {
|
||||
return 0; //no keys
|
||||
}
|
||||
}
|
||||
void _test_skq(){
|
||||
for(int i = 0; i < 257; i++){
|
||||
shellkeyq_put(i+1);
|
||||
}
|
||||
|
||||
//clear it out now
|
||||
while( shellkeyq_get() );
|
||||
}
|
||||
int shell_ready(
|
||||
__attribute__((unused)) void * _self,
|
||||
__attribute__((unused)) int _argc,
|
||||
__attribute__((unused)) char ** _argv ){
|
||||
while( _skq_in > _skq_out ){
|
||||
usleep(10*1000); //sleep until keyboard is caught up
|
||||
}
|
||||
return SH_CONTINUE;
|
||||
}
|
||||
|
||||
void updateValue(float *curr_value)
|
||||
{
|
||||
printf("Current value: %f\n", *curr_value);
|
||||
printf("New value: \n");
|
||||
scanf("%f", curr_value);
|
||||
keyboard_t keyname2keyboard(char * name){
|
||||
/*The line noise at the end of this comment is a vim macro for taking the keyboard.h
|
||||
interface and putting it into the format further below
|
||||
You can load it into vim register k with "kyy
|
||||
and run the macro with @k (and then you can repeat a macro register application with @@ )
|
||||
(substitute k with any register you like)
|
||||
Once you've got all the names quoted, you can J them all together into a nice block.
|
||||
|
||||
_i"ElC",
|
||||
|
||||
*/
|
||||
char * names[] = {
|
||||
"KEY_0", "KEY_1", "KEY_2", "KEY_3", "KEY_4", "KEY_5", "KEY_6", "KEY_7",
|
||||
"KEY_8", "KEY_9", "KEY_STAR", "KEY_HASH", "KEY_ENTER", "KEY_ESC", "KEY_UP",
|
||||
"KEY_DOWN", "KEY_LEFT", "KEY_RIGHT", "KEY_MONI", "KEY_F1", "KEY_F2", "KEY_F3",
|
||||
"KEY_F4", "KEY_F5", "KEY_F6", "KEY_F7", "KEY_F8", "KEY_F9", "KEY_F10",
|
||||
};
|
||||
int numnames = sizeof(names)/sizeof(char*);
|
||||
for( int i = 0; i < numnames; i++ ){
|
||||
if( strcasecmp(name,names[i]+4) == 0 ){ //notice case insensitive
|
||||
/*printf("MATCH with %s\n", names[i]);*/
|
||||
//+4 to skip the KEY_ on all the names
|
||||
//so if name == "2", this whole function will return equivalent to KEY_2 cpp define
|
||||
//and if name=="LEFT", then you get equivalent to KEY_LEFT cpp define
|
||||
return (1 << i);
|
||||
//order matters a great deal in names array, has to match
|
||||
//the bit field generated in interface/keyboard.h
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void printState()
|
||||
int pressKey( __attribute__((unused)) void * _self, int _argc, char ** _argv ){
|
||||
//press a couple keys in sequence
|
||||
/*_climenu_option * self = (_climenu_option*) _self;*/
|
||||
printf("Press Keys: [\n");
|
||||
keyboard_t last = 0;
|
||||
for( int i = 0; i < _argc; i++ ){
|
||||
if( _argv[i] != NULL ){
|
||||
printf("\t%s, \n", _argv[i]);
|
||||
keyboard_t press = keyname2keyboard( _argv[i] );
|
||||
if( press == last ){
|
||||
//otherwise if you send key ENTER DOWN DOWN DOWN DOWN DOWN
|
||||
//it will just hold DOWN for (5/(kbd_task_hz)) seconds
|
||||
//so we need to give it a 0 value to get a 'release'
|
||||
//so the next input is recognized as separate
|
||||
//we only need to do this if we have two identical keys back to back,
|
||||
//because keyboard_t will have a zero for this key's
|
||||
//flag on other keys, which gives us the release we need
|
||||
shellkeyq_put( 0 );
|
||||
}
|
||||
shellkeyq_put(press);
|
||||
last = press;
|
||||
}
|
||||
}
|
||||
printf("\t]\n");
|
||||
shell_ready(NULL,0,NULL);
|
||||
return SH_CONTINUE; // continue
|
||||
}
|
||||
int pressMultiKeys( __attribute__((unused)) void * _self, int _argc, char ** _argv ){
|
||||
//pressMultiKeys allows for key combos by sending all the keys specified in one keyboard_t
|
||||
/*_climenu_option * self = (_climenu_option*) _self;*/
|
||||
printf("Press Keys: [\n");
|
||||
keyboard_t combo = 0;
|
||||
for( int i = 0; i < _argc; i++ ){
|
||||
if( _argv[i] != NULL ){
|
||||
printf("\t%s, \n", _argv[i]);
|
||||
combo |= keyname2keyboard( _argv[i] );
|
||||
}
|
||||
}
|
||||
shellkeyq_put( combo );
|
||||
printf("\t]\n");
|
||||
shell_ready(NULL,0,NULL);
|
||||
return SH_CONTINUE; // continue
|
||||
}
|
||||
//need another function to press them in sequence by loading up a queue for keypress_from_shell to pull from
|
||||
|
||||
|
||||
|
||||
|
||||
int template(void * _self, int _argc, char ** _argv ){
|
||||
_climenu_option * self = (_climenu_option*) _self;
|
||||
printf( "%s\n\t%s\n" , self->name, self->description);
|
||||
|
||||
for( int i = 0; i < _argc; i++ ){
|
||||
if( _argv[i] != NULL ){
|
||||
printf("\tArgs:\t%s\n", _argv[i]);
|
||||
}
|
||||
}
|
||||
return SH_CONTINUE; // continue
|
||||
}
|
||||
|
||||
int screenshot(__attribute__((unused)) void * _self, int _argc, char ** _argv ){
|
||||
char * filename = "screenshot.bmp";
|
||||
if( _argc && _argv[0] != NULL ){
|
||||
filename = _argv[0];
|
||||
}
|
||||
return screenshot_display(filename) == 0 ? SH_CONTINUE : SH_ERR;
|
||||
//screenshot_display returns 0 if ok, which is same as SH_CONTINUE
|
||||
}
|
||||
/*
|
||||
int record_start(__attribute__((unused)) void * _self, int _argc, char ** _argv ){
|
||||
char * filename = "screen.mkv";
|
||||
if( _argc && _argv[0] != NULL ){
|
||||
filename = _argv[0];
|
||||
}
|
||||
//id="xwininfo -name 'OpenRTX' | grep id: |cut -d ' ' -f 4";
|
||||
//system("ffmpeg -f x11grab -show_region 1 -region_border 10 -window_id 0x2600016 -i :0.0 out.mkv");
|
||||
//https://stackoverflow.com/questions/14764873/how-do-i-detect-when-the-contents-of-an-x11-window-have-changed
|
||||
return SH_ERR;
|
||||
}
|
||||
int record_stop(
|
||||
__attribute__((unused)) void * _self,
|
||||
__attribute__((unused)) int _argc,
|
||||
__attribute__((unused)) char ** _argv ){
|
||||
return SH_ERR;
|
||||
}
|
||||
*/
|
||||
int setFloat(void * _self, int _argc, char ** _argv ){
|
||||
_climenu_option * self = (_climenu_option*) _self;
|
||||
|
||||
if( _argc <= 0 || _argv[0] == NULL ){
|
||||
printf("%s is %f\n", self->name, *(float*)(self->var));
|
||||
} else {
|
||||
sscanf(_argv[0], "%f", (float *)self->var);
|
||||
printf("%s is %f\n", self->name, *(float*)(self->var));
|
||||
}
|
||||
return SH_CONTINUE; // continue
|
||||
|
||||
}
|
||||
int toggleVariable(
|
||||
__attribute__((unused)) void * _self,
|
||||
__attribute__((unused)) int _argc,
|
||||
__attribute__((unused)) char ** _argv ){
|
||||
_climenu_option * self = (_climenu_option*) _self;
|
||||
*(int*)self->var = ! *(int*)self->var; //yeah, maybe this got a little out of hand
|
||||
return SH_CONTINUE; // continue
|
||||
|
||||
}
|
||||
int shell_sleep( __attribute__((unused)) void * _self, int _argc, char ** _argv ){
|
||||
if( ! _argc || _argv[0] == NULL ){
|
||||
printf("Provide a number in milliseconds to sleep as an argument\n");
|
||||
return SH_ERR;
|
||||
}
|
||||
useconds_t sleepus = atoi(_argv[0]) * 1000;
|
||||
usleep(sleepus);
|
||||
return SH_CONTINUE;
|
||||
}
|
||||
int shell_quit(
|
||||
__attribute__((unused)) void * _self,
|
||||
__attribute__((unused)) int _argc,
|
||||
__attribute__((unused)) char ** _argv ){
|
||||
printf("QUIT: 73!\n");
|
||||
//could remove history entries here, if we wanted
|
||||
return SH_EXIT_OK; //normal quit
|
||||
}
|
||||
int printState(
|
||||
__attribute__((unused)) void * _self,
|
||||
__attribute__((unused)) int _argc,
|
||||
__attribute__((unused)) char **_argv)
|
||||
{
|
||||
printf("\nCurrent state\n");
|
||||
printf("RSSI : %f\n", Radio_State.RSSI);
|
||||
|
@ -64,43 +283,163 @@ void printState()
|
|||
printf("Volume : %f\n", Radio_State.volumeLevel);
|
||||
printf("Channel: %f\n", Radio_State.chSelector);
|
||||
printf("PTT : %s\n\n", Radio_State.PttStatus ? "true" : "false");
|
||||
|
||||
return SH_CONTINUE;
|
||||
}
|
||||
int shell_nop(
|
||||
__attribute__((unused)) void * _self,
|
||||
__attribute__((unused)) int _argc,
|
||||
__attribute__((unused)) char ** _argv ){
|
||||
//do nothing! what it says on the tin
|
||||
return SH_CONTINUE;
|
||||
}
|
||||
|
||||
int shell_help(void * _self, int _argc, char ** _argv );
|
||||
|
||||
_climenu_option _options[] = {
|
||||
/* name/shortcut description var reference, if available method to call */
|
||||
{"rssi", "Set rssi", (void*)&Radio_State.RSSI, setFloat },
|
||||
{"vbat", "Set vbat", (void*)&Radio_State.Vbat, setFloat },
|
||||
{"mic", "Set miclevel", (void*)&Radio_State.micLevel, setFloat },
|
||||
{"volume", "Set volume", (void*)&Radio_State.volumeLevel,setFloat },
|
||||
{"channel", "Set channel", (void*)&Radio_State.chSelector, setFloat },
|
||||
{"ptt", "Toggle PTT", (void*)&Radio_State.PttStatus, toggleVariable },
|
||||
{"key", "Press keys in sequence (e.g. 'key ENTER DOWN ENTER' will descend through two menus)",
|
||||
NULL, pressKey },
|
||||
{"keycombo", "Press a bunch of keys simultaneously ",
|
||||
NULL, pressMultiKeys },
|
||||
{"show", "Show current radio state (ptt, rssi, etc)",
|
||||
NULL, printState },
|
||||
|
||||
{"screenshot","[screenshot.bmp] Save screenshot to first arg or screenshot.bmp if none given",
|
||||
NULL, screenshot },
|
||||
/*{"record_start", "[screen.mkv] Automatically save a video of the remaining session (or until record_stop is called)",*/
|
||||
/*NULL, record_start },*/
|
||||
/*{"record_stop", "Stop the running recording, or no-op if none started",*/
|
||||
/*NULL, record_stop },*/
|
||||
{"sleep", "Wait some number of ms", NULL, shell_sleep },
|
||||
{"help", "Print this help", NULL, shell_help },
|
||||
{"nop", "Do nothing (useful for comments)",
|
||||
NULL, shell_nop },
|
||||
/*{"ready", */
|
||||
/*"Wait until ready. Currently supports keyboard, so will wait until all keyboard events are processed,"*/
|
||||
/*"but is already implied by key and keycombo so there's not much direct use for it right now",*/
|
||||
/*NULL, shell_ready },*/
|
||||
{"quit", "Quit, close the emulator", NULL, shell_quit },
|
||||
};
|
||||
int num_options = (sizeof( _options )/ sizeof(_climenu_option));
|
||||
|
||||
|
||||
int shell_help(
|
||||
__attribute__((unused)) void * _self,
|
||||
__attribute__((unused)) int _argc,
|
||||
__attribute__((unused)) char ** _argv ){
|
||||
printf("OpenRTX emulator shell\n\n");
|
||||
for( int i = 0; i < num_options; i++ ){
|
||||
_climenu_option * o = &_options[i];
|
||||
printf("%10s -> %s\n", o->name, o->description);
|
||||
}
|
||||
return SH_CONTINUE;
|
||||
}
|
||||
|
||||
|
||||
_climenu_option * findMenuOption(char * tok){
|
||||
for( int i = 0; i < num_options; i++ ){
|
||||
_climenu_option * o = &_options[i];
|
||||
if( strncmp(tok, o->name, strlen(tok)) == 0 ){
|
||||
//strncmp like this allows for typing shortcuts like just "r" instead of the full "rssi"
|
||||
//priority for conflicts (like if there's "s" which could mean
|
||||
// either "show" or "screenshot" )
|
||||
//is set by ordering in the _options array
|
||||
return o;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void striptoken(char * token){
|
||||
for( size_t i = 0; i < strlen(token); i++ ){
|
||||
if( token[i] == '\n' ){
|
||||
token[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
int process_line(char * line){
|
||||
char * token = strtok( line, " ");
|
||||
if( token == NULL ){
|
||||
return SH_ERR;
|
||||
}
|
||||
striptoken(token);
|
||||
_climenu_option * o = findMenuOption(token);
|
||||
char * args[12] = {NULL};
|
||||
int i = 0;
|
||||
for( i = 0; i < 12; i++ ){
|
||||
//immediately strtok again since first is a command rest are args
|
||||
token = strtok(NULL, " ");
|
||||
if( token == NULL ){
|
||||
break;
|
||||
}
|
||||
striptoken(token);
|
||||
args[i] = token;
|
||||
}
|
||||
if( token != NULL ){
|
||||
printf("\nGot too many arguments, args truncated \n");
|
||||
}
|
||||
if( o != NULL ){
|
||||
if( o->fn != NULL ){
|
||||
return o->fn(o, i, args);
|
||||
} else {
|
||||
printf("Bad fn for o, check option array for bad data\n");
|
||||
return SH_ERR;
|
||||
}
|
||||
} else {
|
||||
return SH_WHAT; //not understood
|
||||
}
|
||||
}
|
||||
void *startCLIMenu()
|
||||
{
|
||||
int choice;
|
||||
do
|
||||
{
|
||||
choice = CLIMenu();
|
||||
switch (choice)
|
||||
{
|
||||
case VAL_RSSI:
|
||||
updateValue(&Radio_State.RSSI);
|
||||
break;
|
||||
case VAL_BAT:
|
||||
updateValue(&Radio_State.Vbat);
|
||||
break;
|
||||
case VAL_MIC:
|
||||
updateValue(&Radio_State.micLevel);
|
||||
break;
|
||||
case VAL_VOL:
|
||||
updateValue(&Radio_State.volumeLevel);
|
||||
break;
|
||||
case VAL_CH:
|
||||
updateValue(&Radio_State.chSelector);
|
||||
break;
|
||||
case VAL_PTT:
|
||||
Radio_State.PttStatus = Radio_State.PttStatus ? false : true;
|
||||
break;
|
||||
case PRINT_STATE:
|
||||
printState();
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
printf("\n\n");
|
||||
char * histfile = ".emulatorsh_history";
|
||||
shell_help(NULL,0,NULL);
|
||||
/*printf("\n> ");*/
|
||||
int ret = SH_CONTINUE;
|
||||
using_history();
|
||||
read_history(histfile);
|
||||
do {
|
||||
/*char * r = fgets(shellbuf, 255, stdin);*/
|
||||
char * r = readline(">");
|
||||
if( r == NULL ){
|
||||
ret = SH_EXIT_OK;
|
||||
} else if( strlen(r) > 0 ){
|
||||
add_history(r);
|
||||
ret = process_line(r);
|
||||
} else {
|
||||
ret = SH_CONTINUE;
|
||||
}
|
||||
} while (choice != EXIT);
|
||||
printf("73\n");
|
||||
switch(ret){
|
||||
default:
|
||||
fflush(stdout);
|
||||
break;
|
||||
case SH_WHAT:
|
||||
printf("?\n(type h or help for help)\n");
|
||||
ret = SH_CONTINUE; //i'd rather just fall through, but the compiler warns. blech.
|
||||
/*printf("\n>");*/
|
||||
break;
|
||||
case SH_CONTINUE:
|
||||
/*printf("\n>");*/
|
||||
break;
|
||||
case SH_EXIT_OK:
|
||||
//normal quit
|
||||
break;
|
||||
case SH_ERR:
|
||||
//error
|
||||
printf("Error running that command\n");
|
||||
ret = SH_CONTINUE;
|
||||
break;
|
||||
}
|
||||
free(r); //free the string allocated by readline
|
||||
} while ( ret == SH_CONTINUE );
|
||||
fflush(stdout);
|
||||
write_history(histfile);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
|
Ładowanie…
Reference in New Issue