moved libs to the lib directory

This commit is contained in:
2025-11-13 18:40:06 +03:00
parent 4d1f7fdbe9
commit b80ad585da
634 changed files with 3 additions and 2 deletions

902
lib/e502/e502api_tcp.c Normal file
View 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