Files
sicspsi/sps.c
koennecke eb72d5c486 - Adapted indenation to new agreed upon system
- Fixed bad status in poldi zug driver
2009-02-13 09:01:03 +00:00

715 lines
18 KiB
C

/*--------------------------------------------------------------------------
S P S
Implementation file for the SICS module handling Siemens SPS controllers
at SinQ.
copyright: see copyright.h
I cannot imagine that somebody wants this. It is highly special for SINQ.
It handles a protocoll tailor made by Siemens for Sinq. I cannot imagine
that somebody wants something from Siemens anyway.
Mark Koennnecke, Juli 1998
---------------------------------------------------------------------------*/
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <tcl.h>
#include "fortify.h"
#include "hardsup/serialsinq.h"
#include "sics.h"
#include "lld.h"
#include "bit.h"
#include "sps.i"
#include "sps.h"
#include "commandlog.h"
/*--------------------- some internal defines ----------------------------*/
#define SPSOFFLINE -10
#define COMMDEAD -11
#define COMMRECONNECT -12
#define COMMTMO -13
/*-------------------------------------------------------------------------*/
static float SimRandom(void)
{
float fVal;
fVal = ((float) rand() / (float) RAND_MAX) * 100.0;
return fVal;
}
/*--------------------- static functions ---------------------------------*/
static int init(pSPS self)
{
int iRet;
assert(self);
assert(self->pHost);
/* check if in simulation mode */
if (self->iMode)
return 1;
/* open the port */
iRet =
SerialOpen(&self->pData, self->pHost, self->iPort, self->iChannel);
if ((iRet != 1) || (self->pData == NULL)) {
self->iLastError = COMMDEAD;
return 0;
}
/* configure terminators */
SerialATerm(&self->pData, "1\r\n");
SerialSendTerm(&self->pData, "\r\n");
SerialConfig(&self->pData, 5000);
return 1;
}
/*-------------------------------------------------------------------------*/
static int SPSCommand(pSPS self, char *pCommand, char *pReply,
int iReplyLen)
{
int iRet, i;
char pError[132];
assert(self);
assert(pCommand);
assert(pReply);
/*
try at least three times to get the command through before
giving up
*/
for (i = 0; i < 3; i++) {
iRet = SerialWriteRead(&self->pData, pCommand, pReply, iReplyLen);
if (iRet != 1) {
switch (iRet) {
case TIMEOUT:
self->iLastError = COMMTMO;
continue;
break;
default:
self->iLastError = iRet;
SerialError(iRet, pError, 131);
WriteToCommandLog("SYS: SPS-TROUBLE:", pError);
SerialClose(&self->pData);
iRet = init(self);
if (iRet == 0) {
return 0;
}
continue;
break;
}
}
/* now we may still have a TMO or OFL message */
if (strstr(pReply, "?TMO") != NULL) {
self->iLastError = COMMTMO;
continue;
}
if (strstr(pReply, "?OFL") != NULL) {
self->iLastError = SPSOFFLINE;
return 0;
}
return 1;
}
return 0;
}
/*--------------------------------------------------------------------------*/
int SPSSetButton(pSPS self, SConnection * pCon, int iByte, int iBit)
{
Permission perm;
char pCommand[30];
char pBueffel[256];
int iRet, iTest, i;
assert(self);
assert(pCon);
/* first check permissions */
iRet = LLDnodePtr2First(self->lPermissions);
iTest = 0;
while (iRet != 0) {
LLDnodeDataTo(self->lPermissions, &perm);
if (perm.iByte == iByte) {
if (perm.iBit == iBit) {
iTest = SCMatchRights(pCon, perm.iPrivilege);
break;
}
}
iRet = LLDnodePtr2Next(self->lPermissions);
}
if (!iTest) {
sprintf(pBueffel, "ERROR: you have no permission to flip %d.%d",
iByte, iBit);
SCWrite(pCon, pBueffel, eError);
return 0;
}
/* if in sim mode, return true */
if (self->iMode) {
return 1;
}
/* format command and send a command to set a bit through the
drain in order to simulate a button press
*/
sprintf(pCommand, "S%3.3d%1.1d", iByte, iBit);
iRet = SPSCommand(self, pCommand, pBueffel, 255);
if (!iRet) {
SCWrite(pCon, pBueffel, eError);
SCWrite(pCon, "ERROR: Sending flip command failed", eError);
return 0;
}
return 1;
}
/*--------------------------------------------------------------------------*/
int SPSGetStatus(pSPS self, int iStatus, int *iSet)
{
int iRet, i, i2, iVal;
unsigned char pByte[16];
char pBueffel[256], pNum[10];
char *pPtr;
unsigned char cBit, cMask;
assert(self);
if ((iStatus < 0) || (iStatus >= 128)) {
return -1;
}
/* if in simulation mode, return 1 */
if (self->iMode) {
*iSet = 1;
return 1;
}
/* send an R command down to the SPS */
iRet = SPSCommand(self, "R", pBueffel, 255);
if (!iRet) {
return 0;
}
/* decode the reply into the Byte array */
pPtr = strchr(pBueffel, 'R');
if (pPtr == NULL) {
return -2;
}
pPtr++;
for (i = 0; i < 16; i++) {
/* skip the whitespace */
pPtr++;
pNum[0] = *pPtr;
pPtr++;
pNum[1] = *pPtr;
pPtr++;
pNum[2] = *pPtr;
pPtr++;
pNum[3] = '\0';
pByte[i] = atoi(pNum);
}
/* test the bit */
i = iStatus / 8;
cBit = pByte[i];
i2 = iStatus % 8;
cMask = 1 << i2;
/*
printf("Byte %d, Value %d, Bit %d, Value: %d\n", i,cBit, i2, (cBit & cMask));
*/
if ((cBit & cMask) > 0) {
*iSet = 1;
} else {
*iSet = 0;
}
return 1;
}
/*-------------------------------------------------------------------------
This is a special feature for SANS at SINQ. SANS has a collimator and
the length of the collimator can only be deduced from the SPS status
message by checking each of nine segments separately. For efficiency
this is coded into a special function for SANS. This also needs a special
function for testing bits.
Mark Koennecke, April 1999
*/
static int TestBit(unsigned char cByte, int iBit)
{
unsigned char cMask;
assert(iBit >= 0);
assert(iBit < 8);
cMask = 1 << iBit;
if ((cMask & cByte) > 0) {
return 1;
} else {
return 0;
}
}
/*-----------------------------------------------------------------------*/
int SPSGetSANS(pSPS self, float *fLength)
{
int iRet, i, i2, iVal;
unsigned char pByte[16];
char pBueffel[256], pNum[10];
char *pPtr;
unsigned char cBit, cMask;
float fLang;
assert(self);
/* if in simulation mode, return a random number */
if (self->iMode) {
*fLength = SimRandom();
return 1;
}
/* send an R command down to the SPS */
iRet = SPSCommand(self, "R", pBueffel, 255);
if (!iRet) {
return 0;
}
/* decode the reply into the Byte array */
pPtr = strchr(pBueffel, 'R');
if (pPtr == NULL) {
return -2;
}
pPtr++;
for (i = 0; i < 16; i++) {
/* skip the whitespace */
pPtr++;
pNum[0] = *pPtr;
pPtr++;
pNum[1] = *pPtr;
pPtr++;
pNum[2] = *pPtr;
pPtr++;
pNum[3] = '\0';
pByte[i] = atoi(pNum);
}
fLang = 189.;
if (TestBit(pByte[0], 1) > 0) {
fLang = 18.;
}
/* coll 1 15m */
if (TestBit(pByte[0], 3) > 0) {
fLang = 15.;
}
/* coll 2 11 m */
if (TestBit(pByte[0], 7) > 0) {
fLang = 11.;
}
/* coll 3 8 m */
if (TestBit(pByte[1], 3) > 0) {
fLang -= 3.;
}
/* coll 4 6m */
if (TestBit(pByte[1], 7) > 0) {
fLang -= 2.;
}
/* coll 5 4.5 m */
if (TestBit(pByte[2], 3) > 0) {
fLang -= 1.5;
}
/* coll 6 3 m */
if (TestBit(pByte[2], 7) > 0) {
fLang -= 1.5;
}
/* coll 7 */
if (TestBit(pByte[3], 3) > 0) {
fLang -= 1.;
}
/* coll 8 */
if (TestBit(pByte[3], 6) > 0) {
fLang -= 1.;
}
if (TestBit(pByte[3], 7) > 0) {
fLang -= 0.6;
}
*fLength = fLang;
return 1;
}
/*--------------------------------------------------------------------------*/
int SPSGetADC(pSPS self, int iWhich, int *iValue)
{
int iADC[8];
int i, iRet;
char *pPtr, pBueffel[256], pNum[10];
assert(self);
/* check iWhich */
if ((iWhich < 0) || (iWhich > 7)) {
return 0;
}
/* give a random number in simulation mode */
if (self->iMode) {
*iValue = (int) SimRandom();
return 1;
}
/* send an A command to the box */
iRet = SPSCommand(self, "A", pBueffel, 255);
if (!iRet) {
return 0;
}
/* decode the result */
pPtr = strchr(pBueffel, 'A');
if (pPtr == NULL) { /* a silly answer was returned */
SICSLogWrite("SPS: Silly answer in SPSGetADC", eError);
return 0;
}
pPtr++;
for (i = 0; i < 8; i++) {
pPtr++; /* skip whitespace */
strncpy(pNum, pPtr, 5);
pNum[5] = '\0';
pPtr += 5;
iADC[i] = atoi(pNum);
}
/* now give the value */
*iValue = iADC[iWhich];
return 1;
}
/*-----------------------------------------------------------------------*/
void SPSAddPermission(pSPS self, int iByte, int iBit, int iRights)
{
Permission perm;
assert(self);
perm.iByte = iByte;
perm.iBit = iBit;
perm.iPrivilege = iRights;
LLDnodeAppendFrom(self->lPermissions, &perm);
}
/*-------------------------------------------------------------------------*/
void RemoveSPS(void *pData)
{
pSPS self = NULL;
self = (pSPS) pData;
if (!self)
return;
if (self->pHost) {
free(self->pHost);
}
SerialClose(&self->pData);
if (self->pDes) {
DeleteDescriptor(self->pDes);
}
LLDdelete(self->lPermissions);
free(self);
}
/*---------------------------------------------------------------------------*/
int SPSFactory(SConnection * pCon, SicsInterp * pSics, void *pData,
int argc, char *argv[])
{
int iRet, iVal;
pSPS pNew = NULL;
char pBueffel[256];
assert(pCon);
assert(pSics);
/* we need at least two extra arguments: name and either host or sim */
if (argc < 3) {
SCWrite(pCon,
"ERROR: Insufficient number of arguments for installing SPS",
eError);
return 0;
}
/* allocate a new SPS */
pNew = (pSPS) malloc(sizeof(SPS));
if (!pNew) {
SCWrite(pCon, "ERROR: no memory to allocate SPS", eError);
return 0;
}
memset(pNew, 0, sizeof(SPS));
pNew->pDes = CreateDescriptor("SPS");
pNew->lPermissions = LLDcreate(sizeof(Permission));
if ((!pNew->pDes) || (pNew->lPermissions < 0)) {
SCWrite(pCon, "ERROR: no memory to allocate SPS", eError);
return 0;
}
pNew->pHost = strdup(argv[2]);
/* check if we go for sim */
strtolower(argv[2]);
if (strcmp(argv[2], "sim") == 0) {
pNew->iMode = 1;
} else { /* we are installing a real one and need tons more arguments */
if (argc < 5) {
SCWrite(pCon,
"ERROR: Insufficient number of arguments for installing SPS",
eError);
RemoveSPS(pNew);
return 0;
}
/* get port number */
iRet = Tcl_GetInt(pSics->pTcl, argv[3], &iVal);
if (iRet != TCL_OK) {
sprintf(pBueffel,
"ERROR: expected integer argument for port, got %s",
argv[3]);
SCWrite(pCon, pBueffel, eError);
RemoveSPS(pNew);
return 0;
}
pNew->iPort = iVal;
/* get channel number */
iRet = Tcl_GetInt(pSics->pTcl, argv[4], &iVal);
if (iRet != TCL_OK) {
sprintf(pBueffel,
"ERROR: expected integer argument for channel, got %s",
argv[4]);
SCWrite(pCon, pBueffel, eError);
RemoveSPS(pNew);
return 0;
}
pNew->iChannel = iVal;
}
/* initialise */
iRet = init(pNew);
if (!iRet) {
SCWrite(pCon, "ERROR: Failure to initialise SPS controller", eError);
RemoveSPS(pNew);
return 0;
}
/* install command */
iRet = AddCommand(pSics, argv[1], SPSAction, RemoveSPS, pNew);
if (!iRet) {
sprintf(pBueffel, "ERROR: duplicate SPS command %s NOT created",
argv[1]);
SCWrite(pCon, pBueffel, eError);
RemoveSPS(pNew);
}
return 1;
}
/*-------------------------------------------------------------------------*/
int SPSAction(SConnection * pCon, SicsInterp * pSics, void *pData,
int argc, char *argv[])
{
pSPS self = NULL;
char pBueffel[256];
int iByte, iBit, iSet;
int iRet, i;
float fLang;
self = (pSPS) pData;
assert(self);
/* we need at least 3 arguments */
if (argc < 2) {
sprintf(pBueffel, "ERROR: need at least two arguments to %s", argv[0]);
SCWrite(pCon, pBueffel, eError);
return 0;
}
/* do something according to key word */
strtolower(argv[1]);
if (strcmp(argv[1], "push") == 0) { /* operate a button */
/* four arguments needed */
if (argc < 4) {
sprintf(pBueffel, "ERROR: need at least two arguments to %s push",
argv[0]);
SCWrite(pCon, pBueffel, eError);
return 0;
}
/* convert arguments */
iRet = Tcl_GetInt(pSics->pTcl, argv[2], &iByte);
if (iRet != TCL_OK) {
sprintf(pBueffel,
"ERROR: expected integer argument for byte, got %s",
argv[2]);
SCWrite(pCon, pBueffel, eError);
return 0;
}
iRet = Tcl_GetInt(pSics->pTcl, argv[3], &iBit);
if (iRet != TCL_OK) {
sprintf(pBueffel, "ERROR: expected integer argument for bit, got %s",
argv[3]);
SCWrite(pCon, pBueffel, eError);
return 0;
}
/* try it */
iRet = SPSSetButton(self, pCon, iByte, iBit);
if (!iRet) {
SCWrite(pCon, "ERROR: Pushing button failed", eError);
return 0;
} else {
SCSendOK(pCon);
return 1;
}
} else if (strcmp(argv[1], "status") == 0) { /* status bits */
/* which bit ? */
if (argc < 3) {
sprintf(pBueffel, "ERROR: need at least two arguments to %s push",
argv[0]);
SCWrite(pCon, pBueffel, eError);
return 0;
}
iRet = Tcl_GetInt(pSics->pTcl, argv[2], &iByte);
if (iRet != TCL_OK) {
sprintf(pBueffel, "ERROR: expected integer argument for bit, got %s",
argv[2]);
SCWrite(pCon, pBueffel, eError);
return 0;
}
iRet = SPSGetStatus(self, iByte, &iSet);
if (iRet <= 0) {
sprintf(pBueffel, "ERROR: failed to read status bit %d", iByte);
SCWrite(pCon, pBueffel, eError);
return 0;
}
sprintf(pBueffel, "%s.status.%3.3d = %d", argv[0], iByte, iSet);
SCWrite(pCon, pBueffel, eValue);
return 1;
} else if (strcmp(argv[1], "stat2") == 0) { /* status bits */
if (argc < 4) {
sprintf(pBueffel, "ERROR: need at least two arguments to %s stat2",
argv[0]);
SCWrite(pCon, pBueffel, eError);
return 0;
}
/* which bit ? */
iRet = Tcl_GetInt(pSics->pTcl, argv[2], &iByte);
if (iRet != TCL_OK) {
sprintf(pBueffel, "ERROR: expected integer argument for bit, got %s",
argv[2]);
SCWrite(pCon, pBueffel, eError);
return 0;
}
iRet = Tcl_GetInt(pSics->pTcl, argv[3], &iBit);
if (iRet != TCL_OK) {
sprintf(pBueffel, "ERROR: expected integer argument for bit, got %s",
argv[3]);
SCWrite(pCon, pBueffel, eError);
return 0;
}
if ((iByte <= 0) || (iBit < 0) || (iBit > 7)) {
SCWrite(pCon, "ERROR: arguments out of range for stat2", eError);
return 0;
}
iRet = SPSGetStatus(self, ((iByte - 1) * 8 + iBit), &iSet);
if (iRet <= 0) {
sprintf(pBueffel, "ERROR: failed to read status bit %d", iByte);
SCWrite(pCon, pBueffel, eError);
return 0;
}
sprintf(pBueffel, "%s.status.%3.3d.%1.1d = %d", argv[0], iByte, iBit,
iSet);
SCWrite(pCon, pBueffel, eValue);
return 1;
} else if (strcmp(argv[1], "adc") == 0) { /* ADC values */
/* which ADC ? */
iRet = Tcl_GetInt(pSics->pTcl, argv[2], &iByte);
if (iRet != TCL_OK) {
sprintf(pBueffel, "ERROR: expected integer argument for ADC, got %s",
argv[2]);
SCWrite(pCon, pBueffel, eError);
return 0;
}
iRet = SPSGetADC(self, iByte, &iSet);
if (!iRet) {
sprintf(pBueffel, "ERROR: failed to read ADC %d", iByte);
SCWrite(pCon, pBueffel, eError);
return 0;
}
sprintf(pBueffel, "%s.ADC.%1.1d = %d", argv[0], iByte, iSet);
SCWrite(pCon, pBueffel, eValue);
return 1;
} else if (strcmp(argv[1], "perm") == 0) {
/* only managers may set permissions */
if (!SCMatchRights(pCon, usMugger)) {
SCWrite(pCon,
"ERROR: Security: Only mangagers may configure SPS buttons",
eError);
return 0;
}
/* we need lots of parameters */
if (argc < 5) {
sprintf(pBueffel, "ERROR: need at least three arguments to %s perm",
argv[0]);
SCWrite(pCon, pBueffel, eError);
return 0;
}
/* convert arguments */
iRet = Tcl_GetInt(pSics->pTcl, argv[2], &iByte);
if (iRet != TCL_OK) {
sprintf(pBueffel,
"ERROR: expected integer argument for byte, got %s",
argv[2]);
SCWrite(pCon, pBueffel, eError);
return 0;
}
iRet = Tcl_GetInt(pSics->pTcl, argv[3], &iBit);
if (iRet != TCL_OK) {
sprintf(pBueffel, "ERROR: expected integer argument for bit, got %s",
argv[3]);
SCWrite(pCon, pBueffel, eError);
return 0;
}
/* try to convert user code */
strtolower(argv[4]);
iSet = 0;
iSet = decodeSICSPriv(argv[4]);
if (iSet < 0) {
sprintf(pBueffel, "ERROR: %s is not valid user code", argv[4]);
SCWrite(pCon, pBueffel, eError);
return 0;
}
/* do it, finally */
SPSAddPermission(self, iByte, iBit, iSet);
SCSendOK(pCon);
return 1;
}
/* -------- sans collimator */
else if (strcmp(argv[1], "colli") == 0) {
iRet = SPSGetSANS(self, &fLang);
if (!iRet) {
SCWrite(pCon, "ERROR: cannot read SANS collimator", eError);
return 0;
} else {
sprintf(pBueffel, "SANS.collimator = %f", fLang);
SCWrite(pCon, pBueffel, eValue);
return 1;
}
}
sprintf(pBueffel, "ERROR: %s does not not understand subcommand %s",
argv[0], argv[1]);
SCWrite(pCon, pBueffel, eError);
return 0;
}