manually merged with ARM version
This commit is contained in:
902
x502api-1.1.34/devs/e502/e502api_tcp.c
Normal file
902
x502api-1.1.34/devs/e502/e502api_tcp.c
Normal file
@ -0,0 +1,902 @@
|
||||
#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 <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#if defined _WIN32
|
||||
#include <winsock2.h>
|
||||
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 <errno.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/select.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
//#include <stropts.h>
|
||||
|
||||
#include <linux/sockios.h>
|
||||
|
||||
|
||||
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
|
||||
Reference in New Issue
Block a user