Files
sicspsi/tabledrive.c

957 lines
26 KiB
C

/*---------------------------------------------------------------------------
SICS object for driving a couple of motors along a tabulated given path.
copyright: see file COPYRIGHT
Mark Koennecke, July 2005
---------------------------------------------------------------------------*/
#include <stdio.h>
#include <math.h>
#include <lld.h>
#include "tabledrive.h"
/*--------------------------------------------------------------------------*/
#define OUTOFSYNC 100
#define STARTING 101
#define STEPPING 102
#define WAITING 103
#define WAITFINISH 104
#define IDLE 105
#define ABS(x) (x < 0 ? -(x) : (x))
#define SIGN(x) (x < .0 ? (-1) : (1))
extern char *trim(char *txt);
/*
* copied from motor.c!!
*/
#define SLOW 0
#define SUPP 1
/*=================== the drivable interface functions =====================*/
static int TableDriveHalt(void *pData)
{
pTableDrive self = (pTableDrive) pData;
int status;
tdMotor moti;
if (self == NULL || self->motorTable < 0) {
return 0;
}
status = LLDnodePtr2First(self->motorTable);
while (status != 0) {
LLDnodeDataTo(self->motorTable, &moti);
if (moti.pMot != NULL) {
moti.pMot->pDrivInt->Halt(moti.pMot);
}
status = LLDnodePtr2Next(self->motorTable);
}
self->state = OUTOFSYNC;
return 1;
}
/*-------------------------------------------------------------------------*/
static int TableDriveCheckLimits(void *pData, float fVal, char *error,
int iErrLen)
{
pTableDrive self = (pTableDrive) pData;
tdMotor moti;
if (self == NULL || self->motorTable < 0) {
strlcpy(error, "Path Table Not Defined!", 25);
return 0;
}
if (fVal < 1. || fVal > self->tableLength) {
strlcpy(error, "Out of Range", 25);
return 0;
}
return 1;
}
/*--------------------------------------------------------------------------*/
static long TableDriveSetValue(void *pData, SConnection * pCon, float fVal)
{
pTableDrive self = (pTableDrive) pData;
char pError[132];
if (self == NULL || self->motorTable < 0) {
SCWrite(pCon, "ERROR: no path defined", eError);
return HWFault;
}
strcpy(pError, "ERROR:");
if (!TableDriveCheckLimits(self, fVal, &pError[6], 120)) {
SCWrite(pCon, pError, eError);
return HWFault;
}
self->state = STARTING;
self->targetPosition = fVal;
return OKOK;
}
/*-------------------------------------------------------------------------*/
static int findOrientingMotor(pTableDrive self, ptdMotor moti)
{
int status;
if (!self->oriInvalid) {
*moti = self->oriMotor;
return 1;
}
status = LLDnodePtr2First(self->motorTable);
while (status != 0) {
LLDnodeDataTo(self->motorTable, moti);
if (strcmp(moti->motorName, self->orientMotor) == 0) {
self->oriMotor = *moti;
self->oriInvalid = 0;
return 1;
}
status = LLDnodePtr2Next(self->motorTable);
}
return 0;
}
/*-------------------------------------------------------------------------*/
static float locatePosition(tdMotor moti, SConnection * pCon)
{
int status, begin = 1;
float value;
double diff;
tdEntry lower, upper;
status = MotorGetSoftPosition(moti.pMot, pCon, &value);
if (!status) {
return -9999.99;
}
status = LLDnodePtr2First(moti.table);
while (status != 0) {
LLDnodeDataTo(moti.table, &lower);
status = LLDnodePtr2Next(moti.table);
if (status != 0) {
LLDnodeDataTo(moti.table, &upper);
} else {
/*
* end of table
*/
return lower.tablePos;
}
/**
* we have to deal with ascending and descending tables. This is
* why we have to have some funny logic here
*/
if (upper.position > lower.position) {
/*
* ascending table
*/
if (value >= lower.position && value < upper.position) {
diff = upper.position - lower.position;
return lower.tablePos + (value - lower.position) / diff;
}
if (begin == 1 && value < lower.position) {
return lower.tablePos;
}
} else {
/*
* descending table
*/
if (value <= lower.position && value > upper.position) {
diff = lower.position - upper.position;
return lower.tablePos + ABS(value - lower.position) / diff;
}
if (begin == 1 && value > lower.position) {
return lower.tablePos;
}
}
begin = 0;
}
return -999.99;
}
/*-------------------------------------------------------------------------*/
static void findBracket(tdMotor moti, float value, ptdEntry upper,
ptdEntry lower)
{
int status, targetCount;
float diff;
targetCount = (int) floor(value);
status = LLDnodePtr2First(moti.table);
while (status != 0) {
LLDnodeDataTo(moti.table, lower);
if (lower->tablePos == targetCount) {
LLDnodeDataTo(moti.table, upper);
if (LLDnodePtr2Next(moti.table)) {
LLDnodeDataTo(moti.table, upper);
}
return;
}
status = LLDnodePtr2Next(moti.table);
}
}
/*-------------------------------------------------------------------------*/
static float findTarget(tdMotor moti, float value)
{
int targetCount;
tdEntry lower, upper;
float diff;
targetCount = (int) floor(value);
findBracket(moti, value, &upper, &lower);
if (ABS(targetCount - value) < .00001) {
return lower.position;
} else {
diff = upper.position - lower.position;
return (float) lower.position + (value - targetCount) * diff;
}
}
/*-------------------------------------------------------------------------*/
static void checkSync(pTableDrive self, SConnection * pCon, float value)
{
int status, test;
float motorPosition, targetPosition, tolerance, diff;
tdMotor moti;
char pBueffel[256];
if (self->state != IDLE) {
return;
}
status = LLDnodePtr2First(self->motorTable);
while (status != 0) {
LLDnodeDataTo(self->motorTable, &moti);
test = MotorGetSoftPosition(moti.pMot, pCon, &motorPosition);
if (!test) {
snprintf(pBueffel, 255, "ERROR: failed to read motor %s",
moti.motorName);
SCWrite(pCon, pBueffel, eError);
} else {
MotorGetPar(moti.pMot, "precision", &tolerance);
targetPosition = findTarget(moti, value);
if (ABS(targetPosition - motorPosition) > tolerance) {
snprintf(pBueffel, 256,
"WARNING: motor %s out of sync by %f",
moti.motorName, ABS(targetPosition - motorPosition));
SCWrite(pCon, pBueffel, eWarning);
}
}
status = LLDnodePtr2Next(self->motorTable);
}
}
/*--------------------------------------------------------------------------*/
static float TableDriveGetValue(void *pData, SConnection * pCon)
{
pTableDrive self = (pTableDrive) pData;
tdMotor orient;
float value;
if (self == NULL || self->motorTable < 0) {
SCWrite(pCon, "ERROR: no path defined", eError);
return -9999.99;
}
if (!findOrientingMotor(self, &orient)) {
SCWrite(pCon, "ERROR: table corrupted or orienting motor not found",
eError);
return -9999.99;
}
value = locatePosition(orient, pCon);
checkSync(self, pCon, value);
self->currentPosition = value;
return value;
}
/*-------------------------------------------------------------------------*/
static void tableInfo(pTableDrive self, SConnection * pCon)
{
int status, test;
float motorPosition, targetPosition, tolerance, diff, value;
tdMotor moti;
char pBueffel[256];
value = TableDriveGetValue(self, pCon);
snprintf(pBueffel, 255, " Triffid Position: %8.2f", value);
SCWrite(pCon, pBueffel, eValue);
status = LLDnodePtr2First(self->motorTable);
while (status != 0) {
LLDnodeDataTo(self->motorTable, &moti);
test = MotorGetSoftPosition(moti.pMot, pCon, &motorPosition);
if (!test) {
snprintf(pBueffel, 255, "ERROR: failed to read motor %s",
moti.motorName);
SCWrite(pCon, pBueffel, eError);
} else {
MotorGetPar(moti.pMot, "precision", &tolerance);
targetPosition = findTarget(moti, value);
snprintf(pBueffel, 256,
"Motor %10s, should: %8.2f, is %8.2f, diff = %8.2f",
moti.motorName, targetPosition, motorPosition,
ABS(targetPosition - motorPosition));
SCWrite(pCon, pBueffel, eValue);
}
status = LLDnodePtr2Next(self->motorTable);
}
}
/*------------------------------------------------------------------------*/
static void tableSetPar(pMotor pMot, char *name, float value)
{
MotorSetPar(pMot,pServ->dummyCon,name,value);
}
/*------------------------------------------------------------------------
* Before I can drive the motors, I have to release the software limits..
-------------------------------------------------------------------------*/
static void liberateMotors(pTableDrive self, SConnection * pCon)
{
int status;
tdMotor moti;
float upper, lower;
status = LLDnodePtr2First(self->motorTable);
while (status != 0) {
LLDnodeDataTo(self->motorTable, &moti);
MotorGetPar(moti.pMot, "hardupperlim", &upper);
MotorGetPar(moti.pMot, "hardlowerlim", &lower);
tableSetPar(moti.pMot, "softupperlim", upper);
tableSetPar(moti.pMot, "softlowerlim", lower);
status = LLDnodePtr2Next(self->motorTable);
}
}
/*------------------------------------------------------------------------
* after driving the motors, we have to set the software limits in order
* to prevent the user from manually crashing components
------------------------------------------------------------------------ */
static void closeMotors(pTableDrive self, SConnection * pCon)
{
int status;
tdMotor moti;
tdEntry tdLower, tdUpper;
float upper, lower, diff, targetCount;
targetCount = floor(self->currentPosition);
status = LLDnodePtr2First(self->motorTable);
while (status != 0) {
LLDnodeDataTo(self->motorTable, &moti);
findBracket(moti, self->currentPosition, &tdUpper, &tdLower);
diff = tdUpper.upper - tdLower.upper;
upper = tdLower.upper + (self->currentPosition - targetCount) * diff;
diff = tdUpper.lower - tdLower.lower;
lower = tdLower.lower + (self->currentPosition - targetCount) * diff;
tableSetPar(moti.pMot, "softupperlim", upper);
tableSetPar(moti.pMot, "softlowerlim", lower);
status = LLDnodePtr2Next(self->motorTable);
}
}
/*------------------------------------------------------------------------*/
static float calculateNextStep(pTableDrive self)
{
float step;
step = self->targetPosition - self->currentPosition;
if (ABS(step) > 1.) {
step = SIGN(step) * 1.0;
}
return step;
}
/*------------------------------------------------------------------------*/
static int runToNextStep(pTableDrive self, SConnection * pCon, float value)
{
int status;
tdMotor moti;
float target;
long motID;
self->groupID = GetTaskGroupID(pServ->pTasker);
status = LLDnodePtr2First(self->motorTable);
while (status != 0) {
LLDnodeDataTo(self->motorTable, &moti);
target = findTarget(moti, value);
motID = StartDriveTask(moti.pMot,pCon,moti.motorName,target);
if(motID < 0){
return HWFault;
}
AddTaskToGroup(pServ->pTasker,motID,self->groupID);
status = LLDnodePtr2Next(self->motorTable);
}
return 1;
}
/*------------------------------------------------------------------------*/
static int checkRunning(pTableDrive self, SConnection * pCon)
{
int status;
int test;
tdMotor moti;
if(isTaskGroupRunning(pServ->pTasker,self->groupID)){
return HWBusy;
}
return HWIdle;
}
/*------------------------------------------------------------------------*/
static void showPositions(pTableDrive self, SConnection * pCon,
char *pBueffel, int buffLen)
{
float value;
int status, test, len;
tdMotor moti;
value = TableDriveGetValue(self, pCon);
snprintf(pBueffel, buffLen, " %8.2f : ", value);
status = LLDnodePtr2First(self->motorTable);
while (status != 0) {
LLDnodeDataTo(self->motorTable, &moti);
test = MotorGetSoftPosition(moti.pMot, pCon, &value);
len = strlen(pBueffel);
snprintf(&pBueffel[len], buffLen - len,
"%s = %8.2f ", moti.motorName, value);
status = LLDnodePtr2Next(self->motorTable);
}
}
/*-------------------------------------------------------------------------
* This is the old scheme: drive table positions tablestep by tablestep.
* I leave this code here: may be it is useful in another scenario then
* MARS. Then some means must be found to select the table drive
* algorithm.
* -----------------------------------------------------------------------*/
static int TableDriveCheckStatusOld(void *pData, SConnection * pCon)
{
pTableDrive self = (pTableDrive) pData;
int status;
float step;
char pBueffel[1024];
switch (self->state) {
case STARTING:
/*
* make sure that our current position is up-to-date
*/
TableDriveGetValue(self, pCon);
liberateMotors(self, pCon);
self->state = STEPPING;
return HWBusy;
break;
case STEPPING:
step = calculateNextStep(self);
status = runToNextStep(self, pCon, self->currentPosition + step);
if (status == OKOK) {
if (ABS(step) < 1.) {
self->state = WAITFINISH;
} else {
self->state = WAITING;
}
return HWBusy;
} else {
TableDriveHalt(self);
return HWFault;
}
break;
case WAITING:
status = checkRunning(self, pCon);
switch (status) {
case HWIdle:
case OKOK:
self->state = STEPPING;
if (self->debug > 0) {
showPositions(self, pCon, pBueffel, 1023);
SCWrite(pCon, pBueffel, eValue);
} else {
self->currentPosition += calculateNextStep(self);
}
return HWBusy;
break;
case HWBusy:
return HWBusy;
break;
default:
TableDriveHalt(self);
self->state = WAITFINISH;
return HWBusy;
break;
}
case WAITFINISH:
status = checkRunning(self, pCon);
if (status != HWBusy) {
TableDriveGetValue(self, pCon);
closeMotors(self, pCon);
self->state = IDLE;
return status;
} else {
return HWBusy;
}
break;
case OUTOFSYNC:
SCWrite(pCon, "WARNING: tabledrive out of sync", eWarning);
self->state = IDLE;
return HWFault;
break;
default:
SCWrite(pCon,
"ERROR: programming error in tabledrive, invalid state",
eError);
return HWFault;
break;
}
return HWFault;
}
/*===========================================================================
* This is code for the new scheme of driving MARS tables:
* 1) drive ds and as to 0
* 2) drive all other motors to targets directly
* 3) drive ds and as to desired positions.
* =========================================================================*/
#define WAITDSAS 110
#define WAITOTHER 111
#define ASDSTO0 200
#define ASDSTOTARGET 201
/*-------------------------------------------------------------------------*/
static int startASDS(pTableDrive self, SConnection * pCon, int target)
{
tdMotor moti;
int status;
char name[132];
float targetValue;
long motID;
if (self == NULL || self->motorTable < 0) {
return 0;
}
self->groupID = GetTaskGroupID(pServ->pTasker);
status = LLDnodePtr2First(self->motorTable);
while (status != 0) {
LLDnodeDataTo(self->motorTable, &moti);
strlcpy(name, moti.motorName, 131);
strtolower(name);
if (strstr(name, "ds") != NULL || strstr(name, "as") != NULL) {
if (target == ASDSTO0) {
targetValue = 0.0;
} else {
targetValue = findTarget(moti, self->targetPosition);
}
motID = StartDriveTask(moti.pMot,pCon,moti.motorName,targetValue);
if(motID < 0){
return HWFault;
}
AddTaskToGroup(pServ->pTasker,motID,self->groupID);
}
status = LLDnodePtr2Next(self->motorTable);
}
return OKOK;
}
/*-------------------------------------------------------------------------*/
static int startOthers(pTableDrive self, SConnection * pCon)
{
tdMotor moti;
int status;
char name[132];
float targetValue;
long motID;
if (self == NULL || self->motorTable < 0) {
return 0;
}
self->groupID = GetTaskGroupID(pServ->pTasker);
status = LLDnodePtr2First(self->motorTable);
while (status != 0) {
LLDnodeDataTo(self->motorTable, &moti);
strlcpy(name, moti.motorName, 131);
strtolower(name);
if (strstr(name, "ds") == NULL && strstr(name, "as") == NULL) {
targetValue = findTarget(moti, self->targetPosition);
motID = StartDriveTask(moti.pMot,pCon,moti.motorName,targetValue);
if(motID < 0){
return HWFault;
}
AddTaskToGroup(pServ->pTasker,motID,self->groupID);
}
status = LLDnodePtr2Next(self->motorTable);
}
return OKOK;
}
/*-------------------------------------------------------------------------*/
static int TableDriveCheckStatus(void *pData, SConnection * pCon)
{
pTableDrive self = (pTableDrive) pData;
int status;
float step;
char pBueffel[1024];
switch (self->state) {
case STARTING:
/*
* make sure that our current position is up-to-date
*/
TableDriveGetValue(self, pCon);
liberateMotors(self, pCon);
status = startASDS(self, pCon, ASDSTO0);
if (status != OKOK) {
TableDriveHalt(self);
return HWFault;
}
self->state = WAITDSAS;
return HWBusy;
break;
case WAITDSAS:
status = checkRunning(self, pCon);
switch (status) {
case HWIdle:
case OKOK:
if (self->debug > 0) {
showPositions(self, pCon, pBueffel, 1023);
SCWrite(pCon, pBueffel, eValue);
}
status = startOthers(self, pCon);
if (status != OKOK) {
TableDriveHalt(self);
return HWFault;
}
self->state = WAITOTHER;
return HWBusy;
break;
case HWBusy:
return HWBusy;
break;
default:
TableDriveHalt(self);
self->state = WAITFINISH;
return HWBusy;
break;
}
break;
case WAITOTHER:
status = checkRunning(self, pCon);
switch (status) {
case HWIdle:
case OKOK:
if (self->debug > 0) {
showPositions(self, pCon, pBueffel, 1023);
SCWrite(pCon, pBueffel, eValue);
}
status = startASDS(self, pCon, ASDSTOTARGET);
if (status != OKOK) {
TableDriveHalt(self);
return HWFault;
}
self->state = WAITFINISH;
return HWBusy;
break;
case HWBusy:
return HWBusy;
break;
default:
TableDriveHalt(self);
self->state = WAITFINISH;
return HWBusy;
break;
}
break;
case WAITFINISH:
status = checkRunning(self, pCon);
if (status != HWBusy) {
if (self->debug > 0) {
showPositions(self, pCon, pBueffel, 1023);
SCWrite(pCon, pBueffel, eValue);
}
TableDriveGetValue(self, pCon);
closeMotors(self, pCon);
self->state = IDLE;
return status;
} else {
return HWBusy;
}
break;
case OUTOFSYNC:
SCWrite(pCon, "WARNING: tabledrive out of sync", eWarning);
self->state = IDLE;
return HWFault;
break;
default:
SCWrite(pCon,
"ERROR: programming error in tabledrive, invalid state",
eError);
return HWFault;
break;
}
return HWFault;
}
/*================== live and death ========================================*/
static void *TableDriveInterface(void *pData, int ID)
{
pTableDrive self = (pTableDrive) pData;
if (self == NULL) {
return NULL;
}
if (ID == DRIVEID) {
return self->pDriv;
} else {
return NULL;
}
}
/*--------------------------------------------------------------------------*/
static void clearTable(int table)
{
int status;
tdMotor moti;
status = LLDnodePtr2First(table);
while (status != 0) {
LLDnodeDataTo(table, &moti);
LLDdelete(moti.table);
status = LLDnodePtr2Next(table);
}
}
/*------------------------------------------------------------------------*/
static int loadTable(pTableDrive self, char *filename, SConnection * pCon)
{
FILE *fd = NULL;
tdMotor moti;
tdEntry entry;
char pBueffel[512];
int lineCount, tableCount = -1, read;
if (self->motorTable >= 0) {
clearTable(self->motorTable);
}
fd = fopen(filename, "r");
if (fd == NULL) {
snprintf(pBueffel, 511, "ERROR: failed to open %s for reading",
filename);
SCWrite(pCon, pBueffel, eError);
return 0;
}
self->motorTable = LLDcreate(sizeof(tdMotor));
if (self->motorTable < 0) {
SCWrite(pCon, "ERROR: failed to allocate motor table", eError);
fclose(fd);
return 0;
}
while (fgets(pBueffel, 511, fd) != NULL) {
if (pBueffel[0] == '#') {
strcpy(moti.motorName, trim(&pBueffel[1]));
moti.pMot = FindCommandData(pServ->pSics, moti.motorName, "Motor");
if (moti.pMot == NULL) {
snprintf(pBueffel, 511, "ERROR: motor %s NOT found!",
moti.motorName);
SCWrite(pCon, pBueffel, eError);
fclose(fd);
return 0;
}
moti.table = LLDcreate(sizeof(tdEntry));
if (moti.table < 0) {
SCWrite(pCon, "ERROR: failed to allocate table data", eError);
fclose(fd);
return 0;
}
lineCount = 1;
} else {
read = sscanf(pBueffel, "%lf %lf %lf", &entry.lower, &entry.position,
&entry.upper);
if (read >= 3) {
entry.tablePos = lineCount;
LLDnodeAppendFrom(moti.table, &entry);
lineCount++;
} else {
/*
* we are on a break line
*/
if (tableCount < 0) {
tableCount = lineCount;
} else {
if (lineCount != tableCount) {
SCWrite(pCon,
"ERROR: bad table file, table length mismatch",
eError);
fclose(fd);
return 0;
}
}
LLDnodeAppendFrom(self->motorTable, &moti);
}
}
}
self->tableLength = tableCount - 1;
fclose(fd);
return 1;
}
/*-------------------------------------------------------------------------*/
static void killTableDrive(void *pData)
{
pTableDrive self = (pTableDrive) pData;
if (self == NULL) {
return;
}
if (self->pDes != NULL) {
DeleteDescriptor(self->pDes);
}
if (self->motorTable >= 0) {
clearTable(self->motorTable);
LLDdelete(self->motorTable);
self->motorTable = -1;
}
if (self->pDriv != NULL) {
free(self->pDriv);
}
free(self);
}
/*-------------------------------------------------------------------------*/
int TableDriveFactory(SConnection * pCon, SicsInterp * pSics, void *pData,
int argc, char *argv[])
{
pTableDrive pNew = NULL;
char pBueffel[256];
int status;
if (argc < 3) {
SCWrite(pCon, "ERROR: insufficient parameters to TableDriveFactory",
eError);
return 0;
}
pNew = (pTableDrive) malloc(sizeof(TableDrive));
if (pNew == NULL) {
SCWrite(pCon, "ERROT: out of memory creating table drive", eError);
return 0;
}
memset(pNew, 0, sizeof(TableDrive));
pNew->pDes = CreateDescriptor("TableDrive");
pNew->pDriv = CreateDrivableInterface();
if (pNew->pDes == NULL || pNew->pDriv == NULL) {
SCWrite(pCon, "ERROT: out of memory creating table drive", eError);
return 0;
}
pNew->pDes->GetInterface = TableDriveInterface;
pNew->pDriv->CheckLimits = TableDriveCheckLimits;
pNew->pDriv->CheckStatus = TableDriveCheckStatus;
pNew->pDriv->GetValue = TableDriveGetValue;
pNew->pDriv->Halt = TableDriveHalt;
pNew->pDriv->SetValue = TableDriveSetValue;
pNew->motorTable = -1;
pNew->state = OUTOFSYNC;
pNew->tableLength = 0;
pNew->targetPosition = 0;
pNew->oriInvalid = 1;
if (!loadTable(pNew, argv[2], pCon)) {
killTableDrive(pNew);
return 0;
}
pNew->state = IDLE;
status = AddCommand(pSics, argv[1],
TableDriveAction, killTableDrive, pNew);
if (!status) {
snprintf(pBueffel, 256, "ERROR: duplicate command %s not created",
argv[1]);
SCWrite(pCon, pBueffel, eError);
killTableDrive(pNew);
return 0;
}
return 1;
}
/*====================== interpreter interface ============================*/
int TableDriveAction(SConnection * pCon, SicsInterp * pSics, void *pData,
int argc, char *argv[])
{
pTableDrive self = (pTableDrive) pData;
int status;
char pBueffel[1024];
float value;
pDynString print = NULL;
if (argc < 2) {
value = TableDriveGetValue(self, pCon);
snprintf(pBueffel, 255, "%s = %f", argv[0], value);
SCWrite(pCon, pBueffel, eValue);
if (value > -999) {
return 1;
} else {
return 0;
}
} else {
strtolower(argv[1]);
if (strcmp(argv[1], "load") == 0) {
if (!SCMatchRights(pCon, usMugger)) {
return 0;
}
if (argc < 3) {
SCWrite(pCon, "ERROR: require filename to load", eError);
return 0;
}
status = loadTable(self, argv[2], pCon);
if (status == 1) {
SCSendOK(pCon);
}
return status;
} else if (strcmp(argv[1], "show") == 0) {
SCStartBuffering(pCon);
showPositions(self, pCon, pBueffel, 1023);
SCWrite(pCon, pBueffel, eValue);
print = SCEndBuffering(pCon);
if(print != NULL){
SCWrite(pCon,GetCharArray(print), eValue);
}
return 1;
} else if (strcmp(argv[1], "info") == 0) {
SCStartBuffering(pCon);
tableInfo(self, pCon);
print = SCEndBuffering(pCon);
if (print != NULL) {
SCWrite(pCon, GetCharArray(print), eValue);
}
return 1;
} else if (strcmp(argv[1], "orient") == 0) {
if (argc > 2) {
if (!SCMatchRights(pCon, usMugger)) {
return 0;
}
strlcpy(self->orientMotor, argv[2], 80);
self->oriInvalid = 1;
SCSendOK(pCon);
return 1;
} else {
snprintf(pBueffel, 255, "%s.orient = %s",
argv[0], self->orientMotor);
SCWrite(pCon, pBueffel, eValue);
return 1;
}
} else if (strcmp(argv[1], "debug") == 0) {
if (self->debug == 0) {
self->debug = 1;
} else {
self->debug = 0;
}
SCSendOK(pCon);
return 1;
} else {
SCWrite(pCon, "ERROR: sub command not understood", eError);
return 0;
}
}
return 1;
}