From 3296e4a4f085911c781f94c1c8dd6049d39b9194 Mon Sep 17 00:00:00 2001 From: Grazfather Date: Mon, 18 Sep 2017 21:45:33 -0700 Subject: [PATCH 1/6] Revert "Revert "Support tui"" This reverts commit a40ea65a09f1bfc7981a213ec87ac1f5fbe5b7b6. --- Makefile | 8 +- config.h | 8 + controls | Bin 26348 -> 0 bytes controls.c | 1086 +++++++++++++++++++++++++++++++--------------------- icsim | Bin 29199 -> 0 bytes icsim.c | 818 +++++++++++++++++++++------------------ lib.o | Bin 12440 -> 0 bytes 7 files changed, 1094 insertions(+), 826 deletions(-) create mode 100644 config.h delete mode 100755 controls delete mode 100755 icsim delete mode 100644 lib.o diff --git a/Makefile b/Makefile index a5c3197..e9f4d74 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ CC=gcc -CFLAGS=-I/usr/include/SDL2 +CFLAGS=-I/usr/include/SDL2 -Wall -Werror LDFLAGS=-lSDL2 -lSDL2_image all: icsim controls @@ -8,10 +8,10 @@ icsim: icsim.o lib.o $(CC) $(CFLAGS) -o icsim icsim.c lib.o $(LDFLAGS) controls: controls.o - $(CC) $(CFLAGS) -o controls controls.c $(LDFLAGS) + $(CC) $(CFLAGS) -o controls controls.c $(LDFLAGS) -lpthread lib.o: - $(CC) lib.c + $(CC) -c lib.c clean: - rm -rf icsim controls icsim.o controls.o + rm -rf icsim controls icsim.o controls.o lib.o diff --git a/config.h b/config.h new file mode 100644 index 0000000..1610e4d --- /dev/null +++ b/config.h @@ -0,0 +1,8 @@ +#ifndef CONFIG_H +#define CONFIG_H + +#ifndef DISABLE_SDL +#define DISABLE_SDL 0 +#endif + +#endif // CONFIG_H diff --git a/controls b/controls deleted file mode 100755 index cf99e6833ed9555dccf8c20f96b4cd04b39704e4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26348 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 diff --git a/controls.c b/controls.c index 56e4551..9bb09a4 100644 --- a/controls.c +++ b/controls.c @@ -17,8 +17,16 @@ #include #include #include +#include +#include +#include + +#include "config.h" + +#if !(DISABLE_SDL) #include #include +#endif // !DISABLE_SDL #ifndef DATA_DIR #define DATA_DIR "./data/" @@ -45,6 +53,10 @@ #define OFF 0 #define DOOR_LOCKED 0 #define DOOR_UNLOCKED 1 +#define MAX_SPEED 150.0 // Limiter 260.0 is full gauge speed +#define ACCEL_RATE 8.0 // 0-MAX_SPEED in seconds + +#if !(DISABLE_SDL) #define SCREEN_WIDTH 835 #define SCREEN_HEIGHT 608 #define JOY_UNKNOWN -1 @@ -77,8 +89,6 @@ #define PS3_X_ROT 4 #define PS3_Y_ROT 5 #define PS3_Z_ROT 6 // The rotations are just guessed -#define MAX_SPEED 90.0 // Limiter 260.0 is full guage speed -#define ACCEL_RATE 8.0 // 0-MAX_SPEED in seconds #define USB_CONTROLLER 0 #define PS3_CONTROLLER 1 @@ -103,10 +113,12 @@ int gJoyZ = JOY_UNKNOWN; //Analog joystick dead zone const int JOYSTICK_DEAD_ZONE = 8000; int gLastAccelValue = 0; // Non analog R2 +#endif // !DISABLE_SDL int s; // socket struct canfd_frame cf; char *traffic_log = DEFAULT_CAN_TRAFFIC; + struct ifreq ifr; int door_pos = DEFAULT_DOOR_POS; int signal_pos = DEFAULT_SIGNAL_POS; @@ -119,24 +131,29 @@ int difficulty = DEFAULT_DIFFICULTY; int lock_enabled = 0; int unlock_enabled = 0; char door_state = 0xf; -char signal_state = 0; int throttle = 0; float current_speed = 0; int turning = 0; int door_id, signal_id, speed_id; -int currentTime; +struct timespec currentTime; +int current_ms = 0; int lastAccel = 0; int lastTurnSignal = 0; +char signal_state = 0; +int do_lock[4] = {0}; +int do_unlock[4] = {0}; int seed = 0; int debug = 0; +int play_pid; +int text_mode = 0; +int keyboard_mode = 0; -int play_id; +#if !(DISABLE_SDL) int kk = 0; char data_file[256]; SDL_GameController *gGameController = NULL; SDL_Joystick *gJoystick = NULL; -SDL_Haptic *gHaptic = NULL; SDL_Renderer *renderer = NULL; SDL_Texture *base_texture = NULL; int gControllerType = USB_CONTROLLER; @@ -147,17 +164,18 @@ void kk_check(int); // Uses a single pointer so not to have a memory leak // returns point to data_files or NULL if append is too large char *get_data(char *fname) { - if(strlen(DATA_DIR) + strlen(fname) > 255) return NULL; - strncpy(data_file, DATA_DIR, 255); - strncat(data_file, fname, 255-strlen(data_file)); - return data_file; + if(strlen(DATA_DIR) + strlen(fname) > 255) return NULL; + strncpy(data_file, DATA_DIR, 255); + strncat(data_file, fname, 255-strlen(data_file)); + return data_file; } +#endif // !DISABLE_SDL void send_pkt(int mtu) { - if(write(s, &cf, mtu) != mtu) { - perror("write"); - } + if(write(s, &cf, mtu) != mtu) { + perror("write"); + } } // Randomizes bytes in CAN packet if difficulty is hard enough @@ -191,8 +209,21 @@ void send_unlock(char door) { send_pkt(CAN_MTU); } +void check_locks() { + for (int i = 0; i < 4; i++) { + if (do_lock[i] == 1) { + send_lock(1 << i); + do_lock[i] = 0; + } + if (do_unlock[i] == 1) { + send_unlock(1 << i); + do_unlock[i] = 0; + } + } +} + void send_speed() { - int kph = (current_speed / 0.6213751) * 100; + int kph = (int)current_speed * 100; memset(&cf, 0, sizeof(cf)); cf.can_id = speed_id; cf.len = speed_len; @@ -218,10 +249,10 @@ void send_turn_signal() { } // Checks throttle to see if we should accelerate or decelerate the vehicle -void checkAccel() { +void check_accel() { float rate = MAX_SPEED / (ACCEL_RATE * 100); // Updated every 10 ms - if(currentTime > lastAccel + 10) { + if(current_ms > lastAccel + 10) { if(throttle < 0) { current_speed -= rate; if(current_speed < 1) current_speed = 0; @@ -229,29 +260,31 @@ void checkAccel() { current_speed += rate; if(current_speed > MAX_SPEED) { // Limiter current_speed = MAX_SPEED; - if(gHaptic != NULL) {SDL_HapticRumblePlay( gHaptic, 0.5, 1000); printf("DEBUG HAPTIC\n"); } } } send_speed(); - lastAccel = currentTime; + lastAccel = current_ms; } } // Checks if turning and activates the turn signal -void checkTurn() { - if(currentTime > lastTurnSignal + 500) { +void check_turn() { + if(current_ms > lastTurnSignal + 500) { if(turning < 0) { signal_state ^= CAN_LEFT_SIGNAL; + signal_state &= ~CAN_RIGHT_SIGNAL; } else if(turning > 0) { signal_state ^= CAN_RIGHT_SIGNAL; + signal_state &= ~CAN_LEFT_SIGNAL; } else { signal_state = 0; } send_turn_signal(); - lastTurnSignal = currentTime; + lastTurnSignal = current_ms; } } +#if !(DISABLE_SDL) // Takes R2 joystick value and converts it to throttle speed void accelerate(int value) { // Check dead zones @@ -298,93 +331,82 @@ void ud(int value) { } void kkpay() { - printf("KK\n"); + printf("KK\n"); } void kk_check(int k) { - switch(k) { - case SDLK_RETURN: - if(kk == 0xa) kkpay(); - kk = 0; - break; - case SDLK_UP: - kk = (kk < 2) ? kk+1 : 0; - break; - case SDLK_DOWN: - kk = (kk > 1 && kk < 4) ? kk+1 : 0; - break; - case SDLK_LEFT: - kk = (kk == 4 || kk == 6) ? kk+1 : 0; - break; - case SDLK_RIGHT: - kk = (kk == 5 || kk == 7) ? kk+1 : 0; - break; - case SDLK_a: - kk = kk == 9 ? kk+1 : 0; - break; - case SDLK_b: - kk = kk == 8 ? kk+1 : 0; - break; - default: - kk == 0; - } -} - -// Plays background can traffic -void play_can_traffic() { - char can2can[50]; - snprintf(can2can, 49, "%s=can0", ifr.ifr_name); - if(execlp("canplayer", "canplayer", "-I", traffic_log, "-l", "i", can2can, NULL) == -1) printf("WARNING: Could not execute canplayer. No bg data\n"); -} - -void kill_child() { - kill(play_id, SIGINT); + switch(k) { + case SDLK_RETURN: + if(kk == 0xa) kkpay(); + kk = 0; + break; + case SDLK_UP: + kk = (kk < 2) ? kk+1 : 0; + break; + case SDLK_DOWN: + kk = (kk > 1 && kk < 4) ? kk+1 : 0; + break; + case SDLK_LEFT: + kk = (kk == 4 || kk == 6) ? kk+1 : 0; + break; + case SDLK_RIGHT: + kk = (kk == 5 || kk == 7) ? kk+1 : 0; + break; + case SDLK_a: + kk = kk == 9 ? kk+1 : 0; + break; + case SDLK_b: + kk = kk == 8 ? kk+1 : 0; + break; + default: + kk = 0; + } } -void redraw_screen() { - SDL_RenderCopy(renderer, base_texture, NULL, NULL); - SDL_RenderPresent(renderer); +void redraw_gui() { + SDL_RenderCopy(renderer, base_texture, NULL, NULL); + SDL_RenderPresent(renderer); } // Maps the controllers buttons void map_joy() { switch(gControllerType) { - case USB_CONTROLLER: - gButtonA = BUTTON_A; - gButtonB = BUTTON_B; - gButtonX = BUTTON_X; - gButtonY = BUTTON_Y; - gButtonStart = BUTTON_START; - gButtonLock = BUTTON_LOCK; - gButtonUnlock = BUTTON_UNLOCK; - gAxisL2 = AXIS_L2; - gAxisR2 = AXIS_R2; - gAxisRightH = AXIS_RIGHT_H; - gAxisRightV = AXIS_RIGHT_V; - gAxisLeftH = AXIS_LEFT_H; - gAxisLeftV = AXIS_LEFT_V; - break; - case PS3_CONTROLLER: - gButtonA = PS3_BUTTON_A; - gButtonB = PS3_BUTTON_B; - gButtonX = PS3_BUTTON_X; - gButtonY = PS3_BUTTON_Y; - gButtonStart = PS3_BUTTON_START; - gButtonLock = PS3_BUTTON_LOCK; - gButtonUnlock = PS3_BUTTON_UNLOCK; - gAxisL2 = PS3_AXIS_L2; - gAxisR2 = PS3_AXIS_R2; - gAxisRightH = PS3_AXIS_RIGHT_H; - gAxisRightV = PS3_AXIS_RIGHT_V; - gAxisLeftH = PS3_AXIS_LEFT_H; - gAxisLeftV = PS3_AXIS_LEFT_V; - gJoyX = PS3_X_ROT; - gJoyY = PS3_Y_ROT; - gJoyZ = PS3_Z_ROT; - break; - default: - printf("Unknown controller type for mapping\n"); - } + case USB_CONTROLLER: + gButtonA = BUTTON_A; + gButtonB = BUTTON_B; + gButtonX = BUTTON_X; + gButtonY = BUTTON_Y; + gButtonStart = BUTTON_START; + gButtonLock = BUTTON_LOCK; + gButtonUnlock = BUTTON_UNLOCK; + gAxisL2 = AXIS_L2; + gAxisR2 = AXIS_R2; + gAxisRightH = AXIS_RIGHT_H; + gAxisRightV = AXIS_RIGHT_V; + gAxisLeftH = AXIS_LEFT_H; + gAxisLeftV = AXIS_LEFT_V; + break; + case PS3_CONTROLLER: + gButtonA = PS3_BUTTON_A; + gButtonB = PS3_BUTTON_B; + gButtonX = PS3_BUTTON_X; + gButtonY = PS3_BUTTON_Y; + gButtonStart = PS3_BUTTON_START; + gButtonLock = PS3_BUTTON_LOCK; + gButtonUnlock = PS3_BUTTON_UNLOCK; + gAxisL2 = PS3_AXIS_L2; + gAxisR2 = PS3_AXIS_R2; + gAxisRightH = PS3_AXIS_RIGHT_H; + gAxisRightV = PS3_AXIS_RIGHT_V; + gAxisLeftH = PS3_AXIS_LEFT_H; + gAxisLeftV = PS3_AXIS_LEFT_V; + gJoyX = PS3_X_ROT; + gJoyY = PS3_Y_ROT; + gJoyZ = PS3_Z_ROT; + break; + default: + printf("Unknown controller type for mapping\n"); + } } void print_joy_info() { @@ -392,383 +414,555 @@ void print_joy_info() { printf("Number of Axes: %d\n", SDL_JoystickNumAxes(gJoystick)); printf("Number of Buttons: %d\n", SDL_JoystickNumButtons(gJoystick)); if(SDL_JoystickNumBalls(gJoystick) > 0) printf("Number of Balls: %d\n", SDL_JoystickNumBalls(gJoystick)); - if(strncmp(SDL_JoystickNameForIndex(0), "PLAYSTATION(R)3 Controller", 25) == 0) { + if(strncmp(SDL_JoystickNameForIndex(0), "PLAYSTATION(R)3 Controller", 25) == 0) { // PS3 Rumble controller via BT gControllerType = PS3_CONTROLLER; } - if(strncmp(SDL_JoystickNameForIndex(0), "Sony PLAYSTATION(R)3 Controller", 30) == 0) { + if(strncmp(SDL_JoystickNameForIndex(0), "Sony PLAYSTATION(R)3 Controller", 30) == 0) { // PS3 directly connected gControllerType = PS3_CONTROLLER; } map_joy(); } +#endif // !DISABLE_SDL + +void *watch_input(void* arg) +{ + int c; + struct termios orig_attr; + struct termios new_attr;; + + // Set terminal to raw input + tcgetattr(fileno(stdin), &orig_attr); + memcpy(&new_attr, &orig_attr, sizeof(struct termios)); + new_attr.c_lflag &= ~(ECHO|ICANON); + new_attr.c_cc[VTIME] = 0; + new_attr.c_cc[VMIN] = 0; + tcsetattr(fileno(stdin), TCSANOW, &new_attr); + + // What's a race condition? + while (1) { + c = getc(stdin); + switch(c) { + case 'w': + throttle = 1; + break; + case 'a': + turning = -1; + break; + case 's': + throttle = -1; + break; + case 'd': + turning = 1; + break; + case ' ': + turning = 0; + break; + case 'q': + lock_enabled = 1; + unlock_enabled = 0; + break; + case 'e': + lock_enabled = 0; + unlock_enabled = 1; + break; + case '1': + if (lock_enabled) { + do_lock[0] = 1; + } else if (unlock_enabled) { + do_unlock[0] = 1; + } + break; + case '2': + if (lock_enabled) { + do_lock[1] = 1; + } else if (unlock_enabled) { + do_unlock[1] = 1; + } + break; + case '3': + if (lock_enabled) { + do_lock[2] = 1; + } else if (unlock_enabled) { + do_unlock[2] = 1; + } + break; + case '4': + if (lock_enabled) { + do_lock[3] = 1; + } else if (unlock_enabled) { + do_unlock[3] = 1; + } + break; + } + usleep(5000); + } + // TODO: Restore terminal (this isn't reached) + tcsetattr(fileno(stdin), TCSANOW, &orig_attr); + return NULL; +} +void clear_screen() +{ + write(STDOUT_FILENO, "\e[1;1H\e[2J", 10); +} + +void redraw_tui() { + clear_screen(); + printf("Indicator: "); + if (turning) { + printf("%s\n", turning < 0 ? "LEFT" : "RIGHT"); + } else { + printf("OFF\n"); + } + + printf("Throttle: %s\n", throttle > 0 ? "ON" : "OFF"); + printf("Unlock enabled: %s\n", unlock_enabled ? "YES" : "NO"); + printf("Lock enabled: %s\n", lock_enabled ? "YES" : "NO"); +} + +// Plays background can traffic +void play_can_traffic() { + char can2can[50]; + snprintf(can2can, 49, "%s=can0", ifr.ifr_name); + if(execlp("canplayer", "canplayer", "-I", traffic_log, "-l", "i", can2can, NULL) == -1) { + printf("WARNING: Could not execute canplayer. No bg data\n"); + } +} + +void kill_child() { + kill(play_pid, SIGINT); +} void usage(char *msg) { - if(msg) printf("%s\n", msg); - printf("Usage: controls [options] \n"); - printf("\t-s\tseed value from IC\n"); - printf("\t-l\tdifficulty level. 0-2 (default: %d)\n", DEFAULT_DIFFICULTY); - printf("\t-t\ttraffic file to use for bg CAN traffic\n"); - printf("\t-X\tDisable background CAN traffic. Cheating if doing RE but needed if playing on a real CANbus\n"); - printf("\t-d\tdebug mode\n"); - exit(1); + if(msg) printf("%s\n", msg); + printf("Usage: controls [options] \n"); + printf("\t-s\tseed value from IC\n"); + printf("\t-l\tdifficulty level. 0-2 (default: %d)\n", DEFAULT_DIFFICULTY); + printf("\t-T\ttraffic file to use for bg CAN traffic\n"); + printf("\t-t\ttext mode\n"); + printf("\t-k\tuse keyboard for input\n"); + printf("\t-X\tdisable background CAN traffic. Cheating if doing RE but needed if playing on a real CANbus\n"); + printf("\t-d\tdebug mode\n"); + exit(1); } +struct ui_t { + void (*redraw)(void); +}; + int main(int argc, char *argv[]) { - int opt; - struct sockaddr_can addr; - struct canfd_frame frame; - int running = 1; - int enable_canfd = 1; - int play_traffic = 1; - struct stat st; - SDL_Event event; - - while ((opt = getopt(argc, argv, "Xdl:s:t:h?")) != -1) { - switch(opt) { - case 'l': - difficulty = atoi(optarg); - break; - case 's': - seed = atoi(optarg); - break; - case 't': - traffic_log = optarg; - break; - case 'd': - debug = 1; - break; - case 'X': - play_traffic = 0; - break; - case 'h': - case '?': - default: - usage(NULL); - break; - } - } - - if (optind >= argc) usage("You must specify at least one can device"); - - if(stat(traffic_log, &st) == -1) { - char msg[256]; - snprintf(msg, 255, "CAN Traffic file not found: %s\n", traffic_log); - usage(msg); - } - - /* open socket */ - if ((s = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) { - perror("socket"); - return 1; - } - - addr.can_family = AF_CAN; - - strcpy(ifr.ifr_name, argv[optind]); - if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) { - perror("SIOCGIFINDEX"); - return 1; - } - addr.can_ifindex = ifr.ifr_ifindex; - - if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, - &enable_canfd, sizeof(enable_canfd))){ - printf("error when enabling CAN FD support\n"); - return 1; - } - - if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) { - perror("bind"); - return 1; - } - - door_id = DEFAULT_DOOR_ID; - signal_id = DEFAULT_SIGNAL_ID; - speed_id = DEFAULT_SPEED_ID; - - if (seed) { - srand(seed); - door_id = (rand() % 2046) + 1; - signal_id = (rand() % 2046) + 1; - speed_id = (rand() % 2046) + 1; - door_pos = rand() % 9; - signal_pos = rand() % 9; - speed_pos = rand() % 8; - printf("Seed: %d\n", seed); - door_len = door_pos + 1; - signal_len = signal_pos + 1; - speed_len = speed_len + 2; - } - - if(difficulty > 0) { - if (door_len < 8) { - door_len += rand() % (8 - door_len); - } else { - door_len = 0; + int opt; + struct sockaddr_can addr; + int running = 1; + int enable_canfd = 1; + int enable_background_traffic = 1; + struct stat st; + struct ui_t ui = {0}; + +#if !(DISABLE_SDL) + SDL_Event event; + int button, axis; // Used for checking dynamic joystick mappings + SDL_Surface *image = NULL; + SDL_Window *window = NULL; +#endif // !DISABLE_SDL + + while ((opt = getopt(argc, argv, "Xdl:s:T:tkh?")) != -1) { + switch(opt) { + case 'l': + difficulty = atoi(optarg); + break; + case 's': + seed = atoi(optarg); + break; + case 'T': + traffic_log = optarg; + break; + case 't': + text_mode = 1; + break; + case 'k': + keyboard_mode = 1; + break; + case 'd': + debug = 1; + break; + case 'X': + enable_background_traffic = 0; + break; + case 'h': + case '?': + default: + usage(NULL); + break; + } } - if (signal_len < 8) { - signal_len += rand() % (8 - signal_len); - } else { - signal_len = 0; + +#if DISABLE_SDL + text_mode = 1; + keyboard_mode = 1; +#endif // DISABLE_SDL + + if (optind >= argc) usage("You must specify at least one can device"); + + if(stat(traffic_log, &st) == -1) { + char msg[256]; + snprintf(msg, 255, "CAN Traffic file not found: %s\n", traffic_log); + usage(msg); } - if (speed_len < 8) { - speed_len += rand() % (8 - speed_len); - } else { - speed_len = 0; + + /* open socket */ + if ((s = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) { + perror("socket"); + return 1; + } + + addr.can_family = AF_CAN; + + strcpy(ifr.ifr_name, argv[optind]); + if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) { + perror("SIOCGIFINDEX"); + return 1; } - } - - if(play_traffic) { - play_id = fork(); - if((int)play_id == -1) { - printf("Error: Couldn't fork bg player\n"); - exit(-1); - } else if (play_id == 0) { - play_can_traffic(); - // Shouldn't return - exit(0); + addr.can_ifindex = ifr.ifr_ifindex; + + if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, + &enable_canfd, sizeof(enable_canfd))){ + printf("error when enabling CAN FD support\n"); + return 1; + } + + if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + perror("bind"); + return 1; } - atexit(kill_child); - } - - // GUI Setup - SDL_Window *window = NULL; - SDL_Surface *screenSurface = NULL; - if(SDL_Init ( SDL_INIT_VIDEO | SDL_INIT_JOYSTICK ) < 0 ) { - printf("SDL Could not initializes\n"); - exit(40); - } - if( SDL_NumJoysticks() < 1) { - printf(" Warning: No joysticks connected\n"); - } else { - if(SDL_IsGameController(0)) { - gGameController = SDL_GameControllerOpen(0); - if(gGameController == NULL) { - printf(" Warning: Unable to open game controller. %s\n", SDL_GetError() ); - } else { - gJoystick = SDL_GameControllerGetJoystick(gGameController); - gHaptic = SDL_HapticOpenFromJoystick(gJoystick); - print_joy_info(); - } - } else { - gJoystick = SDL_JoystickOpen(0); - if(gJoystick == NULL) { - printf(" Warning: Could not open joystick\n"); + + door_id = DEFAULT_DOOR_ID; + signal_id = DEFAULT_SIGNAL_ID; + speed_id = DEFAULT_SPEED_ID; + + if (seed) { + srand(seed); + door_id = (rand() % 2046) + 1; + signal_id = (rand() % 2046) + 1; + speed_id = (rand() % 2046) + 1; + door_pos = rand() % 9; + signal_pos = rand() % 9; + speed_pos = rand() % 8; + printf("Seed: %d\n", seed); + door_len = door_pos + 1; + signal_len = signal_pos + 1; + speed_len = speed_len + 2; + } + + if(difficulty > 0) { + if (door_len < 8) { + door_len += rand() % (8 - door_len); } else { - gHaptic = SDL_HapticOpenFromJoystick(gJoystick); - if (gHaptic == NULL) printf("No Haptic support\n"); - print_joy_info(); + door_len = 0; } - } - } - window = SDL_CreateWindow("CANBus Control Panel", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE); - if(window == NULL) { - printf("Window could not be shown\n"); - } - renderer = SDL_CreateRenderer(window, -1, 0); - SDL_Surface *image = IMG_Load(get_data("joypad.png")); - base_texture = SDL_CreateTextureFromSurface(renderer, image); - SDL_RenderCopy(renderer, base_texture, NULL, NULL); - SDL_RenderPresent(renderer); - int button, axis; // Used for checking dynamic joystick mappings - - while(running) { - while( SDL_PollEvent(&event) != 0 ) { - switch(event.type) { - case SDL_QUIT: - running = 0; - break; - case SDL_WINDOWEVENT: - switch(event.window.event) { - case SDL_WINDOWEVENT_ENTER: - case SDL_WINDOWEVENT_RESIZED: - redraw_screen(); - break; + if (signal_len < 8) { + signal_len += rand() % (8 - signal_len); + } else { + signal_len = 0; } - case SDL_KEYDOWN: - switch(event.key.keysym.sym) { - case SDLK_UP: - throttle = 1; - break; - case SDLK_LEFT: - turning = -1; - break; - case SDLK_RIGHT: - turning = 1; - break; - case SDLK_LSHIFT: - lock_enabled = 1; - if(unlock_enabled) send_lock(CAN_DOOR1_LOCK | CAN_DOOR2_LOCK | CAN_DOOR3_LOCK | CAN_DOOR4_LOCK); - break; - case SDLK_RSHIFT: - unlock_enabled = 1; - if(lock_enabled) send_unlock(CAN_DOOR1_LOCK | CAN_DOOR2_LOCK | CAN_DOOR3_LOCK | CAN_DOOR4_LOCK); - break; - case SDLK_a: - if(lock_enabled) { - send_lock(CAN_DOOR1_LOCK); - } else if(unlock_enabled) { - send_unlock(CAN_DOOR1_LOCK); - } - break; - case SDLK_b: - if(lock_enabled) { - send_lock(CAN_DOOR2_LOCK); - } else if(unlock_enabled) { - send_unlock(CAN_DOOR2_LOCK); - } - break; - case SDLK_x: - if(lock_enabled) { - send_lock(CAN_DOOR3_LOCK); - } else if(unlock_enabled) { - send_unlock(CAN_DOOR3_LOCK); - } - break; - case SDLK_y: - if(lock_enabled) { - send_lock(CAN_DOOR4_LOCK); - } else if(unlock_enabled) { - send_unlock(CAN_DOOR4_LOCK); - } - break; + if (speed_len < 8) { + speed_len += rand() % (8 - speed_len); + } else { + speed_len = 0; } - kk_check(event.key.keysym.sym); - break; - case SDL_KEYUP: - switch(event.key.keysym.sym) { - case SDLK_UP: - throttle = -1; - break; - case SDLK_LEFT: - case SDLK_RIGHT: - turning = 0; - break; - case SDLK_LSHIFT: - lock_enabled = 0; - break; - case SDLK_RSHIFT: - unlock_enabled = 0; - break; + } + + if(enable_background_traffic) { + play_pid = fork(); + if((int)play_pid == -1) { + printf("Error: Couldn't fork bg player\n"); + exit(-1); + } else if (play_pid == 0) { + play_can_traffic(); + // Shouldn't return + exit(0); } - break; - case SDL_JOYAXISMOTION: - axis = event.jaxis.axis; - if(axis == gAxisLeftH) { - ud(event.jaxis.value); - } else if(axis == gAxisLeftV) { - turn(event.jaxis.value); - } else if(axis == gAxisR2) { - accelerate(event.jaxis.value); - } else if(axis == gAxisRightH || - axis == gAxisRightV || - axis == gAxisL2 || - axis == gJoyX || - axis == gJoyY || - axis == gJoyZ) { - // Do nothing, the axis is known just not connected - } else { - if (debug) printf("Unkown axis: %d\n", event.jaxis.axis); + atexit(kill_child); + } + + // Input setup + if (keyboard_mode) { + // Spawn input thread + pthread_t input_thread; + if(pthread_create(&input_thread, NULL, watch_input, NULL)) { + printf("Error: Couldn't create input thread\n"); } - break; - case SDL_JOYBUTTONDOWN: - button = event.jbutton.button; - if(button == gButtonLock) { - lock_enabled = 1; - if(unlock_enabled) send_lock(CAN_DOOR1_LOCK | CAN_DOOR2_LOCK | CAN_DOOR3_LOCK | CAN_DOOR4_LOCK); - } else if(button == gButtonUnlock) { - unlock_enabled = 1; - if(lock_enabled) send_unlock(CAN_DOOR1_LOCK | CAN_DOOR2_LOCK | CAN_DOOR3_LOCK | CAN_DOOR4_LOCK); - } else if(button == gButtonA) { - if(lock_enabled) { - send_lock(CAN_DOOR1_LOCK); - } else if(unlock_enabled) { - send_unlock(CAN_DOOR1_LOCK); - } - kk_check(SDLK_a); - } else if (button == gButtonB) { - if(lock_enabled) { - send_lock(CAN_DOOR2_LOCK); - } else if(unlock_enabled) { - send_unlock(CAN_DOOR2_LOCK); - } - kk_check(SDLK_b); - } else if (button == gButtonX) { - if(lock_enabled) { - send_lock(CAN_DOOR3_LOCK); - } else if(unlock_enabled) { - send_unlock(CAN_DOOR3_LOCK); - } - kk_check(SDLK_x); - } else if (button == gButtonY) { - if(lock_enabled) { - send_lock(CAN_DOOR4_LOCK); - } else if(unlock_enabled) { - send_unlock(CAN_DOOR4_LOCK); - } - kk_check(SDLK_y); - } else if (button == gButtonStart) { - kk_check(SDLK_RETURN); - } else { - if(debug) printf("Unassigned button: %d\n", event.jbutton.button); + } else { +#if !(DISABLE_SDL) + if(SDL_Init(SDL_INIT_JOYSTICK) < 0 ) { + printf("SDL Joystick subsystem could not be initialized\n"); + exit(40); } - break; - case SDL_JOYBUTTONUP: - button = event.jbutton.button; - if(button == gButtonLock) { - lock_enabled = 0; - } else if(button == gButtonUnlock) { - unlock_enabled = 0; + if(SDL_NumJoysticks() < 1) { + printf(" Warning: No joysticks connected\n"); } else { - //if(debug) printf("Unassigned button: %d\n", event.jbutton.button); - } - break; - case SDL_JOYDEVICEADDED: - // Only use the first controller - if(event.cdevice.which == 0) { - gJoystick = SDL_JoystickOpen(0); - if(gJoystick) { - gHaptic = SDL_HapticOpenFromJoystick(gJoystick); - print_joy_info(); + if(SDL_IsGameController(0)) { + gGameController = SDL_GameControllerOpen(0); + if(gGameController == NULL) { + printf(" Warning: Unable to open game controller. %s\n", SDL_GetError() ); + } else { + gJoystick = SDL_GameControllerGetJoystick(gGameController); + print_joy_info(); + } + } else { + gJoystick = SDL_JoystickOpen(0); + if(gJoystick == NULL) { + printf(" Warning: Could not open joystick\n"); + } else { + print_joy_info(); + } } } - break; - case SDL_JOYDEVICEREMOVED: - if(event.cdevice.which == 0) { - SDL_JoystickClose(gJoystick); - gJoystick = NULL; +#endif // !DISABLE_SDL + } + + // UI Setup + if (text_mode) { + ui.redraw = redraw_tui; + } else { +#if !(DISABLE_SDL) + ui.redraw = redraw_gui; + if(SDL_Init(SDL_INIT_VIDEO) < 0 ) { + printf("SDL Video subsystem could not be initialized\n"); + exit(40); + } + window = SDL_CreateWindow("CANBus Control Panel", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE); + if(window == NULL) { + printf("Window could not be shown\n"); } - break; - case SDL_CONTROLLERDEVICEADDED: - // Only use the first controller - if(gGameController == NULL) { - gGameController = SDL_GameControllerOpen(0); - gJoystick = SDL_GameControllerGetJoystick(gGameController); - gHaptic = SDL_HapticOpenFromJoystick(gJoystick); - print_joy_info(); + renderer = SDL_CreateRenderer(window, -1, 0); + image = IMG_Load(get_data("joypad.png")); + base_texture = SDL_CreateTextureFromSurface(renderer, image); +#endif // !DISABLE_SDL + } + ui.redraw(); + + while(running) { +#if !(DISABLE_SDL) + if (!keyboard_mode || !text_mode) { + while(SDL_PollEvent(&event) != 0 ) { + switch(event.type) { + case SDL_QUIT: + running = 0; + break; + case SDL_WINDOWEVENT: + switch(event.window.event) { + case SDL_WINDOWEVENT_ENTER: + case SDL_WINDOWEVENT_RESIZED: + ui.redraw(); + break; + } + case SDL_KEYDOWN: + switch(event.key.keysym.sym) { + case SDLK_UP: + throttle = 1; + break; + case SDLK_LEFT: + turning = -1; + break; + case SDLK_RIGHT: + turning = 1; + break; + case SDLK_LSHIFT: + lock_enabled = 1; + if(unlock_enabled) + do_unlock[0] = 1; + do_unlock[1] = 1; + do_unlock[3] = 1; + do_unlock[4] = 1; + break; + case SDLK_RSHIFT: + unlock_enabled = 1; + if(lock_enabled) + do_lock[0] = 1; + do_lock[1] = 1; + do_lock[3] = 1; + do_lock[4] = 1; + break; + case SDLK_a: + if(lock_enabled) { + do_lock[0] = 1; + } else if(unlock_enabled) { + do_unlock[0] = 1; + } + break; + case SDLK_b: + if(lock_enabled) { + do_lock[1] = 1; + } else if(unlock_enabled) { + do_unlock[1] = 1; + } + break; + case SDLK_x: + if(lock_enabled) { + do_lock[2] = 1; + } else if(unlock_enabled) { + do_unlock[2] = 1; + } + break; + case SDLK_y: + if(lock_enabled) { + do_lock[3] = 1; + } else if(unlock_enabled) { + do_unlock[3] = 1; + } + break; + } + kk_check(event.key.keysym.sym); + break; + case SDL_KEYUP: + switch(event.key.keysym.sym) { + case SDLK_UP: + throttle = -1; + break; + case SDLK_LEFT: + case SDLK_RIGHT: + turning = 0; + break; + case SDLK_LSHIFT: + lock_enabled = 0; + break; + case SDLK_RSHIFT: + unlock_enabled = 0; + break; + } + break; + case SDL_JOYAXISMOTION: + axis = event.jaxis.axis; + if(axis == gAxisLeftH) { + ud(event.jaxis.value); + } else if(axis == gAxisLeftV) { + turn(event.jaxis.value); + } else if(axis == gAxisR2) { + accelerate(event.jaxis.value); + } else if(axis == gAxisRightH || + axis == gAxisRightV || + axis == gAxisL2 || + axis == gJoyX || + axis == gJoyY || + axis == gJoyZ) { + // Do nothing, the axis is known just not connected + } else { + if (debug) printf("Unkown axis: %d\n", event.jaxis.axis); + } + break; + case SDL_JOYBUTTONDOWN: + button = event.jbutton.button; + if(button == gButtonLock) { + lock_enabled = 1; + if(unlock_enabled) + do_unlock[0] = 1; + do_unlock[1] = 1; + do_unlock[3] = 1; + do_unlock[4] = 1; + } else if(button == gButtonUnlock) { + unlock_enabled = 1; + if(lock_enabled) + do_lock[0] = 1; + do_lock[1] = 1; + do_lock[3] = 1; + do_lock[4] = 1; + } else if(button == gButtonA) { + if(lock_enabled) { + do_lock[0] = 1; + } else if(unlock_enabled) { + do_unlock[0] = 1; + } + kk_check(SDLK_a); + } else if (button == gButtonB) { + if(lock_enabled) { + do_lock[1] = 1; + } else if(unlock_enabled) { + do_unlock[2] = 1; + } + kk_check(SDLK_b); + } else if (button == gButtonX) { + if(lock_enabled) { + do_lock[2] = 1; + } else if(unlock_enabled) { + do_unlock[2] = 1; + } + kk_check(SDLK_x); + } else if (button == gButtonY) { + if(lock_enabled) { + do_lock[3] = 1; + } else if(unlock_enabled) { + do_unlock[3] = 1; + } + kk_check(SDLK_y); + } else if (button == gButtonStart) { + kk_check(SDLK_RETURN); + } else { + if(debug) printf("Unassigned button: %d\n", event.jbutton.button); + } + break; + case SDL_JOYBUTTONUP: + button = event.jbutton.button; + if(button == gButtonLock) { + lock_enabled = 0; + } else if(button == gButtonUnlock) { + unlock_enabled = 0; + } else { + //if(debug) printf("Unassigned button: %d\n", event.jbutton.button); + } + break; + case SDL_JOYDEVICEADDED: + // Only use the first controller + if(event.cdevice.which == 0) { + gJoystick = SDL_JoystickOpen(0); + if(gJoystick) { + print_joy_info(); + } + } + break; + case SDL_JOYDEVICEREMOVED: + if(event.cdevice.which == 0) { + SDL_JoystickClose(gJoystick); + gJoystick = NULL; + } + break; + case SDL_CONTROLLERDEVICEADDED: + // Only use the first controller + if(gGameController == NULL) { + gGameController = SDL_GameControllerOpen(0); + gJoystick = SDL_GameControllerGetJoystick(gGameController); + print_joy_info(); + } + break; + case SDL_CONTROLLERDEVICEREMOVED: + if(event.cdevice.which == 0) { + SDL_GameControllerClose(gGameController); + gGameController = NULL; + } + break; + } + } } - break; - case SDL_CONTROLLERDEVICEREMOVED: - if(event.cdevice.which == 0) { +#endif // !DISABLE_SDL + clock_gettime(CLOCK_MONOTONIC, ¤tTime); + current_ms = currentTime.tv_sec * 1000 + currentTime.tv_nsec / 1000000; + check_accel(); + check_turn(); + check_locks(); + ui.redraw(); + usleep(5000); + + close(s); +#if !(DISABLE_SDL) + if (!keyboard_mode || !text_mode) { + SDL_DestroyTexture(base_texture); + SDL_FreeSurface(image); SDL_GameControllerClose(gGameController); - gGameController = NULL; + SDL_DestroyRenderer(renderer); + SDL_DestroyWindow(window); + SDL_Quit(); } - break; - } - } - currentTime = SDL_GetTicks(); - checkAccel(); - checkTurn(); - SDL_Delay(5); - } - - close(s); - SDL_DestroyTexture(base_texture); - SDL_FreeSurface(image); - SDL_GameControllerClose(gGameController); - SDL_DestroyRenderer(renderer); - SDL_DestroyWindow(window); - SDL_Quit(); - +#endif // !DISABLE_SDL + } } diff --git a/icsim b/icsim deleted file mode 100755 index 2c81fb99a7c53f48c4164ad0dade97bb83aea0b0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 29199 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 U^k815Apek#h&p1%6bQEe0$aWP$N&HU diff --git a/icsim.c b/icsim.c index baef491..d3fb67b 100644 --- a/icsim.c +++ b/icsim.c @@ -15,17 +15,20 @@ #include #include #include -#include -#include +#include #include "lib.h" +#include "config.h" + +#if !(DISABLE_SDL) +#include +#include +#endif // !DISABLE_SDL #ifndef DATA_DIR #define DATA_DIR "./data/" // Needs trailing slash #endif -#define SCREEN_WIDTH 692 -#define SCREEN_HEIGHT 329 #define DOOR_LOCKED 0 #define DOOR_UNLOCKED 1 #define OFF 0 @@ -33,7 +36,7 @@ #define DEFAULT_DOOR_ID 411 // 0x19b #define DEFAULT_DOOR_BYTE 2 #define CAN_DOOR1_LOCK 1 -#define CAN_DOOR2_LOCK 2 +#define CAN_DOOR2_LOCK 2 #define CAN_DOOR3_LOCK 4 #define CAN_DOOR4_LOCK 8 #define DEFAULT_SIGNAL_ID 392 // 0x188 @@ -43,434 +46,497 @@ #define DEFAULT_SPEED_ID 580 // 0x244 #define DEFAULT_SPEED_BYTE 3 // bytes 3,4 +#if !(DISABLE_SDL) +#define SCREEN_WIDTH 692 +#define SCREEN_HEIGHT 329 +SDL_Renderer *renderer = NULL; +SDL_Texture *base_texture = NULL; +SDL_Texture *needle_tex = NULL; +SDL_Texture *sprite_tex = NULL; +SDL_Rect speed_rect; +#endif // !DISABLE_SDL + const int canfd_on = 1; int debug = 0; int randomize = 0; int seed = 0; -int door_pos = DEFAULT_DOOR_BYTE; -int signal_pos = DEFAULT_SIGNAL_BYTE; -int speed_pos = DEFAULT_SPEED_BYTE; +int text_mode = 0; long current_speed = 0; int door_status[4]; int turn_status[2]; char data_file[256]; -SDL_Renderer *renderer = NULL; -SDL_Texture *base_texture = NULL; -SDL_Texture *needle_tex = NULL; -SDL_Texture *sprite_tex = NULL; -SDL_Rect speed_rect; +int door_pos = DEFAULT_DOOR_BYTE; +int signal_pos = DEFAULT_SIGNAL_BYTE; +int speed_pos = DEFAULT_SPEED_BYTE; // Simple map function long map(long x, long in_min, long in_max, long out_min, long out_max) { - return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; + return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; } // Adds data dir to file name // Uses a single pointer so not to have a memory leak // returns point to data_files or NULL if append is too large char *get_data(char *fname) { - if(strlen(DATA_DIR) + strlen(fname) > 255) return NULL; - strncpy(data_file, DATA_DIR, 255); - strncat(data_file, fname, 255-strlen(data_file)); - return data_file; + if(strlen(DATA_DIR) + strlen(fname) > 255) return NULL; + strncpy(data_file, DATA_DIR, 255); + strncat(data_file, fname, 255-strlen(data_file)); + return data_file; } /* Default vehicle state */ void init_car_state() { - door_status[0] = DOOR_LOCKED; - door_status[1] = DOOR_LOCKED; - door_status[2] = DOOR_LOCKED; - door_status[3] = DOOR_LOCKED; - turn_status[0] = OFF; - turn_status[1] = OFF; + door_status[0] = DOOR_LOCKED; + door_status[1] = DOOR_LOCKED; + door_status[2] = DOOR_LOCKED; + door_status[3] = DOOR_LOCKED; + turn_status[0] = OFF; + turn_status[1] = OFF; } +#if !(DISABLE_SDL) /* Empty IC */ void blank_ic() { - SDL_RenderCopy(renderer, base_texture, NULL, NULL); + SDL_RenderCopy(renderer, base_texture, NULL, NULL); } /* Updates speedo */ void update_speed() { - SDL_Rect dial_rect; - SDL_Point center; - double angle = 0; - dial_rect.x = 200; - dial_rect.y = 80; - dial_rect.h = 130; - dial_rect.w = 300; - SDL_RenderCopy(renderer, base_texture, &dial_rect, &dial_rect); - /* Because it's a curve we do a smaller rect for the top */ - dial_rect.x = 250; - dial_rect.y = 30; - dial_rect.h = 65; - dial_rect.w = 200; - SDL_RenderCopy(renderer, base_texture, &dial_rect, &dial_rect); - // And one more smaller box for the pivot point of the needle - dial_rect.x = 323; - dial_rect.y = 171; - dial_rect.h = 52; - dial_rect.w = 47; - SDL_RenderCopy(renderer, base_texture, &dial_rect, &dial_rect); - center.x = 135; - center.y = 20; - angle = map(current_speed, 0, 280, 0, 180); - if(angle < 0) angle = 0; - if(angle > 180) angle = 180; - SDL_RenderCopyEx(renderer, needle_tex, NULL, &speed_rect, angle, ¢er, SDL_FLIP_NONE); + SDL_Rect dial_rect; + SDL_Point center; + double angle = 0; + dial_rect.x = 200; + dial_rect.y = 80; + dial_rect.h = 130; + dial_rect.w = 300; + SDL_RenderCopy(renderer, base_texture, &dial_rect, &dial_rect); + /* Because it's a curve we do a smaller rect for the top */ + dial_rect.x = 250; + dial_rect.y = 30; + dial_rect.h = 65; + dial_rect.w = 200; + SDL_RenderCopy(renderer, base_texture, &dial_rect, &dial_rect); + // And one more smaller box for the pivot point of the needle + dial_rect.x = 323; + dial_rect.y = 171; + dial_rect.h = 52; + dial_rect.w = 47; + SDL_RenderCopy(renderer, base_texture, &dial_rect, &dial_rect); + center.x = 135; + center.y = 20; + angle = map(current_speed, 0, 280, 0, 180); + if(angle < 0) angle = 0; + if(angle > 180) angle = 180; + SDL_RenderCopyEx(renderer, needle_tex, NULL, &speed_rect, angle, ¢er, SDL_FLIP_NONE); } /* Updates door unlocks simulated by door open icons */ void update_doors() { - SDL_Rect door_area, update, pos; - door_area.x = 390; - door_area.y = 215; - door_area.w = 110; - door_area.h = 85; - SDL_RenderCopy(renderer, base_texture, &door_area, &door_area); - // No update if all doors are locked - if(door_status[0] == DOOR_LOCKED && door_status[1] == DOOR_LOCKED && - door_status[2] == DOOR_LOCKED && door_status[3] == DOOR_LOCKED) return; - // Make the base body red if even one door is unlocked - update.x = 440; - update.y = 239; - update.w = 45; - update.h = 83; - memcpy(&pos, &update, sizeof(SDL_Rect)); - pos.x -= 22; - pos.y -= 22; - SDL_RenderCopy(renderer, sprite_tex, &update, &pos); - if(door_status[0] == DOOR_UNLOCKED) { - update.x = 420; - update.y = 263; - update.w = 21; - update.h = 22; - memcpy(&pos, &update, sizeof(SDL_Rect)); - pos.x -= 22; - pos.y -= 22; - SDL_RenderCopy(renderer, sprite_tex, &update, &pos); - } - if(door_status[1] == DOOR_UNLOCKED) { - update.x = 484; - update.y = 261; - update.w = 21; - update.h = 22; - memcpy(&pos, &update, sizeof(SDL_Rect)); - pos.x -= 22; - pos.y -= 22; - SDL_RenderCopy(renderer, sprite_tex, &update, &pos); - } - if(door_status[2] == DOOR_UNLOCKED) { - update.x = 420; - update.y = 284; - update.w = 21; - update.h = 22; - memcpy(&pos, &update, sizeof(SDL_Rect)); - pos.x -= 22; - pos.y -= 22; - SDL_RenderCopy(renderer, sprite_tex, &update, &pos); - } - if(door_status[3] == DOOR_UNLOCKED) { - update.x = 484; - update.y = 287; - update.w = 21; - update.h = 22; - memcpy(&pos, &update, sizeof(SDL_Rect)); - pos.x -= 22; - pos.y -= 22; - SDL_RenderCopy(renderer, sprite_tex, &update, &pos); - } + SDL_Rect door_area, update, pos; + door_area.x = 390; + door_area.y = 215; + door_area.w = 110; + door_area.h = 85; + SDL_RenderCopy(renderer, base_texture, &door_area, &door_area); + // No update if all doors are locked + if(door_status[0] == DOOR_LOCKED && door_status[1] == DOOR_LOCKED && + door_status[2] == DOOR_LOCKED && door_status[3] == DOOR_LOCKED) return; + // Make the base body red if even one door is unlocked + update.x = 440; + update.y = 239; + update.w = 45; + update.h = 83; + memcpy(&pos, &update, sizeof(SDL_Rect)); + pos.x -= 22; + pos.y -= 22; + SDL_RenderCopy(renderer, sprite_tex, &update, &pos); + if(door_status[0] == DOOR_UNLOCKED) { + update.x = 420; + update.y = 263; + update.w = 21; + update.h = 22; + memcpy(&pos, &update, sizeof(SDL_Rect)); + pos.x -= 22; + pos.y -= 22; + SDL_RenderCopy(renderer, sprite_tex, &update, &pos); + } + if(door_status[1] == DOOR_UNLOCKED) { + update.x = 484; + update.y = 261; + update.w = 21; + update.h = 22; + memcpy(&pos, &update, sizeof(SDL_Rect)); + pos.x -= 22; + pos.y -= 22; + SDL_RenderCopy(renderer, sprite_tex, &update, &pos); + } + if(door_status[2] == DOOR_UNLOCKED) { + update.x = 420; + update.y = 284; + update.w = 21; + update.h = 22; + memcpy(&pos, &update, sizeof(SDL_Rect)); + pos.x -= 22; + pos.y -= 22; + SDL_RenderCopy(renderer, sprite_tex, &update, &pos); + } + if(door_status[3] == DOOR_UNLOCKED) { + update.x = 484; + update.y = 287; + update.w = 21; + update.h = 22; + memcpy(&pos, &update, sizeof(SDL_Rect)); + pos.x -= 22; + pos.y -= 22; + SDL_RenderCopy(renderer, sprite_tex, &update, &pos); + } } /* Updates turn signals */ void update_turn_signals() { - SDL_Rect left, right, lpos, rpos; - left.x = 213; - left.y = 51; - left.w = 45; - left.h = 45; - memcpy(&right, &left, sizeof(SDL_Rect)); - right.x = 482; - memcpy(&lpos, &left, sizeof(SDL_Rect)); - memcpy(&rpos, &right, sizeof(SDL_Rect)); - lpos.x -= 22; - lpos.y -= 22; - rpos.x -= 22; - rpos.y -= 22; - if(turn_status[0] == OFF) { - SDL_RenderCopy(renderer, base_texture, &lpos, &lpos); - } else { - SDL_RenderCopy(renderer, sprite_tex, &left, &lpos); - } - if(turn_status[1] == OFF) { - SDL_RenderCopy(renderer, base_texture, &rpos, &rpos); - } else { - SDL_RenderCopy(renderer, sprite_tex, &right, &rpos); - } + SDL_Rect left, right, lpos, rpos; + left.x = 213; + left.y = 51; + left.w = 45; + left.h = 45; + memcpy(&right, &left, sizeof(SDL_Rect)); + right.x = 482; + memcpy(&lpos, &left, sizeof(SDL_Rect)); + memcpy(&rpos, &right, sizeof(SDL_Rect)); + lpos.x -= 22; + lpos.y -= 22; + rpos.x -= 22; + rpos.y -= 22; + if(turn_status[0] == OFF) { + SDL_RenderCopy(renderer, base_texture, &lpos, &lpos); + } else { + SDL_RenderCopy(renderer, sprite_tex, &left, &lpos); + } + if(turn_status[1] == OFF) { + SDL_RenderCopy(renderer, base_texture, &rpos, &rpos); + } else { + SDL_RenderCopy(renderer, sprite_tex, &right, &rpos); + } } +#endif // !DISABLE_SDL -/* Redraws the IC updating everything + +void clear_screen() +{ + write(STDOUT_FILENO, "\e[1;1H\e[2J", 10); +} + +void draw_tui_doors() +{ + for(int i = 0; i < (sizeof(door_status) / sizeof(*door_status)); i++) { + printf("Door %d: %s\n", i, door_status[i] == DOOR_LOCKED ? "LOCKED" : "UNLOCKED"); + } +} + +void draw_tui_speed() +{ + printf("Speed: %ld mph\n", current_speed); +} + +void draw_tui_turn_signals() +{ + printf("Left indicator: %s\n", turn_status[0] == OFF ? "OFF" : "ON"); + printf("Right indicator: %s\n", turn_status[1] == OFF ? "OFF" : "ON"); +} + +void redraw_tui() { + clear_screen(); + draw_tui_doors(); + draw_tui_speed(); + draw_tui_turn_signals(); +} + + +#if !(DISABLE_SDL) +/* Redraws the IC updating everything * Slowest way to go. Should only use on init */ -void redraw_ic() { - blank_ic(); - update_speed(); - update_doors(); - update_turn_signals(); - SDL_RenderPresent(renderer); +void redraw_gui() { + blank_ic(); + update_speed(); + update_doors(); + update_turn_signals(); + SDL_RenderPresent(renderer); } +#endif // !DISABLE_SDL -/* Parses CAN fram and updates current_speed */ +/* Parses CAN frame and updates current_speed */ void update_speed_status(struct canfd_frame *cf, int maxdlen) { - int len = (cf->len > maxdlen) ? maxdlen : cf->len; - if(len < speed_pos + 1) return; - int speed = cf->data[speed_pos] << 8; - speed += cf->data[speed_pos + 1]; - speed = speed / 100; // speed in kilometers - current_speed = speed * 0.6213751; // mph - update_speed(); - SDL_RenderPresent(renderer); + int len = (cf->len > maxdlen) ? maxdlen : cf->len; + if(len < speed_pos + 1) return; + int speed = cf->data[speed_pos] << 8; + speed += cf->data[speed_pos + 1]; + speed = speed / 100; // speed in kilometers + current_speed = speed * 0.6213751; // mph } /* Parses CAN frame and updates turn signal status */ void update_signal_status(struct canfd_frame *cf, int maxdlen) { - int len = (cf->len > maxdlen) ? maxdlen : cf->len; - if(len < signal_pos) return; - if(cf->data[signal_pos] & CAN_LEFT_SIGNAL) { - turn_status[0] = ON; - } else { - turn_status[0] = OFF; - } - if(cf->data[signal_pos] & CAN_RIGHT_SIGNAL) { - turn_status[1] = ON; - } else { - turn_status[1] = OFF; - } - update_turn_signals(); - SDL_RenderPresent(renderer); + int len = (cf->len > maxdlen) ? maxdlen : cf->len; + if(len < signal_pos) return; + if(cf->data[signal_pos] & CAN_LEFT_SIGNAL) { + turn_status[0] = ON; + } else { + turn_status[0] = OFF; + } + if(cf->data[signal_pos] & CAN_RIGHT_SIGNAL) { + turn_status[1] = ON; + } else { + turn_status[1] = OFF; + } } /* Parses CAN frame and updates door status */ void update_door_status(struct canfd_frame *cf, int maxdlen) { - int len = (cf->len > maxdlen) ? maxdlen : cf->len; - if(len < door_pos) return; - if(cf->data[door_pos] & CAN_DOOR1_LOCK) { - door_status[0] = DOOR_LOCKED; - } else { - door_status[0] = DOOR_UNLOCKED; - } - if(cf->data[door_pos] & CAN_DOOR2_LOCK) { - door_status[1] = DOOR_LOCKED; - } else { - door_status[1] = DOOR_UNLOCKED; - } - if(cf->data[door_pos] & CAN_DOOR3_LOCK) { - door_status[2] = DOOR_LOCKED; - } else { - door_status[2] = DOOR_UNLOCKED; - } - if(cf->data[door_pos] & CAN_DOOR4_LOCK) { - door_status[3] = DOOR_LOCKED; - } else { - door_status[3] = DOOR_UNLOCKED; - } - update_doors(); - SDL_RenderPresent(renderer); + int len = (cf->len > maxdlen) ? maxdlen : cf->len; + if(len < door_pos) return; + if(cf->data[door_pos] & CAN_DOOR1_LOCK) { + door_status[0] = DOOR_LOCKED; + } else { + door_status[0] = DOOR_UNLOCKED; + } + if(cf->data[door_pos] & CAN_DOOR2_LOCK) { + door_status[1] = DOOR_LOCKED; + } else { + door_status[1] = DOOR_UNLOCKED; + } + if(cf->data[door_pos] & CAN_DOOR3_LOCK) { + door_status[2] = DOOR_LOCKED; + } else { + door_status[2] = DOOR_UNLOCKED; + } + if(cf->data[door_pos] & CAN_DOOR4_LOCK) { + door_status[3] = DOOR_LOCKED; + } else { + door_status[3] = DOOR_UNLOCKED; + } } void Usage(char *msg) { - if(msg) printf("%s\n", msg); - printf("Usage: icsim [options] \n"); - printf("\t-r\trandomize IDs\n"); - printf("\t-s\tseed value\n"); - printf("\t-d\tdebug mode\n"); - exit(1); + if(msg) printf("%s\n", msg); + printf("Usage: icsim [options] \n"); + printf("\t-r\trandomize IDs\n"); + printf("\t-s\tseed value\n"); + printf("\t-d\tdebug mode\n"); + printf("\t-t\ttext mode\n"); + exit(1); } +struct ui_t { + void (*redraw)(void); +}; + int main(int argc, char *argv[]) { - int opt; - int can; - struct ifreq ifr; - struct sockaddr_can addr; - struct canfd_frame frame; - struct iovec iov; - struct msghdr msg; - struct cmsghdr *cmsg; - struct timeval tv, timeout_config = { 0, 0 }; - struct stat dirstat; - fd_set rdfs; - char ctrlmsg[CMSG_SPACE(sizeof(struct timeval)) + CMSG_SPACE(sizeof(__u32))]; - int running = 1; - int nbytes, maxdlen; - int ret; - int seed = 0; - int door_id, signal_id, speed_id; - SDL_Event event; - - while ((opt = getopt(argc, argv, "rs:dh?")) != -1) { - switch(opt) { - case 'r': - randomize = 1; - break; - case 's': - seed = atoi(optarg); - break; - case 'd': - debug = 1; - break; - case 'h': - case '?': - default: - Usage(NULL); - break; - } - } - - if (optind >= argc) Usage("You must specify at least one can device"); - - if (seed && randomize) Usage("You can not specify a seed value AND randomize the seed"); - - // Verify data directory exists - if(stat(DATA_DIR, &dirstat) == -1) { - printf("ERROR: DATA_DIR not found. Define in make file or run in src dir\n"); - exit(34); - } - - // Create a new raw CAN socket - can = socket(PF_CAN, SOCK_RAW, CAN_RAW); - if(can < 0) Usage("Couldn't create raw socket"); - - addr.can_family = AF_CAN; - memset(&ifr.ifr_name, 0, sizeof(ifr.ifr_name)); - strncpy(ifr.ifr_name, argv[optind], strlen(argv[optind])); - printf("Using CAN interface %s\n", ifr.ifr_name); - if (ioctl(can, SIOCGIFINDEX, &ifr) < 0) { - perror("SIOCGIFINDEX"); - exit(1); - } - addr.can_ifindex = ifr.ifr_ifindex; - // CAN FD Mode - setsockopt(can, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &canfd_on, sizeof(canfd_on)); - - iov.iov_base = &frame; - iov.iov_len = sizeof(frame); - msg.msg_name = &addr; - msg.msg_namelen = sizeof(addr); - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - msg.msg_control = &ctrlmsg; - msg.msg_controllen = sizeof(ctrlmsg); - msg.msg_flags = 0; - - if (bind(can, (struct sockaddr *)&addr, sizeof(addr)) < 0) { - perror("bind"); - return 1; - } - - init_car_state(); - - door_id = DEFAULT_DOOR_ID; - signal_id = DEFAULT_SIGNAL_ID; - speed_id = DEFAULT_SPEED_ID; - - if (randomize || seed) { - if(randomize) seed = time(NULL); - srand(seed); - door_id = (rand() % 2046) + 1; - signal_id = (rand() % 2046) + 1; - speed_id = (rand() % 2046) + 1; - door_pos = rand() % 9; - signal_pos = rand() % 9; - speed_pos = rand() % 8; - printf("Seed: %d\n", seed); - FILE *fdseed = fopen("/tmp/icsim_seed.txt", "w"); - fprintf(fdseed, "%d\n", seed); - fclose(fdseed); - } - - SDL_Window *window = NULL; - SDL_Surface *screenSurface = NULL; - if(SDL_Init ( SDL_INIT_VIDEO ) < 0 ) { - printf("SDL Could not initializes\n"); - exit(40); - } - window = SDL_CreateWindow("IC Simulator", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN); // | SDL_WINDOW_RESIZABLE); - if(window == NULL) { - printf("Window could not be shown\n"); - } - renderer = SDL_CreateRenderer(window, -1, 0); - SDL_Surface *image = IMG_Load(get_data("ic.png")); - SDL_Surface *needle = IMG_Load(get_data("needle.png")); - SDL_Surface *sprites = IMG_Load(get_data("spritesheet.png")); - base_texture = SDL_CreateTextureFromSurface(renderer, image); - needle_tex = SDL_CreateTextureFromSurface(renderer, needle); - sprite_tex = SDL_CreateTextureFromSurface(renderer, sprites); - - speed_rect.x = 212; - speed_rect.y = 175; - speed_rect.h = needle->h; - speed_rect.w = needle->w; - - // Draw the IC - redraw_ic(); - - /* For now we will just operate on one CAN interface */ - while(running) { - while( SDL_PollEvent(&event) != 0 ) { - switch(event.type) { - case SDL_QUIT: - running = 0; - break; - case SDL_WINDOWEVENT: - switch(event.window.event) { - case SDL_WINDOWEVENT_ENTER: - case SDL_WINDOWEVENT_RESIZED: - redraw_ic(); - break; - } - } - SDL_Delay(3); - } - - nbytes = recvmsg(can, &msg, 0); - if (nbytes < 0) { - perror("read"); - return 1; - } - if ((size_t)nbytes == CAN_MTU) - maxdlen = CAN_MAX_DLEN; - else if ((size_t)nbytes == CANFD_MTU) - maxdlen = CANFD_MAX_DLEN; - else { - fprintf(stderr, "read: incomplete CAN frame\n"); - return 1; - } - for (cmsg = CMSG_FIRSTHDR(&msg); - cmsg && (cmsg->cmsg_level == SOL_SOCKET); - cmsg = CMSG_NXTHDR(&msg,cmsg)) { - if (cmsg->cmsg_type == SO_TIMESTAMP) - tv = *(struct timeval *)CMSG_DATA(cmsg); - else if (cmsg->cmsg_type == SO_RXQ_OVFL) - //dropcnt[i] = *(__u32 *)CMSG_DATA(cmsg); - fprintf(stderr, "Dropped packet\n"); - } -// if(debug) fprint_canframe(stdout, &frame, "\n", 0, maxdlen); - if(frame.can_id == door_id) update_door_status(&frame, maxdlen); - if(frame.can_id == signal_id) update_signal_status(&frame, maxdlen); - if(frame.can_id == speed_id) update_speed_status(&frame, maxdlen); - } - - SDL_DestroyTexture(base_texture); - SDL_DestroyTexture(needle_tex); - SDL_DestroyTexture(sprite_tex); - SDL_FreeSurface(image); - SDL_FreeSurface(needle); - SDL_FreeSurface(sprites); - SDL_DestroyRenderer(renderer); - SDL_DestroyWindow(window); - IMG_Quit(); - SDL_Quit(); - - return 0; + int opt; + int can; + struct ifreq ifr; + struct sockaddr_can addr; + struct canfd_frame frame; + struct iovec iov; + struct msghdr msg; + struct cmsghdr *cmsg; + struct stat dirstat; + char ctrlmsg[CMSG_SPACE(sizeof(struct timeval)) + CMSG_SPACE(sizeof(__u32))]; + int running = 1; + int nbytes, maxdlen; + int seed = 0; + int door_id, signal_id, speed_id; + struct ui_t ui = {0}; +#if !(DISABLE_SDL) + SDL_Event event; + SDL_Window *window = NULL; + SDL_Surface *image = NULL; + SDL_Surface *needle = NULL; + SDL_Surface *sprites = NULL; +#endif // !DISABLE_SDL + + while ((opt = getopt(argc, argv, "rs:dth?")) != -1) { + switch(opt) { + case 'r': + randomize = 1; + break; + case 's': + seed = atoi(optarg); + break; + case 'd': + debug = 1; + break; + case 't': + text_mode = 1; + break; + case 'h': + case '?': + default: + Usage(NULL); + break; + } + } + +#if (DISABLE_SDL) + text_mode = 1; +#endif // !DISABLE_SDL + + if (optind >= argc) Usage("You must specify at least one can device"); + + if (seed && randomize) Usage("You can not specify a seed value AND randomize the seed"); + + // Verify data directory exists + if(stat(DATA_DIR, &dirstat) == -1) { + printf("ERROR: DATA_DIR not found. Define in make file or run in src dir\n"); + exit(34); + } + + // Create a new raw CAN socket + can = socket(PF_CAN, SOCK_RAW, CAN_RAW); + if(can < 0) Usage("Couldn't create raw socket"); + + addr.can_family = AF_CAN; + memset(&ifr.ifr_name, 0, sizeof(ifr.ifr_name)); + strncpy(ifr.ifr_name, argv[optind], strlen(argv[optind])); + printf("Using CAN interface %s\n", ifr.ifr_name); + if (ioctl(can, SIOCGIFINDEX, &ifr) < 0) { + perror("SIOCGIFINDEX"); + exit(1); + } + addr.can_ifindex = ifr.ifr_ifindex; + // CAN FD Mode + setsockopt(can, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &canfd_on, sizeof(canfd_on)); + + iov.iov_base = &frame; + iov.iov_len = sizeof(frame); + msg.msg_name = &addr; + msg.msg_namelen = sizeof(addr); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = &ctrlmsg; + msg.msg_controllen = sizeof(ctrlmsg); + msg.msg_flags = 0; + + if (bind(can, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + perror("bind"); + return 1; + } + + init_car_state(); + + door_id = DEFAULT_DOOR_ID; + signal_id = DEFAULT_SIGNAL_ID; + speed_id = DEFAULT_SPEED_ID; + + if (randomize || seed) { + if(randomize) seed = time(NULL); + srand(seed); + door_id = (rand() % 2046) + 1; + signal_id = (rand() % 2046) + 1; + speed_id = (rand() % 2046) + 1; + door_pos = rand() % 9; + signal_pos = rand() % 9; + speed_pos = rand() % 8; + printf("Seed: %d\n", seed); + FILE *fdseed = fopen("/tmp/icsim_seed.txt", "w"); + fprintf(fdseed, "%d\n", seed); + fclose(fdseed); + } + + if (text_mode) { + ui.redraw = redraw_tui; + } else { +#if !(DISABLE_SDL) + ui.redraw = redraw_gui; + + if(SDL_Init ( SDL_INIT_VIDEO ) < 0 ) { + printf("SDL Could not initialize\n"); + exit(40); + } + window = SDL_CreateWindow("IC Simulator", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN); // | SDL_WINDOW_RESIZABLE); + if(window == NULL) { + printf("Window could not be created\n"); + } + renderer = SDL_CreateRenderer(window, -1, 0); + image = IMG_Load(get_data("ic.png")); + needle = IMG_Load(get_data("needle.png")); + sprites = IMG_Load(get_data("spritesheet.png")); + base_texture = SDL_CreateTextureFromSurface(renderer, image); + needle_tex = SDL_CreateTextureFromSurface(renderer, needle); + sprite_tex = SDL_CreateTextureFromSurface(renderer, sprites); + + speed_rect.x = 212; + speed_rect.y = 175; + speed_rect.h = needle->h; + speed_rect.w = needle->w; +#endif // !DISABLE_SDL + } + + // Draw the IC + ui.redraw(); + + /* For now we will just operate on one CAN interface */ + while(running) { +#if !(DISABLE_SDL) + while( SDL_PollEvent(&event) != 0 ) { + switch(event.type) { + case SDL_QUIT: + running = 0; + break; + case SDL_WINDOWEVENT: + switch(event.window.event) { + case SDL_WINDOWEVENT_ENTER: + case SDL_WINDOWEVENT_RESIZED: + ui.redraw(); + break; + } + } + SDL_Delay(3); + } +#endif // !DISABLE_SDL + + nbytes = recvmsg(can, &msg, 0); + if (nbytes < 0) { + perror("read"); + return 1; + } + if ((size_t)nbytes == CAN_MTU) + maxdlen = CAN_MAX_DLEN; + else if ((size_t)nbytes == CANFD_MTU) + maxdlen = CANFD_MAX_DLEN; + else { + fprintf(stderr, "read: incomplete CAN frame\n"); + return 1; + } + for (cmsg = CMSG_FIRSTHDR(&msg); + cmsg && (cmsg->cmsg_level == SOL_SOCKET); + cmsg = CMSG_NXTHDR(&msg,cmsg)) { + if (cmsg->cmsg_type == SO_RXQ_OVFL) + fprintf(stderr, "Dropped packet\n"); + } + // if(debug) fprint_canframe(stdout, &frame, "\n", 0, maxdlen); + if(frame.can_id == door_id) update_door_status(&frame, maxdlen); + if(frame.can_id == signal_id) update_signal_status(&frame, maxdlen); + if(frame.can_id == speed_id) update_speed_status(&frame, maxdlen); + + usleep(5000); + ui.redraw(); + + } + +#if !(DISABLE_SDL) + SDL_DestroyTexture(base_texture); + SDL_DestroyTexture(needle_tex); + SDL_DestroyTexture(sprite_tex); + SDL_FreeSurface(image); + SDL_FreeSurface(needle); + SDL_FreeSurface(sprites); + SDL_DestroyRenderer(renderer); + SDL_DestroyWindow(window); + IMG_Quit(); + SDL_Quit(); +#endif // !DISABLE_SDL + + return 0; } diff --git a/lib.o b/lib.o deleted file mode 100644 index 43f95ef2feb0d07a8e3bb4e64c8108fa185ea34a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12440 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 Date: Sat, 16 Sep 2017 20:21:08 +0000 Subject: [PATCH 2/6] Fix misplaced } outside ifdef --- controls.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/controls.c b/controls.c index 9bb09a4..0fb404c 100644 --- a/controls.c +++ b/controls.c @@ -953,16 +953,18 @@ int main(int argc, char *argv[]) { ui.redraw(); usleep(5000); - close(s); + } // while(running) + + close(s); + #if !(DISABLE_SDL) - if (!keyboard_mode || !text_mode) { - SDL_DestroyTexture(base_texture); - SDL_FreeSurface(image); - SDL_GameControllerClose(gGameController); - SDL_DestroyRenderer(renderer); - SDL_DestroyWindow(window); - SDL_Quit(); - } -#endif // !DISABLE_SDL + if (!keyboard_mode || !text_mode) { + SDL_DestroyTexture(base_texture); + SDL_FreeSurface(image); + SDL_GameControllerClose(gGameController); + SDL_DestroyRenderer(renderer); + SDL_DestroyWindow(window); + SDL_Quit(); } +#endif // !DISABLE_SDL } From d981cd8bc68367611adc0b169a53b62e01d95189 Mon Sep 17 00:00:00 2001 From: Grazfather Date: Tue, 19 Sep 2017 04:33:24 +0000 Subject: [PATCH 3/6] Improve speed calc accuracy --- controls.c | 3 +++ icsim.c | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/controls.c b/controls.c index 0fb404c..3e8efa8 100644 --- a/controls.c +++ b/controls.c @@ -230,6 +230,7 @@ void send_speed() { cf.data[speed_pos+1] = (char)kph & 0xff; cf.data[speed_pos] = (char)(kph >> 8) & 0xff; if(kph == 0) { // IDLE + // Add some jitter cf.data[speed_pos] = 1; cf.data[speed_pos+1] = rand() % 255+100; } @@ -502,6 +503,7 @@ void *watch_input(void* arg) tcsetattr(fileno(stdin), TCSANOW, &orig_attr); return NULL; } + void clear_screen() { write(STDOUT_FILENO, "\e[1;1H\e[2J", 10); @@ -516,6 +518,7 @@ void redraw_tui() { printf("OFF\n"); } + if (debug) printf("Speed: %.02lf km/h\n", current_speed); printf("Throttle: %s\n", throttle > 0 ? "ON" : "OFF"); printf("Unlock enabled: %s\n", unlock_enabled ? "YES" : "NO"); printf("Lock enabled: %s\n", lock_enabled ? "YES" : "NO"); diff --git a/icsim.c b/icsim.c index d3fb67b..8e5b7e4 100644 --- a/icsim.c +++ b/icsim.c @@ -272,8 +272,8 @@ void update_speed_status(struct canfd_frame *cf, int maxdlen) { if(len < speed_pos + 1) return; int speed = cf->data[speed_pos] << 8; speed += cf->data[speed_pos + 1]; - speed = speed / 100; // speed in kilometers - current_speed = speed * 0.6213751; // mph + current_speed = speed / 100; // speed in kilometers + current_speed = current_speed * 0.6213751; // mph } /* Parses CAN frame and updates turn signal status */ From a4b58f968517a1fdc06d5fb1598851952c7df216 Mon Sep 17 00:00:00 2001 From: Grazfather Date: Tue, 19 Sep 2017 20:46:14 +0000 Subject: [PATCH 4/6] Add 'legend' to text view --- controls.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/controls.c b/controls.c index 3e8efa8..f8de997 100644 --- a/controls.c +++ b/controls.c @@ -522,6 +522,14 @@ void redraw_tui() { printf("Throttle: %s\n", throttle > 0 ? "ON" : "OFF"); printf("Unlock enabled: %s\n", unlock_enabled ? "YES" : "NO"); printf("Lock enabled: %s\n", lock_enabled ? "YES" : "NO"); + + // Print controls + printf("\nControls:\n"); + printf("WASD: Turn left/right, throttle on/off\n"); + printf("Space: Turn off indicator\n"); + printf("Q/E: Enable lock/unlock\n"); + printf("1234: Lock/unlock specified door\n"); + printf("Ctrl-C: Quit\n"); } // Plays background can traffic From 84855f795d1512185d86a736daa2b9871d075417 Mon Sep 17 00:00:00 2001 From: Grazfather Date: Tue, 19 Sep 2017 20:49:18 +0000 Subject: [PATCH 5/6] controls: Make space 'unset' everything (cruise) --- controls.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/controls.c b/controls.c index f8de997..c3df2c5 100644 --- a/controls.c +++ b/controls.c @@ -459,6 +459,9 @@ void *watch_input(void* arg) break; case ' ': turning = 0; + throttle = 0; + lock_enabled = 0; + unlock_enabled = 0; break; case 'q': lock_enabled = 1; @@ -526,9 +529,9 @@ void redraw_tui() { // Print controls printf("\nControls:\n"); printf("WASD: Turn left/right, throttle on/off\n"); - printf("Space: Turn off indicator\n"); printf("Q/E: Enable lock/unlock\n"); printf("1234: Lock/unlock specified door\n"); + printf("Space: Unset everything/cruise\n"); printf("Ctrl-C: Quit\n"); } From 8722e53b8ac8691161b2c545d8fa6408e46a3260 Mon Sep 17 00:00:00 2001 From: Grazfather Date: Tue, 19 Sep 2017 20:55:28 +0000 Subject: [PATCH 6/6] controls: Rate limit CAN message sending Rate limit the main loop so that each can message cannot be sent more than a certain number of times per second (right now it's 1000ms/10ms period = 100Hz). --- Makefile | 2 +- controls.c | 13 ++++++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index e9f4d74..6b8c72c 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ CC=gcc -CFLAGS=-I/usr/include/SDL2 -Wall -Werror +CFLAGS=-I/usr/include/SDL2 -Wall -Werror -std=gnu99 LDFLAGS=-lSDL2 -lSDL2_image all: icsim controls diff --git a/controls.c b/controls.c index c3df2c5..da6a63a 100644 --- a/controls.c +++ b/controls.c @@ -55,6 +55,7 @@ #define DOOR_UNLOCKED 1 #define MAX_SPEED 150.0 // Limiter 260.0 is full gauge speed #define ACCEL_RATE 8.0 // 0-MAX_SPEED in seconds +#define MIN_MESSAGE_PERIOD 10 // Time in ms between CAN messages #if !(DISABLE_SDL) #define SCREEN_WIDTH 835 @@ -571,6 +572,7 @@ int main(int argc, char *argv[]) { int running = 1; int enable_canfd = 1; int enable_background_traffic = 1; + int last_ms = 0; struct stat st; struct ui_t ui = {0}; @@ -959,13 +961,18 @@ int main(int argc, char *argv[]) { } } #endif // !DISABLE_SDL - clock_gettime(CLOCK_MONOTONIC, ¤tTime); - current_ms = currentTime.tv_sec * 1000 + currentTime.tv_nsec / 1000000; check_accel(); check_turn(); check_locks(); ui.redraw(); - usleep(5000); + + // Limit max messages per second + while (current_ms - last_ms < MIN_MESSAGE_PERIOD) { + usleep(1000); + clock_gettime(CLOCK_MONOTONIC, ¤tTime); + current_ms = currentTime.tv_sec * 1000 + currentTime.tv_nsec / 1000000; + } + last_ms = current_ms; } // while(running)