From fae32b062cc8a37222ca16123d7f781243b51670 Mon Sep 17 00:00:00 2001 From: Brendan Bartels <bbartels@iastate.edu> Date: Fri, 21 Apr 2017 12:50:49 -0500 Subject: [PATCH] quad: improve virtual quad cli --- quad/scripts/tests/test_communication.rb | 8 +- quad/scripts/tests/test_logging.rb | 4 +- quad/scripts/tests/test_memory_integrity.rb | 2 +- quad/scripts/tests/test_safety_checks.rb | 2 +- quad/src/virt_quad/README.md | 15 +- quad/src/virt_quad/main.c | 223 ++++++++++++++------ 6 files changed, 176 insertions(+), 78 deletions(-) diff --git a/quad/scripts/tests/test_communication.rb b/quad/scripts/tests/test_communication.rb index 4887a29bc..8797cc16d 100644 --- a/quad/scripts/tests/test_communication.rb +++ b/quad/scripts/tests/test_communication.rb @@ -16,7 +16,7 @@ Timeout::timeout(30) { puts("Setting up...") # Start virtual quad - quad_pid = Process.spawn("./virt-quad -q", + quad_pid = Process.spawn("./virt-quad start -q", { :rlimit_as => 536870912, # 512 MiB total RAM :rlimit_stack => 1048576}) # 1 MiB stack @@ -49,7 +49,7 @@ Timeout::timeout(30) { # Send a debug command Thread.new { - sleep 0.1 + sleep 0.5 send_packet [0xBE, 1, 0, 0, 0, 0, 0, 0xBF] } @@ -58,7 +58,7 @@ Timeout::timeout(30) { # Receive the header msg = [] for i in 1..7 - sleep 0.0001 + sleep 0.01 c = fifo.read(1) msg.push(c) end @@ -68,7 +68,7 @@ Timeout::timeout(30) { msg = [] for i in 1..length - sleep 0.0001 + sleep 0.01 c = fifo.read(1) msg.push(c) end diff --git a/quad/scripts/tests/test_logging.rb b/quad/scripts/tests/test_logging.rb index a0e86e716..58d16f73c 100644 --- a/quad/scripts/tests/test_logging.rb +++ b/quad/scripts/tests/test_logging.rb @@ -16,7 +16,7 @@ Timeout::timeout(30) { puts("Setting up...") # Start virtual quad - quad_pid = Process.spawn("./virt-quad -q", + quad_pid = Process.spawn("./virt-quad start -q", { :rlimit_as => 536870912, # 512 MiB total RAM :rlimit_stack => 1048576}) # 1 MiB stack @@ -83,7 +83,7 @@ Timeout::timeout(30) { # Get logs Thread.new { - sleep 0.5 + sleep 1 puts("Swiching off GEAR...") set_gear GEAR_OFF } diff --git a/quad/scripts/tests/test_memory_integrity.rb b/quad/scripts/tests/test_memory_integrity.rb index d7116c1d4..adb8f9190 100644 --- a/quad/scripts/tests/test_memory_integrity.rb +++ b/quad/scripts/tests/test_memory_integrity.rb @@ -14,7 +14,7 @@ Dir.chdir(bin_dir) puts("Firing up the quad...") # Start virtual quad -quad = Process.spawn("valgrind --leak-check=full --log-file=./valgrind.out ./virt-quad") +quad = Process.spawn("valgrind --leak-check=full --log-file=./valgrind.out ./virt-quad start") sleep 1.5 diff --git a/quad/scripts/tests/test_safety_checks.rb b/quad/scripts/tests/test_safety_checks.rb index c5557cece..c96a8228f 100644 --- a/quad/scripts/tests/test_safety_checks.rb +++ b/quad/scripts/tests/test_safety_checks.rb @@ -17,7 +17,7 @@ Timeout::timeout(60) { puts("Setting up...") # Start virtual quad - quad_pid = Process.spawn("./virt-quad -q", + quad_pid = Process.spawn("./virt-quad start -q", { :rlimit_as => 536870912, # 512 MiB total RAM :rlimit_stack => 1048576}) # 1 MiB stack diff --git a/quad/src/virt_quad/README.md b/quad/src/virt_quad/README.md index 3607ec44c..3b263e528 100644 --- a/quad/src/virt_quad/README.md +++ b/quad/src/virt_quad/README.md @@ -8,17 +8,18 @@ plethoria of things required for flight in Coover 3050. In fact, you don't even have to be in Coover 3050... # Using the Virtual Quad -Start it up: +The virt-quad has help output. Get started with: ``` -make run +./virt-quad ``` -And you can do things with it. You'll notice it will make a bunch of FIFOs in -the current directory. Write to / read from these FIFOs as you see fit. +## Using the UART Driver -## Writing to FIFO from shell +The UART interface is implemented with unix FIFOs. You can treat these FIFOs +as regular unix files. Read from uart-tx to hear with the quad is saying. Write +to uart-rx to tell the quad something. ``` -echo "170000" > virt-quad-fifos/pwm-input-gear # Setting the gear to '1' -cat virt-quad-fifos/pwm-output-motor1 # Read the motor 1 pwm signal +echo "hello world" > virt-quad-fifos/uart-rx +cat virt-quad-fifos/uart-tx ``` \ No newline at end of file diff --git a/quad/src/virt_quad/main.c b/quad/src/virt_quad/main.c index 105a8a5e6..1e24ab458 100644 --- a/quad/src/virt_quad/main.c +++ b/quad/src/virt_quad/main.c @@ -4,15 +4,28 @@ #include "quad_app.h" #include <fcntl.h> +struct VirtQuadIO *virt_quad_io; +int virt_quad_io_file_descriptor; + +enum CLISubCommand { + START, + GET, + SET, + USAGE, + HELP, +}; + +int start_virt_quad(char *argv[]); int handle_io_output(const char *name); int handle_io_input(const char *name, const char *value_str); void set_shm(float value, float *dest, pthread_mutex_t *lock); void print_shm_float(float *value, pthread_mutex_t *lock); void print_shm_int(int *value, pthread_mutex_t *lock); void usage(char *executable_name); - -struct VirtQuadIO *virt_quad_io; -int virt_quad_io_file_descriptor; +enum CLISubCommand parse_sub_command(char *argv[]); +void open_new_shm_io(); +void open_existing_shm_io(); +void help_sub_command(char *argv[]); /** * Implement each of the hardware interfaces. @@ -33,61 +46,91 @@ int setup_hardware(hardware_t *hardware) { } int main(int argc, char *argv[]) { - int fd; + enum CLISubCommand sub_command = parse_sub_command(argv + 1); + + switch (sub_command) { + case START: + open_new_shm_io(); + start_virt_quad(argv + 2); // will block + break; + case SET: + open_existing_shm_io(); + handle_io_input(argv[2], argv[3]); + break; + case GET: + open_existing_shm_io(); + handle_io_output(argv[2]); + break; + case HELP: + help_sub_command(argv); + break; + case USAGE: + usage(argv[0]); + break; + } - // Decide if we are launching the quad or parsing arguments - if (argv[1] == NULL || strcmp(argv[1], "-q") == 0) { - // launch the quad - - // Allow making the quad quiet - if (argv[1] != NULL && strcmp(argv[1], "-q") == 0) { - fd = open("/dev/null", O_WRONLY); - close(STDOUT_FILENO); - dup2(STDOUT_FILENO, fd); - } - - // Prepare the shared memory for io. Clear memory and initialize. - int *fd = &virt_quad_io_file_descriptor; - *fd = shm_open(VIRT_QUAD_SHARED_MEMORY, O_CREAT | O_RDWR | O_TRUNC, 0666); - ftruncate(*fd, sizeof(struct VirtQuadIO)); - virt_quad_io = mmap(NULL, sizeof(struct VirtQuadIO), PROT_READ | PROT_WRITE, MAP_SHARED, *fd, 0); - pthread_mutexattr_t attr; - pthread_mutexattr_init(&attr); - pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED); - pthread_mutex_init(&virt_quad_io->led_lock, &attr); - pthread_mutex_init(&virt_quad_io->motors_lock, &attr); - pthread_mutex_init(&virt_quad_io->rc_lock, &attr); + return 0; +} + +enum CLISubCommand parse_sub_command(char *argv[]) { + if (argv[0] == NULL) { + return USAGE; + } + else if (strcmp(argv[0], "start") == 0) { + return START; + } + else if (strcmp(argv[0], "help") == 0) { + return HELP; + } + else if (strcmp(argv[0], "get") == 0 && argv[1] != NULL) { + return GET; + } + else if (strcmp(argv[0], "set") == 0 && argv[1] != NULL && argv[2] != NULL) { + return SET; } else { - // parse command line arguments + return USAGE; + } +} - // Open exising shared memory for io. DO NOT CLEAR. - int *fd = &virt_quad_io_file_descriptor; - *fd = shm_open(VIRT_QUAD_SHARED_MEMORY, O_CREAT | O_RDWR, 0666); - virt_quad_io = mmap(NULL, sizeof(struct VirtQuadIO), PROT_READ | PROT_WRITE, MAP_SHARED, *fd, 0); +int start_virt_quad(char *argv[]) { + int fd; - if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-h") == 0) { - usage(argv[0]); - exit(0); - } - else if (strcmp(argv[1], "get") == 0 && argv[2] != NULL) { - handle_io_output(argv[2]); - } - else if (strcmp(argv[1], "set") == 0 && argv[2] != NULL && argv[3] != NULL) { - handle_io_input(argv[2], argv[3]); - } - else { - puts("Error in parsing commands"); - usage(argv[0]); - } - return 0; + // Allow making the quad quiet + if (argv[0] != NULL && strcmp(argv[0], "-q") == 0) { + fd = open("/dev/null", O_WRONLY); + close(STDOUT_FILENO); + dup2(STDOUT_FILENO, fd); } - puts("Starting the quad application"); + puts("Starting the virtual quad."); + puts("Open another tab to query and control the virt quad, using the get and set commands."); quad_main(setup_hardware); return 0; } +void open_new_shm_io() { + // Prepare the shared memory for io. Clear memory and initialize. + int *fd = &virt_quad_io_file_descriptor; + *fd = shm_open(VIRT_QUAD_SHARED_MEMORY, O_CREAT | O_RDWR | O_TRUNC, 0666); + ftruncate(*fd, sizeof(struct VirtQuadIO)); + virt_quad_io = mmap(NULL, sizeof(struct VirtQuadIO), PROT_READ | PROT_WRITE, MAP_SHARED, *fd, 0); + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED); + pthread_mutex_init(&virt_quad_io->led_lock, &attr); + pthread_mutex_init(&virt_quad_io->motors_lock, &attr); + pthread_mutex_init(&virt_quad_io->rc_lock, &attr); +} + +void open_existing_shm_io() { + // Open exising shared memory for io. DO NOT CLEAR. + int *fd = &virt_quad_io_file_descriptor; + *fd = shm_open(VIRT_QUAD_SHARED_MEMORY, O_CREAT | O_RDWR, 0666); + virt_quad_io = mmap(NULL, sizeof(struct VirtQuadIO), PROT_READ | PROT_WRITE, MAP_SHARED, *fd, 0); +} + + /** * The user wants to read an output by name. Get the output * and print to stdout. @@ -203,25 +246,79 @@ void print_shm_int(int *value, pthread_mutex_t *lock) { } void usage(char *executable_name) { - printf("Usage: %s [ -h | --help | -q ] [ command ]\n", executable_name); + printf("Usage: %s command [ args ]\n", executable_name); puts("Overview:"); puts(" The virtual quad emulates the behavior of the real quad in the Unix"); puts(" environment. Start the virtual quad in one tab (no arguments), and"); puts(" then control the I/O of the quad through commands."); + puts(""); + puts(" For help on a particular command, pass the command name to the help command"); + puts(" Example:"); + printf(" %s help get\n", executable_name); + puts(""); puts("Commands:"); - puts(" get output"); - puts(" set input value"); - puts("Outpus:"); - puts(" led"); - puts(" motors"); - puts("Inputs:"); - puts(" rc_gear"); - puts(" rc_flap"); - puts(" rc_throttle"); - puts(" rc_pitch"); - puts(" rc_roll"); - puts(" rc_yaw"); - puts("Examples:"); - printf(" %s get led # prints 0 or 1 to stdout\n", executable_name); - printf(" in%s set rc_gear 1 # sets gear to \"on\" \n", executable_name); + puts(" help"); + puts(" get"); + puts(" set"); + puts(" start"); + puts(""); +} + +void help_sub_command(char *argv[]) { + if (argv[2] == NULL) { + usage(argv[0]); + } + else if (strcmp(argv[2], "help") == 0) { + puts("Really?"); + } + else if (strcmp(argv[2], "get") == 0) { + printf("Usage: %s get output_name\n", argv[0]); + puts(""); + puts(" Get an output on the virtual quad, specified by its output_name, and print"); + puts(" to stdout"); + puts(""); + puts(" Possible output names"); + puts(" led"); + puts(" motor1"); + puts(" motor2"); + puts(" motor3"); + puts(" motor4"); + puts(""); + } + else if (strcmp(argv[2], "set") == 0) { + printf("Usage: %s set input_name val\n", argv[0]); + puts(""); + puts(" Set the value of an input on the quad, specified by its input_name"); + puts(""); + puts(" Possible input names"); + puts(" rc_throttle"); + puts(" rc_pitch"); + puts(" rc_roll"); + puts(" rc_yaw"); + puts(" rc_gear"); + puts(" rc_flap"); + puts(" i2c_imu_x"); + puts(" i2c_imu_y"); + puts(" i2c_imu_z"); + puts(" i2c_imu_p"); + puts(" i2c_imu_q"); + puts(" i2c_imu_r"); + puts(" i2c_imu_mag_x"); + puts(" i2c_imu_mag_y"); + puts(" i2c_imu_mag_z"); + puts(""); + } + else if (strcmp(argv[2], "start") == 0) { + printf("Usage: %s start [ -q ]\n", argv[0]); + puts(""); + puts(" Start the virtual quad. Exit using ctrl-c. In order to get and set I/O,"); + puts(" you'll need to open another tab."); + puts(""); + puts(" Flags"); + puts(" q - Keep the quad quiet; don't print logs to the stdout"); + puts(""); + } + else { + usage(argv[0]); + } } -- GitLab