890 lines
24 KiB
C
890 lines
24 KiB
C
/*-------------------------------------------------------------------------
|
|
S E R I A L S I N Q
|
|
Implementation file of the functions for talking with a RS--232 port
|
|
on a SINQ terminal server. This code has been adapted from code
|
|
provided by David Maden for the EL734 motor controller. A new version
|
|
became necessary as the Dornier velocity selector supports a
|
|
completely different protocoll than the EL734. The basics, however, are
|
|
the same.
|
|
|
|
Mark Koennecke, Juli 1997
|
|
|
|
Copyright:
|
|
|
|
Labor fuer Neutronenstreuung
|
|
Paul Scherrer Institut
|
|
CH-5423 Villigen-PSI
|
|
|
|
|
|
The authors hereby grant permission to use, copy, modify, distribute,
|
|
and license this software and its documentation for any purpose, provided
|
|
that existing copyright notices are retained in all copies and that this
|
|
notice is included verbatim in any distributions. No written agreement,
|
|
license, or royalty fee is required for any of the authorized uses.
|
|
Modifications to this software may be copyrighted by their authors
|
|
and need not follow the licensing terms described here, provided that
|
|
the new terms are clearly indicated on the first page of each file where
|
|
they apply.
|
|
|
|
IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
|
|
FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
|
ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
|
|
DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
|
|
POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
|
|
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
|
|
IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
|
|
NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
|
|
MODIFICATIONS.
|
|
----------------------------------------------------------------------------*/
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <assert.h>
|
|
#include <stdio.h>
|
|
#include <time.h>
|
|
#include <sys/time.h>
|
|
#include <unistd.h>
|
|
|
|
#ifdef FORTIFY
|
|
#include "fortify.h"
|
|
#endif
|
|
|
|
#include <stdarg.h>
|
|
#include <errno.h>
|
|
#include <signal.h>
|
|
#include <netdb.h>
|
|
#include <sys/socket.h>
|
|
#include <netinet/in.h>
|
|
|
|
#include <string.h>
|
|
|
|
#ifdef __VMS
|
|
#include <unixio.h>
|
|
#else
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
/*-----------------------------------------------------------------*/
|
|
#include "sinq_prototypes.h"
|
|
#include "el734_def.h"
|
|
#include "rs232c_def.h"
|
|
#include "el734fix.h"
|
|
#include "serialsinq.h"
|
|
|
|
#define True 1
|
|
#define False 0
|
|
|
|
struct SerialInfo {
|
|
int skt;
|
|
int iForce;
|
|
int port;
|
|
int chan;
|
|
char host[20];
|
|
int tmo;
|
|
int msg_id;
|
|
int n_replies, max_replies;
|
|
char pTerms[4];
|
|
char pSendTerm[10];
|
|
struct RS__MsgStruct to_host;
|
|
struct RS__RespStruct from_host;
|
|
SerialSleep pFunc;
|
|
void *pData;
|
|
struct AsynSrv__info sAsync;
|
|
};
|
|
/*------------------- The default sleep function -----------------------*/
|
|
static int SerialNccrrrh(void *pData, int iTime)
|
|
{
|
|
usleep(50);
|
|
return 1;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
int SerialOpen(void **pData, char *pHost, int iPort, int iChannel)
|
|
{
|
|
int status;
|
|
struct SerialInfo *my_info;
|
|
void *my_hndl;
|
|
struct hostent *rmt_hostent;
|
|
struct in_addr *rmt_inet_addr_pntr;
|
|
int rmt_sockname_len;
|
|
struct sockaddr_in lcl_sockname;
|
|
struct sockaddr_in rmt_sockname;
|
|
char msr_cmnd[20];
|
|
struct RS__RplyStruct *rply_ptr;
|
|
|
|
*pData = NULL;
|
|
|
|
/*
|
|
** allocate memory first
|
|
*/
|
|
*pData = malloc(sizeof(struct SerialInfo));
|
|
if (*pData == NULL) {
|
|
return EL734__BAD_MALLOC; /* malloc failed!! */
|
|
}
|
|
my_info = *pData;
|
|
memset(my_info, 0, sizeof(struct SerialInfo));
|
|
|
|
/*
|
|
**-------------------------- Set up the connection
|
|
*/
|
|
my_info->sAsync.port = iPort;
|
|
strcpy(my_info->sAsync.host, pHost);
|
|
my_info->sAsync.chan = iChannel;
|
|
status = AsynSrv_Open(&(my_info->sAsync));
|
|
if (status != 1) {
|
|
return OPENFAILURE;
|
|
}
|
|
|
|
/* intialize data structures */
|
|
StrJoin(my_info->host, sizeof(my_info->host), pHost, "");
|
|
my_info->skt = my_info->sAsync.skt;
|
|
my_info->port = iPort;
|
|
my_info->chan = iChannel;
|
|
my_info->tmo = 100;
|
|
my_info->msg_id = 0;
|
|
my_info->pFunc = SerialNccrrrh;
|
|
my_info->pData = NULL;
|
|
strcpy(my_info->pTerms, "1\r\n\0");
|
|
my_info->iForce = 0;
|
|
memset(my_info->pSendTerm, 0, 9);
|
|
strcpy(my_info->pSendTerm, "\r\n");
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
int SerialForceOpen(void **pData, char *pHost, int iPort, int iChannel)
|
|
{
|
|
int status;
|
|
struct SerialInfo *my_info;
|
|
void *my_hndl;
|
|
struct hostent *rmt_hostent;
|
|
struct in_addr *rmt_inet_addr_pntr;
|
|
int rmt_sockname_len;
|
|
struct sockaddr_in lcl_sockname;
|
|
struct sockaddr_in rmt_sockname;
|
|
char msr_cmnd[20];
|
|
struct RS__RplyStruct *rply_ptr;
|
|
|
|
*pData = NULL;
|
|
|
|
/* create pData */
|
|
*pData = malloc(sizeof(struct SerialInfo));
|
|
if (*pData == NULL) {
|
|
return EL734__BAD_MALLOC; /* malloc failed!! */
|
|
}
|
|
my_info = *pData;
|
|
memset(my_info, 0, sizeof(struct SerialInfo));
|
|
|
|
|
|
/*
|
|
**-------------------------- Set up the connection
|
|
*/
|
|
my_info->sAsync.port = iPort;
|
|
strcpy(my_info->sAsync.host, pHost);
|
|
my_info->sAsync.chan = iChannel;
|
|
status = AsynSrv_OpenNew(&(my_info->sAsync));
|
|
if (status != 1) {
|
|
return OPENFAILURE;
|
|
}
|
|
|
|
/* intialize data structures */
|
|
StrJoin(my_info->host, sizeof(my_info->host), pHost, "");
|
|
my_info->skt = my_info->sAsync.skt;
|
|
my_info->port = iPort;
|
|
my_info->chan = iChannel;
|
|
my_info->tmo = 100;
|
|
my_info->msg_id = 0;
|
|
my_info->pFunc = SerialNccrrrh;
|
|
my_info->pData = NULL;
|
|
strcpy(my_info->pTerms, "1\r\n\0");
|
|
my_info->iForce = 1;
|
|
memset(my_info->pSendTerm, 0, 9);
|
|
strcpy(my_info->pSendTerm, "\r\n");
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
int SerialConfig(void **pData, int iTmo)
|
|
{
|
|
struct SerialInfo *my_info = NULL;
|
|
|
|
my_info = (struct SerialInfo *) *pData;
|
|
assert(my_info);
|
|
|
|
if (iTmo < 100) {
|
|
my_info->tmo = 1;
|
|
return 1;
|
|
} else {
|
|
my_info->tmo = iTmo / 100; /* convert to deci seconds */
|
|
if (my_info->tmo > 9999)
|
|
my_info->tmo = 9999;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
int GetSerialTmo(void **pData)
|
|
{
|
|
struct SerialInfo *my_info = NULL;
|
|
int iTmo;
|
|
|
|
my_info = (struct SerialInfo *) *pData;
|
|
assert(my_info);
|
|
|
|
iTmo = my_info->tmo * 100 - 99; /* convert back to milli seconds */
|
|
|
|
return iTmo;
|
|
}
|
|
int SerialGetTmo(void **pData)
|
|
{
|
|
return GetSerialTmo(pData);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
int SerialGetSocket(void **pData)
|
|
{
|
|
struct SerialInfo *my_info = NULL;
|
|
int iTmo;
|
|
|
|
my_info = (struct SerialInfo *) *pData;
|
|
assert(my_info);
|
|
|
|
return my_info->skt;
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
int SerialClose(void **pData)
|
|
{
|
|
|
|
struct SerialInfo *info_ptr;
|
|
char buff[4];
|
|
|
|
info_ptr = (struct SerialInfo *) *pData;
|
|
if (info_ptr == NULL)
|
|
return True;
|
|
|
|
if (info_ptr->skt != 0) {
|
|
AsynSrv_Close(&(info_ptr->sAsync), 0);
|
|
info_ptr->skt = 0;
|
|
}
|
|
free(*pData);
|
|
*pData = NULL;
|
|
return True;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
int SerialForceClose(void **pData)
|
|
{
|
|
|
|
struct SerialInfo *info_ptr;
|
|
char buff[4];
|
|
|
|
info_ptr = (struct SerialInfo *) *pData;
|
|
if (info_ptr == NULL)
|
|
return True;
|
|
|
|
if (info_ptr->skt != 0) {
|
|
AsynSrv_Close(&(info_ptr->sAsync), 1);
|
|
info_ptr->skt = 0;
|
|
}
|
|
free(*pData);
|
|
*pData = NULL;
|
|
return True;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
int SerialATerm(void **pData, char *pTerm)
|
|
{
|
|
struct SerialInfo *my_info = NULL;
|
|
|
|
my_info = (struct SerialInfo *) *pData;
|
|
if (my_info == NULL) {
|
|
printf("Serious Programming problem: data = NULL\n");
|
|
return 0;
|
|
}
|
|
|
|
/* only three characters in this field */
|
|
if (strlen(pTerm) > 4) {
|
|
return 0;
|
|
}
|
|
memset(my_info->pTerms, 0, 4);
|
|
strcpy(my_info->pTerms, pTerm);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
int SerialAGetTerm(void **pData, char *pTerm, int iTermLen)
|
|
{
|
|
struct SerialInfo *my_info = NULL;
|
|
|
|
my_info = (struct SerialInfo *) *pData;
|
|
assert(my_info);
|
|
|
|
strncpy(pTerm, my_info->pTerms, iTermLen);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
int SerialSendTerm(void **pData, char *pTerm)
|
|
{
|
|
struct SerialInfo *my_info = NULL;
|
|
|
|
my_info = (struct SerialInfo *) *pData;
|
|
assert(my_info);
|
|
|
|
/* only 0 characters in this field */
|
|
if (strlen(pTerm) > 9) {
|
|
return 0;
|
|
}
|
|
strcpy(my_info->pSendTerm, pTerm);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
int SerialSend(void **pData, char *pCommand)
|
|
{
|
|
struct SerialInfo *info_ptr;
|
|
int status, c_len, size, max_size, ncmnds;
|
|
int bytes_to_come, bytes_left;
|
|
int iResult;
|
|
char *nxt_byte_ptr;
|
|
char err_text[80];
|
|
char text[20];
|
|
char *txt_ptr;
|
|
char *cmnd_lst_ptr;
|
|
char *pComCom = NULL;
|
|
|
|
/*
|
|
** Do nothing if no connection - the connection gets
|
|
** closed if an error is detected.
|
|
*/
|
|
info_ptr = (struct SerialInfo *) *pData;
|
|
if (info_ptr == NULL)
|
|
return NOCONNECTION;
|
|
if (info_ptr->skt == 0) {
|
|
memset(info_ptr->from_host.msg_size,
|
|
'0', sizeof(info_ptr->from_host.msg_size));
|
|
return NOCONNECTION;
|
|
}
|
|
|
|
info_ptr->msg_id++; /* Set up an incrementing message id */
|
|
if (info_ptr->msg_id > 9999)
|
|
info_ptr->msg_id = 1;
|
|
sprintf(info_ptr->to_host.msg_id, "%4.4d", info_ptr->msg_id);
|
|
|
|
memcpy(info_ptr->to_host.c_pcol_lvl, RS__PROTOCOL_ID_V01B,
|
|
sizeof(info_ptr->to_host.c_pcol_lvl));
|
|
sprintf(info_ptr->to_host.serial_port, "%4.4d", info_ptr->chan);
|
|
sprintf(info_ptr->to_host.tmo, "%04d", info_ptr->tmo);
|
|
|
|
strncpy(info_ptr->sAsync.eot, info_ptr->pTerms, 4);
|
|
memcpy(info_ptr->to_host.terms, info_ptr->pTerms,
|
|
sizeof(info_ptr->to_host.terms));
|
|
memcpy(info_ptr->to_host.n_cmnds, "0000",
|
|
sizeof(info_ptr->to_host.n_cmnds));
|
|
|
|
|
|
txt_ptr = pCommand; /* Get pntr to cmnd string */
|
|
ncmnds = 0;
|
|
cmnd_lst_ptr = &info_ptr->to_host.cmnds[0];
|
|
bytes_left = sizeof(info_ptr->to_host) -
|
|
OffsetOf(struct RS__MsgStruct, cmnds[0]);
|
|
|
|
size = strlen(txt_ptr) + strlen(info_ptr->pSendTerm);
|
|
if (size > bytes_left) {
|
|
return EL734__BAD_SENDLEN; /* Too much to send */
|
|
} else {
|
|
strcpy(cmnd_lst_ptr + 4, txt_ptr);
|
|
/* make sure that the string is properly terminated */
|
|
if ((strstr(txt_ptr, info_ptr->pSendTerm) == 0) &&
|
|
(strlen(txt_ptr) > 0)) {
|
|
strcpy(cmnd_lst_ptr + 4 + strlen(txt_ptr), info_ptr->pSendTerm);
|
|
c_len = strlen(txt_ptr) + strlen(info_ptr->pSendTerm);
|
|
} else {
|
|
c_len = strlen(txt_ptr);
|
|
}
|
|
sprintf(text, "%4.4d", c_len);
|
|
memcpy(cmnd_lst_ptr, text, 4);
|
|
cmnd_lst_ptr = cmnd_lst_ptr + c_len + 4;
|
|
ncmnds++;
|
|
bytes_left = bytes_left - size;
|
|
}
|
|
|
|
sprintf(text, "%4.4d", ncmnds);
|
|
memcpy(info_ptr->to_host.n_cmnds,
|
|
text, sizeof(info_ptr->to_host.n_cmnds));
|
|
|
|
size = cmnd_lst_ptr - info_ptr->to_host.msg_id;
|
|
size = (size + 3) & (~3); /* Round up to multiple of 4 */
|
|
sprintf(text, "%4.4d", size);
|
|
memcpy(info_ptr->to_host.msg_size, text, 4);
|
|
|
|
status = send(info_ptr->skt, (char *) &info_ptr->to_host, size + 4, 0);
|
|
if (status != (size + 4)) {
|
|
if (status == 0) {
|
|
iResult = EL734__BAD_SEND; /* Server exited (probably) */
|
|
} else if (status == -1) {
|
|
iResult = EL734__BAD_SEND_PIPE; /* Server exited (probably) */
|
|
}
|
|
AsynSrv_Close(&(info_ptr->sAsync), 1);
|
|
info_ptr->skt = 0;
|
|
memset(info_ptr->from_host.msg_size,
|
|
'0', sizeof(info_ptr->from_host.msg_size));
|
|
return iResult;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
int SerialReceive(void **pData, char *pBuffer, int iBufLen)
|
|
{
|
|
struct SerialInfo *info_ptr;
|
|
int status, c_len, size, max_size, ncmnds;
|
|
int bytes_to_come, bytes_left;
|
|
int iResult;
|
|
char *nxt_byte_ptr;
|
|
char err_text[80];
|
|
char text[20];
|
|
char *txt_ptr;
|
|
char *cmnd_lst_ptr;
|
|
struct RS__RplyStruct_V01B *ptr = NULL;
|
|
long lMask = 0L;
|
|
struct timeval tmo = { 0, 1 };
|
|
|
|
|
|
/*
|
|
** Do nothing if no connection - the connection gets
|
|
** closed if an error is detected.
|
|
*/
|
|
info_ptr = (struct SerialInfo *) *pData;
|
|
if (info_ptr == NULL)
|
|
return NOCONNECTION;
|
|
if (info_ptr->skt == 0) {
|
|
memset(info_ptr->from_host.msg_size,
|
|
'0', sizeof(info_ptr->from_host.msg_size));
|
|
return NOCONNECTION;
|
|
}
|
|
|
|
/* try with select if there is data */
|
|
/* lMask = (1 << info_ptr->skt);
|
|
tmo.tv_usec = 10;
|
|
status = select((info_ptr->skt +1), (fd_set *)&lMask, NULL,NULL,&tmo);
|
|
if(status <= 0)
|
|
{
|
|
return SELECTFAIL;
|
|
}
|
|
*/
|
|
|
|
/* try read the message length to come */
|
|
size = sizeof(info_ptr->from_host.msg_size);
|
|
status = recv(info_ptr->skt, info_ptr->from_host.msg_size, size, 0);
|
|
if (status != size) {
|
|
if (status > 0) {
|
|
iResult = EL734__BAD_RECV; /* Server exited (probably) */
|
|
} else if (status == -1) {
|
|
iResult = EL734__BAD_RECV_NET; /* It's some other net problem */
|
|
} else {
|
|
iResult = EL734__BAD_RECV_NET;
|
|
}
|
|
AsynSrv_Close(&(info_ptr->sAsync), 1);
|
|
info_ptr->skt = 0;
|
|
memset(info_ptr->from_host.msg_size,
|
|
'0', sizeof(info_ptr->from_host.msg_size));
|
|
return iResult;
|
|
}
|
|
if (sscanf(info_ptr->from_host.msg_size, "%4d", &bytes_to_come) != 1) {
|
|
return EL734__BAD_NOT_BCD; /* Header not an ASCII BCD integer */
|
|
}
|
|
|
|
max_size = sizeof(info_ptr->from_host) -
|
|
sizeof(info_ptr->from_host.msg_size);
|
|
if (bytes_to_come > max_size) {
|
|
iResult = EL734__BAD_RECVLEN;
|
|
nxt_byte_ptr = &info_ptr->from_host.msg_size[size];
|
|
while (bytes_to_come > 0) { /* Flush out the incoming message */
|
|
bytes_left = bytes_to_come;
|
|
if (bytes_left > max_size)
|
|
bytes_left = max_size;
|
|
status = recv(info_ptr->skt, nxt_byte_ptr, bytes_left, 0);
|
|
if (status <= 0) {
|
|
iResult = EL734__BAD_FLUSH; /* TCP/IP problem whilst flushing */
|
|
AsynSrv_Close(&(info_ptr->sAsync), 1);
|
|
info_ptr->skt = 0;
|
|
memset(info_ptr->from_host.msg_size,
|
|
'0', sizeof(info_ptr->from_host.msg_size));
|
|
return iResult;
|
|
}
|
|
bytes_to_come = bytes_to_come - status;
|
|
}
|
|
memset(info_ptr->from_host.msg_size,
|
|
'0', sizeof(info_ptr->from_host.msg_size));
|
|
return iResult;
|
|
} else {
|
|
nxt_byte_ptr = &info_ptr->from_host.msg_size[size];
|
|
bytes_left = bytes_to_come;
|
|
while (bytes_left > 0) { /* Read the rest of the response */
|
|
status = recv(info_ptr->skt, nxt_byte_ptr, bytes_left, 0);
|
|
if (status <= 0) {
|
|
if (status == 0) {
|
|
iResult = EL734__BAD_RECV1; /* Server exited (probably) */
|
|
} else {
|
|
iResult = EL734__BAD_RECV1_NET; /* It's some other net fault */
|
|
}
|
|
AsynSrv_Close(&(info_ptr->sAsync), 1);
|
|
info_ptr->skt = 0;
|
|
return iResult;
|
|
}
|
|
bytes_left = bytes_left - status;
|
|
nxt_byte_ptr = nxt_byte_ptr + status;
|
|
}
|
|
}
|
|
/* well, we got data, make it available */
|
|
if (sscanf(info_ptr->from_host.n_rply, "%4d",
|
|
&info_ptr->max_replies) != 1)
|
|
info_ptr->max_replies = 0;
|
|
if (info_ptr->max_replies > 0)
|
|
ptr = (struct RS__RplyStruct_V01B *) info_ptr->from_host.u.rplys;
|
|
info_ptr->n_replies = 1;
|
|
if (ptr) {
|
|
strncpy(pBuffer, ptr->rply, iBufLen);
|
|
} else {
|
|
return NOREPLY;
|
|
}
|
|
return True;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
int SerialReceiveWithTerm(void **pData, char *pBuffer,
|
|
int iBufLen, char *cTerm)
|
|
{
|
|
struct SerialInfo *info_ptr;
|
|
int status, c_len, size, max_size, ncmnds;
|
|
int bytes_to_come, bytes_left;
|
|
int iResult;
|
|
char *nxt_byte_ptr;
|
|
char err_text[80];
|
|
char text[20];
|
|
char *txt_ptr;
|
|
char *cmnd_lst_ptr;
|
|
struct RS__RplyStruct_V01B *ptr = NULL;
|
|
long lMask = 0L;
|
|
struct timeval tmo = { 0, 1 };
|
|
|
|
|
|
/*
|
|
** Do nothing if no connection - the connection gets
|
|
** closed if an error is detected.
|
|
*/
|
|
info_ptr = (struct SerialInfo *) *pData;
|
|
if (info_ptr == NULL)
|
|
return NOCONNECTION;
|
|
if (info_ptr->skt == 0) {
|
|
memset(info_ptr->from_host.msg_size,
|
|
'0', sizeof(info_ptr->from_host.msg_size));
|
|
return NOCONNECTION;
|
|
}
|
|
|
|
/* try with select if there is data */
|
|
/* lMask = (1 << info_ptr->skt);
|
|
tmo.tv_usec = 10;
|
|
status = select((info_ptr->skt +1), (fd_set *)&lMask, NULL,NULL,&tmo);
|
|
if(status <= 0)
|
|
{
|
|
return SELECTFAIL;
|
|
}
|
|
*/
|
|
|
|
/* try read the message length to come */
|
|
size = sizeof(info_ptr->from_host.msg_size);
|
|
status = recv(info_ptr->skt, info_ptr->from_host.msg_size, size, 0);
|
|
if (status != size) {
|
|
if (status > 0) {
|
|
iResult = EL734__BAD_RECV; /* Server exited (probably) */
|
|
} else if (status == -1) {
|
|
iResult = EL734__BAD_RECV_NET; /* It's some other net problem */
|
|
} else {
|
|
iResult = EL734__BAD_RECV_NET;
|
|
}
|
|
AsynSrv_Close(&(info_ptr->sAsync), 1);
|
|
info_ptr->skt = 0;
|
|
memset(info_ptr->from_host.msg_size,
|
|
'0', sizeof(info_ptr->from_host.msg_size));
|
|
return iResult;
|
|
}
|
|
if (sscanf(info_ptr->from_host.msg_size, "%4d", &bytes_to_come) != 1) {
|
|
return EL734__BAD_NOT_BCD; /* Header not an ASCII BCD integer */
|
|
}
|
|
|
|
max_size = sizeof(info_ptr->from_host) -
|
|
sizeof(info_ptr->from_host.msg_size);
|
|
if (bytes_to_come > max_size) {
|
|
iResult = EL734__BAD_RECVLEN;
|
|
nxt_byte_ptr = &info_ptr->from_host.msg_size[size];
|
|
while (bytes_to_come > 0) { /* Flush out the incoming message */
|
|
bytes_left = bytes_to_come;
|
|
if (bytes_left > max_size)
|
|
bytes_left = max_size;
|
|
status = recv(info_ptr->skt, nxt_byte_ptr, bytes_left, 0);
|
|
if (status <= 0) {
|
|
iResult = EL734__BAD_FLUSH; /* TCP/IP problem whilst flushing */
|
|
AsynSrv_Close(&(info_ptr->sAsync), 1);
|
|
info_ptr->skt = 0;
|
|
memset(info_ptr->from_host.msg_size,
|
|
'0', sizeof(info_ptr->from_host.msg_size));
|
|
return iResult;
|
|
}
|
|
bytes_to_come = bytes_to_come - status;
|
|
}
|
|
memset(info_ptr->from_host.msg_size,
|
|
'0', sizeof(info_ptr->from_host.msg_size));
|
|
return iResult;
|
|
} else {
|
|
nxt_byte_ptr = &info_ptr->from_host.msg_size[size];
|
|
bytes_left = bytes_to_come;
|
|
while (bytes_left > 0) { /* Read the rest of the response */
|
|
status = recv(info_ptr->skt, nxt_byte_ptr, bytes_left, 0);
|
|
if (status <= 0) {
|
|
if (status == 0) {
|
|
iResult = EL734__BAD_RECV1; /* Server exited (probably) */
|
|
} else {
|
|
iResult = EL734__BAD_RECV1_NET; /* It's some other net fault */
|
|
}
|
|
AsynSrv_Close(&(info_ptr->sAsync), 1);
|
|
info_ptr->skt = 0;
|
|
return iResult;
|
|
}
|
|
bytes_left = bytes_left - status;
|
|
nxt_byte_ptr = nxt_byte_ptr + status;
|
|
}
|
|
}
|
|
/* well, we got data, make it available */
|
|
if (sscanf(info_ptr->from_host.n_rply, "%4d",
|
|
&info_ptr->max_replies) != 1)
|
|
info_ptr->max_replies = 0;
|
|
if (info_ptr->max_replies > 0)
|
|
ptr = (struct RS__RplyStruct_V01B *) info_ptr->from_host.u.rplys;
|
|
info_ptr->n_replies = 1;
|
|
if (ptr) {
|
|
strncpy(pBuffer, ptr->rply, iBufLen);
|
|
*cTerm = ptr->term;
|
|
} else {
|
|
return NOREPLY;
|
|
}
|
|
return True;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
int SerialError(int iErr, char *pBuffer, int iBufLen)
|
|
{
|
|
switch (iErr) {
|
|
case -320:
|
|
strncpy(pBuffer, "Select failed to find data", iBufLen);
|
|
break;
|
|
case -300:
|
|
case NOCONNECTION:
|
|
strncpy(pBuffer, "Not connected", iBufLen);
|
|
break;
|
|
case -301:
|
|
strncpy(pBuffer, "No reply found", iBufLen);
|
|
break;
|
|
case -100:
|
|
strncpy(pBuffer, "No reply found", iBufLen);
|
|
break;
|
|
case EL734__BAD_ADR:
|
|
strncpy(pBuffer, "SERIAL__BAD_ADR", iBufLen);
|
|
break;
|
|
case EL734__BAD_BIND:
|
|
strncpy(pBuffer, "SERIAL__BAD_BIND", iBufLen);
|
|
break;
|
|
case EL734__BAD_CMD:
|
|
strncpy(pBuffer, "SERIAL__BAD_CMD", iBufLen);
|
|
break;
|
|
case EL734__BAD_CONNECT:
|
|
strncpy(pBuffer, "SERIAL__BAD_CONNECT", iBufLen);
|
|
break;
|
|
case EL734__BAD_FLUSH:
|
|
strncpy(pBuffer, "SERIAL__BAD_FLUSH", iBufLen);
|
|
break;
|
|
case EL734__BAD_HOST:
|
|
strncpy(pBuffer, "SERIAL__BAD_HOST", iBufLen);
|
|
break;
|
|
case EL734__BAD_ID:
|
|
strncpy(pBuffer, "SERIAL__BAD_ID", iBufLen);
|
|
break;
|
|
case EL734__BAD_ILLG:
|
|
strncpy(pBuffer, "SERIAL__BAD_ILLG", iBufLen);
|
|
break;
|
|
case EL734__BAD_LOC:
|
|
strncpy(pBuffer, "SERIAL__BAD_LOC", iBufLen);
|
|
break;
|
|
case EL734__BAD_MALLOC:
|
|
strncpy(pBuffer, "SERIAL__BAD_MALLOC", iBufLen);
|
|
break;
|
|
case EL734__BAD_NOT_BCD:
|
|
strncpy(pBuffer, "SERIAL__BAD_NOT_BCD", iBufLen);
|
|
break;
|
|
case EL734__BAD_OFL:
|
|
strncpy(pBuffer, "SERIAL__BAD_OFL", iBufLen);
|
|
break;
|
|
case EL734__BAD_PAR:
|
|
strncpy(pBuffer, "SERIAL__BAD_PAR", iBufLen);
|
|
break;
|
|
|
|
case EL734__BAD_RECV:
|
|
strncpy(pBuffer, "SERIAL__BAD_RECV", iBufLen);
|
|
break;
|
|
case EL734__BAD_RECV_NET:
|
|
strncpy(pBuffer, "SERIAL__BAD_RECV_NET", iBufLen);
|
|
break;
|
|
case EL734__BAD_RECV_PIPE:
|
|
strncpy(pBuffer, "SERIAL__BAD_RECV_PIPE", iBufLen);
|
|
break;
|
|
case EL734__BAD_RECV_UNKN:
|
|
strncpy(pBuffer, "SERIAL__BAD_RECV_UNKN", iBufLen);
|
|
break;
|
|
case EL734__BAD_RECVLEN:
|
|
strncpy(pBuffer, "SERIAL__BAD_RECVLEN", iBufLen);
|
|
break;
|
|
case EL734__BAD_RECV1:
|
|
strncpy(pBuffer, "SERIAL__BAD_RECV1", iBufLen);
|
|
break;
|
|
case EL734__BAD_RECV1_NET:
|
|
strncpy(pBuffer, "SERIAL__BAD_RECV1_NET", iBufLen);
|
|
break;
|
|
case EL734__BAD_RECV1_PIPE:
|
|
strncpy(pBuffer, "SERIAL__BAD_RECV1_PIPE", iBufLen);
|
|
break;
|
|
case EL734__BAD_RNG:
|
|
strncpy(pBuffer, "SERIAL__BAD_RNG", iBufLen);
|
|
break;
|
|
case EL734__BAD_SEND:
|
|
strncpy(pBuffer, "SERIAL__BAD_SEND", iBufLen);
|
|
break;
|
|
case EL734__BAD_SEND_PIPE:
|
|
strncpy(pBuffer, "SERIAL__BAD_SEND_PIPE", iBufLen);
|
|
break;
|
|
case EL734__BAD_SEND_NET:
|
|
strncpy(pBuffer, "SERIAL__BAD_SEND_NET", iBufLen);
|
|
break;
|
|
case EL734__BAD_SEND_UNKN:
|
|
strncpy(pBuffer, "SERIAL__BAD_SEND_UNKN", iBufLen);
|
|
break;
|
|
case EL734__BAD_SENDLEN:
|
|
strncpy(pBuffer, "SERIAL__BAD_SENDLEN", iBufLen);
|
|
break;
|
|
case EL734__BAD_SOCKET:
|
|
strncpy(pBuffer, "SERIAL__BAD_SOCKET", iBufLen);
|
|
break;
|
|
case EL734__BAD_TMO:
|
|
strncpy(pBuffer, "SERIAL__BAD_TMO", iBufLen);
|
|
break;
|
|
case EL734__FORCED_CLOSED:
|
|
strncpy(pBuffer, "SERIAL__FORCED_CLOSED", iBufLen);
|
|
break;
|
|
case OPENFAILURE:
|
|
strncpy(pBuffer,
|
|
"FAILED to open connection to serial port server", iBufLen);
|
|
break;
|
|
default:
|
|
strcpy(pBuffer, "Unknown SERIAL error");
|
|
break;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
int SerialWriteRead(void **pData, char *pCommand,
|
|
char *pBuffer, int iBufLen)
|
|
{
|
|
|
|
struct SerialInfo *pInfo = NULL;
|
|
int iRet;
|
|
time_t tTarget, tCurrent;
|
|
|
|
pInfo = (struct SerialInfo *) *pData;
|
|
|
|
/* write */
|
|
iRet = SerialSend(pData, pCommand);
|
|
if (iRet != 1) {
|
|
SerialError(iRet, pBuffer, iBufLen);
|
|
return iRet;
|
|
}
|
|
|
|
/* check for answers for maximum time out */
|
|
tTarget = tCurrent = time(&tCurrent);
|
|
tTarget += pInfo->tmo * 100 - 90;
|
|
|
|
while (tCurrent < tTarget) {
|
|
pInfo->pFunc(pInfo->pData, 100);
|
|
iRet = SerialReceive(pData, pBuffer, iBufLen);
|
|
if (iRet != 1) {
|
|
if (iRet != SELECTFAIL) {
|
|
/* error ! */
|
|
SerialError(iRet, pBuffer, iBufLen);
|
|
return iRet;
|
|
}
|
|
} else {
|
|
return 1; /* there is data read, we are done */
|
|
}
|
|
tCurrent = time(&tCurrent);
|
|
}
|
|
return TIMEOUT;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
int SerialNoReply(void **pData, char *pCommand)
|
|
{
|
|
|
|
struct SerialInfo *pInfo = NULL;
|
|
int iRet, iOld, i;
|
|
char pBuffer[30];
|
|
|
|
pInfo = (struct SerialInfo *) *pData;
|
|
|
|
iOld = pInfo->tmo;
|
|
pInfo->tmo = 0;
|
|
|
|
/* write */
|
|
iRet = SerialSend(pData, pCommand);
|
|
if (iRet != 1) {
|
|
pInfo->tmo = iOld;
|
|
return iRet;
|
|
}
|
|
|
|
/* try some time to find a TMO */
|
|
for (i = 0; i < 10; i++) {
|
|
usleep(50);
|
|
SerialReceive(pData, pBuffer, 29);
|
|
if (strcmp(pBuffer, "?TMO") == 0) {
|
|
break;
|
|
}
|
|
}
|
|
if (i > 7) {
|
|
printf("TMO received after %d cycles \n", i);
|
|
}
|
|
pInfo->tmo = iOld;
|
|
return 1;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
void SetSerialSleep(void **pData, SerialSleep pFun, void *pUserData)
|
|
{
|
|
struct SerialInfo *pInfo = NULL;
|
|
int iRet;
|
|
|
|
pInfo = (struct SerialInfo *) *pData;
|
|
pInfo->pFunc = pFun;
|
|
pInfo->pData = pUserData;
|
|
|
|
}
|