386 lines
10 KiB
C
386 lines
10 KiB
C
/*-------------------------------------------------------------------------
|
|
|
|
V E L O D O R N
|
|
|
|
Utility functions for talking to a Dornier velocity selector in the
|
|
SINQ setup.
|
|
|
|
Mark Koennecke, Juli 1997
|
|
|
|
Updated to decode the new dornier status messages as coughed up by the new
|
|
style Dornier software.
|
|
|
|
Mark Koennecke, July 2003
|
|
|
|
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 <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <assert.h>
|
|
#include <ctype.h>
|
|
#include <sics.h>
|
|
#include <fortify.h>
|
|
#include "hardsup/sinq_prototypes.h"
|
|
#include "velodorn.h"
|
|
#include "hardsup/serialsinq.h"
|
|
#include <serialwait.h>
|
|
|
|
#define TOK_BUF_L 25
|
|
/*--------------------------- analyse Dornier status string ----------------*/
|
|
int AnalyseDornierStatus(char *pText, pDornierStatus pResult)
|
|
{
|
|
int cnt, key_id, sl, sts;
|
|
long err;
|
|
char ena_str[] = "ENABLED";
|
|
char dis_str[] = "DISABLED";
|
|
char keys[16][9] = {
|
|
"Status:\0 ",
|
|
"S_DREH:\0 ",
|
|
"I_DREH:\0 ",
|
|
"P_VERL:\0 ",
|
|
"STROM:\0 ",
|
|
"T_ROT:\0 ",
|
|
"T_GEH:\0 ",
|
|
"T_VOR:\0 ",
|
|
"T_RUECK:\0",
|
|
"DURCHFL:\0",
|
|
"VAKUUM:\0 ",
|
|
"BESCHL:\0 ",
|
|
"KOM: \0 ",
|
|
"DATE: \0 ",
|
|
"TIME: \0 ",
|
|
"Hz:\0 "
|
|
};
|
|
|
|
char tok_buf[TOK_BUF_L], *ptr_token, *ptr_src, *ptr;
|
|
const char tok_c[] = "/\\\0";
|
|
char status[255];
|
|
|
|
ptr_src = pText;
|
|
memset(pResult, 0, sizeof(DornierStatus));
|
|
|
|
/* skip over first token, should be command echo */
|
|
ptr_token = strtok(ptr_src, tok_c);
|
|
if (ptr_token == NULL)
|
|
return 0; /* error */
|
|
strcpy(pResult->echo, (const char *) ptr_token);
|
|
ptr_src += strlen(ptr_token);
|
|
|
|
ptr_src = NULL; /* necessary for further search with strtok */
|
|
for (;;) {
|
|
/* read text till next separator '/' */
|
|
ptr_token = strtok(ptr_src, tok_c);
|
|
if (ptr_token == NULL)
|
|
break;
|
|
strcpy(tok_buf, ptr_token);
|
|
|
|
for (key_id = 0; key_id <= 15; key_id++) {
|
|
/* search key ? */
|
|
sl = strlen(keys[key_id]);
|
|
if (strncmp(&keys[key_id][0], tok_buf, sl) == 0) {
|
|
/* step over key */
|
|
for (cnt = 0; cnt + sl < TOK_BUF_L; cnt++)
|
|
tok_buf[cnt] = tok_buf[cnt + sl];
|
|
switch (key_id) {
|
|
case 0:{
|
|
strcpy(pResult->rm, tok_buf);
|
|
break;
|
|
}
|
|
case 1:{
|
|
sscanf(tok_buf, "%d", &pResult->nom_rpm);
|
|
break;
|
|
}
|
|
case 2:{
|
|
sscanf(tok_buf, "%d", &pResult->cur_rpm);
|
|
break;
|
|
}
|
|
case 3:{
|
|
sscanf(tok_buf, "%d", &pResult->pwr);
|
|
break;
|
|
}
|
|
case 4:{
|
|
sscanf(tok_buf, "%f", &pResult->curr);
|
|
break;
|
|
}
|
|
case 5:{
|
|
sscanf(tok_buf, "%d", &pResult->rot_temp);
|
|
break;
|
|
}
|
|
case 6:{
|
|
sscanf(tok_buf, "%d", &pResult->cont_temp);
|
|
break;
|
|
}
|
|
case 7:{
|
|
sscanf(tok_buf, "%d", &pResult->inl_temp);
|
|
break;
|
|
}
|
|
case 8:{
|
|
sscanf(tok_buf, "%d", &pResult->outl_temp);
|
|
break;
|
|
}
|
|
case 9:{
|
|
sscanf(tok_buf, "%f", &pResult->cool_wat);
|
|
break;
|
|
}
|
|
case 10:{
|
|
sscanf(tok_buf, "%f", &pResult->vacuum);
|
|
break;
|
|
}
|
|
case 11:{
|
|
sscanf(tok_buf, "%f", &pResult->accel);
|
|
break;
|
|
}
|
|
case 12:{
|
|
if (strcmp(tok_buf, ena_str) == 0) {
|
|
pResult->komm = 1;
|
|
break;
|
|
}
|
|
if (strcmp(tok_buf, dis_str) == 0) {
|
|
pResult->komm = 0;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
case 13:
|
|
break; /* date */
|
|
case 14:
|
|
break; /* time */
|
|
case 15:{
|
|
sscanf(tok_buf, "%d", &pResult->iHz);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return (1);
|
|
}
|
|
|
|
/*--------------------------- analyse Dornier status string ----------------
|
|
This is the version for the NGS037 software from Dornier. Main difference
|
|
is that the keycodes are in germlish.
|
|
-------------------------------------------------------------------------*/
|
|
int DecodeNewDornierStatus(char *pText, pDornierStatus pResult)
|
|
{
|
|
int cnt, key_id, sl, sts;
|
|
long err;
|
|
char ena_str[] = "ENABLED";
|
|
char dis_str[] = "DISABLED";
|
|
char keys[16][14] = {
|
|
"MODE:\0 ",
|
|
"R_SPEED:\0 ",
|
|
"A_SPEED:\0 ",
|
|
"P_LOSS:\0 ",
|
|
"R_Current:\0 ",
|
|
"T_ROT:\0 ",
|
|
"T_HHH:\0 ",
|
|
"T_INL:\0 ",
|
|
"T_OUT:\0",
|
|
"F_RATE:\0",
|
|
"A_Vac:\0 ",
|
|
"V_OSC:\0 ",
|
|
"COM: \0 ",
|
|
"DATE: \0 ",
|
|
"TIME: \0 ",
|
|
"Hz:\0 "
|
|
};
|
|
|
|
char tok_buf[TOK_BUF_L], *ptr_token, *ptr_src, *ptr;
|
|
const char tok_c[] = "/\\\0";
|
|
char status[255];
|
|
|
|
ptr_src = pText;
|
|
memset(pResult, 0, sizeof(DornierStatus));
|
|
|
|
/* skip over first token, should be command echo */
|
|
ptr_token = strtok(ptr_src, tok_c);
|
|
if (ptr_token == NULL)
|
|
return 0; /* error */
|
|
strcpy(pResult->echo, (const char *) ptr_token);
|
|
ptr_src += strlen(ptr_token);
|
|
|
|
ptr_src = NULL; /* necessary for further search with strtok */
|
|
for (;;) {
|
|
/* read text till next separator '/' */
|
|
ptr_token = strtok(ptr_src, tok_c);
|
|
if (ptr_token == NULL)
|
|
break;
|
|
strcpy(tok_buf, ptr_token);
|
|
|
|
for (key_id = 0; key_id <= 15; key_id++) {
|
|
/* search key ? */
|
|
sl = strlen(keys[key_id]);
|
|
if (strncmp(&keys[key_id][0], tok_buf, sl) == 0) {
|
|
/* step over key */
|
|
for (cnt = 0; cnt + sl < TOK_BUF_L; cnt++)
|
|
tok_buf[cnt] = tok_buf[cnt + sl];
|
|
switch (key_id) {
|
|
case 0:{
|
|
strcpy(pResult->rm, tok_buf);
|
|
break;
|
|
}
|
|
case 1:{
|
|
sscanf(tok_buf, "%d", &pResult->nom_rpm);
|
|
break;
|
|
}
|
|
case 2:{
|
|
sscanf(tok_buf, "%d", &pResult->cur_rpm);
|
|
break;
|
|
}
|
|
case 3:{
|
|
sscanf(tok_buf, "%d", &pResult->pwr);
|
|
break;
|
|
}
|
|
case 4:{
|
|
sscanf(tok_buf, "%f", &pResult->curr);
|
|
break;
|
|
}
|
|
case 5:{
|
|
sscanf(tok_buf, "%d", &pResult->rot_temp);
|
|
break;
|
|
}
|
|
case 6:{
|
|
sscanf(tok_buf, "%d", &pResult->cont_temp);
|
|
break;
|
|
}
|
|
case 7:{
|
|
sscanf(tok_buf, "%d", &pResult->inl_temp);
|
|
break;
|
|
}
|
|
case 8:{
|
|
sscanf(tok_buf, "%d", &pResult->outl_temp);
|
|
break;
|
|
}
|
|
case 9:{
|
|
sscanf(tok_buf, "%f", &pResult->cool_wat);
|
|
break;
|
|
}
|
|
case 10:{
|
|
sscanf(tok_buf, "%f", &pResult->vacuum);
|
|
break;
|
|
}
|
|
case 11:{
|
|
sscanf(tok_buf, "%f", &pResult->accel);
|
|
break;
|
|
}
|
|
case 12:{
|
|
if (strcmp(tok_buf, ena_str) == 0) {
|
|
pResult->komm = 1;
|
|
break;
|
|
}
|
|
if (strcmp(tok_buf, dis_str) == 0) {
|
|
pResult->komm = 0;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
case 13:
|
|
break; /* date */
|
|
case 14:
|
|
break; /* time */
|
|
case 15:{
|
|
sscanf(tok_buf, "%d", &pResult->iHz);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return (1);
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
int DornierSend(void **pData, char *pCommand, char *pReply, int iRepLen)
|
|
{
|
|
char pOldCom[10];
|
|
char *pPtr;
|
|
int iRet;
|
|
|
|
/* first copy the command send out, in order to test for echo */
|
|
pPtr = pCommand;
|
|
memset(pOldCom, 0, 10);
|
|
while (isspace(*pPtr) && (*pPtr != '\0')) {
|
|
pPtr++;
|
|
}
|
|
if (*pPtr == '\0') { /* no command */
|
|
return NOCOMMAND;
|
|
}
|
|
strncpy(pOldCom, pPtr, 3);
|
|
|
|
iRet = SerialWriteRead(pData, pCommand, pReply, iRepLen);
|
|
/*
|
|
iRet = SerialSicsExecute(pData,pCommand,pReply,iRepLen);
|
|
*/
|
|
if (iRet != 1) {
|
|
return iRet; /* an error ocurred */
|
|
}
|
|
|
|
/* try to find command in the reply */
|
|
pPtr = strstr(pReply, pOldCom);
|
|
if (pPtr == NULL) {
|
|
SICSLogWrite("Velocity Selector: Bad Reply:", eError);
|
|
SICSLogWrite(pReply, eError);
|
|
return ECHOMISSING;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
int GetDornierStatus(void **pData, pDornierStatus pDornier)
|
|
{
|
|
char pCommand[10] = { "???" };
|
|
char pReply[256];
|
|
int iRet;
|
|
|
|
/* send command */
|
|
iRet = DornierSend(pData, pCommand, pReply, 255);
|
|
if (iRet < 0) {
|
|
return iRet;
|
|
}
|
|
if (strlen(pReply) < 100) {
|
|
SICSLogWrite("Velocity Selector: Bad Reply:", eError);
|
|
SICSLogWrite(pReply, eError);
|
|
return INVALIDSTATUS;
|
|
}
|
|
|
|
|
|
/* analyse reply */
|
|
iRet = AnalyseDornierStatus(pReply, pDornier);
|
|
if (!iRet) {
|
|
return BADANALYSIS;
|
|
}
|
|
if (pDornier->cur_rpm > 70000) {
|
|
printf("Shitty status reply: %s detected \n", pReply);
|
|
}
|
|
return 1;
|
|
}
|