int ty_thread_create(ty_thread *thread, ty_thread_func *f, void *udata) { struct thread_context ctx; int r; ctx.thread = thread; ctx.f = f; ctx.udata = udata; ctx.ev = CreateEvent(NULL, TRUE, FALSE, NULL); if (!ctx.ev) { r = ty_error(TY_ERROR_SYSTEM, "CreateEvent() failed: %s", ty_win32_strerror(0)); goto cleanup; } thread->h = (HANDLE)_beginthreadex(NULL, 0, thread_proc, &ctx, 0, (unsigned int *)&thread->thread_id); if (!thread->h) { r = ty_error(TY_ERROR_SYSTEM, "_beginthreadex() failed: %s", ty_win32_strerror(0)); goto cleanup; } WaitForSingleObject(ctx.ev, INFINITE); r = 0; cleanup: if (ctx.ev) CloseHandle(ctx.ev); return r; }
int ty_firmware_load(const char *filename, const char *format_name, ty_firmware **rfw) { assert(filename); assert(rfw); const ty_firmware_format *format = NULL; if (format_name) { for (unsigned int i = 0; i < ty_firmware_formats_count; i++) { if (strcasecmp(ty_firmware_formats[i].name, format_name) == 0) { format = &ty_firmware_formats[i]; break; } } if (!format) return ty_error(TY_ERROR_UNSUPPORTED, "Firmware file format '%s' unknown", format_name); } else { const char *ext = strrchr(filename, '.'); if (!ext) return ty_error(TY_ERROR_UNSUPPORTED, "Firmware '%s' has no file extension", filename); for (unsigned int i = 0; i < ty_firmware_formats_count; i++) { if (strcmp(ty_firmware_formats[i].ext, ext) == 0) { format = &ty_firmware_formats[i]; break; } } if (!format) return ty_error(TY_ERROR_UNSUPPORTED, "Firmware '%s' uses unrecognized file format", filename); } return (*format->load)(filename, rfw); }
int _ty_firmware_load_ihex(ty_firmware *fw) { assert(fw); struct parser_context ctx = {0}; FILE *fp = NULL; char buf[1024]; int r; ctx.fw = fw; #ifdef _WIN32 fp = fopen(fw->filename, "r"); #else fp = fopen(fw->filename, "re"); #endif if (!fp) { switch (errno) { case EACCES: r = ty_error(TY_ERROR_ACCESS, "Permission denied for '%s'", fw->filename); break; case EIO: r = ty_error(TY_ERROR_IO, "I/O error while opening '%s' for reading", fw->filename); break; case ENOENT: case ENOTDIR: r = ty_error(TY_ERROR_NOT_FOUND, "File '%s' does not exist", fw->filename); break; default: r = ty_error(TY_ERROR_SYSTEM, "fopen('%s') failed: %s", fw->filename, strerror(errno)); break; } goto cleanup; } do { if (!fgets(buf, sizeof(buf), fp)) { if (feof(fp)) { r = parse_error(&ctx); } else { r = ty_error(TY_ERROR_IO, "I/O error while reading '%s'", fw->filename); } goto cleanup; } ctx.line++; // Returns 1 when EOF record is detected r = parse_line(&ctx, buf); if (r < 0) goto cleanup; } while (!r); r = 0; cleanup: if (fp) fclose(fp); return r; }
static int do_stat(int fd, const char *path, ty_file_info *info, bool follow) { struct stat sb; int r; #ifdef HAVE_FSTATAT r = fstatat(fd, path, &sb, !follow ? AT_SYMLINK_NOFOLLOW : 0); #else if (follow) { r = stat(path, &sb); } else { r = lstat(path, &sb); } #endif if (r < 0) { switch (errno) { case EACCES: return ty_error(TY_ERROR_ACCESS, "Permission denied for '%s'", path); case EIO: return ty_error(TY_ERROR_IO, "I/O error while stating '%s'", path); case ENOENT: return ty_error(TY_ERROR_NOT_FOUND, "Path '%s' does not exist", path); case ENOTDIR: return ty_error(TY_ERROR_NOT_FOUND, "Part of '%s' is not a directory", path); } return ty_error(TY_ERROR_SYSTEM, "Failed to stat '%s': %s", path, strerror(errno)); } if (S_ISDIR(sb.st_mode)) { info->type = TY_FILE_DIRECTORY; } else if (S_ISREG(sb.st_mode)) { info->type = TY_FILE_REGULAR; #ifdef S_ISLNK } else if (S_ISLNK(sb.st_mode)) { info->type = TY_FILE_LINK; #endif } else { info->type = TY_FILE_SPECIAL; } info->size = (uint64_t)sb.st_size; #if defined(HAVE_STAT_MTIM) info->mtime = (uint64_t)sb.st_mtim.tv_sec * 1000 + (uint64_t)sb.st_mtim.tv_nsec / 1000000; #elif defined(HAVE_STAT_MTIMESPEC) info->mtime = (uint64_t)sb.st_mtimespec.tv_sec * 1000 + (uint64_t)sb.st_mtimespec.tv_nsec / 1000000; #else info->mtime = (uint64_t)sb.st_mtime * 1000; #endif return 0; }
static int redirect_stdout(int *routfd) { int outfd, r; outfd = dup(STDOUT_FILENO); if (outfd < 0) return ty_error(TY_ERROR_SYSTEM, "dup() failed: %s", strerror(errno)); r = dup2(STDERR_FILENO, STDOUT_FILENO); if (r < 0) return ty_error(TY_ERROR_SYSTEM, "dup2() failed: %s", strerror(errno)); *routfd = outfd; return 0; }
static int start_stdin_thread(void) { input_available = CreateEvent(NULL, TRUE, FALSE, NULL); if (!input_available) return ty_error(TY_ERROR_SYSTEM, "CreateEvent() failed: %s", ty_win32_strerror(0)); input_processed = CreateEvent(NULL, TRUE, TRUE, NULL); if (!input_processed) return ty_error(TY_ERROR_SYSTEM, "CreateEvent() failed: %s", ty_win32_strerror(0)); input_thread = (HANDLE)_beginthreadex(NULL, 0, stdin_thread, NULL, 0, NULL); if (!input_thread) return ty_error(TY_ERROR_SYSTEM, "_beginthreadex() failed: %s", ty_win32_strerror(0)); return 0; }
static unsigned int __stdcall stdin_thread(void *udata) { TY_UNUSED(udata); DWORD len; BOOL success; int r; while (input_run) { WaitForSingleObject(input_processed, INFINITE); ResetEvent(input_processed); success = ReadFile(GetStdHandle(STD_INPUT_HANDLE), input_line, sizeof(input_line), &len, NULL); if (!success) { r = ty_error(TY_ERROR_IO, "I/O error while reading standard input"); goto error; } if (!len) { r = 0; goto error; } input_ret = (ssize_t)len; SetEvent(input_available); } return 0; error: input_ret = r; SetEvent(input_available); return 0; }
int ty_poll(const ty_descriptor_set *set, int timeout) { assert(set); assert(set->count); assert(set->count <= 64); fd_set fds; uint64_t start; struct timeval tv; int r; FD_ZERO(&fds); for (unsigned int i = 0; i < set->count; i++) FD_SET(set->desc[i], &fds); start = ty_millis(); restart: if (timeout >= 0) { tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000; } r = select(FD_SETSIZE, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL); if (r < 0) { switch (errno) { case EINTR: timeout = ty_adjust_timeout(timeout, start); goto restart; case ENOMEM: return ty_error(TY_ERROR_MEMORY, NULL); } return ty_error(TY_ERROR_SYSTEM, "poll() failed: %s", strerror(errno)); } if (!r) return 0; for (unsigned int i = 0; i < set->count; i++) { if (FD_ISSET(set->desc[i], &fds)) return set->id[i]; } assert(false); __builtin_unreachable(); }
int ty_terminal_setup(int flags) { struct termios tio; int r; r = tcgetattr(STDIN_FILENO, &tio); if (r < 0) { if (errno == ENOTTY) return ty_error(TY_ERROR_UNSUPPORTED, "Not a terminal"); return ty_error(TY_ERROR_SYSTEM, "tcgetattr() failed: %s", strerror(errno)); } if (!saved_termios) { orig_termios = tio; saved_termios = true; atexit(ty_terminal_restore); } if (flags & TY_TERMINAL_RAW) { cfmakeraw(&tio); tio.c_oflag |= OPOST | ONLCR; tio.c_lflag |= ISIG; } else { tio.c_iflag = TTYDEF_IFLAG; tio.c_oflag = TTYDEF_OFLAG; tio.c_lflag = TTYDEF_LFLAG; tio.c_cflag = TTYDEF_CFLAG; } tio.c_cc[VMIN] = 1; tio.c_cc[VTIME] = 0; tio.c_lflag |= ECHO; if (flags & TY_TERMINAL_SILENT) tio.c_lflag &= (unsigned int)~ECHO; r = tcsetattr(STDIN_FILENO, TCSADRAIN, &tio); if (r < 0) return ty_error(TY_ERROR_SYSTEM, "tcsetattr() failed: %s", strerror(errno)); return 0; }
int ty_poll(const ty_descriptor_set *set, int timeout) { assert(set); assert(set->count); assert(set->count <= 64); struct pollfd pfd[64]; uint64_t start; int r; for (unsigned int i = 0; i < set->count; i++) { pfd[i].events = POLLIN; pfd[i].fd = set->desc[i]; } if (timeout < 0) timeout = -1; start = ty_millis(); restart: r = poll(pfd, (nfds_t)set->count, ty_adjust_timeout(timeout, start)); if (r < 0) { switch (errno) { case EINTR: goto restart; case ENOMEM: return ty_error(TY_ERROR_MEMORY, NULL); } return ty_error(TY_ERROR_SYSTEM, "poll() failed: %s", strerror(errno)); } if (!r) return 0; for (unsigned int i = 0; i < set->count; i++) { if (pfd[i].revents & (POLLIN | POLLERR | POLLHUP | POLLNVAL)) return set->id[i]; } assert(false); __builtin_unreachable(); }
unsigned short getindex() { unsigned char ch; ch = getbyte(); if (ch != OLF_INDEX) { ty_error(ch, L"Expecting index leaf"); } return(getshort()); }
int ty_firmware_expand_image(ty_firmware *fw, size_t size) { if (size > fw->alloc_size) { uint8_t *tmp; size_t alloc_size; if (size > TY_FIRMWARE_MAX_SIZE) return ty_error(TY_ERROR_RANGE, "Firmware too big (max %u bytes) in '%s'", TY_FIRMWARE_MAX_SIZE, fw->filename); alloc_size = (size + (FIRMWARE_STEP_SIZE - 1)) / FIRMWARE_STEP_SIZE * FIRMWARE_STEP_SIZE; tmp = realloc(fw->image, alloc_size); if (!tmp) return ty_error(TY_ERROR_MEMORY, NULL); fw->image = tmp; fw->alloc_size = alloc_size; } fw->size = size; return 0; }
char *getname() { unsigned char ch; ch = getbyte(); if (ch != OLF_STRING) { ty_error(ch, L"Expecting string leaf"); } return(getstring()); }
int ty_terminal_setup(int flags) { HANDLE handle; DWORD mode; BOOL r; handle = GetStdHandle(STD_INPUT_HANDLE); if (handle == INVALID_HANDLE_VALUE) return ty_error(TY_ERROR_SYSTEM, "GetStdHandle(STD_INPUT_HANDLE) failed"); r = GetConsoleMode(handle, &mode); if (!r) { if (GetLastError() == ERROR_INVALID_HANDLE) return ty_error(TY_ERROR_UNSUPPORTED, "Not a terminal"); return ty_error(TY_ERROR_SYSTEM, "GetConsoleMode(STD_INPUT_HANDLE) failed: %s", ty_win32_strerror(0)); } if (!saved_console_mode) { orig_console_mode = mode; saved_console_mode = true; atexit(ty_terminal_restore); } mode |= ENABLE_PROCESSED_INPUT; mode &= (DWORD)~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT); if (!(flags & TY_TERMINAL_RAW)) mode |= ENABLE_LINE_INPUT; if (!(flags & TY_TERMINAL_SILENT)) mode |= ENABLE_ECHO_INPUT; r = SetConsoleMode(handle, mode); if (!r) return ty_error(TY_ERROR_SYSTEM, "SetConsoleMode(STD_INPUT_HANDLE) failed: %s", ty_win32_strerror(0)); return 0; }
int ty_firmware_new(const char *filename, ty_firmware **rfw) { assert(filename); assert(rfw); ty_firmware *fw; int r; fw = calloc(1, sizeof(ty_firmware)); if (!fw) { r = ty_error(TY_ERROR_MEMORY, NULL); goto error; } fw->refcount = 1; fw->filename = strdup(filename); if (!fw->filename) { r = ty_error(TY_ERROR_MEMORY, NULL); goto error; } if (!fw->name) { fw->name = strdup(get_basename(filename)); if (!fw->name) { r = ty_error(TY_ERROR_MEMORY, NULL); goto error; } } *rfw = fw; return 0; error: ty_firmware_unref(fw); return r; }
long getvalue() { unsigned char ch; char c; short s; ch = getbyte(); if (ch < 128) { return (ch); } switch (ch & 0xff) { case OLF_STRING: s = getbyte(); dump_hex(s, true); return (0); case OLF_1_SIGNED: // Fix for vax compiler bug, doesn't cast procedure return // values correctly c = getbyte(); return (c); case OLF_2_SIGNED: s = getshort(); return (s); case OLF_2_UNSIGNED: return (getshort() & 0xffff); case OLF_4_UNSIGNED: case OLF_4_SIGNED: return (getlong()); case OLF_8_UNSIGNED: case OLF_8_SIGNED: StdOutPuts(L"??? 8 byte values not handled presently\n"); dump_hex(8, true); return(0); default: ty_error(ch, L"Expecting numeric leaf"); return (0); } }
int ty_poll(const ty_descriptor_set *set, int timeout) { assert(set); assert(set->count); assert(set->count <= 64); DWORD ret = WaitForMultipleObjects((DWORD)set->count, set->desc, FALSE, timeout < 0 ? INFINITE : (DWORD)timeout); switch (ret) { case WAIT_FAILED: return ty_error(TY_ERROR_SYSTEM, "WaitForMultipleObjects() failed: %s", ty_win32_strerror(0)); case WAIT_TIMEOUT: return 0; } return set->id[ret - WAIT_OBJECT_0]; }
void ty_delay(unsigned int ms) { struct timespec t, rem; int r; t.tv_sec = (int)(ms / 1000); t.tv_nsec = (int)((ms % 1000) * 1000000); do { r = nanosleep(&t, &rem); if (r < 0) { if (errno != EINTR) { ty_error(TY_ERROR_SYSTEM, "nanosleep() failed: %s", strerror(errno)); return; } t = rem; } } while (r); }
int ty_stat(const char *path, ty_file_info *info, bool follow) { TY_UNUSED(follow); assert(path && path[0]); assert(info); HANDLE h; BY_HANDLE_FILE_INFORMATION attr; int r; // FIXME: check error handling h = CreateFile(path, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); if (h == INVALID_HANDLE_VALUE) { switch (GetLastError()) { case ERROR_ACCESS_DENIED: return ty_error(TY_ERROR_ACCESS, "Permission denied for '%s'", path); case ERROR_NOT_READY: return ty_error(TY_ERROR_IO, "I/O error while stating '%s'", path); case ERROR_FILE_NOT_FOUND: return ty_error(TY_ERROR_NOT_FOUND, "Path '%s' does not exist", path); case ERROR_PATH_NOT_FOUND: return ty_error(TY_ERROR_NOT_FOUND, "Part of '%s' is not a directory", path); } // Let's lie a little, error will be clearer this way return ty_error(TY_ERROR_SYSTEM, "GetFileAttributesEx('%s') failed: %s", path, ty_win32_strerror(0)); } r = GetFileInformationByHandle(h, &attr); if (!r) return ty_error(TY_ERROR_SYSTEM, "GetFileInformationByHandle('%s') failed: %s", path, ty_win32_strerror(0)); if (attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { info->type = TY_FILE_DIRECTORY; } else if (attr.dwFileAttributes & FILE_ATTRIBUTE_DEVICE) { info->type = TY_FILE_SPECIAL; } else { info->type = TY_FILE_REGULAR; } info->size = ((uint64_t)attr.nFileSizeHigh << 32) | attr.nFileSizeLow; info->mtime = filetime_to_unix_time(&attr.ftLastWriteTime); return 0; }
int ty_cond_init(ty_cond *cond) { static bool init; static InitializeConditionVariable_func *InitializeConditionVariable_; if (!init) { HANDLE kernel32 = GetModuleHandle("kernel32.dll"); // Condition Variables appeared on Vista, emulate them on Windows XP InitializeConditionVariable_ = (InitializeConditionVariable_func *)GetProcAddress(kernel32, "InitializeConditionVariable"); if (InitializeConditionVariable_) { WakeConditionVariable_ = (WakeConditionVariable_func *)GetProcAddress(kernel32, "WakeConditionVariable"); WakeAllConditionVariable_ = (WakeAllConditionVariable_func *)GetProcAddress(kernel32, "WakeAllConditionVariable"); SleepConditionVariableCS_ = (SleepConditionVariableCS_func *)GetProcAddress(kernel32, "SleepConditionVariableCS"); } else { WakeConditionVariable_ = WakeConditionVariable_fallback; WakeAllConditionVariable_ = WakeAllConditionVariable_fallback; SleepConditionVariableCS_ = SleepConditionVariableCS_fallback; } init = true; } if (InitializeConditionVariable_) { InitializeConditionVariable_((CONDITION_VARIABLE *)&cond->cv); } else { memset(cond, 0, sizeof(*cond)); cond->xp.ev = CreateEvent(NULL, TRUE, FALSE, NULL); if (!cond->xp.ev) return ty_error(TY_ERROR_SYSTEM, "CreateEvent() failed: %s", ty_win32_strerror(0)); InitializeCriticalSection((CRITICAL_SECTION *)&cond->xp.mutex); } cond->init = true; return 0; }
static int parse_error(struct parser_context *ctx) { return ty_error(TY_ERROR_PARSE, "IHEX parse error on line %u in '%s'", ctx->line, ctx->fw->filename); }
static int parse_line(struct parser_context *ctx, const char *line) { unsigned int length, type; uint32_t address; uint8_t checksum; ctx->ptr = line; ctx->sum = 0; ctx->error = false; // Empty lines are probably OK if (*ctx->ptr++ != ':') return 1; if (strlen(ctx->ptr) < 11) return TY_ERROR_PARSE; length = parse_hex_byte(ctx, true); address = parse_hex_short(ctx); type = parse_hex_byte(ctx, true); if (ctx->error) return TY_ERROR_PARSE; switch (type) { case 0: // data record address += ctx->base_offset; if (address + length > ctx->f->size) { ctx->f->size = address + length; if (ctx->f->size > tyb_firmware_max_size) return ty_error(TY_ERROR_RANGE, "Firmware too big (max %zu bytes)", tyb_firmware_max_size); } for (unsigned int i = 0; i < length; i++) ctx->f->image[address + i] = parse_hex_byte(ctx, true); break; case 1: // EOF record if (length > 0) return TY_ERROR_PARSE; return 0; case 2: // extended segment address record if (length != 2) return TY_ERROR_PARSE; ctx->base_offset = (uint32_t)parse_hex_short(ctx) << 4; break; case 3: // start segment address record break; case 4: // extended linear address record if (length != 2) return TY_ERROR_PARSE; ctx->base_offset = (uint32_t)parse_hex_short(ctx) << 16; break; case 5: // start linear address record break; default: return TY_ERROR_PARSE; } // Don't checksum the checksum :) checksum = parse_hex_byte(ctx, false); if (ctx->error) return TY_ERROR_PARSE; if (((ctx->sum & 0xFF) + (checksum & 0xFF)) & 0xFF) return TY_ERROR_PARSE; // 1 to continue, 0 to stop (EOF record) and negative for errors return 1; }
int ty_firmware_load(const char *filename, const char *format_name, ty_firmware **rfw) { assert(filename); assert(rfw); const ty_firmware_format *format; ty_firmware *fw = NULL; int r; if (format_name) { for (format = ty_firmware_formats; format->name; format++) { if (strcasecmp(format->name, format_name) == 0) break; } if (!format->name) { r = ty_error(TY_ERROR_UNSUPPORTED, "Firmware file format '%s' unknown", format_name); goto error; } } else { const char *ext = strrchr(filename, '.'); if (!ext) { r = ty_error(TY_ERROR_UNSUPPORTED, "Firmware '%s' has no file extension", filename); goto error; } for (format = ty_firmware_formats; format->name; format++) { if (strcmp(format->ext, ext) == 0) break; } if (!format->name) { r = ty_error(TY_ERROR_UNSUPPORTED, "Firmware '%s' uses unrecognized file format", filename); goto error; } } fw = malloc(sizeof(ty_firmware) + strlen(filename) + 1); if (!fw) { r = ty_error(TY_ERROR_MEMORY, NULL); goto error; } memset(fw, 0, sizeof(*fw)); fw->refcount = 1; strcpy(fw->filename, filename); r = (*format->load)(fw); if (r < 0) goto error; if (!fw->name) { fw->name = strdup(get_basename(filename)); if (!fw->name) { r = ty_error(TY_ERROR_MEMORY, NULL); goto error; } } *rfw = fw; return 0; error: ty_firmware_unref(fw); return r; }
int _tyb_firmware_load_ihex(const char *filename, tyb_firmware **rfirmware) { assert(rfirmware); assert(filename); struct parser_context ctx = {0}; FILE *fp = NULL; char buf[1024]; int r; ctx.f = malloc(sizeof(tyb_firmware) + tyb_firmware_max_size); if (!ctx.f) return ty_error(TY_ERROR_MEMORY, NULL); memset(ctx.f, 0, sizeof(*ctx.f)); memset(ctx.f->image, 0xFF, tyb_firmware_max_size); #ifdef _WIN32 fp = fopen(filename, "r"); #else fp = fopen(filename, "re"); #endif if (!fp) { switch (errno) { case EACCES: r = ty_error(TY_ERROR_ACCESS, "Permission denied for '%s'", filename); break; case EIO: r = ty_error(TY_ERROR_IO, "I/O error while opening '%s' for reading", filename); break; case ENOENT: case ENOTDIR: r = ty_error(TY_ERROR_NOT_FOUND, "File '%s' does not exist", filename); break; default: r = ty_error(TY_ERROR_SYSTEM, "fopen('%s') failed: %s", filename, strerror(errno)); break; } goto cleanup; } while (!feof(fp)) { if (!fgets(buf, sizeof(buf), fp)) break; ctx.line++; r = parse_line(&ctx, buf); if (r < 0) { if (r == TY_ERROR_PARSE) ty_error(r, "Parse error (Intel HEX) on line %u in '%s'\n", ctx.line, filename); goto cleanup; } // Either EOF record or real EOF will do, albeit the first is probably // better (guarantees the file is complete) if (r == 0 || feof(fp)) break; } *rfirmware = ctx.f; ctx.f = NULL; r = 0; cleanup: if (fp) fclose(fp); free(ctx.f); return r; }
static int loop(ty_board *board, int outfd) { ty_descriptor_set set = {0}; int timeout; char buf[BUFFER_SIZE]; ssize_t r; restart: r = ty_board_serial_set_attributes(board, device_rate, device_flags); if (r < 0) return (int)r; r = fill_descriptor_set(&set, board); if (r < 0) return (int)r; timeout = -1; ty_log(TY_LOG_INFO, "Monitoring '%s'", ty_board_get_tag(board)); while (true) { if (!set.count) return 0; r = ty_poll(&set, timeout); if (r < 0) return (int)r; switch (r) { case 0: return 0; case 1: r = ty_monitor_refresh(ty_board_get_monitor(board)); if (r < 0) return (int)r; if (!ty_board_has_capability(board, TY_BOARD_CAPABILITY_SERIAL)) { if (!reconnect) return 0; ty_log(TY_LOG_INFO, "Waiting for '%s'...", ty_board_get_tag(board)); r = ty_board_wait_for(board, TY_BOARD_CAPABILITY_SERIAL, -1); if (r < 0) return (int)r; goto restart; } break; case 2: r = ty_board_serial_read(board, buf, sizeof(buf), 0); if (r < 0) { if (r == TY_ERROR_IO && reconnect) { timeout = ERROR_IO_TIMEOUT; ty_descriptor_set_remove(&set, 2); ty_descriptor_set_remove(&set, 3); break; } return (int)r; } #ifdef _WIN32 r = write(outfd, buf, (unsigned int)r); #else r = write(outfd, buf, (size_t)r); #endif if (r < 0) { if (errno == EIO) return ty_error(TY_ERROR_IO, "I/O error on standard output"); return ty_error(TY_ERROR_IO, "Failed to write to standard output: %s", strerror(errno)); } break; case 3: #ifdef _WIN32 if (input_available) { if (input_ret < 0) return (int)input_ret; memcpy(buf, input_line, (size_t)input_ret); r = input_ret; ResetEvent(input_available); SetEvent(input_processed); } else { r = read(STDIN_FILENO, buf, sizeof(buf)); } #else r = read(STDIN_FILENO, buf, sizeof(buf)); #endif if (r < 0) { if (errno == EIO) return ty_error(TY_ERROR_IO, "I/O error on standard input"); return ty_error(TY_ERROR_IO, "Failed to read from standard input: %s", strerror(errno)); } if (!r) { if (timeout_eof >= 0) { /* EOF reached, don't listen to stdin anymore, and start timeout to give some time for the device to send any data before closing down. */ timeout = timeout_eof; ty_descriptor_set_remove(&set, 1); ty_descriptor_set_remove(&set, 3); } break; } #ifdef _WIN32 if (fake_echo) { r = write(outfd, buf, (unsigned int)r); if (r < 0) return (int)r; } #endif r = ty_board_serial_write(board, buf, (size_t)r); if (r < 0) { if (r == TY_ERROR_IO && reconnect) { timeout = ERROR_IO_TIMEOUT; ty_descriptor_set_remove(&set, 2); ty_descriptor_set_remove(&set, 3); break; } return (int)r; } break; } } }