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
	
	 tarxvf
						tarxvf