- Major changes folling the rework of the connection object

- Added support for galil controllers
This commit is contained in:
koennecke
2009-02-03 08:07:30 +00:00
parent 9374bea841
commit 6c7bb14fad
29 changed files with 364 additions and 139 deletions

204
pmacprot.c Normal file
View File

@@ -0,0 +1,204 @@
/**
* This is an asynchronous protocol driver for the Delta-Tau PMAC
* series of controllers, connected via TCP/IP. The PMAC needs its
* commands in a special purpose data structure, describe below.
* As responses, it can send any of the following formats:
* data<CR>data<CR>data>CR><ACK>
* <BELL>ERRxxx<CR>
* <STX>data<CR>
* There can be multiple data and errors in a string. However, I wish to
* restrict this to processing one command at any time. This driver owes
* some insight and little code to the EPICS driver by
* Pete Leicester, Diamond.
*
* ** Before this can be used, I3=2 and I6=1 must be set on the PMAC **
*
* copyright: see file COPYRIGHT
*
* Mark Koennecke, December 2008
*/
#include <errno.h>
#include <ascon.h>
#include <ascon.i>
#include <dynstring.h>
#define ETHERNET_DATA_SIZE 1492
#define INPUT_SIZE (ETHERNET_DATA_SIZE+1) /* +1 to allow space to add terminating ACK */
#define STX '\2'
#define CTRLB '\2'
#define CTRLC '\3'
#define ACK '\6'
#define CTRLF '\6'
#define BELL '\7'
#define CTRLG '\7'
#define CTRLP '\16'
#define CTRLV '\22'
#define CTRLX '\24'
/* PMAC ethernet command structure */
#pragma pack(1)
typedef struct tagEthernetCmd
{
unsigned char RequestType;
unsigned char Request;
unsigned short wValue;
unsigned short wIndex;
unsigned short wLength; /* length of bData */
unsigned char bData[ETHERNET_DATA_SIZE];
} ethernetCmd;
#pragma pack()
#define ETHERNET_CMD_HEADER ( sizeof(ethernetCmd) - ETHERNET_DATA_SIZE )
/* PMAC ethernet commands - RequestType field */
#define VR_UPLOAD 0xC0
#define VR_DOWNLOAD 0x40
/* PMAC ethernet commands - Request field */
#define VR_PMAC_SENDLINE 0xB0
#define VR_PMAC_GETLINE 0xB1
#define VR_PMAC_FLUSH 0xB3
#define VR_PMAC_GETMEM 0xB4
#define VR_PMAC_SETMEN 0xB5
#define VR_PMAC_SETBIT 0xBA
#define VR_PMAC_SETBITS 0xBB
#define VR_PMAC_PORT 0xBE
#define VR_PMAC_GETRESPONSE 0xBF
#define VR_PMAC_READREADY 0xC2
#define VR_CTRL_RESPONSE 0xC4
#define VR_PMAC_GETBUFFER 0xC5
#define VR_PMAC_WRITEBUFFER 0xC6
#define VR_PMAC_WRITEERROR 0xC7
#define VR_FWDOWNLOAD 0xCB
#define VR_IPADDRESS 0xE0
/*---------------------------------------------------------------------------
* a private data structurli to keep track of the PMAC
*---------------------------------------------------------------------------*/
typedef struct {
ethernetCmd cmd;
char *ptr;
int bytesToWrite;
int expectACK;
}PMACPrivate, *pPMACPrivate;
/*---------------------------------------------------------------------------*/
static int PMACHandler(Ascon *a){
char *data = NULL;
int ret, l;
char chr;
pPMACPrivate priv = NULL;
priv = a->private;
switch(a->state){
case AsconWriteStart:
data = GetCharArray(a->wrBuffer);
memset(priv,0,sizeof(PMACPrivate));
priv->cmd.RequestType = VR_DOWNLOAD;
priv->cmd.Request = VR_PMAC_GETRESPONSE;
priv->cmd.wValue = 0;
priv->cmd.wIndex = 0;
priv->cmd.wLength = htons(strlen(data)); /* may be one more */
priv->bytesToWrite = strlen(data) + 1 + ETHERNET_CMD_HEADER;
strcpy((char *)priv->cmd.bData,data);
priv->expectACK = 1;
priv->ptr = (char *)&priv->cmd;
a->state = AsconWriting;
a->wrPos = 0;
break;
case AsconWriting:
AsconReadGarbage(a->fd);
l = priv->bytesToWrite - a->wrPos;
ret = AsconWriteChars(a->fd, priv->ptr, l);
if (ret < 0) {
if(errno != EINTR && errno != EAGAIN){
AsconError(a, "send failed:", errno);
}
/*
* Ooops: which state shall we go to after a write fail?
* This seems to retry.
*/
} else {
a->wrPos += ret;
if (a->wrPos >= priv->bytesToWrite) {
a->state = AsconWriteDone;
} else {
priv->ptr += ret;
}
}
break;
case AsconReading:
ret = AsconReadChar(a->fd, &chr);
if(ret < 0){
/* EINTR means we must retry */
if(errno != EINTR && errno != EAGAIN){
AsconError(a, "AsconReadChar failed:", errno);
}
return 1;
} else if (ret > 0) {
a->start = DoubleTime();
if(chr == STX || chr == BELL){
priv->expectACK = 0;
return 1;
}
if(priv->expectACK && chr == ACK){
if(GetDynStringLength(a->rdBuffer) == 0){
DynStringConcat(a->rdBuffer,"ACK");
}
DynStringConcatChar(a->rdBuffer, '\0');
a->state = AsconReadDone;
break;
}
if(priv->expectACK == 0 && chr == '\r'){
DynStringConcatChar(a->rdBuffer, '\0');
a->state = AsconReadDone;
break;
}
if (DynStringConcatChar(a->rdBuffer, chr) == 0) {
AsconError(a, "DynStringConcatChar failed:", ENOMEM);
break;
}
} else if(ret == 0){
if (a->timeout > 0) {
if (DoubleTime() - a->start > a->timeout) {
AsconError(a, "read timeout", 0);
a->state = AsconTimeout;
}
}
}
break;
default:
return AsconStdHandler(a);
}
return 1;
}
/*------------------------------------------------------------------------*/
static int PMACInit(Ascon *a, SConnection *con,
int argc, char *argv[]) {
pPMACPrivate priv = NULL;
priv = calloc(sizeof(PMACPrivate), 1);
a->fd = -1;
a->state = AsconConnectStart;
a->reconnectInterval = 10;
a->hostport = strdup(argv[1]);
if(argc > 2){
a->timeout = atof(argv[2]);
} else {
a->timeout = 2.0; /* sec */
}
a->private = priv;
a->killPrivate = free;
return 1;
}
/*------------------------------------------------------------------------*/
void AddPMACProtocoll(){
AsconProtocol *prot = NULL;
prot = calloc(sizeof(AsconProtocol), 1);
prot->name = strdup("pmac");
prot->init = PMACInit;
prot->handler = PMACHandler;
AsconInsertProtocol(prot);
}