Something went wrong on our end
-
James Talbert authoredJames Talbert authored
main.c 9.21 KiB
#include <stdio.h>
#include <unistd.h>
#include "hw_impl_unix.h"
#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);
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.
*/
int setup_hardware(hardware_t *hardware) {
hardware->i2c_0 = create_unix_i2c();
hardware->i2c_1 = create_unix_i2c();
hardware->rc_receiver = create_unix_rc_receiver();
hardware->motors = create_unix_motors();
hardware->uart_0 = create_unix_uart();
hardware->comm = create_unix_comm(&hardware->uart_0);
hardware->global_timer = create_unix_global_timer();
hardware->axi_timer = create_unix_axi_timer();
hardware->mio7_led = create_unix_mio7_led();
hardware->sys = create_unix_system();
hardware->imu = create_unix_imu(&hardware->i2c_0);
hardware->lidar = create_unix_lidar(&hardware->i2c_1);
hardware->of = create_unix_optical_flow(&hardware->i2c_0);
return 0;
}
int main(int argc, char *argv[]) {
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;
}
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 {
return USAGE;
}
}
int start_virt_quad(char *argv[]) {
int fd;
// 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 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);
pthread_mutex_init(&virt_quad_io->i2c_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.
*/
int handle_io_output(const char *name) {
int ret = 0;
struct VirtQuadIO *io = virt_quad_io;
if (strcmp(name, "led") == 0) {
print_shm_int(&io->led, &io->led_lock);
}
else if (strcmp(name, "motor1") == 0) {
print_shm_float(&io->motors[0], &io->motors_lock);
}
else if (strcmp(name, "motor2") == 0) {
print_shm_float(&io->motors[1], &io->motors_lock);
}
else if (strcmp(name, "motor3") == 0) {
print_shm_float(&io->motors[2], &io->motors_lock);
}
else if (strcmp(name, "motor4") == 0) {
print_shm_float(&io->motors[3], &io->motors_lock);
}
else {
puts("Given output not recognized.");
ret = -1;
}
return ret;
}
/**
* The user wants to set an input by name, and has supplied
* a value. Set the appropriate input to the given value.
*/
int handle_io_input(const char *name, const char *value_str) {
int ret = 0;
errno = 0;
float value = strtof(value_str, NULL);
if (errno) {
ret = -1;
puts("Given number format was bad.");
}
else {
struct VirtQuadIO *io = virt_quad_io;
if (strcmp(name, "rc_throttle") == 0) {
set_shm(value, &io->rc_receiver[THROTTLE], &io->rc_lock);
}
else if (strcmp(name, "rc_roll") == 0) {
set_shm(value, &io->rc_receiver[ROLL], &io->rc_lock);
}
else if (strcmp(name, "rc_pitch") == 0) {
set_shm(value, &io->rc_receiver[PITCH], &io->rc_lock);
}
else if (strcmp(name, "rc_yaw") == 0) {
set_shm(value, &io->rc_receiver[YAW], &io->rc_lock);
}
else if (strcmp(name, "rc_gear") == 0) {
set_shm(value, &io->rc_receiver[GEAR], &io->rc_lock);
}
else if (strcmp(name, "rc_flap") == 0) {
set_shm(value, &io->rc_receiver[FLAP], &io->rc_lock);
}
else if (strcmp(name, "i2c_imu_x") == 0) {
set_shm(value, &io->gam.accel_x, &io->i2c_lock);
}
else if (strcmp(name, "i2c_imu_y") == 0) {
set_shm(value, &io->gam.accel_y, &io->i2c_lock);
}
else if (strcmp(name, "i2c_imu_z") == 0) {
set_shm(value, &io->gam.accel_z, &io->i2c_lock);
}
else if (strcmp(name, "i2c_imu_p") == 0) {
set_shm(value, &io->gam.gyro_xVel_p, &io->i2c_lock);
}
else if (strcmp(name, "i2c_imu_q") == 0) {
set_shm(value, &io->gam.gyro_yVel_q, &io->i2c_lock);
}
else if (strcmp(name, "i2c_imu_r") == 0) {
set_shm(value, &io->gam.gyro_zVel_r, &io->i2c_lock);
}
else if (strcmp(name, "i2c_imu_mag_x") == 0) {
set_shm(value, &io->gam.mag_x, &io->i2c_lock);
}
else if (strcmp(name, "i2c_imu_mag_y") == 0) {
set_shm(value, &io->gam.mag_y, &io->i2c_lock);
}
else if (strcmp(name, "i2c_imu_mag_z") == 0) {
set_shm(value, &io->gam.mag_z, &io->i2c_lock);
}
else {
puts("Given input not recognized.");
ret = -1;
}
}
return ret;
}
void set_shm(float value, float *dest, pthread_mutex_t *lock) {
pthread_mutex_lock(lock);
*dest = value;
pthread_mutex_unlock(lock);
}
void print_shm_float(float *value, pthread_mutex_t *lock) {
pthread_mutex_lock(lock);
printf("%f\n", *value);
pthread_mutex_unlock(lock);
}
void print_shm_int(int *value, pthread_mutex_t *lock) {
pthread_mutex_lock(lock);
printf("%d\n", *value);
pthread_mutex_unlock(lock);
}
void usage(char *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, and then control the I/O");
puts(" of the virtual 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(" 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]);
}
}