- Rearranged directory structure for forking out ANSTO
- Refactored site specific stuff into a site module - PSI specific stuff is now in the PSI directory. - The old version has been tagged with pre-ansto
This commit is contained in:
496
ecb.c
Normal file
496
ecb.c
Normal file
@ -0,0 +1,496 @@
|
||||
/*-----------------------------------------------------------------------
|
||||
The ECB is a rack controller from Risoe based on a Z80 processor.
|
||||
This module provides some functions for communicating with such a
|
||||
device. This is the implementation file.
|
||||
|
||||
WARNING: This contains code which may be endian dependent!
|
||||
|
||||
copyright: see file COPYRIGHT
|
||||
|
||||
Mark Koennecke, January 2002, with some bits taken from the original
|
||||
tascom code.
|
||||
-------------------------------------------------------------------------*/
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <tcl.h>
|
||||
#include <unistd.h>
|
||||
#include "fortify.h"
|
||||
#include "sics.h"
|
||||
#include "ecb.h"
|
||||
#include "ecb.i"
|
||||
/*------------- private defines and error codes ------------------------*/
|
||||
#define ACKN ('\6') /* Acknowledge character */
|
||||
#define READ_BYTES 3
|
||||
#define WRITE_BYTES 4
|
||||
#define DMAREAD 5
|
||||
#define ECB_BYTES 65536L
|
||||
|
||||
typedef union /* Used to swap bytes in 'address' and 'byte_count' */
|
||||
{
|
||||
unsigned short word;
|
||||
struct
|
||||
{
|
||||
unsigned char msb; /* Most significant byte */
|
||||
unsigned char lsb; /* Least significant byte */
|
||||
}b;
|
||||
}Swap;
|
||||
/* ------- error codes */
|
||||
#define ECBILLEGALFUNC -100
|
||||
#define ECBOVERFLOW -101
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
static int ecbSendFunc(pECB self, int func){
|
||||
unsigned char function, response;
|
||||
int count, status;
|
||||
|
||||
/*
|
||||
send function code
|
||||
*/
|
||||
function = (unsigned char)func;
|
||||
count = 1;
|
||||
status = GPIBsend(self->gpib,self->ecbDeviceID,&function,count);
|
||||
if(status < 0){
|
||||
self->lastError = status;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
read acknowledge byte
|
||||
*/
|
||||
status = GPIBread(self->gpib,self->ecbDeviceID,&response,count);
|
||||
if(status < 0){
|
||||
self->lastError = status;
|
||||
return 0;
|
||||
}
|
||||
if(response != ACKN){
|
||||
self->lastError = ECBILLEGALFUNC;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
/*-----------------------------------------------------------------------*/
|
||||
int ecbExecute(pECB self, int func, Z80_reg in, Z80_reg *out){
|
||||
int count, status;
|
||||
|
||||
assert(self != NULL);
|
||||
assert(self->gpib != NULL);
|
||||
self->lastError = 0;
|
||||
|
||||
/*
|
||||
send function code
|
||||
*/
|
||||
status = ecbSendFunc(self,func);
|
||||
if(status <= 0){
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
send input register
|
||||
*/
|
||||
count = 4;
|
||||
status = GPIBsend(self->gpib,self->ecbDeviceID, &in, count);
|
||||
if(status < 0){
|
||||
self->lastError = status;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
read result register
|
||||
*/
|
||||
status = GPIBread(self->gpib,self->ecbDeviceID, out, count);
|
||||
if(status < 0){
|
||||
self->lastError = status;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
/*----------------------------------------------------------------------*/
|
||||
static int ecbPrepareIO(pECB self, int func, unsigned short address,
|
||||
unsigned short byteCount){
|
||||
Swap save, adr, count;
|
||||
int status, bytes;
|
||||
|
||||
if(byteCount > ECB_BYTES){
|
||||
self->lastError = ECBOVERFLOW;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Swap address and byteCount?? This may be a portability issue!
|
||||
This may not be necessary on some platforms
|
||||
*/
|
||||
save.word = address; /* Swap address bytes */
|
||||
adr.b.lsb = save.b.msb;
|
||||
adr.b.msb = save.b.lsb;
|
||||
save.word = byteCount; /* Swap byte count bytes */
|
||||
count.b.lsb = save.b.msb;
|
||||
count.b.msb = save.b.lsb;
|
||||
|
||||
status = ecbSendFunc(self,func);
|
||||
if(status <= 0){
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
send address
|
||||
*/
|
||||
bytes = 2;
|
||||
status = GPIBsend(self->gpib,self->ecbDeviceID,&adr,bytes);
|
||||
if(status < 0){
|
||||
self->lastError = status;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
send byte count
|
||||
*/
|
||||
status = GPIBsend(self->gpib,self->ecbDeviceID,&count,bytes);
|
||||
if(status < 0){
|
||||
self->lastError = status;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
/*-----------------------------------------------------------------------*/
|
||||
int ecbRead(pECB self, unsigned short address,
|
||||
void *buffer, int byteCount){
|
||||
|
||||
int status, count;
|
||||
|
||||
assert(self != NULL);
|
||||
assert(self->gpib != NULL);
|
||||
self->lastError = 0;
|
||||
|
||||
status = ecbPrepareIO(self,READ_BYTES,address,(unsigned short)byteCount);
|
||||
if(status <= 0){
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
actual read
|
||||
*/
|
||||
status = GPIBread(self->gpib,self->ecbDeviceID, buffer, byteCount);
|
||||
if(status < 0){
|
||||
self->lastError = status;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
/*----------------------------------------------------------------------*/
|
||||
int ecbDMARead(pECB self, unsigned short address, void *buffer,
|
||||
unsigned short byteCount){
|
||||
int status, count;
|
||||
|
||||
assert(self != NULL);
|
||||
assert(self->gpib != NULL);
|
||||
self->lastError = 0;
|
||||
|
||||
status = ecbPrepareIO(self,DMAREAD,address,(unsigned short)byteCount);
|
||||
if(status <= 0){
|
||||
return 0;
|
||||
}
|
||||
|
||||
usleep(20*1000);
|
||||
|
||||
/*
|
||||
actual read
|
||||
*/
|
||||
status = GPIBread(self->gpib,self->ecbDeviceID, buffer, byteCount);
|
||||
if(status < 0){
|
||||
self->lastError = status;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
/*----------------------------------------------------------------------*/
|
||||
int ecbWrite(pECB self, unsigned short address,
|
||||
void *buffer, int byteCount){
|
||||
|
||||
int status, count;
|
||||
|
||||
assert(self != NULL);
|
||||
assert(self->gpib != NULL);
|
||||
self->lastError = 0;
|
||||
|
||||
status = ecbPrepareIO(self,WRITE_BYTES,address,(unsigned short)byteCount);
|
||||
if(status <= 0){
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
actual read
|
||||
*/
|
||||
status = GPIBsend(self->gpib,self->ecbDeviceID, buffer, byteCount);
|
||||
if(status < 0){
|
||||
self->lastError = status;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
/*-----------------------------------------------------------------------*/
|
||||
void ecbErrorDescription(pECB self, char *buffer, int maxBuffer){
|
||||
int positive;
|
||||
|
||||
switch(self->lastError){
|
||||
case ECBILLEGALFUNC:
|
||||
strncpy(buffer,"Illegal ECB function called",maxBuffer);
|
||||
return;
|
||||
case ECBOVERFLOW:
|
||||
strncpy(buffer,
|
||||
"You tried to copy more then 64K onto the poor ECB, REFUSED!",
|
||||
maxBuffer);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
GPIB error codes
|
||||
*/
|
||||
GPIBerrorDescription(self->gpib,self->lastError,buffer, maxBuffer);
|
||||
}
|
||||
/*----------------------------------------------------------------------*/
|
||||
void ecbClear(pECB self){
|
||||
GPIBclear(self->gpib, self->ecbDeviceID);
|
||||
}
|
||||
/*-----------------------------------------------------------------------*/
|
||||
int fixECBError(pECB self){
|
||||
int pos;
|
||||
|
||||
switch(self->lastError){
|
||||
case ECBILLEGALFUNC:
|
||||
case ECBOVERFLOW:
|
||||
return HWFault;
|
||||
}
|
||||
|
||||
/*
|
||||
GPIB error
|
||||
*/
|
||||
pos = -self->lastError;
|
||||
switch(pos){
|
||||
case GPIBEABO:
|
||||
return HWRedo;
|
||||
default:
|
||||
return HWFault;
|
||||
}
|
||||
}
|
||||
/*------------------------------------------------------------------------*/
|
||||
int ECBAction(SConnection *pCon, SicsInterp *pSics, void *pData,
|
||||
int argc, char *argv[]){
|
||||
pECB self = (pECB)pData;
|
||||
Z80_reg in, out;
|
||||
char pBuffer[80], pError[132];
|
||||
int status, iVal, func;
|
||||
|
||||
assert(self != NULL);
|
||||
|
||||
/*
|
||||
Only managers will be allowed to wrestle directly with ECB
|
||||
controllers.
|
||||
*/
|
||||
if(!SCinMacro(pCon)){
|
||||
if(!SCMatchRights(pCon,usMugger)){
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if(argc < 2){
|
||||
SCWrite(pCon,"ERROR: keyword required for ECB",eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
strtolower(argv[1]);
|
||||
if(strcmp(argv[1],"func") == 0){
|
||||
if(argc < 7){
|
||||
SCWrite(pCon,"ERROR: require function code and four register values",
|
||||
eError);
|
||||
return 0;
|
||||
}
|
||||
status = Tcl_GetInt(pSics->pTcl, argv[2],&func);
|
||||
if(status != TCL_OK){
|
||||
SCWrite(pCon,"ERROR: failed to convert argument to int",eError);
|
||||
return 0;
|
||||
}
|
||||
status = Tcl_GetInt(pSics->pTcl, argv[3],&iVal);
|
||||
if(status != TCL_OK){
|
||||
SCWrite(pCon,"ERROR: failed to convert argument to int",eError);
|
||||
return 0;
|
||||
}
|
||||
in.d = (unsigned char)iVal;
|
||||
status = Tcl_GetInt(pSics->pTcl, argv[4],&iVal);
|
||||
if(status != TCL_OK){
|
||||
SCWrite(pCon,"ERROR: failed to convert argument to int",eError);
|
||||
return 0;
|
||||
}
|
||||
in.e = (unsigned char)iVal;
|
||||
status = Tcl_GetInt(pSics->pTcl, argv[5],&iVal);
|
||||
if(status != TCL_OK){
|
||||
SCWrite(pCon,"ERROR: failed to convert argument to int",eError);
|
||||
return 0;
|
||||
}
|
||||
in.b = (unsigned char)iVal;
|
||||
status = Tcl_GetInt(pSics->pTcl, argv[6],&iVal);
|
||||
if(status != TCL_OK){
|
||||
SCWrite(pCon,"ERROR: failed to convert argument to int",eError);
|
||||
return 0;
|
||||
}
|
||||
in.c = (unsigned char)iVal;
|
||||
|
||||
status = ecbExecute(self,func,in,&out);
|
||||
if(status != 1){
|
||||
ecbErrorDescription(self,pBuffer,79);
|
||||
sprintf(pError,"ERROR: %s", pBuffer);
|
||||
SCWrite(pCon,pError,eError);
|
||||
return 0;
|
||||
}
|
||||
sprintf(pBuffer,"%d %d %d %d",
|
||||
out.d, out.e, out.b, out.c);
|
||||
SCWrite(pCon,pBuffer,eValue);
|
||||
return 1;
|
||||
} else if(strcmp(argv[1],"clear") == 0){
|
||||
ecbClear(self);
|
||||
SCSendOK(pCon);
|
||||
return 1;
|
||||
}else if(strcmp(argv[1],"toint")== 0){
|
||||
sprintf(pBuffer,"%d",argv[2][0]);
|
||||
SCWrite(pCon,pBuffer,eValue);
|
||||
} else {
|
||||
SCWrite(pCon,"ERROR: ECB does not understand keyword", eError);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------*/
|
||||
int ecbAssignEncoder(pECB self, int encoder, int motorNumber){
|
||||
|
||||
if(encoder <= 0 || encoder > 3){
|
||||
return 0;
|
||||
}
|
||||
|
||||
self->encoder[encoder-1] = motorNumber;
|
||||
self->encoderDirty = 1;
|
||||
return 1;
|
||||
}
|
||||
/*----------------------------------------------------------------------*/
|
||||
int ecbLoadEncoder(pECB self){
|
||||
Z80_reg in, out;
|
||||
int status;
|
||||
|
||||
if(self->encoderDirty != 1){
|
||||
/*
|
||||
no need to do it if no change
|
||||
*/
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(self->encoder[0] != 0){
|
||||
in.d = self->encoder[0];
|
||||
}else {
|
||||
in.d = 0;
|
||||
}
|
||||
if(self->encoder[1] != 0){
|
||||
in.e = self->encoder[1];
|
||||
}else {
|
||||
in.e = 0;
|
||||
}
|
||||
if(self->encoder[2] != 0){
|
||||
in.b = self->encoder[2];
|
||||
}else {
|
||||
in.b = 0;
|
||||
}
|
||||
in.c = 1;
|
||||
|
||||
status = ecbExecute(self,152,in,&out);
|
||||
return status;
|
||||
}
|
||||
/*-----------------------------------------------------------------------*/
|
||||
void ECBKill(void *pData){
|
||||
pECB self = (pECB)pData;
|
||||
|
||||
if(self == NULL){
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
Detaching here may be dangerous: If the GPIB has been deleted first,
|
||||
this makes a core dump. Best is the GPIB keeps a list of attached
|
||||
things and cleans them itself.
|
||||
|
||||
GPIBdetach(self->gpib,self->ecbDeviceID);
|
||||
*/
|
||||
if(self->pDes){
|
||||
DeleteDescriptor(self->pDes);
|
||||
}
|
||||
free(self);
|
||||
}
|
||||
/*----------------------------------------------------------------------
|
||||
MakeECB name gpibcontroller boardNo gpib-address
|
||||
-----------------------------------------------------------------------*/
|
||||
int MakeECB(SConnection *pCon, SicsInterp *pSics, void *pData,
|
||||
int argc, char *argv[]){
|
||||
pECB self = NULL;
|
||||
int address, status, boardNo;
|
||||
pGPIB gpib = NULL;
|
||||
char pError[132];
|
||||
|
||||
/*
|
||||
we need a name, the GPIB controller and an address on the GPIB bus for
|
||||
the ECB as arguments
|
||||
*/
|
||||
if(argc < 5){
|
||||
SCWrite(pCon,"ERROR: insufficient arguments to MakeECB",eError);
|
||||
return 0;
|
||||
}
|
||||
gpib = FindCommandData(pSics,argv[2],"GPIB");
|
||||
if(gpib == NULL){
|
||||
sprintf(pError,"ERROR: no GPIB controller %s found", argv[2]);
|
||||
SCWrite(pCon,pError,eError);
|
||||
return 0;
|
||||
}
|
||||
status = Tcl_GetInt(pSics->pTcl,argv[3], &boardNo);
|
||||
if(status != TCL_OK){
|
||||
sprintf(pError,"ERROR: failed to convert %s to integer",argv[3]);
|
||||
SCWrite(pCon,pError,eError);
|
||||
return 0;
|
||||
}
|
||||
status = Tcl_GetInt(pSics->pTcl,argv[4], &address);
|
||||
if(status != TCL_OK){
|
||||
sprintf(pError,"ERROR: failed to convert %s to integer",argv[4]);
|
||||
SCWrite(pCon,pError,eError);
|
||||
return 0;
|
||||
}
|
||||
if(address < 0 || address > 30){
|
||||
SCWrite(pCon,"ERROR: invalid GPIB address specified",eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
self = (pECB)malloc(sizeof(ECB));
|
||||
if(self == NULL){
|
||||
SCWrite(pCon,"ERROR: no memory to allocate ECB",eError);
|
||||
return 0;
|
||||
}
|
||||
memset(self,0,sizeof(ECB));
|
||||
self->pDes = CreateDescriptor("ECB");
|
||||
if(self->pDes == NULL){
|
||||
SCWrite(pCon,"ERROR: no memory to allocate ECB",eError);
|
||||
return 0;
|
||||
}
|
||||
self->gpib = gpib;
|
||||
self->boardNumber = boardNo;
|
||||
self->ecbAddress = address;
|
||||
self->ecbDeviceID =GPIBattach(self->gpib,self->boardNumber,
|
||||
self->ecbAddress,0,
|
||||
13,0,1);
|
||||
if(self->ecbDeviceID <= 0){
|
||||
SCWrite(pCon,"ERROR: failed to initialize ECB connection",
|
||||
eError);
|
||||
ECBKill(self);
|
||||
return 0;
|
||||
}
|
||||
AddCommand(pSics,argv[1],ECBAction,ECBKill,self);
|
||||
return 1;
|
||||
}
|
||||
|
Reference in New Issue
Block a user