unbundled

This commit is contained in:
Marty Kraimer
1999-12-09 21:54:03 +00:00
parent d83d6bc033
commit 2183d4bc98
12 changed files with 0 additions and 6614 deletions

View File

@@ -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);
}

View File

@@ -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

File diff suppressed because it is too large Load Diff

View File

@@ -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*/

View File

@@ -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 */
};

View File

@@ -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

View File

@@ -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 */
};

File diff suppressed because it is too large Load Diff

View File

@@ -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

View File

@@ -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
};

View File

@@ -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

View File

@@ -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