unbundled
This commit is contained in:
@@ -1,803 +0,0 @@
|
||||
/* devBBInteract.c */
|
||||
/* share/src/devOpt $Id$
|
||||
*
|
||||
* Author: Ned D. Arnold
|
||||
* Date: 06/19/91
|
||||
*
|
||||
* Experimental Physics and Industrial Control System (EPICS)
|
||||
*
|
||||
* Copyright 1988, 1989, the Regents of the University of California,
|
||||
* and the University of Chicago Board of Governors.
|
||||
*
|
||||
* This software was produced under U.S. Government contracts:
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
|
||||
* and (W-31-109-ENG-38) at Argonne National Laboratory.
|
||||
*
|
||||
* Initial development by:
|
||||
* The Controls and Automation Group (AT-8)
|
||||
* Ground Test Accelerator
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Co-developed with
|
||||
* The Controls and Computing Group
|
||||
* Accelerator Systems Division
|
||||
* Advanced Photon Source
|
||||
* Argonne National Laboratory
|
||||
*
|
||||
* All rights reserved. No part of this publication may be reproduced,
|
||||
* stored in a retrieval system, transmitted, in any form or by any
|
||||
* means, electronic, mechanical, photocopying, recording, or otherwise
|
||||
* without prior written permission of Los Alamos National Laboratory
|
||||
* and Argonne National Laboratory.
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .01 06-19-91 nda initial coding & debugging
|
||||
* .02 09-23-91 jrw added proper multi-link support
|
||||
* .03 10-04-91 jrw rewrote as BI.c for use with BitBus
|
||||
* .04 02-12-92 jrw added HEX file downloading support
|
||||
*
|
||||
*/
|
||||
|
||||
#include <vxWorks.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <taskLib.h>
|
||||
|
||||
#include <alarm.h>
|
||||
#include <cvtTable.h>
|
||||
#include <dbDefs.h>
|
||||
#include <dbAccess.h>
|
||||
#include <devSup.h>
|
||||
#include <drvSup.h>
|
||||
#include <link.h>
|
||||
#include <module_types.h>
|
||||
#include <dbCommon.h>
|
||||
#include <fast_lock.h>
|
||||
|
||||
#include <drvBitBusInterface.h>
|
||||
|
||||
extern struct {
|
||||
long number;
|
||||
DRVSUPFUN report;
|
||||
DRVSUPFUN init;
|
||||
DRVSUPFUN qReq;
|
||||
} drvBitBus;
|
||||
|
||||
struct cmdPvt {
|
||||
int busy;
|
||||
long int count;
|
||||
};
|
||||
|
||||
#define LIST_SIZE 10
|
||||
|
||||
static struct dpvtBitBusHead adpvt[LIST_SIZE+1]; /* last one is used for the 'F' command */
|
||||
|
||||
/* declare other required variables used by more than one routine */
|
||||
|
||||
int bbMsgDly = 0;
|
||||
|
||||
extern int bbDebug;
|
||||
static int replyIsBack;
|
||||
|
||||
static int sendMsg();
|
||||
static int bbWork();
|
||||
static int configMsg();
|
||||
static int getInt();
|
||||
static int getChar();
|
||||
static int getString();
|
||||
static int showBbMsg();
|
||||
static int timingStudy();
|
||||
static int pingEm();
|
||||
static int downLoadCode();
|
||||
static int hex2bin();
|
||||
static int sendOnly(void);
|
||||
|
||||
static int firstTime = 1;
|
||||
static FAST_LOCK msgReply;
|
||||
|
||||
int
|
||||
BI()
|
||||
{
|
||||
unsigned char ans;
|
||||
int cnt;
|
||||
|
||||
if(firstTime)
|
||||
{
|
||||
firstTime = 0;
|
||||
FASTLOCKINIT(&msgReply);
|
||||
FASTUNLOCK(&msgReply);
|
||||
FASTLOCK(&msgReply); /* Make sure is locked at the begining */
|
||||
|
||||
for (cnt = 0; cnt <= LIST_SIZE; cnt++)
|
||||
{
|
||||
adpvt[cnt].finishProc = bbWork;
|
||||
adpvt[cnt].priority = 0;
|
||||
|
||||
adpvt[cnt].next = NULL;
|
||||
adpvt[cnt].prev = NULL;
|
||||
adpvt[cnt].txMsg.data = (unsigned char *)malloc(BB_MAX_DAT_LEN);
|
||||
adpvt[cnt].txMsg.length = 7;
|
||||
adpvt[cnt].txMsg.route = 0x40;
|
||||
adpvt[cnt].rxMsg.data = (unsigned char *)malloc(BB_MAX_DAT_LEN);
|
||||
adpvt[cnt].rxMsg.length = 7;
|
||||
adpvt[cnt].psyncSem = NULL;
|
||||
adpvt[cnt].rxMaxLen = BB_MAX_MSG_LENGTH;
|
||||
}
|
||||
}
|
||||
|
||||
ans = 0; /* set loop not to exit */
|
||||
printf("\n\n");
|
||||
|
||||
while ((ans != 'q') && (ans != 'Q'))
|
||||
{
|
||||
printf("\n\nInteractive BB Program\n");
|
||||
printf("Select a function:\n"); /* main menu */
|
||||
printf(" 'C' to configure send message content\n");
|
||||
printf(" 'D' to display transmit & receive messages\n");
|
||||
printf(" 'P' to ping all Bitbus device addresses\n");
|
||||
printf(" 'S' to send & receive a message one time\n");
|
||||
printf(" 'T' to do timing on messages\n");
|
||||
printf(" 'R' to turn on the BB debugging flag\n");
|
||||
printf(" 'r' to turn off the BB debugging flag\n");
|
||||
printf(" 'F' to download intel HEX file to a bug\n");
|
||||
printf(" 'Q' to quit program\n");
|
||||
printf(">");
|
||||
ans = 0; /* clear previous selection */
|
||||
getChar(&ans);
|
||||
|
||||
switch (ans) {
|
||||
case 'c': /* configure message contents */
|
||||
case 'C':
|
||||
configMsg();
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
case 'P': /* ping all the bug addresses */
|
||||
pingEm();
|
||||
break;
|
||||
|
||||
case 's':
|
||||
case 'S': /* one shot: send one message */
|
||||
sendMsg();
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
case 'U':
|
||||
sendOnly(); /* Send a pair of messages */
|
||||
break;
|
||||
|
||||
case 't':
|
||||
case 'T': /* Timing analysis */
|
||||
/*timingStudy();*/
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
case 'D': /* Display message contents */
|
||||
for (cnt = 1; cnt < LIST_SIZE; cnt++) /* for each message */
|
||||
{
|
||||
printf("message %d Transmit buffer:\n", cnt);
|
||||
showBbMsg(&(adpvt[cnt].txMsg));
|
||||
printf("message %d Receive buffer:\n", cnt);
|
||||
showBbMsg(&(adpvt[cnt].rxMsg));
|
||||
}
|
||||
break;
|
||||
|
||||
case 'q':
|
||||
case 'Q': /* quit */
|
||||
break;
|
||||
|
||||
case 'r': /* turn off bbDebug */
|
||||
bbDebug = 0;
|
||||
break;
|
||||
case 'R': /* turn on bbDebug */
|
||||
bbDebug = 1;
|
||||
break;
|
||||
case 'f':
|
||||
case 'F':
|
||||
downLoadCode();
|
||||
break;
|
||||
} /* end case */
|
||||
} /* end of while ans== q or Q */
|
||||
return(0);
|
||||
} /* end of main */
|
||||
|
||||
#ifdef DONT_DO_THIS
|
||||
static int
|
||||
timingStudy()
|
||||
{
|
||||
struct bbIntCmd *pCmd[LIST_SIZE];
|
||||
int inInt; /* input integer from operator */
|
||||
int reps; /* number of times to send a message */
|
||||
ULONG startTime;
|
||||
ULONG endTime;
|
||||
ULONG delta;
|
||||
int Reps;
|
||||
int i;
|
||||
int j;
|
||||
|
||||
for (i=0; i<LIST_SIZE; i++)
|
||||
{
|
||||
printf("\nEnter Message# to Send (1 thru 5, <cr> to terminate list) > ");
|
||||
if (getInt(&inInt))
|
||||
{
|
||||
if (inInt>0 && inInt<LIST_SIZE)
|
||||
{
|
||||
pCmd[i] = &bbIntCmds[inInt]; /* assign pointer to desired entry */
|
||||
pCmd[i]->busy = 0; /* mark message 'not in queue' */
|
||||
pCmd[i]->count = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
pCmd[i] = NULL; /* terminate the list */
|
||||
i = LIST_SIZE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pCmd[i] = NULL; /* terminate the list */
|
||||
i = LIST_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
printf("Enter the number of messages to send > ");
|
||||
if (!getInt(&inInt))
|
||||
return; /* if no entry, return to main menu */
|
||||
if(inInt < 0)
|
||||
return;
|
||||
reps = inInt;
|
||||
Reps = reps;
|
||||
|
||||
startTime = tickGet(); /* time the looping started */
|
||||
|
||||
while(reps)
|
||||
{
|
||||
for(i=0; i<LIST_SIZE && reps; i++)
|
||||
{
|
||||
if (pCmd[i] != NULL)
|
||||
{
|
||||
if (!pCmd[i]->busy)
|
||||
{
|
||||
pCmd[i]->count++;
|
||||
pCmd[i]->busy = 1; /* mark the xact as busy */
|
||||
(*(drvBitBus.qReq))(pCmd[i]->link, &(pCmd[i]), BB_Q_HIGH);
|
||||
reps--;
|
||||
if (reps%10000 == 0)
|
||||
{
|
||||
printf("Timing study in progress with %d messages left, current status:\n", reps);
|
||||
for (j=0; j<LIST_SIZE; j++)
|
||||
{
|
||||
if(pCmd[j] != NULL)
|
||||
{
|
||||
printf("Message %d transmissions: %ld\n", j, pCmd[j]->count);
|
||||
}
|
||||
else
|
||||
j = LIST_SIZE;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
i = LIST_SIZE; /* force an exit from the loop */
|
||||
}
|
||||
FASTLOCK(&msgReply);
|
||||
}
|
||||
|
||||
endTime = tickGet();
|
||||
delta = (endTime - startTime); /* measured time in ticks */
|
||||
if (delta == 0)
|
||||
delta = 1;
|
||||
printf("Total transmit and receiving time = %ld/60 Sec\n", delta);
|
||||
printf("Messages/second = %.2f\n", (float) (60*Reps)/(float)delta);
|
||||
|
||||
for (i=0; i<LIST_SIZE; i++)
|
||||
{
|
||||
if(pCmd[i] != NULL)
|
||||
{
|
||||
printf("Message %d transmissions: %ld\n", i, pCmd[i]->count);
|
||||
}
|
||||
else
|
||||
i = LIST_SIZE;
|
||||
}
|
||||
return(OK);
|
||||
}
|
||||
#endif
|
||||
static int
|
||||
sendOnly(void)
|
||||
{
|
||||
int msgNum; /* index to array of messages */
|
||||
|
||||
printf("\nEnter Message # to Send (1 thru 5) > ");
|
||||
if (!getInt(&msgNum))
|
||||
return(ERROR); /* if no entry, return to main menu */
|
||||
|
||||
if((msgNum >= LIST_SIZE) || (msgNum < 0))
|
||||
return(ERROR);
|
||||
|
||||
return((*(drvBitBus.qReq))(&(adpvt[msgNum]), BB_Q_HIGH));
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* sendMsg()
|
||||
*****************************************************************************/
|
||||
|
||||
static int
|
||||
sendMsg(void)
|
||||
{
|
||||
int msgNum; /* index to array of messages */
|
||||
|
||||
printf("\nEnter Message # to Send (1 thru 5) > ");
|
||||
if (!getInt(&msgNum))
|
||||
return(ERROR); /* if no entry, return to main menu */
|
||||
if((msgNum >= LIST_SIZE) || (msgNum < 0))
|
||||
return(ERROR);
|
||||
|
||||
adpvt[msgNum].ageLimit = 0; /* Don't really need to reset each time */
|
||||
if ((*(drvBitBus.qReq))(&(adpvt[msgNum]), BB_Q_HIGH) != ERROR)
|
||||
{
|
||||
FASTLOCK(&msgReply); /* wait for response to return */
|
||||
|
||||
taskDelay(bbMsgDly);
|
||||
|
||||
printf("response message:\n");
|
||||
showBbMsg(&(adpvt[msgNum].rxMsg));
|
||||
return(OK);
|
||||
}
|
||||
else
|
||||
return(ERROR);
|
||||
}
|
||||
|
||||
static int
|
||||
bbWork(pdpvt)
|
||||
struct dpvtBitBusHead *pdpvt;
|
||||
{
|
||||
if (bbDebug)
|
||||
printf("BI's bbWork():entered\n");
|
||||
|
||||
replyIsBack = TRUE;
|
||||
FASTUNLOCK(&msgReply);
|
||||
return(0);
|
||||
}
|
||||
static int
|
||||
pingEm()
|
||||
{
|
||||
struct dpvtBitBusHead pdpvt;
|
||||
char str[100];
|
||||
int inInt;
|
||||
|
||||
pdpvt.finishProc = bbWork;
|
||||
pdpvt.priority = 0;
|
||||
|
||||
pdpvt.next = NULL;
|
||||
pdpvt.prev = NULL;
|
||||
pdpvt.txMsg.data = (unsigned char *)malloc(BB_MAX_DAT_LEN);
|
||||
pdpvt.txMsg.length = 15;
|
||||
pdpvt.txMsg.route = 0x40;
|
||||
pdpvt.rxMsg.data = (unsigned char *)malloc(BB_MAX_DAT_LEN);
|
||||
pdpvt.rxMsg.length = 7;
|
||||
pdpvt.psyncSem = NULL;
|
||||
pdpvt.rxMaxLen = BB_MAX_MSG_LENGTH;
|
||||
|
||||
/* build a "send ID's" message */
|
||||
|
||||
printf("Enter BB Link (hex) [00]: ");
|
||||
gets(str);
|
||||
if (sscanf(str, "%x", &inInt) == 1)
|
||||
pdpvt.link = inInt;
|
||||
else
|
||||
pdpvt.link = 0;
|
||||
|
||||
pdpvt.txMsg.tasks = 0;
|
||||
pdpvt.txMsg.cmd = 3;
|
||||
pdpvt.txMsg.node = 0;
|
||||
|
||||
while (pdpvt.txMsg.node < 255)
|
||||
{
|
||||
pdpvt.ageLimit = 0;
|
||||
if ((*(drvBitBus.qReq))(&(pdpvt), BB_Q_HIGH) == ERROR)
|
||||
return(ERROR);
|
||||
|
||||
FASTLOCK(&msgReply); /* wait for response to return */
|
||||
if (pdpvt.rxMsg.cmd == 0)
|
||||
{
|
||||
printf("response message:\n");
|
||||
showBbMsg(&(pdpvt.rxMsg));
|
||||
}
|
||||
pdpvt.txMsg.node++;
|
||||
}
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------
|
||||
* configMsg()
|
||||
*
|
||||
* - Purpose
|
||||
* Prompts the operator for the contents of a BB message
|
||||
* Displays current value of the field as the default entry
|
||||
*
|
||||
*/
|
||||
|
||||
static int
|
||||
configMsg()
|
||||
{
|
||||
int msgNum; /* index to array of messages */
|
||||
int inInt;
|
||||
int cnt;
|
||||
char str[100];
|
||||
|
||||
printf("\nEnter Message # to Configure (1 thru 5) > ");
|
||||
if (!getInt(&inInt))
|
||||
return(0); /* if no entry, return to main menu */
|
||||
if((inInt >= LIST_SIZE) || (inInt < 0))
|
||||
return(0);
|
||||
|
||||
msgNum = inInt;
|
||||
|
||||
printf("\n\n Configuring Send Message # %d at %p \n", msgNum, &(adpvt[msgNum].txMsg));
|
||||
|
||||
/* Prompt the Operator with the current value of each parameter If
|
||||
* only a <CR> is typed, keep current value, else replace value with
|
||||
* entered value
|
||||
*/
|
||||
|
||||
adpvt[msgNum].txMsg.link = 0;
|
||||
|
||||
printf("Enter BB Link (hex) [%2.2X]: ", (int) adpvt[msgNum].link);
|
||||
gets(str);
|
||||
if (sscanf(str, "%x", &inInt) == 1)
|
||||
adpvt[msgNum].link = inInt;
|
||||
|
||||
printf("Enter route (hex) [%2.2X]: ", adpvt[msgNum].txMsg.route);
|
||||
gets(str);
|
||||
if (sscanf(str, "%x", &inInt) == 1)
|
||||
adpvt[msgNum].txMsg.route = inInt;
|
||||
|
||||
printf("Enter Node (hex) [%2.2X]: ", adpvt[msgNum].txMsg.node);
|
||||
gets(str);
|
||||
if (sscanf(str, "%x", &inInt) == 1)
|
||||
adpvt[msgNum].txMsg.node = inInt;
|
||||
|
||||
printf("Enter tasks (hex) [%2.2X]: ", adpvt[msgNum].txMsg.tasks);
|
||||
gets(str);
|
||||
if (sscanf(str, "%x", &inInt) == 1)
|
||||
adpvt[msgNum].txMsg.tasks = inInt;
|
||||
|
||||
printf("Enter command (hex) [%2.2X]: ", adpvt[msgNum].txMsg.cmd);
|
||||
gets(str);
|
||||
if (sscanf(str, "%x", &inInt) == 1)
|
||||
adpvt[msgNum].txMsg.cmd = inInt;
|
||||
|
||||
adpvt[msgNum].txMsg.length = 7;
|
||||
printf("Enter data 1 byte per line. Enter a dot to terminate list (hex)\n");
|
||||
for (cnt=0; cnt<BB_MAX_DAT_LEN; cnt++)
|
||||
{
|
||||
printf("[%2.2X]: ", adpvt[msgNum].txMsg.data[cnt]);
|
||||
gets(str);
|
||||
if (str[0] == '.')
|
||||
break;
|
||||
if (sscanf(str, "%x", &inInt) == 1)
|
||||
adpvt[msgNum].txMsg.data[cnt] = inInt;
|
||||
adpvt[msgNum].txMsg.length++;
|
||||
}
|
||||
printf("Transmit message #%d for BitBus link %d:\n", msgNum, adpvt[msgNum].link);
|
||||
showBbMsg(&(adpvt[msgNum].txMsg));
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* downLoadCode()
|
||||
*
|
||||
* This lets a user download an Intel HEX file to a bitbus node.
|
||||
*
|
||||
* The format of a hex record is:
|
||||
* :nnoooottb0b1b2b3b4b5b6b7b8b9b0babbbcbdbebfss\n
|
||||
*
|
||||
* where:
|
||||
* nn = number of data bytes on the line
|
||||
* oooo = offset address where the data is supposed to reside when loaded
|
||||
* tt = record type 00 = data, 01 = end, 02 = segment record, 03 = program entry record
|
||||
* b0-bf= hex data bytes
|
||||
* ss = checksum of the record
|
||||
*
|
||||
* This loader only recognises data records and end records, any others are
|
||||
* treated as errors.
|
||||
*/
|
||||
|
||||
static int
|
||||
downLoadCode()
|
||||
{
|
||||
static char fnameStr[200] = ""; /* File name for F command */
|
||||
char str[200];
|
||||
char hexBuf[100]; /* place to read intel HEX file lines */
|
||||
FILE *fp;
|
||||
unsigned int msgBytes; /* current number of bytes in the message being built */
|
||||
unsigned char hexTotal; /* number of data bytes in the current HEX file line */
|
||||
unsigned char hexBytes; /* number of data bytes converted in HEX file line */
|
||||
unsigned char recType; /* type of record being processed */
|
||||
|
||||
unsigned int totalBytes; /* total bytes sent to bug memory */
|
||||
unsigned int totalMsg; /* total messages sent to the bug */
|
||||
int status;
|
||||
int inInt;
|
||||
struct dpvtBitBusHead *pdpvt = &(adpvt[LIST_SIZE]);
|
||||
int oldDebug;
|
||||
|
||||
oldDebug = bbDebug;
|
||||
bbDebug = 0;
|
||||
|
||||
|
||||
/* open the hex file */
|
||||
printf("Enter (Intel-standard) HEX file name\n[%s]\n:", fnameStr);
|
||||
gets(str);
|
||||
sscanf("%s", str);
|
||||
if (str[0] != '\0')
|
||||
strcpy (fnameStr, str);
|
||||
|
||||
if ((fp = fopen(fnameStr, "r")) == NULL)
|
||||
{
|
||||
printf("Error: Can't open file >%s<\n", fnameStr);
|
||||
return(ERROR);
|
||||
}
|
||||
/* get the link number */
|
||||
printf("Enter BB Link (hex) [%2.2X]: ", (int) pdpvt->link);
|
||||
gets(str);
|
||||
if (sscanf(str, "%x", &inInt) == 1)
|
||||
pdpvt->link = inInt;
|
||||
|
||||
/* get the bug number */
|
||||
printf("Enter Node (hex) [%2.2X]: ", pdpvt->txMsg.node);
|
||||
gets(str);
|
||||
if (sscanf(str, "%x", &inInt) == 1)
|
||||
pdpvt->txMsg.node = inInt;
|
||||
|
||||
pdpvt->txMsg.cmd = RAC_DOWNLOAD_MEM;
|
||||
pdpvt->txMsg.tasks = BB_RAC_TASK;
|
||||
|
||||
totalBytes = 0;
|
||||
totalMsg = 0;
|
||||
status = OK;
|
||||
|
||||
FASTUNLOCK(&msgReply); /* prime for first loop */
|
||||
FASTLOCK(&msgReply);
|
||||
|
||||
/* read the file 1 line at a time & send the code to the bug */
|
||||
msgBytes=0;
|
||||
while (fgets(hexBuf, sizeof(hexBuf), fp) != NULL)
|
||||
{
|
||||
/* parse the headers in the hex record */
|
||||
if (hexBuf[0] != ':' || (hex2bin(&(hexBuf[7]) ,&recType) == ERROR))
|
||||
{
|
||||
printf("Bad line in HEX file. Line:\n%s", hexBuf);
|
||||
status = ERROR;
|
||||
break;
|
||||
}
|
||||
if (recType == 1) /* EOF record located */
|
||||
break;
|
||||
|
||||
if (recType != 0) /* unrecognised record type encountered */
|
||||
{
|
||||
printf("Unrecognised record type 0x%2.2X in HEX file. Line:\n%s", recType, hexBuf);
|
||||
status = ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
/* find the starting address */
|
||||
if ((hex2bin(&(hexBuf[3]), &(pdpvt->txMsg.data[0])) == ERROR) ||
|
||||
(hex2bin(&(hexBuf[5]), &(pdpvt->txMsg.data[1])) == ERROR))
|
||||
{
|
||||
printf("Invalid characters in HEX record offset field. Line:\n%s", hexBuf);
|
||||
status = ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
/* find the number of bytes in the hex record */
|
||||
if (hex2bin(&(hexBuf[1]), &hexTotal) == ERROR)
|
||||
{
|
||||
printf("Invalid characters in HEX record count field. Line:\n%s", hexBuf);
|
||||
status = ERROR;
|
||||
break;
|
||||
}
|
||||
hexTotal += hexTotal; /* double since is printable format */
|
||||
hexBytes = 0;
|
||||
msgBytes = 2; /* skip over the address field of the bitbus message */
|
||||
|
||||
while ((hexBytes < hexTotal) && (status == OK))
|
||||
{
|
||||
while ((msgBytes < 13) && (hexBytes < hexTotal))
|
||||
{ /* convert up to 1 message worth of data (or hit EOL) */
|
||||
hex2bin(&(hexBuf[hexBytes+9]), &(pdpvt->txMsg.data[msgBytes]));
|
||||
msgBytes++;
|
||||
hexBytes+=2;
|
||||
}
|
||||
if (msgBytes > 2)
|
||||
{ /* send the bitbus RAC command message */
|
||||
|
||||
/* length = hexBytes + header size of the bitbus message */
|
||||
pdpvt->txMsg.length = msgBytes+7;
|
||||
|
||||
pdpvt->ageLimit = 0; /* need to reset each time */
|
||||
|
||||
if ((*(drvBitBus.qReq))(pdpvt, BB_Q_LOW) != ERROR)
|
||||
{
|
||||
FASTLOCK(&msgReply); /* wait for last message to finish */
|
||||
|
||||
*((unsigned short int *)(pdpvt->txMsg.data)) += msgBytes-2; /* ready for next message */
|
||||
|
||||
totalBytes += msgBytes-2;
|
||||
totalMsg++;
|
||||
msgBytes=2;
|
||||
|
||||
if (pdpvt->rxMsg.cmd != 0)
|
||||
{
|
||||
printf("Bad message response status 0x%2.2X\n", pdpvt->rxMsg.cmd);
|
||||
status = ERROR;
|
||||
}
|
||||
}
|
||||
else
|
||||
status = ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* close the hex file */
|
||||
fclose(fp);
|
||||
|
||||
printf("Total bytes down loaded to BUG = %u = 0x%4.4X\n", totalBytes, totalBytes);
|
||||
printf("Total messages sent = %u = 0x%4.4X\n", totalMsg, totalMsg);
|
||||
|
||||
bbDebug = oldDebug;
|
||||
return(status);
|
||||
}
|
||||
/*
|
||||
* This function translates a printable ascii string containing hex
|
||||
* digits into a binary value.
|
||||
*/
|
||||
static int
|
||||
hex2bin(pstr, pchar)
|
||||
char *pstr; /* string containing the ascii bytes */
|
||||
unsigned char *pchar; /* where to return the binary value */
|
||||
{
|
||||
int ctr;
|
||||
|
||||
ctr = 0;
|
||||
*pchar = 0;
|
||||
while(ctr < 2)
|
||||
{
|
||||
*pchar = (*pchar) << 4;
|
||||
|
||||
if ((pstr[ctr] >= '0') && (pstr[ctr] <= '9'))
|
||||
(*pchar) += (pstr[ctr] & 0x0f); /* is 0-9 value */
|
||||
else if ((pstr[ctr] >= 'A') && (pstr[ctr] <= 'F'))
|
||||
(*pchar) += (pstr[ctr] - 'A' + 0x0a); /* is A-f value */
|
||||
else if ((pstr[ctr] >= 'a') && (pstr[ctr] <= 'f'))
|
||||
(*pchar) += (pstr[ctr] - 'a' + 0x0a); /* is a-f value */
|
||||
else
|
||||
return (ERROR); /* invalid character found in input string */
|
||||
ctr++;
|
||||
}
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
/*
|
||||
* getInt(pInt) ****************************************************
|
||||
*
|
||||
* gets a line of input from STDIN (10 characters MAX !!!!) scans the line
|
||||
* for an integer.
|
||||
*
|
||||
* Parm1 : pointer to an integer
|
||||
*
|
||||
* Returns (0) if a <CR> was hit, *pInt left unchanged. Returns (1) if a new
|
||||
* value was written to *pvalue. Returns (2) if a entry was not a valid
|
||||
* integer entry
|
||||
*
|
||||
*/
|
||||
|
||||
static int
|
||||
getInt(pInt)
|
||||
int *pInt;
|
||||
{
|
||||
char input[10];
|
||||
int inval;
|
||||
|
||||
gets(input);
|
||||
|
||||
if (input[0] == 0) /* if only a <CR> */
|
||||
return (0);
|
||||
else
|
||||
{
|
||||
if (sscanf(input, "%d", &inval) == 1)
|
||||
{ /* if a valid entry ... */
|
||||
*pInt = inval;
|
||||
return (1);
|
||||
}
|
||||
else /* if not a valid entry, return 2 */
|
||||
return (2);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* int getChar(pChar) **************************************************
|
||||
*
|
||||
* gets a line of input from STDIN (10 characters MAX !!!!) scans the line
|
||||
* for a character entry
|
||||
*
|
||||
* Parm1 : pointer to an unsigned character variable
|
||||
*
|
||||
* Returns(0) if a <CR> was hit, *pChar left unchanged. Returns(1) if a new
|
||||
* value was written to *pChar
|
||||
*
|
||||
*/
|
||||
|
||||
static int
|
||||
getChar(pChar)
|
||||
unsigned char *pChar;
|
||||
{
|
||||
char input[10];
|
||||
unsigned char inval;
|
||||
|
||||
gets(input);
|
||||
|
||||
if (input[0] == 0)
|
||||
return (0);
|
||||
else
|
||||
{
|
||||
sscanf(input, "%c", &inval);
|
||||
*pChar = inval;
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* int getString(pString) ****************************************************
|
||||
*
|
||||
* gets a line of input from STDIN (100 characters MAX !!!!) .
|
||||
* If length is greater than 0, copies string into pString
|
||||
*
|
||||
* Parm1 : pointer to an character string
|
||||
*
|
||||
* Returns : 0 if a <CR> was hit, *pvalue left unchanged Returns : 1 if a
|
||||
* new value was written to *pvalue
|
||||
*
|
||||
*/
|
||||
|
||||
static int
|
||||
getString(pString)
|
||||
char *pString;
|
||||
{
|
||||
char input[100];
|
||||
|
||||
gets(input);
|
||||
|
||||
if (input[0] == 0)
|
||||
return (0);
|
||||
else
|
||||
{
|
||||
strcpy(pString, input);
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Print the bb message contents onto the screen.
|
||||
* msgNum selects the message to be displayed
|
||||
*/
|
||||
|
||||
static int
|
||||
showBbMsg(msg)
|
||||
struct bitBusMsg *msg;
|
||||
{
|
||||
int i;
|
||||
|
||||
printf(" %p:link=%4.4X length=%2.2X route=%2.2X node=%2.2X tasks=%2.2X cmd=%2.2X\n",
|
||||
msg, msg->link, msg->length, msg->route, msg->node, msg->tasks, msg->cmd);
|
||||
printf(" data :");
|
||||
for (i = 0; i < msg->length - 7; i++)
|
||||
{
|
||||
printf(" %2.2X", msg->data[i]);
|
||||
}
|
||||
putchar('\n');
|
||||
return(0);
|
||||
}
|
||||
@@ -5,7 +5,6 @@
|
||||
TOP = ../../../..
|
||||
include $(TOP)/config/CONFIG_BASE
|
||||
|
||||
INC += drvAb.h
|
||||
INC += drvAt5Vxi.h
|
||||
INC += drvEpvxi.h
|
||||
INC += drvHp1404a.h
|
||||
@@ -15,7 +14,6 @@ INC += drvMz8310.h
|
||||
INC += drvStc.h
|
||||
INC += epvxi.h
|
||||
|
||||
SRCS.c += ../drvAb.c
|
||||
SRCS.c += ../drvAt5Vxi.c
|
||||
SRCS.c += ../drvEpvxi.c
|
||||
SRCS.c += ../drvEpvxiMsg.c
|
||||
|
||||
1891
src/drv/ansi/drvAb.c
1891
src/drv/ansi/drvAb.c
File diff suppressed because it is too large
Load Diff
@@ -1,93 +0,0 @@
|
||||
/* drvAb.h */
|
||||
/* header file for the Allen-Bradley Remote Serial IO
|
||||
* This defines interface between driver and device support
|
||||
*
|
||||
* Author: Marty Kraimer
|
||||
* Date: 03-06-95
|
||||
*
|
||||
* Experimental Physics and Industrial Control System (EPICS)
|
||||
*
|
||||
* Copyright 1991, the Regents of the University of California,
|
||||
* and the University of Chicago Board of Governors.
|
||||
*
|
||||
* This software was produced under U.S. Government contracts:
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
|
||||
* and (W-31-109-ENG-38) at Argonne National Laboratory.
|
||||
*
|
||||
* Initial development by:
|
||||
* The Controls and Automation Group (AT-8)
|
||||
* Ground Test Accelerator
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Co-developed with
|
||||
* The Controls and Computing Group
|
||||
* Accelerator Systems Division
|
||||
* Advanced Photon Source
|
||||
* Argonne National Laboratory
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* 01 03-06-95 mrk Moved all driver specific code to drvAb.c
|
||||
*/
|
||||
|
||||
#ifndef INCdrvAbh
|
||||
#define INCdrvAbh 1
|
||||
#include "dbScan.h"
|
||||
|
||||
|
||||
/* interface types */
|
||||
typedef enum {typeNotAssigned,typeBi,typeBo,typeBiBo,typeAi,typeAo,typeBt}
|
||||
cardType;
|
||||
/* status values*/
|
||||
typedef enum{abSuccess,abNewCard,abCardConflict,abNoCard,abNotInitialized,
|
||||
abBtqueued,abBusy,abTimeout,abAdapterDown,abFailure} abStatus;
|
||||
extern char **abStatusMessage;
|
||||
|
||||
typedef enum{abBitNotdefined,abBit8,abBit16,abBit32} abNumBits;
|
||||
extern char **abNumBitsMessage;
|
||||
|
||||
/*entry table for dev to drv routines*/
|
||||
typedef struct {
|
||||
abStatus (*registerCard)
|
||||
(unsigned short link,unsigned short adapter, unsigned short card,
|
||||
cardType type, const char *card_name,
|
||||
void (*callback)(void *drvPvt),
|
||||
void **drvPvt);
|
||||
void (*getLocation)
|
||||
(void *drvPvt,
|
||||
unsigned short *link, unsigned short *adapter,unsigned short *card);
|
||||
abStatus (*setNbits)(void *drvPvt, abNumBits nbits);
|
||||
void (*setUserPvt)(void *drvPvt, void *userPvt);
|
||||
void *(*getUserPvt)(void *drvPvt);
|
||||
abStatus (*getStatus)(void *drvPvt);
|
||||
abStatus(*startScan)
|
||||
(void *drvPvt, unsigned short update_rate,
|
||||
unsigned short *pwrite_msg, unsigned short write_msg_len,
|
||||
unsigned short *pread_msg, unsigned short read_msg_len);
|
||||
abStatus(*updateAo)(void *drvPvt);
|
||||
abStatus(*updateBo) (void *drvPvt,unsigned long value,unsigned long mask);
|
||||
abStatus(*readBo) (void *drvPvt,unsigned long *value,unsigned long mask);
|
||||
abStatus(*readBi) (void *drvPvt,unsigned long *value,unsigned long mask);
|
||||
abStatus(*btRead)(void *drvPvt,unsigned short *pread_msg,
|
||||
unsigned short read_msg_len);
|
||||
abStatus(*btWrite)(void *drvPvt,unsigned short *pwrite_msg,
|
||||
unsigned short write_msg_len);
|
||||
abStatus (*adapterStatus)
|
||||
(unsigned short link,unsigned short adapter);
|
||||
abStatus (*cardStatus)
|
||||
(unsigned short link,unsigned short adapter, unsigned short card);
|
||||
}abDrv;
|
||||
|
||||
extern abDrv *pabDrv;
|
||||
|
||||
int ab_reset(void);
|
||||
int ab_reset_link(int link);
|
||||
int abConfigNlinks(int nlinks);
|
||||
int abConfigVme(int link, int base, int vector, int level);
|
||||
int abConfigBaud(int link, int baud);
|
||||
int abConfigScanList(int link, int scan_list_len, char *scan_list);
|
||||
int abConfigScanListAscii(int link, char *filename,int setRackSize);
|
||||
int abConfigAuto(int link);
|
||||
|
||||
#endif /*INCdrvAbh*/
|
||||
@@ -1,590 +0,0 @@
|
||||
/* base/src/drv $Id$ */
|
||||
/*
|
||||
* Author: John Winans
|
||||
* Date: 05-21-92
|
||||
* EPICS BITBUS -> R/S-232 driver
|
||||
*
|
||||
* Experimental Physics and Industrial Control System (EPICS)
|
||||
*
|
||||
* Copyright 1991, the Regents of the University of California,
|
||||
* and the University of Chicago Board of Governors.
|
||||
*
|
||||
* This software was produced under U.S. Government contracts:
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
|
||||
* and (W-31-109-ENG-38) at Argonne National Laboratory.
|
||||
*
|
||||
* Initial development by:
|
||||
* The Controls and Automation Group (AT-8)
|
||||
* Ground Test Accelerator
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Co-developed with
|
||||
* The Controls and Computing Group
|
||||
* Accelerator Systems Division
|
||||
* Advanced Photon Source
|
||||
* Argonne National Laboratory
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .01 09-30-91 jrw created
|
||||
*
|
||||
*/
|
||||
|
||||
#define DRVBB232_C
|
||||
|
||||
#include <vxWorks.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
#include <dbDefs.h>
|
||||
#include <epicsPrint.h>
|
||||
#include <task_params.h>
|
||||
#include <module_types.h>
|
||||
#include <drvSup.h>
|
||||
#include <devSup.h>
|
||||
#include <dbCommon.h>
|
||||
#include <dbAccess.h>
|
||||
#include <link.h>
|
||||
#include <callback.h>
|
||||
#include <fast_lock.h>
|
||||
|
||||
#include <drvMsg.h>
|
||||
#include <drvBitBusInterface.h>
|
||||
#include <drvRs232.h>
|
||||
#include <drvBB232.h>
|
||||
|
||||
int drvBB232Debug = 0;
|
||||
int softBB232 = 0;
|
||||
|
||||
extern struct drvBitBusEt drvBitBus;
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
******************************************************************************/
|
||||
#define BB232LINK_PRI 50
|
||||
#define BB232LINK_OPT VX_FP_TASK|VX_STDIO
|
||||
#define BB232LINK_STACK 5000
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
******************************************************************************/
|
||||
static long
|
||||
report()
|
||||
{
|
||||
printf("Report for BITBUS -> RS-232 driver\n");
|
||||
return(OK);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
******************************************************************************/
|
||||
static long
|
||||
init(pparms)
|
||||
msgDrvIniParm *pparms;
|
||||
{
|
||||
if (drvBB232Debug)
|
||||
printf("Init for BITBUS -> RS-232 driver\n");
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* This function is called to allocate any structures needed to hold
|
||||
* device-specific data that is added to the msgXact structure.
|
||||
*
|
||||
* It is also responsible for filling in the msgXact.phwpvt pointer.
|
||||
*
|
||||
******************************************************************************/
|
||||
static long
|
||||
genXact(p)
|
||||
msgDrvGenXParm *p;
|
||||
{
|
||||
long stat = -1;
|
||||
char message[100];
|
||||
drvBB232Link *pdrvBB232Link;
|
||||
struct dpvtBitBusHead *pdpvtBitBusHead;
|
||||
|
||||
if (p->plink->type != BITBUS_IO)
|
||||
{
|
||||
p->pmsgXact->prec->pact = TRUE;
|
||||
sprintf("%s: invalid device type in devSup.ascii (%d)\n", p->pmsgXact->prec->name, p->plink->type);
|
||||
errMessage(S_db_badField, message);
|
||||
return(ERROR);
|
||||
}
|
||||
|
||||
if (drvBB232Debug)
|
||||
printf("BB232 genXact entered for link %d, bug %d, port %d, parm %s\n", p->plink->value.bitbusio.link, p->plink->value.bitbusio.node, p->plink->value.bitbusio.port, p->plink->value.bitbusio.parm);
|
||||
|
||||
p->pmsgXact->phwpvt = p->pmsgXact->pparmBlock->pmsgHwpvt;
|
||||
|
||||
/* try to find the hwpvt structure for the required link, bug, and port */
|
||||
while ((p->pmsgXact->phwpvt != NULL) && (stat == -1))
|
||||
{
|
||||
pdrvBB232Link = (drvBB232Link *)(p->pmsgXact->phwpvt->pmsgLink->p);
|
||||
|
||||
if ((pdrvBB232Link->link == p->plink->value.bitbusio.link)
|
||||
&& (pdrvBB232Link->node == p->plink->value.bitbusio.node)
|
||||
&& (pdrvBB232Link->port == p->plink->value.bitbusio.port))
|
||||
{
|
||||
if (pdrvBB232Link->pparmBlock != p->pmsgXact->pparmBlock)
|
||||
{
|
||||
sprintf(message, "%s: Two different devices on same BB232 port\n", p->pmsgXact->prec->name);
|
||||
errMessage(S_db_badField, message);
|
||||
return(ERROR);
|
||||
}
|
||||
else
|
||||
stat = 0; /* Found the correct hwpvt structure */
|
||||
}
|
||||
else
|
||||
p->pmsgXact->phwpvt = p->pmsgXact->phwpvt->next;
|
||||
}
|
||||
if (stat != 0)
|
||||
{ /* Could not find a msgHwpvt for the right link, create a new one */
|
||||
if ((p->pmsgXact->phwpvt = drvMsg_genHwpvt(p->pmsgXact->pparmBlock, p->plink)) == NULL)
|
||||
return(ERROR);
|
||||
}
|
||||
/* Set again in case hwpvt was just allocated (and to make compiler happy) */
|
||||
pdrvBB232Link = (drvBB232Link *)(p->pmsgXact->phwpvt->pmsgLink->p);
|
||||
|
||||
p->pmsgXact->callback.callback = NULL;
|
||||
p->pmsgXact->psyncSem = NULL;
|
||||
|
||||
/* Create the skeleton bitbus driver message */
|
||||
pdpvtBitBusHead = (struct dpvtBitBusHead *) malloc(sizeof(struct dpvtBitBusHead));
|
||||
(struct dpvtBitBusHead *)(p->pmsgXact->p) = pdpvtBitBusHead;
|
||||
|
||||
pdpvtBitBusHead->finishProc = NULL;
|
||||
pdpvtBitBusHead->psyncSem = malloc(sizeof(SEM_ID));
|
||||
*(pdpvtBitBusHead->psyncSem) = semBCreate(SEM_Q_PRIORITY, SEM_EMPTY);
|
||||
pdpvtBitBusHead->link = pdrvBB232Link->link;
|
||||
|
||||
pdpvtBitBusHead->txMsg.route = BB_STANDARD_TX_ROUTE;
|
||||
pdpvtBitBusHead->txMsg.node = pdrvBB232Link->node;
|
||||
pdpvtBitBusHead->txMsg.tasks = BB_232_TASK;
|
||||
pdpvtBitBusHead->txMsg.cmd = 0xff;
|
||||
|
||||
pdpvtBitBusHead->rxMsg.data = (unsigned char *) malloc(BB_MAX_DAT_LEN);
|
||||
|
||||
/* in case I read before write */
|
||||
pdpvtBitBusHead->rxMsg.cmd = 0;
|
||||
pdpvtBitBusHead->rxMsg.length = BB_MSG_HEADER_SIZE;
|
||||
pdpvtBitBusHead->status = BB_OK;
|
||||
|
||||
pdpvtBitBusHead->rxMaxLen = 0;
|
||||
pdpvtBitBusHead->ageLimit = 0;
|
||||
|
||||
if (sscanf(p->plink->value.bitbusio.parm,"%d", &(p->pmsgXact->parm)) != 1)
|
||||
{
|
||||
p->pmsgXact->prec->pact = TRUE;
|
||||
sprintf("%s: invalid parameter string >%s<\n", p->pmsgXact->prec->name, p->plink->value.bitbusio.parm);
|
||||
errMessage(S_db_badField, message);
|
||||
return(ERROR);
|
||||
}
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* This function is called to allocate any structures needed to hold
|
||||
* device-specific data that is added to the msgHwpvt structure.
|
||||
*
|
||||
* It is also responsible for filling in the msgHwpvt.pmsgLink pointer.
|
||||
*
|
||||
******************************************************************************/
|
||||
static long
|
||||
genHwpvt(p)
|
||||
msgDrvGenHParm *p;
|
||||
{
|
||||
int stat = ERROR;
|
||||
|
||||
if (drvBB232Debug)
|
||||
printf("BB232 genHwpvt entered\n");
|
||||
|
||||
p->pmsgHwpvt->pmsgLink = drvBB232Block.pmsgLink;
|
||||
while ((p->pmsgHwpvt->pmsgLink != NULL) && (stat == ERROR))
|
||||
{
|
||||
if ((((drvBB232Link *)(p->pmsgHwpvt->pmsgLink->p))->link == p->plink->value.bitbusio.link)
|
||||
&& (((drvBB232Link *)(p->pmsgHwpvt->pmsgLink->p))->node == p->plink->value.bitbusio.node)
|
||||
&& (((drvBB232Link *)(p->pmsgHwpvt->pmsgLink->p))->port == p->plink->value.bitbusio.port))
|
||||
stat = OK;
|
||||
else
|
||||
p->pmsgHwpvt->pmsgLink = p->pmsgHwpvt->pmsgLink->next;
|
||||
}
|
||||
if (stat != OK)
|
||||
{
|
||||
if ((p->pmsgHwpvt->pmsgLink = drvMsg_genLink(p->pparmBlock, p->plink)) == NULL)
|
||||
return(ERROR);
|
||||
}
|
||||
return(OK);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* This function is called to allocate any structures needed to hold
|
||||
* device-specific data that is added to the msgLink structure.
|
||||
*
|
||||
******************************************************************************/
|
||||
static long
|
||||
genLink(p)
|
||||
msgDrvGenLParm *p;
|
||||
{
|
||||
char message[100];
|
||||
drvBB232Link *pdrvBB232Link;
|
||||
|
||||
if (drvBB232Debug)
|
||||
printf("BB232 genLink, link = %d, node = %d port = %d\n",
|
||||
p->plink->value.bitbusio.link, p->plink->value.bitbusio.node,
|
||||
p->plink->value.bitbusio.port);
|
||||
|
||||
switch (p->op) {
|
||||
case MSG_GENLINK_CREATE:
|
||||
|
||||
/* BUG -- verify that the link and node numbers are within range! */
|
||||
|
||||
if (p->plink->value.bitbusio.port & (~DD_232_PORT))
|
||||
{
|
||||
sprintf(message, "drvBB232: port number %d out of range\n", p->plink->value.bitbusio.port);
|
||||
errMessage(S_db_badField, message);
|
||||
return(ERROR);
|
||||
}
|
||||
|
||||
if ((p->pmsgLink->p = malloc(sizeof(drvBB232Link))) == NULL)
|
||||
return(ERROR);
|
||||
|
||||
pdrvBB232Link = (drvBB232Link *)(p->pmsgLink->p);
|
||||
|
||||
pdrvBB232Link->link = p->plink->value.bitbusio.link;
|
||||
pdrvBB232Link->node = p->plink->value.bitbusio.node;
|
||||
pdrvBB232Link->port = p->plink->value.bitbusio.port;
|
||||
pdrvBB232Link->pparmBlock = p->pparmBlock;
|
||||
|
||||
|
||||
return(OK);
|
||||
|
||||
case MSG_GENLINK_ABORT:
|
||||
|
||||
if (drvBB232Debug)
|
||||
printf("BB232 genLink: called with abort status\n");
|
||||
|
||||
pdrvBB232Link = (drvBB232Link *)(p->pmsgLink->p);
|
||||
/* BUG - free(p->pmsgLink->p); Don't forget to take it out of the list */
|
||||
return(OK);
|
||||
}
|
||||
return(ERROR);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* This function is called to allow the device to indicate that a device-related
|
||||
* event has occurred. If an event had occurred, it would have to place the
|
||||
* address of a valid transaction structure in pxact. This xact structure
|
||||
* will then be processed by the message link task as indicated by the
|
||||
* return code of this function.
|
||||
*
|
||||
* MSG_EVENT_NONE = no event has occurred, pxact not filled in.
|
||||
* MSG_EVENT_WRITE = event occurred, process the writeOp assoc'd w/pxact.
|
||||
* MSG_EVENT_READ = event occurred, process the readOp assoc'd w/pxact.
|
||||
*
|
||||
* Note that MSG_EVENT_READ only makes sense when returned with a transaction
|
||||
* that has deferred readback specified for its readOp function. Because if
|
||||
* it is NOT a deferred readback, it will be done immediately after the writeOp.
|
||||
* Even if that writeOp was due to a MSG_EVENT_WRITE from this function.
|
||||
*
|
||||
******************************************************************************/
|
||||
static long
|
||||
checkEvent(p)
|
||||
msgChkEParm *p;
|
||||
{
|
||||
return(MSG_EVENT_NONE);
|
||||
}
|
||||
/******************************************************************************
|
||||
*
|
||||
* This IOCTL function is used to handle non-I/O related operations required
|
||||
* to operate the RS-232 interface.
|
||||
*
|
||||
******************************************************************************/
|
||||
static long
|
||||
command(p)
|
||||
ioctlCommand *p;
|
||||
{
|
||||
msgXact *pxact;
|
||||
struct dpvtBitBusHead *pdpvtBitBusHead;
|
||||
drvBB232Link *pdrvBB232Link;
|
||||
|
||||
switch (p->cmd) {
|
||||
case IOCTL232_BREAK: /* send a BREAK signal to the serial port. */
|
||||
/* Build a break message to send */
|
||||
pxact = (msgXact *) (p->pparm);
|
||||
pdpvtBitBusHead = (struct dpvtBitBusHead *) pxact->p;
|
||||
pdrvBB232Link = (drvBB232Link *)(pxact->phwpvt->pmsgLink->p);
|
||||
pdpvtBitBusHead->status = BB_OK;
|
||||
pdpvtBitBusHead->rxMaxLen = 0;
|
||||
pdpvtBitBusHead->txMsg.length = BB_MSG_HEADER_SIZE;
|
||||
pdpvtBitBusHead->txMsg.cmd = BB_232_BREAK + pdrvBB232Link->port;
|
||||
pdpvtBitBusHead->rxMsg.cmd = 0;
|
||||
|
||||
if (drvBB232Debug > 7)
|
||||
{
|
||||
printf("drvBB232.control (tx L%d N%d P%d)\n", pdrvBB232Link->link, pdrvBB232Link->node, pdrvBB232Link->port);
|
||||
drvBitBusDumpMsg(&(pdpvtBitBusHead->txMsg));
|
||||
}
|
||||
|
||||
(*(drvBitBus.qReq))(pdpvtBitBusHead, BB_Q_LOW);
|
||||
semTake(*(pdpvtBitBusHead->psyncSem), WAIT_FOREVER);
|
||||
|
||||
if ((pdpvtBitBusHead->status == BB_OK) && !(pdpvtBitBusHead->rxMsg.cmd & 1))
|
||||
return(OK);
|
||||
else
|
||||
return(ERROR);
|
||||
}
|
||||
|
||||
if (drvBB232Debug)
|
||||
printf("drvBB232.control: bad command 0x%2.2X\n", p->cmd);
|
||||
return(ERROR);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* This function is used to write a string of characters out to an RS-232
|
||||
* device.
|
||||
*
|
||||
* Note that the BUGs reply to the write messages with the first 13 bytes
|
||||
* of the machine's response string (if there is one.) This response string
|
||||
* will be left in the pdpvtBitBusHead->rxMsg buffer when the drvRead()
|
||||
* function is called later.
|
||||
*
|
||||
******************************************************************************/
|
||||
static long
|
||||
drvWrite(pxact, pwrParm)
|
||||
msgXact *pxact;
|
||||
msgStrParm *pwrParm;
|
||||
{
|
||||
int len;
|
||||
drvBB232Link *pdrvBB232Link = (drvBB232Link *)(pxact->phwpvt->pmsgLink->p);
|
||||
struct dpvtBitBusHead *pdpvtBitBusHead = (struct dpvtBitBusHead *) pxact->p;
|
||||
unsigned char loopLen;
|
||||
|
||||
/* build a bitbus message and call the bitbus driver */
|
||||
|
||||
if (pwrParm->len == -1)
|
||||
len = strlen(pwrParm->buf);
|
||||
else
|
||||
len = pwrParm->len;
|
||||
|
||||
pdpvtBitBusHead->txMsg.data = (unsigned char *) pwrParm->buf;
|
||||
pdpvtBitBusHead->status = BB_OK;
|
||||
pdpvtBitBusHead->rxMaxLen = BB_MAX_MSG_LENGTH;
|
||||
|
||||
pdpvtBitBusHead->txMsg.cmd = BB_232_CMD + pdrvBB232Link->port;
|
||||
pdpvtBitBusHead->rxMsg.cmd = 0;
|
||||
|
||||
while (len && (pdpvtBitBusHead->status == BB_OK) &&
|
||||
!(pdpvtBitBusHead->rxMsg.cmd & 1))
|
||||
{
|
||||
if (len > BB_MAX_DAT_LEN)
|
||||
loopLen = BB_MAX_DAT_LEN;
|
||||
else
|
||||
loopLen = len;
|
||||
|
||||
pdpvtBitBusHead->txMsg.length = loopLen + BB_MSG_HEADER_SIZE;
|
||||
if (softBB232)
|
||||
{
|
||||
printf("drvBB232.drvWrite(tx L%d N%d P%d):\n", pdrvBB232Link->link, pdrvBB232Link->node, pdrvBB232Link->port);
|
||||
drvBitBusDumpMsg(&(pdpvtBitBusHead->txMsg));
|
||||
}
|
||||
else
|
||||
{
|
||||
(*(drvBitBus.qReq))(pdpvtBitBusHead, BB_Q_LOW); /* do it */
|
||||
semTake(*(pdpvtBitBusHead->psyncSem), WAIT_FOREVER); /* wait for completion */
|
||||
if (drvBB232Debug > 10)
|
||||
{
|
||||
printf("drvBB232.drvWrite (tx L%d N%d P%d)\n", pdrvBB232Link->link, pdrvBB232Link->node, pdrvBB232Link->port);
|
||||
drvBitBusDumpMsg(&(pdpvtBitBusHead->txMsg));
|
||||
}
|
||||
}
|
||||
|
||||
pdpvtBitBusHead->txMsg.data += loopLen;
|
||||
len -= loopLen;
|
||||
}
|
||||
|
||||
if ((pdpvtBitBusHead->status != BB_OK) || (pdpvtBitBusHead->rxMsg.cmd & 1))
|
||||
{
|
||||
if (drvBB232Debug)
|
||||
printf("BB232 write error on link %d, node %d, port %d, driver %2.2X, message %2.2X\n", pdrvBB232Link->link, pdrvBB232Link->node, pdrvBB232Link->port, pdpvtBitBusHead->status, pdpvtBitBusHead->rxMsg.cmd);
|
||||
|
||||
pxact->status = XACT_IOERR;
|
||||
}
|
||||
|
||||
return(pxact->status);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* This function is used to read a string of characters from an RS-232 device.
|
||||
*
|
||||
* It is assumed that pdpvtBitBusHead->rxMsg has already got up to 13
|
||||
* bytes of the response data already filled in (left there by the prior
|
||||
* call to drvWrite().) If a call to this function is made when there is
|
||||
* garbage in the initial pdpvtBitBusHead->rxMsg buffer, set the length field
|
||||
* to 0 and the status field to BB_OK.
|
||||
*
|
||||
******************************************************************************/
|
||||
static long
|
||||
drvRead(pxact, prdParm)
|
||||
msgXact *pxact;
|
||||
msgStrParm *prdParm;
|
||||
{
|
||||
drvBB232Link *pdrvBB232Link = (drvBB232Link *)(pxact->phwpvt->pmsgLink->p);
|
||||
struct dpvtBitBusHead *pdpvtBitBusHead = (struct dpvtBitBusHead *) pxact->p;
|
||||
int len = prdParm->len;
|
||||
int loopLen = 0;
|
||||
|
||||
/* check if data already loaded into pdpvtBitBusHead->rxMsg */
|
||||
if ((pdpvtBitBusHead->rxMsg.length > BB_MSG_HEADER_SIZE) && (pdpvtBitBusHead->status == BB_OK))
|
||||
{
|
||||
loopLen = pdpvtBitBusHead->rxMsg.length - BB_MSG_HEADER_SIZE;
|
||||
|
||||
if (prdParm->len < loopLen)
|
||||
loopLen = prdParm->len;
|
||||
|
||||
if (drvBB232Debug > 9)
|
||||
{
|
||||
printf("drvBB232.drvRead (rx L%d N%d P%d)\n", pdrvBB232Link->link, pdrvBB232Link->node, pdrvBB232Link->port);
|
||||
drvBitBusDumpMsg(&(pdpvtBitBusHead->rxMsg));
|
||||
}
|
||||
bcopy(pdpvtBitBusHead->rxMsg.data, prdParm->buf, loopLen);
|
||||
len -= loopLen;
|
||||
}
|
||||
|
||||
pdpvtBitBusHead->txMsg.length = BB_MSG_HEADER_SIZE;
|
||||
pdpvtBitBusHead->txMsg.cmd = BB_232_CMD + pdrvBB232Link->port;
|
||||
|
||||
pdpvtBitBusHead->rxMsg.data = (unsigned char *) (&(prdParm->buf[loopLen]));
|
||||
|
||||
if (!(pdpvtBitBusHead->rxMsg.cmd & BB_232_EOI))
|
||||
{ /* If we did not hit EOI yet, keep reading */
|
||||
|
||||
while (len && (pdpvtBitBusHead->status == BB_OK))
|
||||
{
|
||||
if (len > BB_MAX_DAT_LEN)
|
||||
loopLen = BB_MAX_DAT_LEN;
|
||||
else
|
||||
loopLen = len;
|
||||
|
||||
pdpvtBitBusHead->rxMaxLen = loopLen + BB_MSG_HEADER_SIZE;
|
||||
if (softBB232)
|
||||
{
|
||||
printf("drvBB232.drvRead(tx L%d N%d P%d)\n", pdrvBB232Link->link, pdrvBB232Link->node, pdrvBB232Link->port);
|
||||
drvBitBusDumpMsg(&(pdpvtBitBusHead->txMsg));
|
||||
pdpvtBitBusHead->status = BB_232_EOI;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (drvBB232Debug > 10)
|
||||
{
|
||||
printf("drvBB232.drvRead(tx L%d N%d P%d)\n", pdrvBB232Link->link, pdrvBB232Link->node, pdrvBB232Link->port);
|
||||
drvBitBusDumpMsg(&(pdpvtBitBusHead->txMsg));
|
||||
}
|
||||
|
||||
(*(drvBitBus.qReq))(pdpvtBitBusHead, BB_Q_LOW); /* do it */
|
||||
semTake(*(pdpvtBitBusHead->psyncSem), WAIT_FOREVER); /* wait for completion */
|
||||
|
||||
if (drvBB232Debug > 9)
|
||||
{
|
||||
printf("drvBB232.drvRead (rx L%d N%d P%d)\n", pdrvBB232Link->link, pdrvBB232Link->node, pdrvBB232Link->port);
|
||||
drvBitBusDumpMsg(&(pdpvtBitBusHead->rxMsg));
|
||||
}
|
||||
}
|
||||
|
||||
if (pdpvtBitBusHead->rxMsg.cmd & (~BB_232_EOI))
|
||||
{ /* Something is wrong... */
|
||||
if (drvBB232Debug > 6)
|
||||
{
|
||||
printf("drvBB232.drvRead (rx L%d N%d P%d) Error response from BUG\n", pdrvBB232Link->link, pdrvBB232Link->node, pdrvBB232Link->port);
|
||||
drvBitBusDumpMsg(&(pdpvtBitBusHead->rxMsg));
|
||||
}
|
||||
pxact->status = XACT_IOERR;
|
||||
break; /* note that we will fall thru to the null-term code */
|
||||
}
|
||||
if (pdpvtBitBusHead->rxMsg.cmd & BB_232_EOI)
|
||||
{
|
||||
pdpvtBitBusHead->rxMsg.data += pdpvtBitBusHead->rxMsg.length - BB_MSG_HEADER_SIZE;
|
||||
len -= pdpvtBitBusHead->rxMsg.length - BB_MSG_HEADER_SIZE;
|
||||
break;
|
||||
}
|
||||
|
||||
pdpvtBitBusHead->rxMsg.data += loopLen;
|
||||
len -= loopLen;
|
||||
}
|
||||
}
|
||||
/* Null-terminate the input string (if there is room) */
|
||||
if (len)
|
||||
*(pdpvtBitBusHead->rxMsg.data) = '\0';
|
||||
else
|
||||
pxact->status = XACT_LENGTH;
|
||||
|
||||
/* Note that the following error check, takes priority over a length error */
|
||||
if (pdpvtBitBusHead->status != BB_OK)
|
||||
{
|
||||
if (drvBB232Debug)
|
||||
printf("BB232 read error on link %d, node %d, port %d\n", pdrvBB232Link->link, pdrvBB232Link->node, pdrvBB232Link->port);
|
||||
pxact->status = XACT_IOERR;
|
||||
}
|
||||
|
||||
/* BUG -- this can print unterminated strings !! */
|
||||
if (drvBB232Debug > 7)
|
||||
printf("drvRead: got >%s<\n", prdParm->buf);
|
||||
|
||||
pdpvtBitBusHead->rxMsg.length = BB_MSG_HEADER_SIZE; /* in case keep reading */
|
||||
return(pxact->status);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* This handles any IOCTL calls made to BB-232 devices.
|
||||
*
|
||||
******************************************************************************/
|
||||
static long
|
||||
drvIoctl(cmd, pparm)
|
||||
int cmd;
|
||||
void *pparm;
|
||||
{
|
||||
switch (cmd) {
|
||||
case MSGIOCTL_REPORT:
|
||||
return(report());
|
||||
case MSGIOCTL_INIT:
|
||||
return(init(pparm));
|
||||
case MSGIOCTL_INITREC:
|
||||
if (drvBB232Debug)
|
||||
printf("drvBB232Block.drvIoctl got a MSGIOCTL_INITREC request!\n");
|
||||
return(ERROR);
|
||||
case MSGIOCTL_GENXACT:
|
||||
return(genXact(pparm));
|
||||
case MSGIOCTL_GENHWPVT:
|
||||
return(genHwpvt(pparm));
|
||||
case MSGIOCTL_GENLINK:
|
||||
return(genLink(pparm));
|
||||
case MSGIOCTL_CHECKEVENT:
|
||||
return(checkEvent(pparm));
|
||||
case MSGIOCTL_COMMAND:
|
||||
return(command(pparm));
|
||||
}
|
||||
return(ERROR);
|
||||
}
|
||||
|
||||
|
||||
msgDrvBlock drvBB232Block = {
|
||||
"BB232", /* taskName */
|
||||
BB232LINK_PRI, /* taskPri */
|
||||
BB232LINK_OPT, /* taskOpt */
|
||||
BB232LINK_STACK, /* taskStack */
|
||||
NULL, /* pmsgLink (linked list header) */
|
||||
drvWrite, /* drvWrite */
|
||||
drvRead, /* drvRead */
|
||||
drvIoctl /* drvIoctl */
|
||||
};
|
||||
@@ -1,69 +0,0 @@
|
||||
/* share/epicsH $Id$ */
|
||||
/*
|
||||
* Author: John Winans
|
||||
* Date: 5-21-92
|
||||
*
|
||||
* Experimental Physics and Industrial Control System (EPICS)
|
||||
*
|
||||
* Copyright 1988, 1989, the Regents of the University of California,
|
||||
* and the University of Chicago Board of Governors.
|
||||
*
|
||||
* This software was produced under U.S. Government contracts:
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
|
||||
* and (W-31-109-ENG-38) at Argonne National Laboratory.
|
||||
*
|
||||
* Initial development by:
|
||||
* The Controls and Automation Group (AT-8)
|
||||
* Ground Test Accelerator
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Co-developed with
|
||||
* The Controls and Computing Group
|
||||
* Accelerator Systems Division
|
||||
* Advanced Photon Source
|
||||
* Argonne National Laboratory
|
||||
*
|
||||
* All rights reserved. No part of this publication may be reproduced,
|
||||
* stored in a retrieval system, transmitted, in any form or by any
|
||||
* means, electronic, mechanical, photocopying, recording, or otherwise
|
||||
* without prior written permission of Los Alamos National Laboratory
|
||||
* and Argonne National Laboratory.
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .01 05-21-92 jrw Initial release
|
||||
* .02 02-19-92 joh cpu independent clk rate
|
||||
*/
|
||||
|
||||
#ifndef DRVBB232_H
|
||||
#define DRVBB232_H
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Additional fields needed for the msgParmBlock structure.
|
||||
*
|
||||
******************************************************************************/
|
||||
typedef struct {
|
||||
int dmaTimeout; /* Clock ticks to wait for DMA to complete */
|
||||
int baud; /* baud rate to run the interface */
|
||||
} drvBB232ParmBlock;
|
||||
|
||||
typedef struct {
|
||||
int link; /* The BB card/link number */
|
||||
int node; /* the bug's node number */
|
||||
int port; /* The tty port number on that card */
|
||||
/* The pparmBlock is used to make sure only 1 device type is requested */
|
||||
/* on one single port. */
|
||||
msgParmBlock *pparmBlock;
|
||||
} drvBB232Link;
|
||||
|
||||
#ifndef DRVBB232_C
|
||||
extern
|
||||
#endif
|
||||
msgDrvBlock drvBB232Block;
|
||||
|
||||
#define BB232_DEFAULT_AGE (sysClkRateGet()) /* 1 second */
|
||||
|
||||
#define BB_232_EOI 0x20
|
||||
#endif
|
||||
@@ -1,590 +0,0 @@
|
||||
/* base/src/drv $Id$ */
|
||||
/*
|
||||
* Author: John Winans
|
||||
* Date: 05-21-92
|
||||
* EPICS BITBUS driver for message based I/O
|
||||
*
|
||||
* Experimental Physics and Industrial Control System (EPICS)
|
||||
*
|
||||
* Copyright 1991, the Regents of the University of California,
|
||||
* and the University of Chicago Board of Governors.
|
||||
*
|
||||
* This software was produced under U.S. Government contracts:
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
|
||||
* and (W-31-109-ENG-38) at Argonne National Laboratory.
|
||||
*
|
||||
* Initial development by:
|
||||
* The Controls and Automation Group (AT-8)
|
||||
* Ground Test Accelerator
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Co-developed with
|
||||
* The Controls and Computing Group
|
||||
* Accelerator Systems Division
|
||||
* Advanced Photon Source
|
||||
* Argonne National Laboratory
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .01 08-10-92 jrw created
|
||||
*
|
||||
*/
|
||||
|
||||
#include <vxWorks.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <iosLib.h>
|
||||
#include <taskLib.h>
|
||||
#include <semLib.h>
|
||||
#include <wdLib.h>
|
||||
#include <wdLib.h>
|
||||
#include <tickLib.h>
|
||||
#include <vme.h>
|
||||
|
||||
#include <task_params.h>
|
||||
#include <module_types.h>
|
||||
#include <drvSup.h>
|
||||
#include <devSup.h>
|
||||
#include <dbDefs.h>
|
||||
#include <dbCommon.h>
|
||||
#include <dbAccess.h>
|
||||
#include <link.h>
|
||||
#include <callback.h>
|
||||
#include <fast_lock.h>
|
||||
|
||||
#include <drvMsg.h>
|
||||
#include <drvBitBusInterface.h>
|
||||
|
||||
int drvBBMsgDebug = 0;
|
||||
|
||||
extern struct drvBitBusEt drvBitBus;
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
******************************************************************************/
|
||||
#define BBMSGLINK_PRI 50
|
||||
#define BBMSGLINK_OPT VX_FP_TASK|VX_STDIO
|
||||
#define BBMSGLINK_STACK 5000
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
******************************************************************************/
|
||||
static long
|
||||
report()
|
||||
{
|
||||
printf("Report for BITBUS message driver\n");
|
||||
return(OK);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
******************************************************************************/
|
||||
static long
|
||||
init(pparms)
|
||||
msgDrvIniParm *pparms;
|
||||
{
|
||||
if (drvBBMsgDebug)
|
||||
printf("Init for BITBUS message driver\n");
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* This function is called to allocate any structures needed to hold
|
||||
* device-specific data that is added to the msgXact structure.
|
||||
*
|
||||
* It is also responsible for filling in the msgXact.phwpvt pointer.
|
||||
*
|
||||
******************************************************************************/
|
||||
static long
|
||||
genXact(p)
|
||||
msgDrvGenXParm *p;
|
||||
{
|
||||
long stat = -1;
|
||||
char message[100];
|
||||
drvBBMsgLink *pdrvBBMsgLink;
|
||||
struct dpvtBitBusHead *pdpvtBitBusHead;
|
||||
|
||||
if (p->plink->type != BITBUS_IO)
|
||||
{
|
||||
p->pmsgXact->prec->pact = TRUE;
|
||||
sprintf("%s: invalid device type in devSup.ascii (%d)\n", p->pmsgXact->prec->name, p->plink->type);
|
||||
errMessage(S_db_badField, message);
|
||||
return(ERROR);
|
||||
}
|
||||
|
||||
if (drvBBMsgDebug)
|
||||
printf("BBMsg genXact entered for link %d, bug %d, port %d, parm %s\n", p->plink->value.bitbusio.link, p->plink->value.bitbusio.node, p->plink->value.bitbusio.port, p->plink->value.bitbusio.parm);
|
||||
|
||||
p->pmsgXact->phwpvt = p->pmsgXact->pparmBlock->pmsgHwpvt;
|
||||
|
||||
/* try to find the hwpvt structure for the required link, bug, and port */
|
||||
while ((p->pmsgXact->phwpvt != NULL) && (stat == -1))
|
||||
{
|
||||
pdrvBBMsgLink = (drvBBMsgLink *)(p->pmsgXact->phwpvt->pmsgLink->p);
|
||||
|
||||
if ((pdrvBBMsgLink->link == p->plink->value.bitbusio.link)
|
||||
&& (pdrvBBMsgLink->node == p->plink->value.bitbusio.node)
|
||||
&& (pdrvBBMsgLink->port == p->plink->value.bitbusio.port))
|
||||
{
|
||||
if (pdrvBBMsgLink->pparmBlock != p->pmsgXact->pparmBlock)
|
||||
{
|
||||
sprintf(message, "%s: Two different devices on same BBMsg port\n", p->pmsgXact->prec->name);
|
||||
errMessage(S_db_badField, message);
|
||||
return(ERROR);
|
||||
}
|
||||
else
|
||||
stat = 0; /* Found the correct hwpvt structure */
|
||||
}
|
||||
else
|
||||
p->pmsgXact->phwpvt = p->pmsgXact->phwpvt->next;
|
||||
}
|
||||
if (stat != 0)
|
||||
{ /* Could not find a msgHwpvt for the right link, create a new one */
|
||||
if ((p->pmsgXact->phwpvt = drvMsg_genHwpvt(p->pmsgXact->pparmBlock, p->plink)) == NULL)
|
||||
return(ERROR);
|
||||
}
|
||||
/* Set again in case hwpvt was just allocated (and to make compiler happy) */
|
||||
pdrvBBMsgLink = (drvBBMsgLink *)(p->pmsgXact->phwpvt->pmsgLink->p);
|
||||
|
||||
p->pmsgXact->callback.callback = NULL;
|
||||
p->pmsgXact->psyncSem = NULL;
|
||||
|
||||
/* Create the skeleton bitbus driver message */
|
||||
pdpvtBitBusHead = (struct dpvtBitBusHead *) malloc(sizeof(struct dpvtBitBusHead));
|
||||
(struct dpvtBitBusHead *)(p->pmsgXact->p) = pdpvtBitBusHead;
|
||||
|
||||
pdpvtBitBusHead->finishProc = NULL;
|
||||
pdpvtBitBusHead->psyncSem = malloc(sizeof(SEM_ID));
|
||||
*(pdpvtBitBusHead->psyncSem) = semBCreate(SEM_Q_PRIORITY, SEM_EMPTY);
|
||||
pdpvtBitBusHead->link = pdrvBBMsgLink->link;
|
||||
|
||||
pdpvtBitBusHead->txMsg.route = BB_STANDARD_TX_ROUTE;
|
||||
pdpvtBitBusHead->txMsg.node = pdrvBBMsgLink->node;
|
||||
pdpvtBitBusHead->txMsg.tasks = BB_MSG_TASK;
|
||||
pdpvtBitBusHead->txMsg.cmd = 0xff;
|
||||
|
||||
pdpvtBitBusHead->rxMsg.data = (unsigned char *) malloc(BB_MAX_DAT_LEN);
|
||||
|
||||
/* in case I read before write */
|
||||
pdpvtBitBusHead->rxMsg.cmd = 0;
|
||||
pdpvtBitBusHead->rxMsg.length = BB_MSG_HEADER_SIZE;
|
||||
pdpvtBitBusHead->status = BB_OK;
|
||||
|
||||
pdpvtBitBusHead->rxMaxLen = 0;
|
||||
pdpvtBitBusHead->ageLimit = 0;
|
||||
|
||||
if (sscanf(p->plink->value.bitbusio.parm,"%d", &(p->pmsgXact->parm)) != 1)
|
||||
{
|
||||
p->pmsgXact->prec->pact = TRUE;
|
||||
sprintf("%s: invalid parameter string >%s<\n", p->pmsgXact->prec->name, p->plink->value.bitbusio.parm);
|
||||
errMessage(S_db_badField, message);
|
||||
return(ERROR);
|
||||
}
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* This function is called to allocate any structures needed to hold
|
||||
* device-specific data that is added to the msgHwpvt structure.
|
||||
*
|
||||
* It is also responsible for filling in the msgHwpvt.pmsgLink pointer.
|
||||
*
|
||||
******************************************************************************/
|
||||
static long
|
||||
genHwpvt(p)
|
||||
msgDrvGenHParm *p;
|
||||
{
|
||||
int stat = ERROR;
|
||||
|
||||
if (drvBBMsgDebug)
|
||||
printf("BBMSG genHwpvt entered\n");
|
||||
|
||||
p->pmsgHwpvt->pmsgLink = drvBBMSGBlock.pmsgLink;
|
||||
while ((p->pmsgHwpvt->pmsgLink != NULL) && (stat == ERROR))
|
||||
{
|
||||
if ((((drvBBMsgLink *)(p->pmsgHwpvt->pmsgLink->p))->link == p->plink->value.bitbusio.link)
|
||||
&& (((drvBBMsgLink *)(p->pmsgHwpvt->pmsgLink->p))->node == p->plink->value.bitbusio.node)
|
||||
&& (((drvBBMsgLink *)(p->pmsgHwpvt->pmsgLink->p))->port == p->plink->value.bitbusio.port))
|
||||
stat = OK;
|
||||
else
|
||||
p->pmsgHwpvt->pmsgLink = p->pmsgHwpvt->pmsgLink->next;
|
||||
}
|
||||
if (stat != OK)
|
||||
{
|
||||
if ((p->pmsgHwpvt->pmsgLink = drvMsg_genLink(p->pparmBlock, p->plink)) == NULL)
|
||||
return(ERROR);
|
||||
}
|
||||
return(OK);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* This function is called to allocate any structures needed to hold
|
||||
* device-specific data that is added to the msgLink structure.
|
||||
*
|
||||
******************************************************************************/
|
||||
static long
|
||||
genLink(p)
|
||||
msgDrvGenLParm *p;
|
||||
{
|
||||
char name[20];
|
||||
char message[100];
|
||||
drvBBMsgLink *pdrvBBMsgLink;
|
||||
|
||||
if (drvBBMsgDebug)
|
||||
printf("BBMsg genLink, link = %d, node = %d\n", p->plink->value.bitbusio.link, p->plink->value.bitbusio.node, p->plink->value.bitbusio.port);
|
||||
|
||||
switch (p->op) {
|
||||
case MSG_GENLINK_CREATE:
|
||||
|
||||
/* BUG -- verify that the link and node numbers are within range! */
|
||||
|
||||
if (p->plink->value.bitbusio.port & (~DD_MSG_PORT))
|
||||
{
|
||||
sprintf(message, "drvBBMsg: port number %d out of range\n", p->plink->value.bitbusio.port);
|
||||
errMessage(S_db_badField, message);
|
||||
return(ERROR);
|
||||
}
|
||||
|
||||
if ((p->pmsgLink->p = malloc(sizeof(drvBBMsgLink))) == NULL)
|
||||
return(ERROR);
|
||||
|
||||
pdrvBBMsgLink = (drvBBMsgLink *)(p->pmsgLink->p);
|
||||
|
||||
pdrvBBMsgLink->link = p->plink->value.bitbusio.link;
|
||||
pdrvBBMsgLink->node = p->plink->value.bitbusio.node;
|
||||
pdrvBBMsgLink->port = p->plink->value.bitbusio.port;
|
||||
pdrvBBMsgLink->pparmBlock = p->pparmBlock;
|
||||
|
||||
|
||||
return(OK);
|
||||
|
||||
case MSG_GENLINK_ABORT:
|
||||
|
||||
if (drvBBMsgDebug)
|
||||
printf("BBMsg genLink: called with abort status\n");
|
||||
|
||||
pdrvBBMsgLink = (drvBBMsgLink *)(p->pmsgLink->p);
|
||||
/* BUG - free(p->pmsgLink->p); Don't forget to take it out of the list */
|
||||
return(OK);
|
||||
}
|
||||
return(ERROR);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* This function is called to allow the device to indicate that a device-related
|
||||
* event has occurred. If an event had occurred, it would have to place the
|
||||
* address of a valid transaction structure in pxact. This xact structure
|
||||
* will then be processed by the message link task as indicated by the
|
||||
* return code of this function.
|
||||
*
|
||||
* MSG_EVENT_NONE = no event has occurred, pxact not filled in.
|
||||
* MSG_EVENT_WRITE = event occurred, process the writeOp assoc'd w/pxact.
|
||||
* MSG_EVENT_READ = event occurred, process the readOp assoc'd w/pxact.
|
||||
*
|
||||
* Note that MSG_EVENT_READ only makes sense when returned with a transaction
|
||||
* that has deferred readback specified for its readOp function. Because if
|
||||
* it is NOT a deferred readback, it will be done immediately after the writeOp.
|
||||
* Even if that writeOp was due to a MSG_EVENT_WRITE from this function.
|
||||
*
|
||||
******************************************************************************/
|
||||
static long
|
||||
checkEvent(p)
|
||||
msgChkEParm *p;
|
||||
{
|
||||
return(MSG_EVENT_NONE);
|
||||
}
|
||||
/******************************************************************************
|
||||
*
|
||||
* This IOCTL function is used to handle non-I/O related operations required
|
||||
* to operate the RS-MSG interface.
|
||||
*
|
||||
******************************************************************************/
|
||||
static long
|
||||
command(p)
|
||||
ioctlCommand *p;
|
||||
{
|
||||
msgXact *pxact;
|
||||
struct dpvtBitBusHead *pdpvtBitBusHead;
|
||||
drvBBMsgLink *pdrvBBMsgLink;
|
||||
|
||||
switch (p->cmd) {
|
||||
case IOCTLMSG_BREAK: /* send a BREAK signal to the serial port. */
|
||||
/* Build a break message to send */
|
||||
pxact = (msgXact *) (p->pparm);
|
||||
pdpvtBitBusHead = (struct dpvtBitBusHead *) pxact->p;
|
||||
pdrvBBMsgLink = (drvBBMsgLink *)(pxact->phwpvt->pmsgLink->p);
|
||||
pdpvtBitBusHead->status = BB_OK;
|
||||
pdpvtBitBusHead->rxMaxLen = 0;
|
||||
pdpvtBitBusHead->txMsg.length = BB_MSG_HEADER_SIZE;
|
||||
pdpvtBitBusHead->txMsg.cmd = BB_MSG_BREAK + pdrvBBMsgLink->port;
|
||||
pdpvtBitBusHead->rxMsg.cmd = 0;
|
||||
|
||||
if (drvBBMsgDebug > 7)
|
||||
{
|
||||
printf("drvBBMsg.control (tx L%d N%d P%d)\n", pdrvBBMsgLink->link, pdrvBBMsgLink->node, pdrvBBMsgLink->port);
|
||||
drvBitBusDumpMsg(&(pdpvtBitBusHead->txMsg));
|
||||
}
|
||||
|
||||
(*(drvBitBus.qReq))(pdpvtBitBusHead, BB_Q_LOW);
|
||||
semTake(*(pdpvtBitBusHead->psyncSem), WAIT_FOREVER);
|
||||
|
||||
if ((pdpvtBitBusHead->status == BB_OK) && !(pdpvtBitBusHead->rxMsg.cmd & 1))
|
||||
return(OK);
|
||||
else
|
||||
return(ERROR);
|
||||
}
|
||||
|
||||
if (drvBBMsgDebug)
|
||||
printf("drvBBMsg.control: bad command 0x%02.2X\n", p->cmd);
|
||||
return(ERROR);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* This function is used to write a string of characters out to an BB_MSG
|
||||
* device.
|
||||
*
|
||||
* Note that the BUGs reply to the write messages with the first 13 bytes
|
||||
* of the machine's response string (if there is one.) This response string
|
||||
* will be left in the pdpvtBitBusHead->rxMsg buffer when the drvRead()
|
||||
* function is called later.
|
||||
*
|
||||
******************************************************************************/
|
||||
static long
|
||||
drvWrite(pxact, pwrParm)
|
||||
msgXact *pxact;
|
||||
msgStrParm *pwrParm;
|
||||
{
|
||||
int len;
|
||||
drvBBMsgLink *pdrvBBMsgLink = (drvBBMsgLink *)(pxact->phwpvt->pmsgLink->p);
|
||||
struct dpvtBitBusHead *pdpvtBitBusHead = (struct dpvtBitBusHead *) pxact->p;
|
||||
unsigned char loopLen;
|
||||
|
||||
/* build a bitbus message and call the bitbus driver */
|
||||
|
||||
if (pwrParm->len == -1)
|
||||
len = strlen(pwrParm->buf);
|
||||
else
|
||||
len = pwrParm->len;
|
||||
|
||||
pdpvtBitBusHead->txMsg.data = (unsigned char *) pwrParm->buf;
|
||||
pdpvtBitBusHead->status = BB_OK;
|
||||
pdpvtBitBusHead->rxMaxLen = BB_MAX_MSG_LENGTH;
|
||||
|
||||
pdpvtBitBusHead->txMsg.cmd = BB_MSG_CMD + pdrvBBMsgLink->port;
|
||||
pdpvtBitBusHead->rxMsg.cmd = 0;
|
||||
|
||||
while (len && (pdpvtBitBusHead->status == BB_OK) &&
|
||||
!(pdpvtBitBusHead->rxMsg.cmd & 1))
|
||||
{
|
||||
if (len > BB_MAX_DAT_LEN)
|
||||
loopLen = BB_MAX_DAT_LEN;
|
||||
else
|
||||
loopLen = len;
|
||||
|
||||
pdpvtBitBusHead->txMsg.length = loopLen + BB_MSG_HEADER_SIZE;
|
||||
if (softBBMsg)
|
||||
{
|
||||
printf("drvBBMsg.drvWrite(tx L%d N%d P%d):\n", pdrvBBMsgLink->link, pdrvBBMsgLink->node, pdrvBBMsgLink->port);
|
||||
drvBitBusDumpMsg(&(pdpvtBitBusHead->txMsg));
|
||||
}
|
||||
else
|
||||
{
|
||||
(*(drvBitBus.qReq))(pdpvtBitBusHead, BB_Q_LOW); /* do it */
|
||||
semTake(*(pdpvtBitBusHead->psyncSem), WAIT_FOREVER); /* wait for completion */
|
||||
if (drvBBMsgDebug > 10)
|
||||
{
|
||||
printf("drvBBMsg.drvWrite (tx L%d N%d P%d)\n", pdrvBBMsgLink->link, pdrvBBMsgLink->node, pdrvBBMsgLink->port);
|
||||
drvBitBusDumpMsg(&(pdpvtBitBusHead->txMsg));
|
||||
}
|
||||
}
|
||||
|
||||
pdpvtBitBusHead->txMsg.data += loopLen;
|
||||
len -= loopLen;
|
||||
}
|
||||
|
||||
if ((pdpvtBitBusHead->status != BB_OK) || (pdpvtBitBusHead->rxMsg.cmd & 1))
|
||||
{
|
||||
if (drvBBMsgDebug)
|
||||
printf("BBMsg write error on link %d, node %d, port %d, driver %02.2X, message %02.2X\n", pdrvBBMsgLink->link, pdrvBBMsgLink->node, pdrvBBMsgLink->port, pdpvtBitBusHead->status, pdpvtBitBusHead->rxMsg.cmd);
|
||||
|
||||
pxact->status = XACT_IOERR;
|
||||
}
|
||||
|
||||
return(pxact->status);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* This function is used to read a string of characters from an RS-Msg device.
|
||||
*
|
||||
* It is assumed that pdpvtBitBusHead->rxMsg has already got up to 13
|
||||
* bytes of the response data already filled in (left there by the prior
|
||||
* call to drvWrite().) If a call to this function is made when there is
|
||||
* garbage in the initial pdpvtBitBusHead->rxMsg buffer, set the length field
|
||||
* to 0 and the status field to BB_OK.
|
||||
*
|
||||
******************************************************************************/
|
||||
static long
|
||||
drvRead(pxact, prdParm)
|
||||
msgXact *pxact;
|
||||
msgStrParm *prdParm;
|
||||
{
|
||||
drvBBMsgLink *pdrvBBMsgLink = (drvBBMsgLink *)(pxact->phwpvt->pmsgLink->p);
|
||||
struct dpvtBitBusHead *pdpvtBitBusHead = (struct dpvtBitBusHead *) pxact->p;
|
||||
int len = prdParm->len;
|
||||
int loopLen = 0;
|
||||
unsigned char *tmp = pdpvtBitBusHead->rxMsg.data;
|
||||
|
||||
/* check if data already loaded into pdpvtBitBusHead->rxMsg */
|
||||
if ((pdpvtBitBusHead->rxMsg.length > BB_MSG_HEADER_SIZE) && (pdpvtBitBusHead->status == BB_OK))
|
||||
{
|
||||
loopLen = pdpvtBitBusHead->rxMsg.length - BB_MSG_HEADER_SIZE;
|
||||
|
||||
if (prdParm->len < loopLen)
|
||||
loopLen = prdParm->len;
|
||||
|
||||
if (drvBBMsgDebug > 9)
|
||||
{
|
||||
printf("drvBBMsg.drvRead (rx L%d N%d P%d)\n", pdrvBBMsgLink->link, pdrvBBMsgLink->node, pdrvBBMsgLink->port);
|
||||
drvBitBusDumpMsg(&(pdpvtBitBusHead->rxMsg));
|
||||
}
|
||||
bcopy(pdpvtBitBusHead->rxMsg.data, prdParm->buf, loopLen);
|
||||
len -= loopLen;
|
||||
}
|
||||
|
||||
pdpvtBitBusHead->txMsg.length = BB_MSG_HEADER_SIZE;
|
||||
pdpvtBitBusHead->txMsg.cmd = BB_MSG_CMD + pdrvBBMsgLink->port;
|
||||
|
||||
pdpvtBitBusHead->rxMsg.data = (unsigned char *) (&(prdParm->buf[loopLen]));
|
||||
|
||||
if (!(pdpvtBitBusHead->rxMsg.cmd & BB_MSG_EOI))
|
||||
{ /* If we did not hit EOI yet, keep reading */
|
||||
|
||||
while (len && (pdpvtBitBusHead->status == BB_OK))
|
||||
{
|
||||
if (len > BB_MAX_DAT_LEN)
|
||||
loopLen = BB_MAX_DAT_LEN;
|
||||
else
|
||||
loopLen = len;
|
||||
|
||||
pdpvtBitBusHead->rxMaxLen = loopLen + BB_MSG_HEADER_SIZE;
|
||||
if (softBBMsg)
|
||||
{
|
||||
printf("drvBB232.drvRead(tx L%d N%d P%d)\n", pdrvBBMsgLink->link, pdrvBBMsgLink->node, pdrvBBMsgLink->port);
|
||||
drvBitBusDumpMsg(&(pdpvtBitBusHead->txMsg));
|
||||
pdpvtBitBusHead->status = BB_232_EOI;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (drvBBMsgDebug > 10)
|
||||
{
|
||||
printf("drvBB232.drvRead(tx L%d N%d P%d)\n", pdrvBBMsgLink->link, pdrvBBMsgLink->node, pdrvBBMsgLink->port);
|
||||
drvBitBusDumpMsg(&(pdpvtBitBusHead->txMsg));
|
||||
}
|
||||
|
||||
(*(drvBitBus.qReq))(pdpvtBitBusHead, BB_Q_LOW); /* do it */
|
||||
semTake(*(pdpvtBitBusHead->psyncSem), WAIT_FOREVER); /* wait for completion */
|
||||
|
||||
if (drvBBMsgDebug > 9)
|
||||
{
|
||||
printf("drvBB232.drvRead (rx L%d N%d P%d)\n", pdrvBBMsgLink->link, pdrvBBMsgLink->node, pdrvBBMsgLink->port);
|
||||
drvBitBusDumpMsg(&(pdpvtBitBusHead->rxMsg));
|
||||
}
|
||||
}
|
||||
|
||||
if (pdpvtBitBusHead->rxMsg.cmd & (~BB_232_EOI))
|
||||
{ /* Something is wrong... */
|
||||
if (drvBBMsgDebug > 6)
|
||||
{
|
||||
printf("drvBB232.drvRead (rx L%d N%d P%d) Error response from BUG\n", pdrvBBMsgLink->link, pdrvBBMsgLink->node, pdrvBBMsgLink->port);
|
||||
drvBitBusDumpMsg(&(pdpvtBitBusHead->rxMsg));
|
||||
}
|
||||
pxact->status = XACT_IOERR;
|
||||
break; /* note that we will fall thru to the null-term code */
|
||||
}
|
||||
if (pdpvtBitBusHead->rxMsg.cmd & BB_232_EOI)
|
||||
{
|
||||
pdpvtBitBusHead->rxMsg.data += pdpvtBitBusHead->rxMsg.length - BB_MSG_HEADER_SIZE;
|
||||
len -= pdpvtBitBusHead->rxMsg.length - BB_MSG_HEADER_SIZE;
|
||||
break;
|
||||
}
|
||||
|
||||
pdpvtBitBusHead->rxMsg.data += loopLen;
|
||||
len -= loopLen;
|
||||
}
|
||||
}
|
||||
/* Null-terminate the input string (if there is room) */
|
||||
if (len)
|
||||
*(pdpvtBitBusHead->rxMsg.data) = '\0';
|
||||
else
|
||||
pxact->status = XACT_LENGTH;
|
||||
|
||||
/* Note that the following error check, takes priority over a length error */
|
||||
if (pdpvtBitBusHead->status != BB_OK)
|
||||
{
|
||||
if (drvBBMsgDebug)
|
||||
printf("BB232 read error on link %d, node %d, port %d\n", pdrvBBMsgLink->link, pdrvBBMsgLink->node, pdrvBBMsgLink->port);
|
||||
pxact->status = XACT_IOERR;
|
||||
}
|
||||
|
||||
/* BUG -- this can print unterminated strings !! */
|
||||
if (drvBBMsgDebug > 7)
|
||||
printf("drvRead: got >%s<\n", prdParm->buf);
|
||||
|
||||
pdpvtBitBusHead->rxMsg.length = BB_MSG_HEADER_SIZE; /* in case keep reading */
|
||||
return(pxact->status);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* This handles any IOCTL calls made to BB-MSG devices.
|
||||
*
|
||||
******************************************************************************/
|
||||
static long
|
||||
drvIoctl(cmd, pparm)
|
||||
int cmd;
|
||||
void *pparm;
|
||||
{
|
||||
switch (cmd) {
|
||||
case MSGIOCTL_REPORT:
|
||||
return(report());
|
||||
case MSGIOCTL_INIT:
|
||||
return(init(pparm));
|
||||
case MSGIOCTL_INITREC:
|
||||
if (drvBBMsgDebug)
|
||||
printf("drvBBMsgBlock.drvIoctl got a MSGIOCTL_INITREC request!\n");
|
||||
return(ERROR);
|
||||
case MSGIOCTL_GENXACT:
|
||||
return(genXact(pparm));
|
||||
case MSGIOCTL_GENHWPVT:
|
||||
return(genHwpvt(pparm));
|
||||
case MSGIOCTL_GENLINK:
|
||||
return(genLink(pparm));
|
||||
case MSGIOCTL_CHECKEVENT:
|
||||
return(checkEvent(pparm));
|
||||
case MSGIOCTL_COMMAND:
|
||||
return(command(pparm));
|
||||
}
|
||||
return(ERROR);
|
||||
}
|
||||
|
||||
|
||||
msgDrvBlock drvBBMsgBlock = {
|
||||
"BBMSG", /* taskName */
|
||||
BBMSGLINK_PRI, /* taskPri */
|
||||
BBMSGLINK_OPT, /* taskOpt */
|
||||
BBMSGLINK_STACK, /* taskStack */
|
||||
NULL, /* pmsgLink (linked list header) */
|
||||
drvWrite, /* drvWrite */
|
||||
drvRead, /* drvRead */
|
||||
drvIoctl /* drvIoctl */
|
||||
};
|
||||
1422
src/drv/old/drvMsg.c
1422
src/drv/old/drvMsg.c
File diff suppressed because it is too large
Load Diff
@@ -1,485 +0,0 @@
|
||||
/* share/epicsH $Id$ */
|
||||
/*
|
||||
* Author: John Winans
|
||||
* Date: 11-19-91
|
||||
*
|
||||
* Experimental Physics and Industrial Control System (EPICS)
|
||||
*
|
||||
* Copyright 1988, 1989, the Regents of the University of California,
|
||||
* and the University of Chicago Board of Governors.
|
||||
*
|
||||
* This software was produced under U.S. Government contracts:
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
|
||||
* and (W-31-109-ENG-38) at Argonne National Laboratory.
|
||||
*
|
||||
* Initial development by:
|
||||
* The Controls and Automation Group (AT-8)
|
||||
* Ground Test Accelerator
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Co-developed with
|
||||
* The Controls and Computing Group
|
||||
* Accelerator Systems Division
|
||||
* Advanced Photon Source
|
||||
* Argonne National Laboratory
|
||||
*
|
||||
* All rights reserved. No part of this publication may be reproduced,
|
||||
* stored in a retrieval system, transmitted, in any form or by any
|
||||
* means, electronic, mechanical, photocopying, recording, or otherwise
|
||||
* without prior written permission of Los Alamos National Laboratory
|
||||
* and Argonne National Laboratory.
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .02 05-26-92 jrw added enumeration of record types
|
||||
* .03 08-10-92 jrw cleaned up the documentation
|
||||
* & removed multi-parm stuff
|
||||
*/
|
||||
|
||||
#ifndef DEVXXMSG_H
|
||||
#define DEVXXMSG_H
|
||||
/******************************************************************************
|
||||
*
|
||||
* This structure holds device-related data on a per-device basis and is
|
||||
* referenced by the xact structures. They are built using a linked
|
||||
* list starting from parmBlock.phwpvt. There is one linked list for each
|
||||
* specific device type.
|
||||
*
|
||||
* Different types of device links could have different formatted hwpvt structs.
|
||||
* The msgHwpvt structure includes those fields that are common to all device
|
||||
* types. The customized part should be attached to msgHwpvt.p during the
|
||||
* genHwpvt phase if the initilization process.
|
||||
*
|
||||
******************************************************************************/
|
||||
struct msgHwpvt {
|
||||
struct msgHwpvt *next; /* Next structure for same type device */
|
||||
|
||||
struct msgLink *pmsgLink; /* Associated link structure */
|
||||
|
||||
unsigned long tmoVal; /* Time last timeout occurred */
|
||||
unsigned long tmoCount; /* Total timeouts since boot time */
|
||||
|
||||
void *p; /* Place to add device-specific fields */
|
||||
};
|
||||
typedef struct msgHwpvt msgHwpvt;
|
||||
/******************************************************************************
|
||||
*
|
||||
* Any I/O request made must consist of the msgXact structure defined below.
|
||||
*
|
||||
* In general, one EPICS database record will have one and only one of these
|
||||
* msgXact attached to it's dbCommon.dpvt field.
|
||||
*
|
||||
* The message driver system does not reference any database record fields that
|
||||
* are not in dbCommon -- unless a user-provided function calls a
|
||||
* record-specific support function.
|
||||
*
|
||||
******************************************************************************/
|
||||
struct msgXact {
|
||||
CALLBACK callback;
|
||||
SEM_ID *psyncSem; /* if not NULL, points to sem given w/RX */
|
||||
|
||||
struct msgXact *next; /* used to link dpvt's together */
|
||||
struct msgXact *prev; /* used to link dpvt's together */
|
||||
|
||||
struct msgHwpvt *phwpvt; /* assoc'd hwpvt structure */
|
||||
struct msgParmBlock *pparmBlock; /* assoc'd parm block */
|
||||
struct dbCommon *prec; /* useful to msg based device support */
|
||||
unsigned int parm; /* operation parm number */
|
||||
int status; /* transaction completion status */
|
||||
|
||||
void *p; /* A place to add on device specific data */
|
||||
};
|
||||
typedef struct msgXact msgXact;
|
||||
/******************************************************************************
|
||||
*
|
||||
* Valid msgXact.status values are:
|
||||
*
|
||||
******************************************************************************/
|
||||
#define XACT_OK 0 /* all went as expected */
|
||||
#define XACT_LENGTH 1 /* received message overflowed the buffer */
|
||||
#define XACT_TIMEOUT 3 /* response took too long from node */
|
||||
#define XACT_BADLINK 4 /* request sent to an invalid link number */
|
||||
#define XACT_BADPRIO 5 /* request had bad queueing priority */
|
||||
#define XACT_IOERR 6 /* some sort of I/O error occurred */
|
||||
#define XACT_BADCMD 7 /* bad command ID-number */
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Transaction requests are placed on queues (by the drvMsg_qXact() function)
|
||||
* when submitted. These queues are described with the xactQueue structure.
|
||||
*
|
||||
******************************************************************************/
|
||||
struct xactQueue {
|
||||
struct msgXact *head; /* head of the linked list */
|
||||
struct msgXact *tail; /* tail of the linked list */
|
||||
FAST_LOCK lock; /* semaphore for the queue list */
|
||||
};
|
||||
typedef struct xactQueue xactQueue;
|
||||
/******************************************************************************
|
||||
*
|
||||
* A task is started to manage each message based link. It uses the msgLink
|
||||
* structure to access the queues of work.
|
||||
*
|
||||
* A link is defined by the device-specific part of the genHwpvt() function.
|
||||
* A link task will be started if the genHwpvt() function invokes the genLink()
|
||||
* function to define a new link.
|
||||
*
|
||||
******************************************************************************/
|
||||
struct msgLink{
|
||||
struct xactQueue queue[NUM_CALLBACK_PRIORITIES]; /* prioritized request queues */
|
||||
struct msgLink *next; /* next in msgDrvBlock list */
|
||||
SEM_ID linkEventSem;
|
||||
void *p; /* A place to add on device specific data */
|
||||
};
|
||||
typedef struct msgLink msgLink;
|
||||
/******************************************************************************
|
||||
*
|
||||
* The msgParmBlock is defined by the user-contributed device support module.
|
||||
* It is used to tell the message-driver what device driver to used to perform
|
||||
* the I/O operations as well as to provide access to the command table, and
|
||||
* other parameters.
|
||||
*
|
||||
* The msgParmBlock contains those parts that are common to all device types.
|
||||
* Some devices may require more operating parameters. These additional
|
||||
* parameters should be added via msgParmBlock.p.
|
||||
*
|
||||
******************************************************************************/
|
||||
struct msgParmBlock{
|
||||
int *debugFlag; /* pointer to debug flag */
|
||||
struct msgHwpvt *pmsgHwpvt; /* pointer to the hwpvt list for device type */
|
||||
struct msgCmd *pcmds; /* pointer to command list */
|
||||
int numCmds; /* number of elements in the command list */
|
||||
char *name; /* pointer to a string containing device name */
|
||||
struct msgDrvBlock *pdrvBlock; /* link to the driver hook data structure */
|
||||
DRVSUPFUN doOp; /* user spec'd operation wedge function */
|
||||
void *p; /* A place to add device specific data */
|
||||
};
|
||||
typedef struct msgParmBlock msgParmBlock;
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* The msgCmd structure is used to define each entry in the command table.
|
||||
* This table is used to define all the commands that a specific device type
|
||||
* can handle.
|
||||
*
|
||||
* When a transaction is processed, the following happens:
|
||||
*
|
||||
* 1) if A defered read event has occurred, cmd.readOp is called.
|
||||
* otherwise:
|
||||
* 1) if cmd.writeOp is non-NULL, it is called and passed wrParm
|
||||
* The job of writeOp is to send a string to the instrument
|
||||
* 2) if cmd.readOp is non-NULL, it is called and passed rdParm
|
||||
* The job of readOp is to read a string from the instrument
|
||||
*
|
||||
******************************************************************************/
|
||||
struct msgCmdOp {
|
||||
unsigned int op;
|
||||
void *p;
|
||||
};
|
||||
typedef struct msgCmdOp msgCmdOp;
|
||||
|
||||
struct msgCmd{
|
||||
struct msgRecEnum *recTyp;/* used to indicate record type supported */
|
||||
unsigned int flags; /* 1 if readback is deferred, 0 if not */
|
||||
|
||||
struct msgCmdOp writeOp;
|
||||
struct msgCmdOp readOp;
|
||||
|
||||
struct devMsgNames *namelist;/* pointer to name strings */
|
||||
int companion;
|
||||
};
|
||||
typedef struct msgCmd msgCmd;
|
||||
|
||||
/* Possible values for msgCmd.flags (OR the set required together) */
|
||||
#define READ_NDLY 0 /* Do read now */
|
||||
#define READ_DEFER 1 /* Defer read, an event will signal it */
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Valid writeOp and readOp values.
|
||||
*
|
||||
* Any user-add-on codes start at MSG_OP_USER and continue upward.
|
||||
*
|
||||
******************************************************************************/
|
||||
#define MSG_OP_NOP 0 /* Do nothing */
|
||||
#define MSG_OP_WRITE 1 /* Unformatted character write */
|
||||
|
||||
#define MSG_OP_FAI 2 /* Read and parse an analog input */
|
||||
#define MSG_OP_FAO 3 /* Format and output an analog output */
|
||||
#define MSG_OP_FBI 4 /* Read and parse */
|
||||
#define MSG_OP_FBO 5 /* Format and output */
|
||||
#define MSG_OP_FMI 6 /* Read and parse */
|
||||
#define MSG_OP_FMO 7 /* Format and output */
|
||||
#define MSG_OP_FLI 8 /* Read and parse */
|
||||
#define MSG_OP_FLO 9 /* Format and output */
|
||||
#define MSG_OP_FSI 10 /* Read and parse */
|
||||
#define MSG_OP_FSO 11 /* Format and output */
|
||||
|
||||
#define MSG_OP_RSI 12 /* Read a string raw */
|
||||
#define MSG_OP_RSO 13 /* Write a string raw */
|
||||
|
||||
#define MSG_OP_ACK 14 /* Read string and set alarm if not match */
|
||||
|
||||
#define MSG_OP_SBI 15 /* Read string, set BI on substring comparison */
|
||||
|
||||
/* NOT CURRENTLY SUPPORTED OPERATIONS */
|
||||
#if FALSE
|
||||
#define MSG_OP_EBI /* enumerated operations */
|
||||
#define MSG_OP_EBO
|
||||
#define MSG_OP_EMI
|
||||
#define MSG_OP_EMO
|
||||
#endif
|
||||
|
||||
#define MSG_OP_USER 200 /* Start of user added operation codes */
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* The following represent the op-codes that can be passed to the
|
||||
* msgDrvBlock.genlink function.
|
||||
*
|
||||
******************************************************************************/
|
||||
#define MSG_GENLINK_CREATE 0 /* Create structures for a new link */
|
||||
#define MSG_GENLINK_ABORT 1 /* Link failed init */
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Codes that can be returned from event checker routines.
|
||||
*
|
||||
******************************************************************************/
|
||||
#define MSG_EVENT_NONE 0
|
||||
#define MSG_EVENT_READ 1
|
||||
#define MSG_EVENT_WRITE 2
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* This is used to define the strings that are used for button labels.
|
||||
* These strings are put into the record's znam & onam foelds if the
|
||||
* record is a BI or BO type and into the zrst, onst... fields of an
|
||||
* MBBI or MBBO record.
|
||||
*
|
||||
* Before these strings are placed into the record, the record is
|
||||
* check to see if there is already a string defined (could be user-entered
|
||||
* with DCT.) If there is already a string present, it will be preserved.
|
||||
*
|
||||
* There MUST ALWAYS be 2 and only 2 entries in the names.item list
|
||||
* for BI and BO records if a name list is being specified for them here.
|
||||
* The names.count field is ignored for BI and BO record types, but
|
||||
* should be properly specified as 2 for future compatibility.
|
||||
*
|
||||
* NOTE:
|
||||
* If a name string is filled in an an MBBI/MBBO record, it's corresponding
|
||||
* value will be filled in as well. For this reason, there MUST be
|
||||
* a value array and a valid nobt value for every MBBI/MBBO record that
|
||||
* contains an item array!
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
struct drvMsgNames {
|
||||
int count; /* CURRENTLY only used for MBBI and MBBO */
|
||||
char **item;
|
||||
unsigned long *value; /* CURRENTLY only used for MBBI and MBBO */
|
||||
short nobt; /* CURRENTLY only used for MBBI and MBBO */
|
||||
};
|
||||
typedef struct drvMsgNames drvMsgNames;
|
||||
/******************************************************************************
|
||||
*
|
||||
* Public functions available from the message driver.
|
||||
*
|
||||
******************************************************************************/
|
||||
msgXact *drvMsg_genXact();
|
||||
msgHwpvt *drvMsg_genHwpvt();
|
||||
msgLink *drvMsg_genLink();
|
||||
long drvMsg_qXact();
|
||||
long drvMsg_reportMsg();
|
||||
long drvMsg_initMsg();
|
||||
long drvMsg_xactWork();
|
||||
long drvMsg_initCallback();
|
||||
long drvMsg_checkParm();
|
||||
long drvMsg_drvWrite();
|
||||
long drvMsg_drvRead();
|
||||
|
||||
long drvMsg_initAi(), drvMsg_initAo();
|
||||
long drvMsg_initBi(), drvMsg_initBo();
|
||||
long drvMsg_initMi(), drvMsg_initMo();
|
||||
long drvMsg_initLi(), drvMsg_initLo();
|
||||
long drvMsg_initSi(), drvMsg_initSo();
|
||||
long drvMsg_initWf();
|
||||
|
||||
long drvMsg_procAi(), drvMsg_procAo();
|
||||
long drvMsg_procBi(), drvMsg_procBo();
|
||||
long drvMsg_procMi(), drvMsg_procMo();
|
||||
long drvMsg_procLi(), drvMsg_procLo();
|
||||
long drvMsg_procSi(), drvMsg_procSo();
|
||||
long drvMsg_procWf();
|
||||
|
||||
long drvMsg_proc();
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* The msgDrvBlock is used by a message driver designer to specify functions
|
||||
* that are to be invoked to initialize structures and to check for events
|
||||
* that might have caused the link task to wake up. This is where hooks to
|
||||
* device specific functions and data structures are added to the message
|
||||
* based driver.
|
||||
*
|
||||
******************************************************************************/
|
||||
struct msgDrvBlock{
|
||||
char *taskName; /* Used for the taskSpawn and messages */
|
||||
int taskPri; /* Used for the taskSpawn */
|
||||
int taskOpt; /* Used for the taskSpawn */
|
||||
int taskStack; /* Used for the taskSpawn */
|
||||
struct msgLink *pmsgLink; /* associated msgLink list head */
|
||||
|
||||
DRVSUPFUN drvWrite; /* Write string from buffer */
|
||||
DRVSUPFUN drvRead; /* Read string into buffer */
|
||||
DRVSUPFUN drvIoctl; /* perform device specific control function */
|
||||
};
|
||||
typedef struct msgDrvBlock msgDrvBlock;
|
||||
|
||||
/* IOCTL functions that each message driver MUST support */
|
||||
#define MSGIOCTL_REPORT 0
|
||||
#define MSGIOCTL_INIT 1
|
||||
#define MSGIOCTL_INITREC 2
|
||||
#define MSGIOCTL_GENXACT 3
|
||||
#define MSGIOCTL_GENHWPVT 4
|
||||
#define MSGIOCTL_GENLINK 5
|
||||
#define MSGIOCTL_CHECKEVENT 6
|
||||
#define MSGIOCTL_COMMAND 7 /* device-type specific */
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* The parameter passed to the IOCTL function is different depending on the
|
||||
* function-code used in the IOCTL call. These parameters are defined below.
|
||||
*
|
||||
******************************************************************************/
|
||||
struct msgDrvIniParm {
|
||||
int parm;
|
||||
struct msgDset *pdset;
|
||||
};
|
||||
typedef struct msgDrvIniParm msgDrvIniParm;
|
||||
|
||||
struct msgDrvGenXParm {
|
||||
struct link *plink;
|
||||
struct msgXact *pmsgXact;
|
||||
};
|
||||
typedef struct msgDrvGenXParm msgDrvGenXParm;
|
||||
|
||||
struct msgDrvGenHParm {
|
||||
struct msgParmBlock *pparmBlock;
|
||||
struct link *plink;
|
||||
struct msgHwpvt *pmsgHwpvt;
|
||||
};
|
||||
typedef struct msgDrvGenHParm msgDrvGenHParm;
|
||||
|
||||
struct msgDrvGenLParm {
|
||||
struct msgLink *pmsgLink;
|
||||
struct link *plink;
|
||||
int op;
|
||||
struct msgParmBlock *pparmBlock;
|
||||
};
|
||||
typedef struct msgDrvGenLParm msgDrvGenLParm;
|
||||
|
||||
struct msgChkEParm {
|
||||
struct msgDrvBlock *pdrvBlock;
|
||||
struct msgLink *pmsgLink;
|
||||
struct msgXact **pxact;
|
||||
};
|
||||
typedef struct msgChkEParm msgChkEParm;
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Each DSET ppoints to a msgRecEnum structure. This structure defines the
|
||||
* type of record the dset represents. The idea here is that the address
|
||||
* of this structure represents the enumeration value for a given record type.
|
||||
*
|
||||
* New record types may be added by the application developer
|
||||
* by defining a msgRecEnum structure and then using its address in the
|
||||
* DSET for the new record type.
|
||||
*
|
||||
* In the future it is intended that this structure be used to describe
|
||||
* the locations and types of the I/O sensitive fields within a record.
|
||||
*
|
||||
******************************************************************************/
|
||||
struct msgRecEnum{
|
||||
char recType[20]; /* Holds string describing record type */
|
||||
};
|
||||
typedef struct msgRecEnum msgRecEnum;
|
||||
|
||||
extern msgRecEnum drvMsgAi;
|
||||
extern msgRecEnum drvMsgAo;
|
||||
extern msgRecEnum drvMsgBi;
|
||||
extern msgRecEnum drvMsgBo;
|
||||
extern msgRecEnum drvMsgMi;
|
||||
extern msgRecEnum drvMsgMo;
|
||||
extern msgRecEnum drvMsgLi;
|
||||
extern msgRecEnum drvMsgLo;
|
||||
extern msgRecEnum drvMsgSi;
|
||||
extern msgRecEnum drvMsgSo;
|
||||
extern msgRecEnum drvMsgWf;
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* This is a modified DSET that is used by device support modules that use
|
||||
* the message driver's services. It starts the same as a regular DSET, and
|
||||
* then includes 2 extra pointers. One to the parmBlock structure for the
|
||||
* device type being defined. And one that points to the record-type
|
||||
* enumeration structure.
|
||||
*
|
||||
******************************************************************************/
|
||||
struct msgDset{
|
||||
long number;
|
||||
DEVSUPFUN funPtr[10];
|
||||
msgParmBlock *pparmBlock;
|
||||
msgRecEnum *precEnum;
|
||||
};
|
||||
typedef struct msgDset msgDset;
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* This represents the parameters that are passed to the raw read and raw
|
||||
* write physical device drivers when data is to be transferred.
|
||||
*
|
||||
* It is assumed that the 'len' values found in the following structures
|
||||
* is the number of valid characters to transfer. There is always a '\0'
|
||||
* added to the ens of this buffer, so the actual buffer size must be at
|
||||
* least len+1 bytes long.
|
||||
*
|
||||
******************************************************************************/
|
||||
typedef struct {
|
||||
char *buf; /* Buffer to hold the data bytes */
|
||||
int len; /* Max number of bytes to read/write */
|
||||
int actual; /* actual number of bytes transfered */
|
||||
} msgStrParm;
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* The following are the parameters that are passed to the record-specific
|
||||
* conversion functions. These functions are provided by the message driver
|
||||
* for convenience only. They are only invoked if the command table contains
|
||||
* the proper op-codes and/or if the user-supplied code calls them.
|
||||
*
|
||||
******************************************************************************/
|
||||
typedef struct {
|
||||
char *format; /* Format string for the sprintf function */
|
||||
} msgFoParm;
|
||||
|
||||
typedef struct {
|
||||
char *format; /* Format string for the sscanf function */
|
||||
int startLoc; /* where to start scanning the input string from */
|
||||
int len; /* Max number of bytes to read in */
|
||||
} msgFiParm;
|
||||
|
||||
typedef struct {
|
||||
char *str; /* value to compare response against */
|
||||
int index; /* index to start location of comparison */
|
||||
int len; /* max number of chars to read from device */
|
||||
} msgAkParm;
|
||||
|
||||
typedef struct {
|
||||
char *str; /* string to compare */
|
||||
int index; /* character position to start comparison */
|
||||
int len; /* max bytes to read from device */
|
||||
} msgSBIParm;
|
||||
|
||||
#endif
|
||||
@@ -1,541 +0,0 @@
|
||||
/* base/src/drv $Id$ */
|
||||
/*
|
||||
* Author: John Winans
|
||||
* Date: 04-13-92
|
||||
* EPICS R/S-232 driver for the VxWorks's tty driver
|
||||
*
|
||||
* Experimental Physics and Industrial Control System (EPICS)
|
||||
*
|
||||
* Copyright 1991, the Regents of the University of California,
|
||||
* and the University of Chicago Board of Governors.
|
||||
*
|
||||
* This software was produced under U.S. Government contracts:
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
|
||||
* and (W-31-109-ENG-38) at Argonne National Laboratory.
|
||||
*
|
||||
* Initial development by:
|
||||
* The Controls and Automation Group (AT-8)
|
||||
* Ground Test Accelerator
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Co-developed with
|
||||
* The Controls and Computing Group
|
||||
* Accelerator Systems Division
|
||||
* Advanced Photon Source
|
||||
* Argonne National Laboratory
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .01 09-30-91 jrw created
|
||||
*
|
||||
*/
|
||||
|
||||
#define DRVRS232_C
|
||||
|
||||
#include <vxWorks.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <dbDefs.h>
|
||||
#include <epicsPrint.h>
|
||||
#include <task_params.h>
|
||||
#include <module_types.h>
|
||||
#include <drvSup.h>
|
||||
#include <devSup.h>
|
||||
#include <dbCommon.h>
|
||||
#include <dbAccess.h>
|
||||
#include <link.h>
|
||||
#include <callback.h>
|
||||
#include <fast_lock.h>
|
||||
|
||||
#include <drvMsg.h>
|
||||
#include <drvRs232.h>
|
||||
#include <drvTy232.h>
|
||||
|
||||
int drv232Debug = 0;
|
||||
|
||||
static void callbackAbortSerial();
|
||||
static void dogAbortSerial();
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
******************************************************************************/
|
||||
#define RSLINK_PRI 50
|
||||
#define RSLINK_OPT VX_FP_TASK|VX_STDIO
|
||||
#define RSLINK_STACK 5000
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
******************************************************************************/
|
||||
static long
|
||||
report()
|
||||
{
|
||||
printf("Report for RS-232 driver\n");
|
||||
return(OK);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
******************************************************************************/
|
||||
static long
|
||||
init(pparms)
|
||||
msgDrvIniParm *pparms;
|
||||
{
|
||||
if (drv232Debug)
|
||||
printf("Init for RS-232 driver\n");
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* This function is called to allocate any structures needed to hold
|
||||
* device-specific data that is added to the msgXact structure.
|
||||
*
|
||||
* It is also responsible for filling in the msgXact.phwpvt pointer.
|
||||
*
|
||||
******************************************************************************/
|
||||
static long
|
||||
genXact(p)
|
||||
msgDrvGenXParm *p;
|
||||
{
|
||||
long stat = -1;
|
||||
char message[100];
|
||||
devTy232Link *pdevTy232Link;
|
||||
|
||||
if (drv232Debug)
|
||||
printf("RS-232 genXact entered for link %d, addr %d, parm %s\n", p->plink->value.gpibio.link, p->plink->value.gpibio.addr, p->plink->value.gpibio.parm);
|
||||
|
||||
p->pmsgXact->phwpvt = p->pmsgXact->pparmBlock->pmsgHwpvt;
|
||||
|
||||
|
||||
while ((p->pmsgXact->phwpvt != NULL) && (stat == -1))
|
||||
{
|
||||
pdevTy232Link = (devTy232Link *)(p->pmsgXact->phwpvt->pmsgLink->p);
|
||||
|
||||
if ((pdevTy232Link->link == p->plink->value.gpibio.link)
|
||||
&& (pdevTy232Link->port == p->plink->value.gpibio.addr))
|
||||
{
|
||||
if (pdevTy232Link->pparmBlock != p->pmsgXact->pparmBlock)
|
||||
{
|
||||
sprintf(message, "%s: Two different devices on same RS-232 port\n", p->pmsgXact->prec->name);
|
||||
errMessage(S_db_badField, message);
|
||||
return(ERROR);
|
||||
}
|
||||
else
|
||||
stat = 0; /* Found the correct hwpvt structure */
|
||||
}
|
||||
else
|
||||
p->pmsgXact->phwpvt = p->pmsgXact->phwpvt->next;
|
||||
}
|
||||
if (stat != 0)
|
||||
{ /* Could not find a msgHwpvt for the right link, create a new one */
|
||||
if ((p->pmsgXact->phwpvt = drvMsg_genHwpvt(p->pmsgXact->pparmBlock, p->plink)) == NULL)
|
||||
return(ERROR);
|
||||
}
|
||||
p->pmsgXact->callback.callback = NULL;
|
||||
p->pmsgXact->psyncSem = NULL;
|
||||
if (sscanf(p->plink->value.gpibio.parm,"%d", &(p->pmsgXact->parm)) != 1)
|
||||
{
|
||||
p->pmsgXact->prec->pact = TRUE;
|
||||
sprintf("%s: invalid parameter string >%s<\n", p->pmsgXact->prec->name, p->plink->value.gpibio.parm);
|
||||
errMessage(S_db_badField, message);
|
||||
return(ERROR);
|
||||
}
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* This function is called to allocate any structures needed to hold
|
||||
* device-specific data that is added to the msgHwpvt structure.
|
||||
*
|
||||
* It is also responsible for filling in the msgHwpvt.pmsgLink pointer.
|
||||
*
|
||||
******************************************************************************/
|
||||
static long
|
||||
genHwpvt(p)
|
||||
msgDrvGenHParm *p;
|
||||
{
|
||||
int stat = ERROR;
|
||||
|
||||
if (drv232Debug)
|
||||
printf("rs232-genHwpvt entered\n");
|
||||
|
||||
p->pmsgHwpvt->pmsgLink = drv232Block.pmsgLink;
|
||||
while ((p->pmsgHwpvt->pmsgLink != NULL) && (stat == ERROR))
|
||||
{
|
||||
if ((((devTy232Link *)(p->pmsgHwpvt->pmsgLink->p))->link == p->plink->value.gpibio.link)
|
||||
&& (((devTy232Link *)(p->pmsgHwpvt->pmsgLink->p))->port == p->plink->value.gpibio.addr))
|
||||
stat = OK;
|
||||
else
|
||||
p->pmsgHwpvt->pmsgLink = p->pmsgHwpvt->pmsgLink->next;
|
||||
}
|
||||
if (stat != OK)
|
||||
{
|
||||
if ((p->pmsgHwpvt->pmsgLink = drvMsg_genLink(p->pparmBlock, p->plink)) == NULL)
|
||||
return(ERROR);
|
||||
}
|
||||
return(OK);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* This function is called to allocate any structures needed to hold
|
||||
* device-specific data that is added to the msgLink structure.
|
||||
*
|
||||
******************************************************************************/
|
||||
static long
|
||||
genLink(p)
|
||||
msgDrvGenLParm *p;
|
||||
{
|
||||
char name[20];
|
||||
char message[100];
|
||||
devTy232Link *pdevTy232Link;
|
||||
|
||||
if (drv232Debug)
|
||||
printf("In RS-232's genLink, link = %d, addr = %d\n", p->plink->value.gpibio.link,p->plink->value.gpibio.addr);
|
||||
|
||||
switch (p->op) {
|
||||
case MSG_GENLINK_CREATE:
|
||||
|
||||
if ((p->pmsgLink->p = malloc(sizeof(devTy232Link))) == NULL)
|
||||
return(ERROR);
|
||||
|
||||
pdevTy232Link = (devTy232Link *)(p->pmsgLink->p);
|
||||
|
||||
pdevTy232Link->link = p->plink->value.gpibio.link;
|
||||
pdevTy232Link->port = p->plink->value.gpibio.addr;
|
||||
pdevTy232Link->pparmBlock = p->pparmBlock;
|
||||
|
||||
if ((pdevTy232Link->doggie = wdCreate()) == NULL)
|
||||
{
|
||||
printf("RS-232 driver can't create a watchdog\n");
|
||||
/* errMessage(******, message); */
|
||||
return(ERROR);
|
||||
}
|
||||
|
||||
sprintf(name, "/tyCo/%d", p->plink->value.gpibio.addr);
|
||||
|
||||
if (drv232Debug)
|
||||
printf ("in genlink opening >%s<, baud %d\n", name, ((devTy232ParmBlock *)(p->pparmBlock->p))->baud);
|
||||
|
||||
if ((((devTy232Link *)(p->pmsgLink->p))->ttyFd = open(name, O_RDWR, 0)) != -1)
|
||||
{
|
||||
if (drv232Debug)
|
||||
printf("Successful open w/fd=%d\n", pdevTy232Link->ttyFd);
|
||||
|
||||
/* set baud rate and unbuffered mode */
|
||||
(void) ioctl (pdevTy232Link->ttyFd, FIOBAUDRATE, ((devTy232ParmBlock *)(p->pparmBlock->p))->baud);
|
||||
(void) ioctl (pdevTy232Link->ttyFd, FIOSETOPTIONS, ((devTy232ParmBlock *)(p->pparmBlock->p))->ttyOptions);
|
||||
|
||||
pdevTy232Link->callback.callback = callbackAbortSerial;
|
||||
pdevTy232Link->callback.priority = priorityHigh;
|
||||
pdevTy232Link->callback.user = (void *) pdevTy232Link;
|
||||
|
||||
return(OK);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("RS-232 genLink failed to open the tty port\n");
|
||||
free(p->pmsgLink->p);
|
||||
return(ERROR);
|
||||
}
|
||||
|
||||
case MSG_GENLINK_ABORT:
|
||||
if (drv232Debug)
|
||||
printf("RS-232 genLink called with abort status\n");
|
||||
|
||||
pdevTy232Link = (devTy232Link *)(p->pmsgLink->p);
|
||||
/* free(p->pmsgLink->p); Don't forget to take it out of the list */
|
||||
return(OK);
|
||||
}
|
||||
return(ERROR);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* This function is called to allow the device to indicate that a device-related
|
||||
* event has occurred. If an event had occurred, it would have to place the
|
||||
* address of a valid transaction structure in pxact. This xact structure
|
||||
* will then be processed by the message link task as indicated by the
|
||||
* return code of this function.
|
||||
*
|
||||
* MSG_EVENT_NONE = no event has occurred, pxact not filled in.
|
||||
* MSG_EVENT_WRITE = event occurred, process the writeOp assoc'd w/pxact.
|
||||
* MSG_EVENT_READ = event occurred, process the readOp assoc'd w/pxact.
|
||||
*
|
||||
* Note that MSG_EVENT_READ only makes sense when returned with a transaction
|
||||
* that has deferred readback specified for its readOp function. Because if
|
||||
* it is NOT a deferred readback, it will be done immediately after the writeOp.
|
||||
* Even if that writeOp was due to a MSG_EVENT_WRITE from this function.
|
||||
*
|
||||
******************************************************************************/
|
||||
static long
|
||||
checkEvent(p)
|
||||
msgChkEParm *p;
|
||||
{
|
||||
return(MSG_EVENT_NONE);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
dogAbortSerial(pdevTy232Link)
|
||||
devTy232Link *pdevTy232Link;
|
||||
{
|
||||
logMsg("RS-232 driver watch-dog timeout on link %d, port %d, fd=%d\n", pdevTy232Link->link, pdevTy232Link->port, pdevTy232Link->ttyFd);
|
||||
|
||||
/* Annoying vxWorks implementation... can't IOCTL from here */
|
||||
callbackRequest(&(pdevTy232Link->callback));
|
||||
}
|
||||
|
||||
static void
|
||||
callbackAbortSerial(p)
|
||||
CALLBACK *p;
|
||||
{
|
||||
((devTy232Link *)(p->user))->dogAbort = TRUE;
|
||||
|
||||
ioctl(((devTy232Link *)(p->user))->ttyFd, FIOCANCEL);
|
||||
/* I am not sure if I should really do this, but... */
|
||||
ioctl(((devTy232Link *)(p->user))->ttyFd, FIOFLUSH);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* This function is used to write a string of characters out to an RS-232
|
||||
* device.
|
||||
*
|
||||
******************************************************************************/
|
||||
static long
|
||||
drvWrite(pxact, pwrParm)
|
||||
msgXact *pxact;
|
||||
msgStrParm *pwrParm;
|
||||
{
|
||||
devTy232Link *pdevTy232Link = (devTy232Link *)(pxact->phwpvt->pmsgLink->p);
|
||||
int len;
|
||||
char *out;
|
||||
char in;
|
||||
|
||||
if (wdStart(pdevTy232Link->doggie, ((devTy232ParmBlock *)(pxact->pparmBlock->p))->dmaTimeout, dogAbortSerial, pdevTy232Link) == ERROR)
|
||||
{
|
||||
printf("RS-232 driver can not start watchdog timer\n");
|
||||
/* errMessage(***,message); */
|
||||
pxact->status = XACT_IOERR;
|
||||
return(pxact->status);
|
||||
}
|
||||
|
||||
if (((devTy232ParmBlock *)(pxact->pparmBlock->p))->flags & ECHO)
|
||||
{ /* ping-pong the characters out */
|
||||
|
||||
/*BUG ??? This will only work if we are sure that the RX buffer is clean */
|
||||
ioctl(pdevTy232Link->ttyFd, FIORFLUSH);
|
||||
|
||||
out = pwrParm->buf;
|
||||
while ((*out != '\0') && (pxact->status == XACT_OK))
|
||||
{
|
||||
if (drv232Debug > 5)
|
||||
printf("out >%c<\n", *out);
|
||||
if (write(pdevTy232Link->ttyFd, out, 1) != 1)
|
||||
{
|
||||
printf("RS-232 write error on link %d, port %d\n", pdevTy232Link->link, pdevTy232Link->port);
|
||||
pxact->status = XACT_IOERR;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (read(pdevTy232Link->ttyFd, &in, 1) != 1)
|
||||
{
|
||||
printf("Read problem encountered in echo reading mode of a write operation\n");
|
||||
if (pdevTy232Link->dogAbort)
|
||||
pxact->status = XACT_TIMEOUT;
|
||||
else
|
||||
pxact->status = XACT_IOERR;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (*out != in)
|
||||
printf("echo response out of sync! sent >%c< got >%c<\n", *out, in);
|
||||
|
||||
if (drv232Debug > 5)
|
||||
printf("in >%c<\n", in);
|
||||
|
||||
if ((*out == '\r') && (((devTy232ParmBlock *)(pxact->pparmBlock->p))->flags & CRLF))
|
||||
{
|
||||
if (read(pdevTy232Link->ttyFd, &in, 1) != 1)
|
||||
{
|
||||
printf("Read problem encountered in echo reading mode of a write operation\n");
|
||||
if (pdevTy232Link->dogAbort)
|
||||
pxact->status = XACT_TIMEOUT;
|
||||
else
|
||||
pxact->status = XACT_IOERR;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (drv232Debug > 5)
|
||||
printf("in >%c<\n", in);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
out++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pwrParm->len == -1)
|
||||
len = strlen(pwrParm->buf);
|
||||
else
|
||||
len = pwrParm->len;
|
||||
|
||||
if (drv232Debug > 4)
|
||||
printf("block-writing >%s<\n", pwrParm->buf);
|
||||
|
||||
if (write(pdevTy232Link->ttyFd, pwrParm->buf, len) != len)
|
||||
{
|
||||
printf("RS-232 write error on link %d, port %d\n", pdevTy232Link->link, pdevTy232Link->port);
|
||||
pxact->status = XACT_IOERR;
|
||||
}
|
||||
}
|
||||
if (wdCancel(pdevTy232Link->doggie) == ERROR)
|
||||
printf("Can not cancel RS-232 watchdog timer\n");
|
||||
|
||||
return(pxact->status);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* This function is used to read a string of characters from an RS-232 device.
|
||||
*
|
||||
******************************************************************************/
|
||||
static long
|
||||
drvRead(pxact, prdParm)
|
||||
msgXact *pxact;
|
||||
msgStrParm *prdParm;
|
||||
{
|
||||
devTy232Link *pdevTy232Link = (devTy232Link *)(pxact->phwpvt->pmsgLink->p);
|
||||
int len;
|
||||
int clen;
|
||||
char *ch;
|
||||
int flags;
|
||||
int eoi;
|
||||
devTy232ParmBlock *pdevTy232ParmBlock = (devTy232ParmBlock *)(pxact->pparmBlock->p);
|
||||
|
||||
pdevTy232Link->dogAbort = FALSE;
|
||||
if (wdStart(pdevTy232Link->doggie, pdevTy232ParmBlock->dmaTimeout, dogAbortSerial, pdevTy232Link) == ERROR)
|
||||
{
|
||||
printf("RS-232 driver can not start watchdog timer\n");
|
||||
/* errMessage(***,message); */
|
||||
pxact->status = XACT_IOERR;
|
||||
return(pxact->status);
|
||||
}
|
||||
|
||||
ch = prdParm->buf;
|
||||
len = prdParm->len - 1;
|
||||
|
||||
flags = pdevTy232ParmBlock->flags;
|
||||
/* BUG -- This should have a timeout check specified in here */
|
||||
if ((pdevTy232ParmBlock->eoi != -1) || (flags & KILL_CRLF))
|
||||
{
|
||||
eoi = 0;
|
||||
while ((!eoi) && (len > 0))
|
||||
{
|
||||
if (read(pdevTy232Link->ttyFd, ch, 1) != 1)
|
||||
{
|
||||
printf("Read problem encountered in eoi/KILL_CRLF reading mode\n");
|
||||
if (pdevTy232Link->dogAbort)
|
||||
pxact->status = XACT_TIMEOUT;
|
||||
else
|
||||
pxact->status = XACT_IOERR;
|
||||
eoi = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (drv232Debug > 6)
|
||||
printf("in >%c<\n", *ch);
|
||||
|
||||
if (*ch == pdevTy232ParmBlock->eoi)
|
||||
eoi = 1;
|
||||
|
||||
if (!(flags & KILL_CRLF) || ((*ch != '\n') && (*ch != '\r')))
|
||||
{
|
||||
ch++;
|
||||
len--; /* To count the \n's and \r's or not to count... */
|
||||
}
|
||||
}
|
||||
}
|
||||
if (len == 0)
|
||||
{
|
||||
printf("buffer length overrun during read operation\n");
|
||||
pxact->status = XACT_LENGTH;
|
||||
}
|
||||
|
||||
*ch = '\0';
|
||||
}
|
||||
else
|
||||
{ /* Read xact->rxLen bytes from the device */
|
||||
while(len)
|
||||
{
|
||||
clen = read(pdevTy232Link->ttyFd, ch, len);
|
||||
if (pdevTy232Link->dogAbort)
|
||||
{
|
||||
printf("Read problem encountered in raw mode\n");
|
||||
pxact->status = XACT_TIMEOUT;
|
||||
len = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
len -= clen;
|
||||
ch += clen;
|
||||
}
|
||||
}
|
||||
*ch = '\0';
|
||||
}
|
||||
if (drv232Debug)
|
||||
printf("drvRead: got >%s<\n", prdParm->buf);
|
||||
|
||||
if (wdCancel(pdevTy232Link->doggie) == ERROR)
|
||||
printf("Can not cancel RS-232 watchdog timer, dogAbort=%d \n", pdevTy232Link->dogAbort);
|
||||
|
||||
return(pxact->status);
|
||||
}
|
||||
|
||||
static long
|
||||
drvIoctl(cmd, pparm)
|
||||
int cmd;
|
||||
void *pparm;
|
||||
{
|
||||
switch (cmd) {
|
||||
case MSGIOCTL_REPORT:
|
||||
return(report());
|
||||
case MSGIOCTL_INIT:
|
||||
return(init(pparm));
|
||||
case MSGIOCTL_INITREC:
|
||||
printf("drv232Block.drvIoctl got a MSGIOCTL_INITREC request!\n");
|
||||
return(ERROR);
|
||||
case MSGIOCTL_GENXACT:
|
||||
return(genXact(pparm));
|
||||
case MSGIOCTL_GENHWPVT:
|
||||
return(genHwpvt(pparm));
|
||||
case MSGIOCTL_GENLINK:
|
||||
return(genLink(pparm));
|
||||
case MSGIOCTL_CHECKEVENT:
|
||||
return(checkEvent(pparm));
|
||||
case MSGIOCTL_COMMAND: /* BUG -- finish this routine! */
|
||||
return(ERROR);
|
||||
}
|
||||
return(ERROR);
|
||||
}
|
||||
|
||||
|
||||
msgDrvBlock drv232Block = {
|
||||
"RS232",
|
||||
RSLINK_PRI,
|
||||
RSLINK_OPT,
|
||||
RSLINK_STACK,
|
||||
NULL,
|
||||
drvWrite,
|
||||
drvRead,
|
||||
drvIoctl
|
||||
};
|
||||
@@ -1,51 +0,0 @@
|
||||
/* share/epicsH $Id$ */
|
||||
/*
|
||||
* Author: John Winans
|
||||
* Date: 04-16-92
|
||||
*
|
||||
* Experimental Physics and Industrial Control System (EPICS)
|
||||
*
|
||||
* Copyright 1988, 1989, the Regents of the University of California,
|
||||
* and the University of Chicago Board of Governors.
|
||||
*
|
||||
* This software was produced under U.S. Government contracts:
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
|
||||
* and (W-31-109-ENG-38) at Argonne National Laboratory.
|
||||
*
|
||||
* Initial development by:
|
||||
* The Controls and Automation Group (AT-8)
|
||||
* Ground Test Accelerator
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Co-developed with
|
||||
* The Controls and Computing Group
|
||||
* Accelerator Systems Division
|
||||
* Advanced Photon Source
|
||||
* Argonne National Laboratory
|
||||
*
|
||||
* All rights reserved. No part of this publication may be reproduced,
|
||||
* stored in a retrieval system, transmitted, in any form or by any
|
||||
* means, electronic, mechanical, photocopying, recording, or otherwise
|
||||
* without prior written permission of Los Alamos National Laboratory
|
||||
* and Argonne National Laboratory.
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .01 04-16-92 jrw Initial release
|
||||
* .02 07-04-92 jrw Moved tty-specific stuff to devTy232.h
|
||||
*
|
||||
* This file contains the common parts of the RS-232 device support info.
|
||||
*/
|
||||
|
||||
#ifndef EPICS_DRVRS232_H
|
||||
#define EPICS_DRVRS232_H
|
||||
|
||||
typedef struct {
|
||||
int cmd;
|
||||
void *pparm;
|
||||
} ioctlCommand;
|
||||
|
||||
#define IOCTL232_BREAK 1
|
||||
|
||||
#endif
|
||||
@@ -1,77 +0,0 @@
|
||||
/* share/epicsH $Id$ */
|
||||
/*
|
||||
* Author: John Winans
|
||||
* Date: 04-16-92
|
||||
*
|
||||
* Experimental Physics and Industrial Control System (EPICS)
|
||||
*
|
||||
* Copyright 1988, 1989, the Regents of the University of California,
|
||||
* and the University of Chicago Board of Governors.
|
||||
*
|
||||
* This software was produced under U.S. Government contracts:
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
|
||||
* and (W-31-109-ENG-38) at Argonne National Laboratory.
|
||||
*
|
||||
* Initial development by:
|
||||
* The Controls and Automation Group (AT-8)
|
||||
* Ground Test Accelerator
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Co-developed with
|
||||
* The Controls and Computing Group
|
||||
* Accelerator Systems Division
|
||||
* Advanced Photon Source
|
||||
* Argonne National Laboratory
|
||||
*
|
||||
* All rights reserved. No part of this publication may be reproduced,
|
||||
* stored in a retrieval system, transmitted, in any form or by any
|
||||
* means, electronic, mechanical, photocopying, recording, or otherwise
|
||||
* without prior written permission of Los Alamos National Laboratory
|
||||
* and Argonne National Laboratory.
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .01 04-16-92 jrw Initial release
|
||||
*/
|
||||
|
||||
#ifndef EPICS_DEVTY232_H
|
||||
#define EPICS_DEVTY232_H
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Additional fields needed for the msgParmBlock structure.
|
||||
*
|
||||
******************************************************************************/
|
||||
typedef struct {
|
||||
int timeWindow; /* Clock ticks to skip after a timeout */
|
||||
int dmaTimeout; /* Clock ticks to wait for DMA to complete */
|
||||
int flags; /* set to FALSE if does NOT echo characters */
|
||||
int eoi; /* eoi char value or -1 if none */
|
||||
int baud; /* baud rate to run the interface */
|
||||
int ttyOptions; /* ioctl options for the serial port */
|
||||
} devTy232ParmBlock;
|
||||
|
||||
#define ECHO 1 /* Device echos characters sent to it */
|
||||
/* The CRLF option is only valid when ECHO is set */
|
||||
#define CRLF 2 /* Device does CR -> CR LF expansion */
|
||||
#define KILL_CRLF 4 /* Remove all CR and LF characters from input */
|
||||
|
||||
typedef struct {
|
||||
CALLBACK callback; /* Used to do the ioctl when the dog wakes up */
|
||||
WDOG_ID doggie; /* For I/O timing */
|
||||
int dogAbort; /* Used to flag a timeout */
|
||||
int link; /* The tty card/link number */
|
||||
int port; /* The tty port number on that card */
|
||||
int ttyFd; /* The open file descriptor */
|
||||
/* The pparmBlock is used to make sure only 1 device type is requested */
|
||||
/* on one single port. */
|
||||
msgParmBlock *pparmBlock;
|
||||
} devTy232Link;
|
||||
|
||||
#ifndef DRVTY232_C
|
||||
extern
|
||||
#endif
|
||||
msgDrvBlock drv232Block;
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user