306 lines
7.6 KiB
C
306 lines
7.6 KiB
C
/*--------------------------------------------------------------------------
|
|
V E L O S I M
|
|
|
|
A software simulation for a velocity selector. For the case the
|
|
real one is broken(most of the time) and you need to test the
|
|
software or for simulation purposes.
|
|
|
|
Author: Mark Koennecke, June 1997
|
|
|
|
Copyright:
|
|
|
|
Labor fuer Neutronenstreuung
|
|
Paul Scherrer Institut
|
|
CH-5423 Villigen-PSI
|
|
|
|
|
|
The authors hereby grant permission to use, copy, modify, distribute,
|
|
and license this software and its documentation for any purpose, provided
|
|
that existing copyright notices are retained in all copies and that this
|
|
notice is included verbatim in any distributions. No written agreement,
|
|
license, or royalty fee is required for any of the authorized uses.
|
|
Modifications to this software may be copyrighted by their authors
|
|
and need not follow the licensing terms described here, provided that
|
|
the new terms are clearly indicated on the first page of each file where
|
|
they apply.
|
|
|
|
IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
|
|
FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
|
ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
|
|
DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
|
|
POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
|
|
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
|
|
IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
|
|
NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
|
|
MODIFICATIONS.
|
|
----------------------------------------------------------------------------*/
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <assert.h>
|
|
#include <math.h>
|
|
#include <time.h>
|
|
#include <strlutil.h>
|
|
#include "fortify.h"
|
|
#include "conman.h"
|
|
#include "stringdict.h"
|
|
#include "event.h"
|
|
#include "logv2.h"
|
|
typedef struct __VelSelDriv *pVelSelDriv;
|
|
|
|
#include "velodriv.h"
|
|
|
|
/* VELO* MUST be the same as in velo.i!*/
|
|
#define VELOREDO 2
|
|
#define VELOFAIL 0
|
|
#define VELOOK 1
|
|
#define VSNOCON 0
|
|
#define VSOK 1
|
|
#define VSACCEL -7
|
|
#define VSFAIL -2
|
|
|
|
#define FAILURE 1 /* a flat 1% error rate for trouble detection */
|
|
|
|
|
|
/* -------- A private datastructure for velocity selector simulation */
|
|
|
|
typedef struct {
|
|
long lTime;
|
|
float fPos;
|
|
} Simi, *pSimi;
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
static float SimRandom(void)
|
|
{
|
|
float fVal;
|
|
|
|
fVal = ((float) rand() / (float) RAND_MAX) * 100.0;
|
|
return fVal;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
static int RunComplete(pVelSelDriv self)
|
|
{
|
|
time_t tD;
|
|
pSimi pDriv;
|
|
|
|
pDriv = (pSimi) self->pPrivate;
|
|
if ((int) time(&tD) > pDriv->lTime) {
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
static int SimInit(pVelSelDriv self, SConnection * pCon)
|
|
{
|
|
pSimi pDriv;
|
|
|
|
assert(self);
|
|
|
|
pDriv = (pSimi) self->pPrivate;
|
|
pDriv->fPos = 0.0;
|
|
return 1;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
static int GetSimPos(pVelSelDriv self, float *fPos)
|
|
{
|
|
|
|
pSimi pDriv;
|
|
|
|
assert(self);
|
|
if (SimRandom() < FAILURE) {
|
|
*fPos = SimRandom();
|
|
return VELOFAIL;
|
|
}
|
|
|
|
pDriv = (pSimi) self->pPrivate;
|
|
if (RunComplete(self)) {
|
|
*fPos = pDriv->fPos;
|
|
} else { /* simulate a selector running at a strange speed */
|
|
|
|
if (SimRandom() < FAILURE) {
|
|
*fPos = pDriv->fPos - 10.;
|
|
} else {
|
|
*fPos = pDriv->fPos;
|
|
}
|
|
return VELOOK;
|
|
}
|
|
return VELOOK;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
static int SimRun(pVelSelDriv self, float fVal)
|
|
{
|
|
float fDiff;
|
|
time_t tD;
|
|
pSimi pDriv;
|
|
|
|
assert(self);
|
|
|
|
/* calculate time for completion */
|
|
pDriv = (pSimi) self->pPrivate;
|
|
fDiff = fVal - pDriv->fPos;
|
|
if (fDiff < .0)
|
|
fDiff = -fDiff;
|
|
pDriv->lTime = (int) time(&tD) + (int) (fDiff / 10000.);
|
|
|
|
/* in a fifth the failures, simply die, else simply do not find pos */
|
|
if (SimRandom() < (FAILURE / 5)) {
|
|
return HWFault;
|
|
} else {
|
|
pDriv->fPos = fVal;
|
|
return OKOK;
|
|
}
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
static int SimError(pVelSelDriv self, int *iCode, char *error, int iErrLen)
|
|
{
|
|
assert(self);
|
|
|
|
if (RunComplete(self)) {
|
|
*iCode = 56;
|
|
strlcpy(error,
|
|
"ERROR: HW: Simulated selector error on simulated selector",
|
|
iErrLen);
|
|
} else {
|
|
*iCode = 12;
|
|
strlcpy(error, "Selector still creeping along", iErrLen - 1);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
static int SimFix(pVelSelDriv self, int iError)
|
|
{
|
|
float fRand;
|
|
|
|
/* return the three values MOTREDO, MOTFAIL, MOTOK with a third
|
|
randomness
|
|
*/
|
|
assert(self);
|
|
fRand = SimRandom();
|
|
|
|
if (iError == 12) {
|
|
return VELOREDO;
|
|
}
|
|
|
|
Log(ERROR,"dev","%s","Selector dying randomly");
|
|
if (fRand < 0.3333) {
|
|
return VELOOK;
|
|
} else if (fRand < 0.66666) {
|
|
return VELOREDO;
|
|
} else {
|
|
return VELOFAIL;
|
|
}
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
static int SimHalt(pVelSelDriv self)
|
|
{
|
|
pSimi pDriv;
|
|
|
|
assert(self);
|
|
pDriv = (pSimi) self->pPrivate;
|
|
|
|
pDriv->lTime = 0;
|
|
return OKOK;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
static int SimStat(pVelSelDriv self, int *iCode, float *fVal)
|
|
{
|
|
pSimi pDriv;
|
|
|
|
assert(self);
|
|
pDriv = (pSimi) self->pPrivate;
|
|
|
|
*iCode = ROTMOVE;
|
|
if (RunComplete(self)) {
|
|
*fVal = pDriv->fPos;
|
|
return VSOK;
|
|
} else {
|
|
if (SimRandom() < FAILURE / 2) {
|
|
return VSFAIL;
|
|
} else if (SimRandom() < FAILURE) {
|
|
return VSFAIL;
|
|
}
|
|
*fVal = random() / 150678;
|
|
return VSACCEL;
|
|
}
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
static int SimText(pVelSelDriv self, char *pText, int iTextLen)
|
|
{
|
|
strlcpy(pText, "Simulated Info on a simulated velocity selector",
|
|
iTextLen);
|
|
return 1;
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
static int SimLoss(pVelSelDriv self, float *fLoss)
|
|
{
|
|
*fLoss = 20.33338;
|
|
return 1;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
static void SimKill(void *pData)
|
|
{
|
|
free(pData);
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
pVelSelDriv VSCreateSim(void)
|
|
{
|
|
pVelSelDriv pNew = NULL;
|
|
|
|
/* business as usual: allocate memory */
|
|
pNew = (pVelSelDriv) malloc(sizeof(VelSelDriv));
|
|
if (!pNew) {
|
|
return NULL;
|
|
}
|
|
/* zero the world */
|
|
memset(pNew, 0, sizeof(VelSelDriv));
|
|
pNew->pPrivate = malloc(sizeof(Simi));
|
|
if (!pNew->pPrivate) {
|
|
free(pNew);
|
|
return NULL;
|
|
}
|
|
|
|
/* initialise function pointers */
|
|
pNew->DeletePrivate = SimKill;
|
|
pNew->Halt = SimHalt;
|
|
pNew->GetError = SimError;
|
|
pNew->TryAndFixIt = SimFix;
|
|
pNew->GetRotation = GetSimPos;
|
|
pNew->SetRotation = SimRun;
|
|
pNew->GetStatus = SimStat;
|
|
pNew->GetDriverText = SimText;
|
|
pNew->GetLossCurrent = SimLoss;
|
|
pNew->Init = SimInit;
|
|
|
|
/* done it */
|
|
return pNew;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
void VSDeleteDriver(pVelSelDriv self)
|
|
{
|
|
assert(self);
|
|
|
|
/* try to delete the private parts */
|
|
if (self->DeletePrivate) {
|
|
self->DeletePrivate(self->pPrivate);
|
|
}
|
|
|
|
/* now we cleans ourselves */
|
|
free(self);
|
|
}
|