diff --git a/Makefile b/Makefile index de9ef632f18533f70020bd2625096bad00277fcf..cb56594d2a06e470778c2d41e171f406c95546e3 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,5 @@ -.PHONY: flash/ids_% flash/bch_% reset_% +.PHONY: reset_% +.SECONDARY: $(bin/*.axf) #### Setup #### XMC = $(shell pwd)/XMC @@ -16,19 +17,19 @@ LIBS = $(CMSIS)/Lib/GCC/libarm_cortexM4lf_math.a LINKER_FILE = $(CMSIS)/Infineon/$(UC)_series/Source/GCC/XMC4500x1024.ld CMSIS_SRC += $(CMSIS)/Infineon/$(UC)_series/Source/System_$(UC).c -JLINK = JLinkExe SYSCC = $(TOOLCHAIN)-gcc CC = patmos-clang CP = $(TOOLCHAIN)-objcopy OD = $(TOOLCHAIN)-objdump GDB = $(TOOLCHAIN)-gdb -#STACK_SIZE?=2048 STACK_SIZE?=16384 +JLINK = JLinkExe JLFLAGS = -device XMC4500-1024 -if SWD -speed 900 -CFLAGS = -target armv6m--none-eabi -mcpu=cortex-m4 -mthumb -integrated-as -ccc-gcc-name arm-none-eabi-gcc +CFLAGS = -mcpu=cortex-m4 -target armv7m-none-eabi -msoft-float +CFLAGS+= -integrated-as -ccc-gcc-name arm-none-eabi-gcc CFLAGS+= -fno-builtin CFLAGS+= -Os -ffunction-sections -fdata-sections CFLAGS+= -MD -std=c99 -Wall @@ -36,6 +37,7 @@ CFLAGS+= -DUC_ID=$(UC_ID) -DARM_MATH_CM4 -DINTERRUPT_CONTROL_ENDPOINT CFLAGS+= -DXMC4500_F100x1024 CFLAGS+= -I$(CMSIS)/Include -I$(CMSIS)/Infineon/$(UC)_series/Include CFLAGS+= -Ilib/LUFA -I$(XMC)/XMCLib/inc +CFLAGS+= $(CFLAGS_GENE) ASFLAGS = -target armv6m--none-eabi -mcpu=cortex-m4 -marm -mthumb ASFLAGS+= -O0 -ffunction-sections -fdata-sections @@ -60,7 +62,7 @@ OBJS += src/System_$(UC).o OBJS_MAIN = $(OBJS) $(SRC_MAIN:.c=.o) #### Rules #### -all: $(OBJS) bin/xmc.bin xmccomm +all: $(OBJS) src/System_$(UC).o: $(CMSIS_SRC) $(CC) -c $(CFLAGS) $< -o $@ @@ -88,24 +90,10 @@ bin/ids_%.axf: $(OBJS) bin/startup_XMC4500.o bin/ids_%.o %.bin: %.axf $(CP) $(CPFLAGS) $^ $@ -flash/ids_%: bin/ids_%.bin - echo "connect\n\ - loadbin $< 0x8000000\n\ - r\n\ - g\n\ - exit\n" | $(JLINK) $(JLFLAGS) -SelectEmuBySN $* - -flash/bch_%: bin/xmc.bin - echo "connect\n\ - loadbin bin/xmc.bin 0x8000000\n\ - r\n\ - g\n\ - exit\n" | $(JLINK) $(JLFLAGS) -SelectEmuBySN $* - -bin/xmc.axf: $(OBJS_MAIN) bin/startup_XMC4500.o gene.o +bin/system_%.axf: $(OBJS_MAIN) bin/startup_XMC4500.o %.o mkdir -p bin - @echo LD $< - @$(CC) -T $(LINKER_FILE) $(LFLAGS) -o bin/xmc.axf $^ $(LIBS) + @echo LD $@ + @$(CC) -T $(LINKER_FILE) $(LFLAGS) -o $@ $^ $(LIBS) reset_%: echo "connect\n\ @@ -124,8 +112,7 @@ fastgdb: sleep 1 make gdb -xmccomm: xmccomm.c - gcc -std=c99 -g xmccomm.c -o xmccomm - clean: rm -f src/*.o src/*.d bin/* + +print-% : ; @echo $* = $($*) diff --git a/README.md b/README.md index cf0df44d3fd34556e9804a396a9631cd843f28c1..f4189f0b8241d9fe969cc9eba9e823f1853e62cb 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,9 @@ The **bch** supports the following requests: * `eic`: enable instruction cache * `bch`: run benchmark +Building the **bch** system requires a prior execution of GenE to generate +the file containing the actual benchmark (`gene.o`). + Usage: Communicate with the System ---------------------------------- diff --git a/src/main.c b/src/main.c index 3aaa7e3b08fd09a004f8a464ce1063fe9a8cd8e8..08b0f8e5566b4549a42aed574770b57463cdc67f 100644 --- a/src/main.c +++ b/src/main.c @@ -11,7 +11,7 @@ #include "timer.h" #endif /* ifndef ID_SYSTEM */ -#define IHANDLER __attribute__ ((naked)) +#define IHANDLER #define xstr(s) str(s) #define str(s) #s @@ -22,25 +22,48 @@ #define SERIALSTR "<none>" #endif +#define VOID_ARG_TYPE 1 +#define UINT32_ARG_TYPE 2 + +#ifndef BENCHMARK_MAIN + #if defined(BENCHMARK_ARG) || defined(BENCHMARK_INIT) + #error BENCHMARK_MAIN, BENCHMARK_ARG, BENCHMARK_INIT must be defined + #endif + #define BENCHMARK_MAIN gene_main + #define BENCHMARK_ARG uint32_t + #define ARG_TYPE UINT32_ARG_TYPE + #define BENCHMARK_INIT gene_init +#endif + +// use void as default +#ifndef BENCHMARK_ARG + #define ARG_TYPE VOID_ARG_TYPE + #define BENCHMARK_ARG void +#endif + +void BENCHMARK_MAIN(BENCHMARK_ARG); +void BENCHMARK_INIT(void); + extern int errno; void _init() {} +void _sbrk() {} /* Clock configuration */ XMC_SCU_CLOCK_CONFIG_t clock_config = { - .syspll_config.p_div = 2, - .syspll_config.n_div = 80, - .syspll_config.k_div = 4, - .syspll_config.mode = XMC_SCU_CLOCK_SYSPLL_MODE_NORMAL, + .syspll_config.p_div = 2, + .syspll_config.n_div = 80, + .syspll_config.k_div = 4, + .syspll_config.mode = XMC_SCU_CLOCK_SYSPLL_MODE_NORMAL, .syspll_config.clksrc = XMC_SCU_CLOCK_SYSPLLCLKSRC_OSCHP, - .enable_oschp = true, - .calibration_mode = XMC_SCU_CLOCK_FOFI_CALIBRATION_MODE_FACTORY, - .fsys_clksrc = XMC_SCU_CLOCK_SYSCLKSRC_PLL, - .fsys_clkdiv = 1, - .fcpu_clkdiv = 1, - .fccu_clkdiv = 1, - .fperipheral_clkdiv = 1 + .enable_oschp = true, + .calibration_mode = XMC_SCU_CLOCK_FOFI_CALIBRATION_MODE_FACTORY, + .fsys_clksrc = XMC_SCU_CLOCK_SYSCLKSRC_PLL, + .fsys_clkdiv = 1, + .fcpu_clkdiv = 1, + .fccu_clkdiv = 1, + .fperipheral_clkdiv = 1 }; @@ -58,10 +81,7 @@ void SystemCoreClockSetup(void) SystemCoreClockUpdate(); } - -void gene_main(uint32_t); -void gene_init(void); - +/*** Begin: Interrupt Handlers ***/ IHANDLER void PendSV_Handler() { P1_1_set(); while(1) {} } IHANDLER void SysTick_Handler() { P1_1_set(); while(1) {} } IHANDLER void SVC_Handler() { P1_1_set(); while(1) {} } @@ -70,6 +90,8 @@ IHANDLER void NMI_Handler() { P1_1_set(); while(1) {} } IHANDLER void MemManage_Handler() { P1_1_set(); while(1) {} } IHANDLER void UsageFault_Handler() { P1_1_set(); while(1) {} } IHANDLER void BusFault_Handler() { P1_1_set(); while(1) {} } +/*** End: Interrupt Handlers ***/ + static void uint64_to_string(char *buf, uint64_t value) { if(0 == value) { @@ -85,62 +107,87 @@ static void uint64_to_string(char *buf, uint64_t value) { } } + +/*** Begin: USB helper functions ***/ +static void usb_send(const char *str) { + CDC_Device_SendString(&VirtualSerial_CDC_Interface, str); +} + +static void usb_send2(const char *str1, const char *str2) { + usb_send(str1); + usb_send(str2); +} + +static void usb_send3(const char *str1, const char *str2, const char *str3) { + usb_send(str1); + usb_send(str2); + usb_send(str3); +} + +static void usb_flush() { CDC_Device_Flush(&VirtualSerial_CDC_Interface); } +/*** End: USB helper functions ***/ + + #ifndef ID_SYSTEM static void command_bch(char *arg) { errno = 0; unsigned long long val = strtoull(arg, NULL, 10); if(0 != errno || val > (unsigned long long) UINT32_MAX) { - CDC_Device_SendString(&VirtualSerial_CDC_Interface, "e:ov\n"); - CDC_Device_Flush(&VirtualSerial_CDC_Interface); + usb_send("e:ov\n"); + usb_flush(); return; } - CDC_Device_SendString(&VirtualSerial_CDC_Interface, "o:start\r"); - CDC_Device_Flush(&VirtualSerial_CDC_Interface); + usb_send("o:start\r"); + usb_flush(); P1_0_toggle(); uint32_t old_basepri = __get_BASEPRI(); __set_BASEPRI(1 << (8 - __NVIC_PRIO_BITS)); - gene_init(); + BENCHMARK_INIT(); // flush instruction cache prior to executing the benchmark to // ensure a "clean" system state XMC_PREFETCH_InvalidateInstructionBuffer(); timer_reset(); + + P5_7_set(); timer_start(); - gene_main(val); +#if ARG_TYPE == VOID_ARG_TYPE + BENCHMARK_MAIN(); +#else + BENCHMARK_MAIN(val); +#endif timer_stop(); + P5_7_reset(); + uint64_t cycles = timer_get(); __set_BASEPRI(old_basepri); P1_0_toggle(); - CDC_Device_SendString(&VirtualSerial_CDC_Interface, "o:end "); - CDC_Device_USBTask(&VirtualSerial_CDC_Interface); char buf[64] = {0}; uint64_to_string(buf, cycles); - CDC_Device_SendString(&VirtualSerial_CDC_Interface, buf); - CDC_Device_SendString(&VirtualSerial_CDC_Interface, "\n"); - CDC_Device_Flush(&VirtualSerial_CDC_Interface); - + usb_send3("o:end ", buf, "\n"); + usb_flush(); CDC_Device_USBTask(&VirtualSerial_CDC_Interface); } static void command_dic(char *arg) { XMC_PREFETCH_DisableInstructionBuffer(); - CDC_Device_SendString(&VirtualSerial_CDC_Interface, "o\n"); - CDC_Device_Flush(&VirtualSerial_CDC_Interface); + usb_send("o\n"); + usb_flush(); CDC_Device_USBTask(&VirtualSerial_CDC_Interface); } static void command_eic(char *arg) { XMC_PREFETCH_EnableInstructionBuffer(); - CDC_Device_SendString(&VirtualSerial_CDC_Interface, "o\n"); - CDC_Device_Flush(&VirtualSerial_CDC_Interface); + usb_send("o\n"); + usb_flush(); CDC_Device_USBTask(&VirtualSerial_CDC_Interface); } @@ -159,53 +206,39 @@ static void command_inf(char *arg) { // send FREQUENCY char buf[128] = {0}; uint64_to_string(buf, SystemCoreClock); - CDC_Device_SendString(&VirtualSerial_CDC_Interface, "o:freq "); - CDC_Device_SendString(&VirtualSerial_CDC_Interface, buf); - CDC_Device_SendString(&VirtualSerial_CDC_Interface, "\r"); + usb_send3("o:freq ", buf, "\r"); // send PFLASH { char buf[128] = {0}; uint64_to_string(buf, (FLASH0->FCON & (uint32_t)FLASH_FCON_WSPFLASH_Msk) >> FLASH_FCON_WSPFLASH_Pos); - CDC_Device_SendString(&VirtualSerial_CDC_Interface, "o:wspflash "); - CDC_Device_SendString(&VirtualSerial_CDC_Interface, buf); - CDC_Device_SendString(&VirtualSerial_CDC_Interface, "\r"); + usb_send3("o:wspflash ", buf, "\r"); } // send DWT status switch(DWT->CTRL & 0xFF000000) { - case 0x40000000: CDC_Device_SendString(&VirtualSerial_CDC_Interface, "o:4wt\r"); break; - case 0x4F000000: CDC_Device_SendString(&VirtualSerial_CDC_Interface, "o:4w\r"); break; - case 0x10000000: CDC_Device_SendString(&VirtualSerial_CDC_Interface, "o:1wt\r"); break; - case 0x1F000000: CDC_Device_SendString(&VirtualSerial_CDC_Interface, "o:1w\r"); break; - case 0x00000000: CDC_Device_SendString(&VirtualSerial_CDC_Interface, "o:0\r"); break; - default: CDC_Device_SendString(&VirtualSerial_CDC_Interface, "e:v\r"); break; + case 0x40000000: usb_send("o:4wt\r"); break; + case 0x4F000000: usb_send("o:4w\r"); break; + case 0x10000000: usb_send("o:1wt\r"); break; + case 0x1F000000: usb_send("o:1w\r"); break; + case 0x00000000: usb_send("o:0\r"); break; + default: usb_send("e:v\r"); break; } #ifndef ID_SYSTEM - if(timer_has_overflow_detection()) { - CDC_Device_SendString(&VirtualSerial_CDC_Interface, "o:ov e\r"); - } else { - CDC_Device_SendString(&VirtualSerial_CDC_Interface, "o:ov d\r"); - } + usb_send(timer_has_overflow_detection() ? "o:ov e\r" : "o:ov d\r"); #endif /* ifndef ID_SYSTEM */ + usb_send((PREF->PCON & PREF_PCON_IBYP_Msk) ? "o:ic d\n" : "o:ic e\n"); - if(PREF->PCON & PREF_PCON_IBYP_Msk) { - CDC_Device_SendString(&VirtualSerial_CDC_Interface, "o:ic d\n"); - } else { - CDC_Device_SendString(&VirtualSerial_CDC_Interface, "o:ic e\n"); - } - - CDC_Device_Flush(&VirtualSerial_CDC_Interface); + usb_flush(); CDC_Device_USBTask(&VirtualSerial_CDC_Interface); } -void* __aeabi_memset(void *s, int c, size_t n){ - size_t i; - for (i = 0; i < n; i++) { - ((char *)s)[i] = (char)c; - } - return s; +void* __aeabi_memset(void *s, int c, size_t n) { + for(size_t i = 0; i < n; i++) { + ((char *)s)[i] = (char)c; + } + return s; } int main(void) { @@ -216,12 +249,12 @@ int main(void) { P1_1_set_mode(OUTPUT_PP_GP); P1_1_set_driver_strength(STRONG); - #define BUFFER_SIZE 32 - - char buffer[BUFFER_SIZE + 1]; - buffer[BUFFER_SIZE] = '\0'; + P5_7_set_mode(OUTPUT_PP_GP); + P5_7_set_driver_strength(WEAK); + #define BUFFER_SIZE 32 uint8_t pos = 0; + char buffer[BUFFER_SIZE + 1] = {0}; // enable monitor debugging CoreDebug->DHCSR = 0xA05F << CoreDebug_DHCSR_DBGKEY_Pos; @@ -270,8 +303,8 @@ int main(void) { #undef COMMAND if(!handled) { - CDC_Device_SendString(&VirtualSerial_CDC_Interface, "e:uc\n"); - CDC_Device_Flush(&VirtualSerial_CDC_Interface); + usb_send("e:uc\n"); + usb_flush(); } pos = 0; @@ -283,8 +316,8 @@ int main(void) { buffer[pos] = byte; ++pos; } else { - CDC_Device_SendString(&VirtualSerial_CDC_Interface, "e:OVERFLOW IN COMMAND BUFFER\n"); - CDC_Device_Flush(&VirtualSerial_CDC_Interface); + usb_send("e:ov\n"); + usb_flush(); pos = 0; } diff --git a/xmccomm.c b/xmccomm.c deleted file mode 100644 index 7b08b755df437ec14b7b40202c1b821d0eb92d98..0000000000000000000000000000000000000000 --- a/xmccomm.c +++ /dev/null @@ -1,294 +0,0 @@ -#define _POSIX_C_SOURCE 199309L -#define _XOPEN_SOURCE 500 - -#include <errno.h> -#include <stdbool.h> -#include <stdio.h> -#include <stdlib.h> -#include <sys/ioctl.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <string.h> -#include <stdint.h> -#include <fcntl.h> -#include <termios.h> -#include <unistd.h> - -#define SHELL_ESC "\x1b" - -#define streq(A,B) (!strcmp(A,B)) - -// stty -F /dev/ttyACM0 115200 - -static void print_ok() { - printf(SHELL_ESC"[;32;02m[ok] "SHELL_ESC"[m"); -} - -static void print_er() { - printf(SHELL_ESC"[;31;02m[ER] "SHELL_ESC"[m"); -} - -static void print_vb(char *msg) { - fprintf(stderr, SHELL_ESC"[;36;02m[vb] "SHELL_ESC"[m%s", msg); -} - -static bool recv_response(FILE *fh, char *buf, size_t buf_size) { - int pos = 0; - - while(pos < buf_size) { - int c = fgetc(fh); - if(EOF != c) { - if('\n' == c) { - buf[pos] = '\0'; - return true; - } else if('\r' == c) { - buf[pos] = '\0'; - return false; - } else { - buf[pos] = c; - ++pos; - } - } else { - if(ferror(fh)) { - perror("fgetc(TTY)"); - exit(EXIT_FAILURE); - } else { - fprintf(stderr, "Unexpected EOF\n"); - exit(EXIT_FAILURE); - } - } - } -} - -static int connect_tty(char *tty) { - - bool exists = false; - unsigned retry = 0; - do { - print_vb(""); - fprintf(stderr, "open('%s') try %u\n", tty, retry); - ++retry; - - struct stat sbuf; - int res = stat(tty, &sbuf); - - exists = (0 == res); - if(!exists) { - usleep(500 * 1000); - } - } while(!exists && errno != EACCES && retry < 10); - - int fd = open(tty, O_RDWR | O_NOCTTY); - if(-1 == fd) { - perror("open(TTY)"); - if(EACCES == errno) { - fprintf(stderr, "Make sure current user `%s` is in group `dialout`\n", getlogin()); - } - exit(EXIT_FAILURE); - } else { - print_vb(""); fprintf(stderr, "%s successfully opened\n", tty); - } - - // setup control structure - struct termios toptions; - - if(0 != tcgetattr(fd, &toptions)) { perror("tcgetattr"); } - if(0 != cfsetispeed(&toptions, B115200)) { perror("cfsetispeed"); } - if(0 != cfsetospeed(&toptions, B115200)) { perror("cfsetospeed"); } - - toptions.c_cflag &= ~PARENB; // no parity bit - toptions.c_cflag &= ~CSTOPB; // no stop bits - toptions.c_cflag &= ~CSIZE; // char. size - toptions.c_cflag |= CS8; // 8 bits - - /* enable receiver, ignore status lines */ - toptions.c_cflag |= CREAD | CLOCAL; - - /* disable input/output flow control, disable restart chars */ - toptions.c_iflag &= ~(IXON | IXOFF | IXANY); - - /* disable canonical input, disable echo, - disable visually erase chars, - disable terminal-generated signals */ - toptions.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); - - toptions.c_oflag &= ~OPOST; // disable postprocessing - - if(0 != tcsetattr(fd, TCSANOW, &toptions)) { perror("tcsetattr"); } - if(0 != tcflush(fd, TCIFLUSH)) { perror("tcflush"); } - - return fd; -} - -static char* strsw(char *str, char *start) { - const uint32_t N = strlen(start); - if(!strncmp(str, start, N)) { - return &str[N]; - } - - return NULL; -} - -uint32_t remote_frequency = 0; - -static void resp_inf(bool success, char *resp) { - char *rem = NULL; - - if(streq(resp, "4wt")) { printf("DWT: 4 comparators for watchpoints+triggers available"); } - else if(streq(resp, "4w" )) { printf("DWT: 4 comparators for watchpoints available"); } - else if(streq(resp, "1wt")) { printf("DWT: 1 comparator for watchpoints+triggers available"); } - else if(streq(resp, "1w" )) { printf("DWT: 1 comparator for watchpoints available"); } - else if(streq(resp, "0" )) { printf("DWT: NOT AVAILABLE"); } - else if(streq(resp, "v" )) { printf("Unexpected value ain DWT->CTRL"); } - else if(rem = strsw(resp, "freq ")) { - remote_frequency = strtoull(rem, NULL, 10); - - char prefixes[] = { ' ', 'k', 'M', 'G' }; - double freq_dbl = remote_frequency; - int idx = 0; - while(freq_dbl > 500) { - ++idx; - freq_dbl /= 1000.; - } - - printf("Frequency: %.2f%cHz", freq_dbl, prefixes[idx]); - } else if(rem = strsw(resp, "ic ")) { - printf("Instruction Cache: Currently %s", ('e' == *rem) ? "enabled" : "disabled"); - } else if(rem = strsw(resp, "ov ")) { - printf("Timer Overflow Detection: Currently %s", ('e' == *rem) ? "enabled" : "disabled"); - } else if(rem = strsw(resp, "id ")) { - printf("Device ID: %s", rem); - } else if(rem = strsw(resp, "wspflash ")) { - printf("Flash Wait States: %s", rem); - } else { - printf("Unparsed: %s", resp); - } -} - -static void resp_bch(bool success, char *resp) { - - char *rem = NULL; - - if(streq(resp, "start")) { - printf("Benchmark started..."); - } else if(rem = strsw(resp, "end ")) { - printf("Benchmark done: "); - - uint64_t cycles = strtoull(rem, NULL, 10); - printf("%lu cy / %0.2f s", cycles, (double)cycles / remote_frequency); - } else if(rem = strsw(resp, "ov")) { - printf("Overflow in input data"); - } else { - printf("Unparsed: %s", resp); - } -} - -static void resp_dic(bool success, char *resp) { - printf("Instruction Cache now disabled!"); -} - -static void resp_eic(bool success, char *resp) { - printf("Instruction Cache now enabled!"); -} - -static void response_loop(FILE *fh, void (*cb)(bool, char*)) { - bool done = false; - char buf[128]; - - while(!done) { - done = recv_response(fh, buf, 128); - - bool success; - switch(buf[0]) { - case 'o': - success = true; - print_ok(); - break; - - case 'e': - success = false; - print_er(); - break; - - default: - printf(SHELL_ESC"[;31;02m[ER] Invalid response!"); - return; - } - - char *rem = NULL; - if(rem = strsw(buf, "e:uc")) { - printf("Command not known to device; are you trying to benchmark on an IDS?\n"); - exit(EXIT_FAILURE); - } else { - cb(success, '\0' != &buf[1] ? &buf[2] : NULL); - } - - printf(SHELL_ESC"[m\n"); - fflush(stdout); - } -} - -struct command { - char *cmd; - uint32_t nparam; - void (*callback)(bool, char*); -}; - -static struct command commands[] = { - {"bch", 1, resp_bch}, - {"dic", 0, resp_dic}, - {"eic", 0, resp_eic}, - {"inf", 0, resp_inf}, - {"rst", 0, NULL} -}; -static const size_t commands_count = sizeof(commands)/sizeof(struct command); - -int main(int argc, char *argv[]) { - if(2 != argc) { - fprintf(stderr, "Usage: %s <tty> \n", argv[0]); - return EXIT_FAILURE; - } - - int fd = connect_tty(argv[1]); - FILE *fh = fdopen(fd, "r+"); - if(fh == NULL) { - perror("fdopen(TTY)"); - return EXIT_FAILURE; - } - - print_vb("Requesting device info...\n"); - fprintf(fh, "inf \n"); - fflush(fh); - response_loop(fh, resp_inf); - - print_vb("Sending user commands...\n"); - - - char input[512]; - while(NULL != fgets(input, sizeof(input), stdin)) { - struct command *cmd = NULL; - - input[strlen(input) - 1] = '\0'; - - for(int j = 0; j < commands_count && NULL == cmd; ++j) { - if(!strncmp(input, commands[j].cmd, strlen(commands[j].cmd))) { - cmd = &commands[j]; - } - } - - if(NULL == cmd) { - print_er(); - printf("Unknown command `%s`; ABORTING\n", input); - return EXIT_FAILURE; - } - - print_vb(""); fprintf(stderr, "Sending command '%s'...\n", input); - - fprintf(fh, "%s \n", input); - fflush(fh); - - response_loop(fh, cmd->callback); - } - - return EXIT_SUCCESS; -}