#ifdef ENABLE_TCP #include "e502api_private.h" #include "e502_tcp_protocol.h" #include "ltimer.h" #include "e502_fpga_regs.h" #include "e502api_tcp_private.h" #include "osspec.h" #include #include #if defined _WIN32 #include typedef int socklen_t; typedef SOCKET t_socket; #define SOCK_ERR_SIGBREAK() 0 #define L_SOCK_LAST_ERR_BLOCK() (WSAEWOULDBLOCK == WSAGetLastError()) #define L_SOCK_LAST_ERR_RESET() (WSAECONNRESET == WSAGetLastError()) #else #include #include #include #include #include #include #include #include #include #include #include #include //#include #include typedef int t_socket; #define INVALID_SOCKET -1 #define SOCKET_ERROR -1 #define SOCK_ERR_SIGBREAK() (EINTR == errno) #define L_SOCK_LAST_ERR_BLOCK() ((EAGAIN==errno) || (EWOULDBLOCK==errno)) #ifdef ECONNRESET #define L_SOCK_LAST_ERR_RESET() (ECONNRESET==errno) #endif #define closesocket(sock) close(sock) #endif #ifndef MSG_NOSIGNAL #define MSG_NOSIGNAL 0 #endif #define E502_TCP_REQ_TOUT 5000 #define E502_TCP_STOP_WAIT_TOUT 5000 #define X502_MUTEX_TCP_IOCTL_LOCK_TOUT 5000 #define X502_MUTEX_TCP_DATA_LOCK_TOUT 5000 #define TCP_CTL_REQ_MAX_SIZE 512 #define TCP_IN_STREAM_BUF_MIN 128 #define TCP_IOCTL_INLINE_MAX_DATA_SIZE 64 #if 0 #define dprintf(...) fprintf(stderr, __VA_ARGS__) #else #define dprintf(...) #endif typedef struct { t_socket cmd_sock; t_socket data_sock; uint32_t ip_addr; uint32_t open_tout; uint16_t data_port; t_mutex ioctl_mutex; t_mutex data_mutex; uint32_t data_chs_en; uint32_t recv_part_wrd; /**< принятое неполностью слово */ uint32_t send_part_wrd; /**< переданное неполностью слово */ uint8_t recv_part_size; /**< кол-во принятых байт в последнем неполном слове */ uint8_t send_part_size; /**< кол-во неотправленных байт в последнем переданном не полностью слове */ } t_tcp_iface_data; static int32_t f_iface_free_devinfo_ptr(t_x502_devrec_inptr *devinfo_ptr); static int32_t f_iface_open(t_x502_hnd hnd, const t_x502_devrec *devrec); static int32_t f_iface_close(t_x502_hnd hnd); static int32_t f_iface_stream_cfg(t_x502_hnd hnd, uint32_t ch, t_x502_stream_ch_params *params); static int32_t f_iface_stream_start(t_x502_hnd hnd, uint32_t ch, uint32_t signle); static int32_t f_iface_stream_stop(t_x502_hnd hnd, uint32_t ch, uint32_t flags); static int32_t f_iface_stream_free(t_x502_hnd hnd, uint32_t ch, uint32_t flags); static int32_t f_iface_stream_read(t_x502_hnd hnd, uint32_t *buf, uint32_t size, uint32_t tout); static int32_t f_iface_stream_write(t_x502_hnd hnd, const uint32_t *buf, uint32_t size, uint32_t tout) ; static int32_t f_iface_stream_get_rdy_cnt(t_x502_hnd hnd, uint32_t ch, uint32_t *rdy_cnt); static int32_t f_iface_gen_ioctl(t_x502_hnd hnd, uint32_t cmd_code, uint32_t param, const void* snd_data, uint32_t snd_size, void* rcv_data, uint32_t recv_size, uint32_t* recvd_size, uint32_t tout); static const t_x502_dev_iface f_tcp_iface = { E502_REGS_ARM_HARD_ID, TCP_IN_STREAM_BUF_MIN, TCP_CTL_REQ_MAX_SIZE, TCP_CTL_REQ_MAX_SIZE/4, TCP_CTL_REQ_MAX_SIZE, //flash rd size TCP_CTL_REQ_MAX_SIZE, //flash wr size f_iface_free_devinfo_ptr, f_iface_open, f_iface_close, e502_iface_fpga_read, e502_iface_fpga_write, f_iface_stream_cfg, f_iface_stream_start, f_iface_stream_stop, f_iface_stream_free, e502_iface_stream_running, f_iface_stream_read, f_iface_stream_write, f_iface_stream_get_rdy_cnt, e502_iface_bf_mem_block_rd, e502_iface_bf_mem_block_wr, e502_iface_bf_firm_load, e502_iface_flash_rd, e502_iface_flash_wr, e502_iface_flash_erase, e502_iface_flash_set_prot, e502_iface_reload_dev_info, e502_iface_cycle_load_start, e502_iface_cycle_setup, e502_iface_cycle_stop, e502_iface_cycle_check_setup, e502_iface_fpga_mode_init, f_iface_gen_ioctl, e502_iface_check_feature }; static void f_set_timeval_left(t_ltimer* tmr, struct timeval* tval) { t_lclock_ticks left = ltimer_expiration(tmr); tval->tv_sec = left / LCLOCK_TICKS_PER_SECOND; tval->tv_usec = (left % LCLOCK_TICKS_PER_SECOND) * 1000000/LCLOCK_TICKS_PER_SECOND; } static int32_t f_con_sock(t_socket *psock, uint32_t ip_addr, uint16_t port, uint32_t tout) { int32_t err = X502_ERR_OK; struct sockaddr_in peer; int connected = 0; t_socket s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (s == INVALID_SOCKET) err = X502_ERR_SOCKET_OPEN; /* Переводим сокет в неблокирующий режим работы */ if (err == X502_ERR_OK) { #ifdef _WIN32 ULONG nonblocking = 1; if (SOCKET_ERROR == ioctlsocket(s, FIONBIO, &nonblocking)) err = X502_ERR_SOCKET_OPEN; #else int n = fcntl(s, F_GETFL, 0); if (fcntl(s, F_SETFL, n|O_NONBLOCK)==-1) { err = X502_ERR_SOCKET_OPEN; } #endif } if (err == X502_ERR_OK) { /* заполняем структуру с адресом LTR-сервера */ memset(&peer, 0, sizeof(peer)); peer.sin_family = AF_INET; peer.sin_port = htons(port); peer.sin_addr.s_addr = htonl(ip_addr); } while (!connected && (err==X502_ERR_OK)) { t_ltimer tmr; ltimer_set(&tmr, LTIMER_MS_TO_CLOCK_TICKS(tout)); if (SOCKET_ERROR == connect(s, (struct sockaddr*)&peer, sizeof(peer))) { int sockerr = 0; fd_set fd_w, fd_e; #ifdef _WIN32 if (WSAEWOULDBLOCK != WSAGetLastError()) { #else if (errno != EINPROGRESS) { #endif err = X502_ERR_SOCKET_OPEN; } else { struct timeval tval; FD_ZERO(&fd_w); FD_SET(s, &fd_w); FD_ZERO(&fd_e); FD_SET(s, &fd_e); f_set_timeval_left(&tmr, &tval); if (select((int)s+1, NULL, &fd_w, &fd_e, &tval) < 1) err = X502_ERR_CONNECTION_TOUT; } if (err == X502_ERR_OK) { /* судя по man - если произошла ошибка, то сокет становится writable! так что в fd_w тоже нужно проверять ошибку */ socklen_t optlen = sizeof(sockerr); if (SOCKET_ERROR == getsockopt(s, SOL_SOCKET, SO_ERROR, (char*)&sockerr, &optlen)) { err = X502_ERR_SOCKET_OPEN; } else if (sockerr) { #ifdef EHOSTUNREACH if (sockerr == EHOSTUNREACH) { err = X502_ERR_HOST_UNREACHABLE; } #endif #ifdef ECONNRESET if (sockerr == ECONNRESET) { err = X502_ERR_CONNECTION_RESET; } #endif if (err == X502_ERR_OK) err = X502_ERR_TCP_CONNECTION_ERROR; } } /* проверяем, что соединились успешно */ if ((err == X502_ERR_OK) && !sockerr && (FD_ISSET(s, &fd_w))) connected = 1; } else { /* удалось соединится без ожидания */ connected = 1; } } /* while (!connected && !err) */ if (err != X502_ERR_OK) { if (s!=INVALID_SOCKET) { closesocket(s); } } else if (psock!=NULL) { *psock = s; } return err; } static int32_t f_recv(t_socket s, uint8_t *buf, uint32_t size, t_ltimer *ptmr) { int32_t err = X502_ERR_OK; uint32_t offset = 0; int timed_out = 0; fd_set fd_r; struct timeval tval; if ((err == X502_ERR_OK) && (size!=0)) { while (!err && !timed_out && (offset < size)) { FD_ZERO(&fd_r); FD_SET(s, &fd_r); f_set_timeval_left(ptmr, &tval); switch (select((int)s+1, &fd_r, NULL, NULL, &tval)) { case SOCKET_ERROR: /* Если пришел сигнал, то это не ошибка приема. * Но скорее всего управление стоит вернуть сразу, хотя * может сделать опцию... */ if (SOCK_ERR_SIGBREAK()) { ltimer_set(ptmr, 0); timed_out = 1; } else { err = X502_ERR_RECV; } break; case 0: // таймаут timed_out = 1; break; default: { /* дождались готовности на чтение */ int res = recv(s, buf + offset, size - offset, 0); if (SOCKET_ERROR == res) { if (!L_SOCK_LAST_ERR_BLOCK()) { err = X502_ERR_RECV; } } else if (0 == res) { /* соединение закрыто */ err = X502_ERR_CONNECTION_CLOSED_BY_DEV; } else { offset += res; } } break; } } /* switch (select(ch->sock+1, &fd_r, NULL, NULL, &tval)) */ } return err ? err : (int32_t)offset; } int32_t f_send(t_socket s, const uint8_t *buf, uint32_t size, t_ltimer *ptmr) { int32_t err = X502_ERR_OK; uint32_t offset = 0; int timed_out = 0; fd_set fd_w; if ((err == X502_ERR_OK) && (size != 0)) { while ((err == X502_ERR_OK) && !timed_out && (offset < size)) { /* Сначала пробуем сделать запись без ожидания */ int res = send(s, buf + offset, size - offset, MSG_NOSIGNAL); if (res == SOCKET_ERROR) { struct timeval tval; if (L_SOCK_LAST_ERR_BLOCK()) { /* Надо ждать освобождения сокета */ FD_ZERO(&fd_w); FD_SET(s, &fd_w); f_set_timeval_left(ptmr, &tval); switch (select((int)s+1, NULL, &fd_w, NULL, &tval)) { case SOCKET_ERROR: if (SOCK_ERR_SIGBREAK()) { ltimer_set(ptmr, 0); timed_out = 1; } else { err = X502_ERR_SEND; } break; case 0: // таймаут timed_out = 1; break; default: if (ltimer_expired(ptmr)) timed_out = 1; break; } } else { err = X502_ERR_SEND; } } else { // no error offset += res; } } } return (err) ? err : (int)offset; } static int32_t f_recv_exact(t_socket s, uint8_t *buf, uint32_t size, t_ltimer *ptmr) { int32_t ret = f_recv(s, buf, size, ptmr); return ret == (int32_t)size ? X502_ERR_OK : ret < 0 ? ret : X502_ERR_RECV_INSUFFICIENT_WORDS; } static int32_t f_send_exact(t_socket s, const uint8_t *buf, uint32_t size, t_ltimer *ptmr) { int32_t ret = f_send(s, buf, size, ptmr); return ret == (int32_t)size ? X502_ERR_OK : ret < 0 ? ret : X502_ERR_SEND_INSUFFICIENT_WORDS; } static int32_t f_iface_gen_ioctl(t_x502_hnd hnd, uint32_t cmd_code, uint32_t param, const void* snd_data, uint32_t snd_size, void* rcv_data, uint32_t recv_size, uint32_t* recvd_size, uint32_t tout) { struct { t_e502_tcp_cmd_hdr hdr; uint8_t data[TCP_IOCTL_INLINE_MAX_DATA_SIZE]; } cmd; t_e502_tcp_resp_hdr cmd_resp; int32_t err = X502_ERR_OK; t_ltimer tmr; t_tcp_iface_data* iface_data = (t_tcp_iface_data*)hnd->iface_data; t_socket s = iface_data->cmd_sock; err = osspec_mutex_lock(iface_data->ioctl_mutex, X502_MUTEX_TCP_IOCTL_LOCK_TOUT); if (err == X502_ERR_OK) { ltimer_set(&tmr, LTIMER_MS_TO_CLOCK_TICKS(tout == 0 ? E502_TCP_REQ_TOUT : tout)); cmd.hdr.sign = E502_TCP_CMD_SIGNATURE; cmd.hdr.cmd = cmd_code; cmd.hdr.par = param; cmd.hdr.data_len = snd_size; cmd.hdr.resp_len = recv_size; /* чтобы избежать двух передач по TCP, если данных, передаваемых с командой, * меньше заданного порога, то объединяем их вместе с заголовком и посылаем * за один вызов send */ if (snd_size <= TCP_IOCTL_INLINE_MAX_DATA_SIZE) { if (snd_size > 0) memcpy(cmd.data, snd_data, snd_size); err = f_send_exact(s, (uint8_t*)&cmd, E502_TCP_CMD_HDR_SIZE + snd_size, &tmr); } else { err = f_send_exact(s, (uint8_t*)&cmd.hdr, E502_TCP_CMD_HDR_SIZE, &tmr); if (err == X502_ERR_OK) { err = f_send_exact(s, snd_data, snd_size, &tmr); } } if (err == X502_ERR_OK) { err = f_recv_exact(s, (uint8_t*)&cmd_resp, E502_TCP_CMD_RESP_SIZE, &tmr); if (err == X502_ERR_RECV_INSUFFICIENT_WORDS) { err = X502_ERR_NO_CMD_RESPONSE; } } if ((err == X502_ERR_OK) && (cmd_resp.len > 0)) { if (cmd_resp.len > recv_size) { err = X502_ERR_IOCTL_INVALID_RESP_SIZE; } else { err = f_recv_exact(s, rcv_data, cmd_resp.len, &tmr); } } if (err == X502_ERR_OK) { if (recvd_size != NULL) { *recvd_size = cmd_resp.len; } else if (cmd_resp.len != recv_size) { err = X502_ERR_IOCTL_INVALID_RESP_SIZE; } } if ((err == X502_ERR_OK) && (cmd_resp.res!=0)) { err = cmd_resp.res; } osspec_mutex_release(iface_data->ioctl_mutex); } return err; } static int32_t f_iface_free_devinfo_ptr(t_x502_devrec_inptr *devinfo_ptr) { t_tcp_devinfo_data *devinfo_data = (t_tcp_devinfo_data*)devinfo_ptr->iface_data; #ifdef ENABLE_DNSSD if ((devinfo_data != NULL) && (devinfo_data->svc_rec != NULL)) E502_EthSvcRecordFree(devinfo_data->svc_rec); #endif free(devinfo_ptr->iface_data); free(devinfo_ptr); return X502_ERR_OK; } static int32_t f_iface_open(t_x502_hnd hnd, const t_x502_devrec *devrec) { int32_t err = X502_ERR_OK; t_tcp_devinfo_data *devinfo_data = (t_tcp_devinfo_data*)devrec->internal->iface_data; t_socket s = INVALID_SOCKET; #ifdef ENABLE_DNSSD if (devinfo_data->svc_rec) { err = e502_svc_fill_devinfo(devinfo_data); } #endif if (err == X502_ERR_OK) { err = f_con_sock(&s, devinfo_data->ip_addr, devinfo_data->cmd_port, devinfo_data->open_tout); if (err == X502_ERR_OK) { int flag = 1; if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (char*)&flag, sizeof(flag))==SOCKET_ERROR) err = X502_ERR_SOCKET_OPEN; } } if (err == X502_ERR_OK) { t_tcp_iface_data *iface_data = malloc(sizeof(t_tcp_iface_data)); if (iface_data == NULL) { err = X502_ERR_MEMORY_ALLOC; } else { t_lboot_devinfo lboot_info; iface_data->cmd_sock = s; iface_data->data_sock = INVALID_SOCKET; iface_data->ip_addr = devinfo_data->ip_addr; iface_data->open_tout = devinfo_data->open_tout; iface_data->data_port = devinfo_data->data_port; iface_data->ioctl_mutex = osspec_mutex_create(); iface_data->data_mutex = osspec_mutex_create(); iface_data->data_chs_en = 0; if ((iface_data->ioctl_mutex == OSSPEC_INVALID_MUTEX) || (iface_data->data_mutex == OSSPEC_INVALID_MUTEX)) { err = X502_ERR_MUTEX_CREATE; } else { hnd->iface_data = iface_data; err = hnd->iface_hnd->gen_ioctl(hnd, E502_CM4_CMD_GET_MODULE_INFO, 0, NULL, 0, &lboot_info, sizeof(lboot_info), NULL, 0); if (err == X502_ERR_OK) { if (strcmp(lboot_info.devname, devrec->devname)) { err = X502_ERR_INVALID_DEVICE; } else { e502_devinfo_init(&hnd->info, &lboot_info); err = e502_fill_devflags(hnd); } } } if (err != X502_ERR_OK) { if (iface_data->ioctl_mutex != OSSPEC_INVALID_MUTEX) osspec_mutex_destroy(iface_data->ioctl_mutex); if (iface_data->data_mutex != OSSPEC_INVALID_MUTEX) osspec_mutex_destroy(iface_data->data_mutex); hnd->iface_data = NULL; free(iface_data); } } } if ((err != X502_ERR_OK) && (s != INVALID_SOCKET)) { closesocket(s); } return err; } static int32_t f_iface_close(t_x502_hnd hnd) { int32_t err = X502_ERR_OK; t_tcp_iface_data *tcp_data = (t_tcp_iface_data*)hnd->iface_data; if (tcp_data != NULL) { if (tcp_data->data_sock!=INVALID_SOCKET) { closesocket(tcp_data->data_sock); tcp_data->data_sock = INVALID_SOCKET; } if (tcp_data->cmd_sock!=INVALID_SOCKET) { closesocket(tcp_data->cmd_sock); tcp_data->cmd_sock = INVALID_SOCKET; } if (tcp_data->ioctl_mutex != OSSPEC_INVALID_MUTEX) { osspec_mutex_destroy(tcp_data->ioctl_mutex); tcp_data->ioctl_mutex = OSSPEC_INVALID_MUTEX; } if (tcp_data->data_mutex != OSSPEC_INVALID_MUTEX) { osspec_mutex_destroy(tcp_data->data_mutex); tcp_data->data_mutex = OSSPEC_INVALID_MUTEX; } free(hnd->iface_data); hnd->iface_data = NULL; } return err; } static int32_t f_iface_stream_cfg(t_x502_hnd hnd, uint32_t ch, t_x502_stream_ch_params *params) { int32_t err = X502_ERR_OK; t_tcp_iface_data *tcp_data = (t_tcp_iface_data*)hnd->iface_data; err = osspec_mutex_lock(tcp_data->data_mutex, X502_MUTEX_TCP_DATA_LOCK_TOUT); if (err == X502_ERR_OK) { if (tcp_data->data_sock == INVALID_SOCKET) { err = f_iface_gen_ioctl(hnd, E502_CM4_CMD_DROP_DATA_CON, 0, NULL, 0, NULL, 0, NULL, 0); if (err == X502_ERR_OK) { err = f_con_sock(&tcp_data->data_sock, tcp_data->ip_addr, tcp_data->data_port, tcp_data->open_tout); } if (err == X502_ERR_OK) { int flag = 1; if (setsockopt(tcp_data->data_sock, IPPROTO_TCP, TCP_NODELAY, (char*)&flag, sizeof(flag))==SOCKET_ERROR) err = X502_ERR_SOCKET_OPEN; } } if (err == X502_ERR_OK) { unsigned buf_size = params->buf_size*4; if (ch==X502_STREAM_CH_IN) { tcp_data->recv_part_size = 0; if (setsockopt(tcp_data->data_sock, SOL_SOCKET, SO_RCVBUF, (char*)&buf_size, sizeof(buf_size))==SOCKET_ERROR) { err = X502_ERR_SOCKET_SET_BUF_SIZE; } else { dprintf("set SO_RCVBUF to %d\n", buf_size); } #ifndef _WIN32 setsockopt(tcp_data->data_sock, SOL_SOCKET, SO_RCVBUFFORCE, (char*)&buf_size, sizeof(buf_size)); #endif socklen_t opt_len = sizeof(buf_size); if (getsockopt(tcp_data->data_sock, SOL_SOCKET, SO_RCVBUF, (char*)&buf_size, &opt_len) != SOCKET_ERROR) { dprintf("get SO_RCVBUF = %d\n", buf_size); } #ifdef _WIN32 else { dprintf("getsockopt error = %d\n", WSAGetLastError()); } #endif } else { tcp_data->send_part_size = 0; if (setsockopt(tcp_data->data_sock, SOL_SOCKET, SO_SNDBUF, (char*)&buf_size, sizeof(buf_size))==SOCKET_ERROR) { err = X502_ERR_SOCKET_SET_BUF_SIZE; } } } if (err == X502_ERR_OK) { tcp_data->data_chs_en |= (1UL << ch); } osspec_mutex_release(tcp_data->data_mutex); } return err; } static int32_t f_iface_stream_start(t_x502_hnd hnd, uint32_t ch, uint32_t flags) { int32_t err = 0; if (!err && !(flags & X502_STREAM_FLAG_NO_REQUEST)) { err = f_iface_gen_ioctl(hnd, E502_CM4_CMD_STREAM_START, (ch<<16), NULL, 0, NULL, 0, NULL, 0); } return err; } static int32_t f_iface_stream_stop(t_x502_hnd hnd, uint32_t ch, uint32_t flags) { int32_t err = 0; if (!(flags & X502_STREAM_FLAG_NO_REQUEST)) { int32_t running; err = hnd->iface_hnd->stream_running(hnd, ch, &running); if (!err && running) { err = f_iface_gen_ioctl(hnd, E502_CM4_CMD_STREAM_STOP, (ch << 16), NULL, 0, NULL, 0, NULL, 0); } } return err; } static int32_t f_iface_stream_free(t_x502_hnd hnd, uint32_t ch, uint32_t flags) { t_tcp_iface_data *tcp_data = (t_tcp_iface_data *)hnd->iface_data; int32_t err = osspec_mutex_lock(tcp_data->data_mutex, X502_MUTEX_TCP_DATA_LOCK_TOUT); if (err == X502_ERR_OK) { err = hnd->iface_hnd->stream_stop(hnd, ch, flags); if (err == X502_ERR_OK) { tcp_data->data_chs_en &= ~(1UL << ch); if ((tcp_data->data_chs_en == 0) && (tcp_data->data_sock != INVALID_SOCKET)) { closesocket(tcp_data->data_sock); tcp_data->data_sock = INVALID_SOCKET; } } osspec_mutex_release(tcp_data->data_mutex); } return err; } static int32_t f_iface_stream_read(t_x502_hnd hnd, uint32_t *buf, uint32_t size, uint32_t tout) { t_tcp_iface_data *tcp_data = (t_tcp_iface_data*)hnd->iface_data; int32_t recvd; t_ltimer tmr; if (tcp_data->data_sock == INVALID_SOCKET) { recvd = X502_ERR_NO_DATA_CONNECTION; } else { ltimer_set(&tmr, LTIMER_MS_TO_CLOCK_TICKS(tout)); if (tcp_data->recv_part_size != 0) { buf[0] = tcp_data->recv_part_wrd; } recvd = f_recv(tcp_data->data_sock, (uint8_t*)buf + tcp_data->recv_part_size, size *sizeof(buf[0]) - tcp_data->recv_part_size, &tmr); if (recvd > 0) { recvd += tcp_data->recv_part_size; tcp_data->recv_part_size = recvd % sizeof(buf[0]); recvd /= sizeof(buf[0]); if (tcp_data->recv_part_size!=0) { tcp_data->recv_part_wrd = buf[recvd]; } } } return recvd; } static int32_t f_iface_stream_write(t_x502_hnd hnd, const uint32_t *buf, uint32_t size, uint32_t tout) { int32_t sent = 0; t_ltimer tmr; t_tcp_iface_data *tcp_data = (t_tcp_iface_data*)hnd->iface_data; if (tcp_data->data_sock == INVALID_SOCKET) { sent = X502_ERR_NO_DATA_CONNECTION; } else { ltimer_set(&tmr, LTIMER_MS_TO_CLOCK_TICKS(tout)); /* проверяем, не осталось ли не переданного некратного слова => если осталось * то пробуем сперва дослать его */ if (tcp_data->send_part_size!=0) { sent = f_send(tcp_data->data_sock, (uint8_t*)&tcp_data->send_part_wrd, tcp_data->send_part_size, &tmr); if (sent >= 0) { tcp_data->send_part_size -= (uint8_t)sent; if (tcp_data->send_part_size != 0) { tcp_data->send_part_wrd >>= 8*sent; } sent = 0; } } /* новые данные пересылаем только если старое неполное слово точно ушло */ if ((sent == 0) && (tcp_data->send_part_size==0)) { sent = f_send(tcp_data->data_sock, (uint8_t*)buf, size * sizeof(buf[0]), &tmr); if (sent >= 0) { /* если не полностью передали последнее слово, то нужно сохранить * остаток слова, чтобы потом передать его */ tcp_data->send_part_size = sent % sizeof(buf[0]); sent /= sizeof(buf[0]); if (tcp_data->send_part_size!=0) { tcp_data->send_part_wrd = buf[sent] >> (8*tcp_data->send_part_size); tcp_data->send_part_size = sizeof(buf[0]) - tcp_data->send_part_size; sent++; } } } } return sent; } static int32_t f_iface_stream_get_rdy_cnt(t_x502_hnd hnd, uint32_t ch, uint32_t *rdy_cnt) { int32_t err = 0; t_tcp_iface_data *tcp_data = (t_tcp_iface_data *)hnd->iface_data; #ifdef _WIN32 if (ch == X502_STREAM_CH_IN) { u_long val; if (ioctlsocket(tcp_data->data_sock, FIONREAD, &val) == SOCKET_ERROR) { err = X502_ERR_IOCTL_FAILD; } else { *rdy_cnt = val/4; } } else { err = X502_ERR_NOT_IMPLEMENTED; } #else if (ch == X502_STREAM_CH_IN) { int val; if (ioctl(tcp_data->data_sock, SIOCINQ, &val)==-1) { err = X502_ERR_IOCTL_FAILD; } else { *rdy_cnt = val/4; } } else { err = X502_ERR_NOT_IMPLEMENTED; #if 0 /* Данный вариант в реальности не работает корректно */ int buf_len, val; socklen_t optlen = sizeof(buf_len); if (getsockopt(tcp_data->data_sock, SOL_SOCKET, SO_SNDBUF, (char*)&buf_len, &optlen)==SOCKET_ERROR) { err = X502_ERR_IOCTL_FAILD; } else if (ioctl(tcp_data->data_sock, SIOCOUTQ, &val)==-1) { err = X502_ERR_IOCTL_FAILD; } else { *rdy_cnt = (buf_len - val)/4; } #endif } #endif return err; } int32_t e502_make_tcp_rec(t_x502_devrec *devrec, uint32_t flags, uint32_t tout, char const *devname) { int32_t err = (devrec == NULL) ? X502_ERR_INVALID_DEVICE_RECORD : X502_ERR_OK; X502_DevRecordInit(devrec); if (err==X502_ERR_OK) { t_tcp_devinfo_data *devinfo_data = malloc(sizeof(t_tcp_devinfo_data)); t_x502_devrec_inptr *devinfo_ptr = malloc(sizeof(t_x502_devrec_inptr)); if ((devinfo_data==NULL) || (devinfo_ptr == NULL)) { err = X502_ERR_MEMORY_ALLOC; } else { strcpy(devrec->devname, devname); devinfo_data->cmd_port = E502_TCP_DEFAULT_CMD_PORT; devinfo_data->data_port = E502_TCP_DEFAULT_DATA_PORT; devinfo_data->open_tout = tout; devinfo_data->flags = flags; devinfo_ptr->iface = &f_tcp_iface; devinfo_ptr->iface_data = devinfo_data; devrec->internal = devinfo_ptr; devrec->iface = X502_IFACE_ETH; devrec->flags = X502_DEVFLAGS_IFACE_SUPPORT_USB | X502_DEVFLAGS_IFACE_SUPPORT_ETH; } if (err != X502_ERR_OK) { free(devinfo_data); free(devinfo_ptr); } } return err; } X502_EXPORT(int32_t) E502_MakeDevRecordByIpAddr2(t_x502_devrec *devrec, uint32_t ip_addr, uint32_t flags, uint32_t tout, char const *devname) { int32_t err = e502_make_tcp_rec(devrec, flags, tout, devname); if (err == X502_ERR_OK) { t_tcp_devinfo_data *devinfo_data = (t_tcp_devinfo_data *)devrec->internal->iface_data; devinfo_data->ip_addr = ip_addr; #ifdef ENABLE_DNSSD devinfo_data->svc_rec = NULL; #endif sprintf(devrec->location, "%d.%d.%d.%d", (ip_addr>>24) & 0xFF, (ip_addr>>16) & 0xFF, (ip_addr>>8) & 0xFF, (ip_addr>>0) & 0xFF); devrec->location_type = X502_LOCATION_TYPE_ADDR; } return err; } X502_EXPORT(int32_t) E502_MakeDevRecordByIpAddr(t_x502_devrec *devrec, uint32_t ip_addr, uint32_t flags, uint32_t tout) { return E502_MakeDevRecordByIpAddr2(devrec, ip_addr, flags, tout, E502_DEVICE_NAME); } X502_EXPORT(int32_t) E502_EthDevRecordSetCmdPort(t_x502_devrec *devrec, uint16_t cmd_port) { int32_t err = ((devrec == NULL) || (devrec->internal->iface != &f_tcp_iface)) ? X502_ERR_INVALID_DEVICE_RECORD : X502_ERR_OK; if (err == X502_ERR_OK) { t_tcp_devinfo_data *devinfo_data = (t_tcp_devinfo_data *)devrec->internal->iface_data; devinfo_data->cmd_port = cmd_port; } return err; } X502_EXPORT(int32_t) E502_EthDevRecordSetDataPort(t_x502_devrec *devrec, uint16_t data_port) { int32_t err = ((devrec == NULL) || (devrec->internal->iface != &f_tcp_iface)) ? X502_ERR_INVALID_DEVICE_RECORD : X502_ERR_OK; if (err == X502_ERR_OK) { t_tcp_devinfo_data *devinfo_data = (t_tcp_devinfo_data *)devrec->internal->iface_data; devinfo_data->data_port = data_port; } return err; } X502_EXPORT(int32_t) E16_OpenByIpAddr(t_x502_hnd hnd, uint32_t ip_addr, uint32_t flags, uint32_t tout) { int32_t err = X502_CHECK_HND(hnd); if (err == X502_ERR_OK) { t_x502_devrec devinfo; err = E502_MakeDevRecordByIpAddr2(&devinfo, ip_addr, flags, tout, E16_DEVICE_NAME); if (err == X502_ERR_OK) { err = X502_OpenByDevRecord(hnd, &devinfo); X502_FreeDevRecordList(&devinfo, 1); } } return err; } X502_EXPORT(int32_t) E502_OpenByIpAddr(t_x502_hnd hnd, uint32_t ip_addr, uint32_t flags, uint32_t tout) { int32_t err = X502_CHECK_HND(hnd); if (err == X502_ERR_OK) { t_x502_devrec devinfo; err = E502_MakeDevRecordByIpAddr(&devinfo, ip_addr, flags, tout); if (err == X502_ERR_OK) { err = X502_OpenByDevRecord(hnd, &devinfo); X502_FreeDevRecordList(&devinfo, 1); } } return err; } X502_EXPORT(int32_t) E502_GetIpAddr(t_x502_hnd hnd, uint32_t *ip_addr) { int32_t err = X502_CHECK_HND_OPENED(hnd); if (err == X502_ERR_OK) { if (hnd->iface != X502_IFACE_ETH) { err = X502_ERR_INVALID_OP_FOR_IFACE; } else { t_tcp_iface_data *tcp_data = (t_tcp_iface_data *)hnd->iface_data; *ip_addr = tcp_data->ip_addr; } } return err; } #else #include "e502api.h" X502_EXPORT(int32_t) E502_MakeDevRecordByIpAddr(t_x502_devrec *devrec, uint32_t ip_addr, uint32_t flags, uint32_t tout) { return X502_ERR_NOT_IMPLEMENTED; } X502_EXPORT(int32_t) E502_EthDevRecordSetCmdPort(t_x502_devrec *devrec, uint16_t cmd_port) { return X502_ERR_NOT_IMPLEMENTED; } X502_EXPORT(int32_t) E502_EthDevRecordSetDataPort(t_x502_devrec *devrec, uint16_t data_port) { return X502_ERR_NOT_IMPLEMENTED; } X502_EXPORT(int32_t) E502_OpenByIpAddr(t_x502_hnd hnd, uint32_t ip_addr, uint32_t flags, uint32_t tout) { return X502_ERR_NOT_IMPLEMENTED; } X502_EXPORT(int32_t) E502_GetIpAddr(t_x502_hnd hnd, uint32_t *ip_addr) { return X502_ERR_NOT_IMPLEMENTED; } #endif