/* devChinoLog.c */
/****************************************************************************
* COPYRIGHT NOTIFICATION
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
****************************************************************************/
/* Author : Makoto Tobiyama 19/Jul/2005 */
/* Modification Log:
* -----------------
*/
#include <dbFldTypes.h>
#include "drvNetMpf.h"
#include "devNetDev.h"
#ifndef EPICS_REVISION
#include <epicsVersion.h>
#endif
#if EPICS_REVISION == 14 && EPICS_MODIFICATION >= 2
#include <epicsExport.h>
#endif
#define CHINO_CMND_LENGTH 8 /* not correct */
#define CHINO_UDP_PORT 11111
#define CHINO_GET_PROTO chino_get_protocol()
#define CHINO_MAX_NDATA 5120
#define CHINO_DATA_OFFSET 3
LOCAL int finsUseSamePortNumber = MPF_SAMEPORT;
LOCAL unsigned short calCRC(unsigned char cd[], int nmax);
LOCAL int TwoRawToVal(unsigned char bu[],int offset, float *res );
LOCAL long chino_parse_link(
struct link *,
struct sockaddr_in *,
int *,
void *
);
LOCAL int chino_get_protocol(void);
LOCAL void *chino_calloc(int, int, int, int, int);
typedef struct
{
int unit;
int type;
int chan;
int bit;
int width;
int slvA;
int cmd;
int start;
int ndata;
char *lopt;
} CHINO_LOG;
LOCAL long chino_config_command(uint8_t *, int *, void *, int, int, int *, CHINO_LOG *, int);
LOCAL long chino_parse_response(uint8_t *, int *, void *, int, int, int *, CHINO_LOG *, int);
int chinoLogUseTcp = 1;
LOCAL int chino_get_protocol(void)
{
if (chinoLogUseTcp)
{
return MPF_TCP;
}
return MPF_UDP;
}
LOCAL void *chino_calloc(
int unit,
int type,
int chan,
int bit,
int width
)
{
CHINO_LOG *d;
d = (CHINO_LOG *) calloc(1, sizeof(CHINO_LOG));
if (!d)
{
errlogPrintf("devChinoLog: calloc failed\n");
return NULL;
}
d->unit = unit;
d->type = type;
d->chan = chan;
d->bit = bit;
d->width = width;
return d;
}
#include "devWaveformChinoLog.c"
/*********************************************************************************
* Link field parser for command/response I/O
*********************************************************************************/
LOCAL long chino_parse_link(
struct link *plink,
struct sockaddr_in *peer_addr,
int *option,
void *device
)
{
char *protocol = NULL;
char *unit = NULL;
char *type = NULL;
char *addr = NULL;
char *route = NULL;
char *lopt = NULL;
CHINO_LOG *d = (CHINO_LOG *) device;
if (parseLinkPlcCommon(
plink,
peer_addr,
&protocol,
&route, /* dummy */
&unit,
&type,
&addr,
&lopt
))
{
errlogPrintf("devChinoLog: illeagal input specification\n");
return ERROR;
}
if (sscanf(unit,"%x",&d->slvA) !=1)
{
errlogPrintf("devChinoLog :cannot get slave address\n");
}
if (sscanf(type,"%x",&d->cmd) !=1)
{
errlogPrintf("devChinoLog :cannot get command\n");
}
if (sscanf(addr,"%d",&d->start) != 1)
{
errlogPrintf("devChinoLog : cannot get start address\n");
}
return OK;
}
/******************************************************************************
* Command constructor for command/response I/O
******************************************************************************/
LOCAL unsigned short calCRC(unsigned char cd[], int nmax)
{
int i,j;
unsigned short iCRC;
unsigned short iCY,iP;
unsigned char iC1,iC2;
iCRC = 0xffff;
for (i=0;i<nmax;i++)
{
iCRC = iCRC ^ cd[i];
for (j=1; j<=8; j++)
{
iCY = iCRC & 0x1;
if ((iCRC & 0x8000) == 0x8000)
{
iP = 0x4000;
iCRC = iCRC & 0x7fff;
}
else
{
iP = 0x0;
}
iCRC = iCRC>>1;
iCRC = iCRC | iP;
if (iCY == 1){
iCRC = iCRC ^ 0xa001;
}
}
}
if ((iCRC & 0x8000) == 0x8000)
{
iP = 0x80;
iCRC = iCRC & 0x7fff;
}
else
{
iP = 0;
}
iC1 = iCRC & 0xff;
iC2 = ((iCRC & 0x7f00) >>8) | iP;
return iC1*256 + iC2;
}
LOCAL long chino_config_command(
uint8_t *buf, /* driver buf addr */
int *len, /* driver buf size */
void *bptr, /* record buf addr */
int ftvl, /* record field type */
int ndata, /* n to be transferred */
int *option, /* direction etc. */
CHINO_LOG *d,
int sid
)
{
int nwrite;
int n;
int resCRC;
LOGMSG("devChinoLog: chino_config_command(0x%08x,%d,0x%08x,%d,%d,%d,0x%08x)\n",
buf,*len,bptr,ftvl,ndata,*option,d,0,0);
n = ndata;
nwrite = isWrite(*option) ? (d->width)*n : 0;
if (*len < CHINO_CMND_LENGTH + nwrite)
{
errlogPrintf("devChinoLog: buffer is running short\n");
return ERROR;
}
buf[ 0] = d->slvA; /* slave address */
buf[ 1] = d->cmd; /* command */
buf[ 2] = d->start>>8; /* start address (H)*/
buf[ 3] = d->start; /* start address (L)*/
buf[ 4] = 0x00; /* number (H) */
buf[ 5] = 0x18; /* number (L) 0x0c */
resCRC = calCRC(buf,6);
buf[ 6] = resCRC>>8; /* crc (H) */
buf[ 7] = resCRC ; /* crc (L) */
/* errlogPrintf("devChinoLog: command = %x %x %x %x %x %x %x %x\n",buf[0],buf[1],buf[2],buf[3],buf[4],buf[5],buf[6],buf[7]); */
*len = CHINO_CMND_LENGTH;
/* if (isWrite(*option))
{
if (fromRecordVal(
&buf[CHINO_CMND_LENGTH],
d->width,
bptr,
d->noff,
ftvl,
n,
CHINO_NEEDS_SWAP
))
{
errlogPrintf("devChinoLog: illeagal command\n");
return ERROR;
}
}
*/
/*
nread = isRead(*option)? (d->width)*n:0;
return (CHINO_DATA_OFFSET + nread);
*/
return 0;
}
/*******************************************************************************
* Response parser for command/response I/O
*******************************************************************************/
LOCAL int TwoRawToVal(unsigned char bu[],int offset, float *res )
{
float f1;
if ((bu[offset+2] & 0x20) == 0x20){
f1 = bu[offset]*256 + bu[offset+1];
}
else if ((bu[offset] & 0x80) == 0x80){
f1 = (bu[offset]-255)*256 +(bu[offset+1]-255);
}
else{
f1 = bu[offset]*256+bu[offset+1];
}
switch (bu[offset+3] & 0x0f)
{
case 0:
*res = f1;
break;
case 1:
*res = f1*0.1;
break;
case 2:
*res = f1*0.01;
break;
case 3:
*res = f1*0.001;
break;
case 4:
*res = f1*0.0001;
break;
default:
return -1;
}
return (bu[offset+3] & 0xf0);
}
LOCAL long chino_parse_response(
uint8_t *buf, /* driver buf addr */
int *len, /* driver buf size */
void *bptr, /* record buf addr */
int ftvl, /* record field type */
int ndata, /* n to be transferred */
int *option, /* direction etc. */
CHINO_LOG *d,
int sid
)
{
int i;
int ret;
float temp[1000],*rawVal,*ptemp;
rawVal = bptr;
LOGMSG("devChinoLog: chino_parse_response(0x%08x,%d,0x%08x,%d,%d,%d,0x%08x)\n",
buf,len,bptr,ftvl,ndata,*option,d,0,0);
/* for (i=0;i<12;i++)
{
errlogPrintf("devChinoLog buffer %d = %x %x %x %x\n",i*4,buf[CHINO_DATA_OFFSET+i*4],buf[CHINO_DATA_OFFSET+i*4+1],buf[CHINO_DATA_OFFSET+i*4+2],buf[CHINO_DATA_OFFSET+i*4+3]);
} */
if (isRead(*option))
{
for (i=0;i<12;i++)
{
ret = TwoRawToVal(buf,CHINO_DATA_OFFSET+i*4,&temp[i]);
if (ret != 0){
errlogPrintf("devGhinoLog Emergency code for %d =%x\n",i,ret);
}
}
}
ndata = 12;
ptemp = temp;
i= 12;
while (i--)
{
*rawVal++ = (float) *ptemp ++;
}
ret = 0;
return ret;
}