1025 lines
24 KiB
C
1025 lines
24 KiB
C
/*--------------------------------------------------------------------------
|
|
S L S M A G N E T
|
|
|
|
This file contains the driver for the PSI-DSP magnet controller as
|
|
aquired from SLS.
|
|
|
|
This device runs a binary protocoll on its RS232 interface. And the lowest
|
|
speed this device understands is 115KB! This is why this driver accesses
|
|
the terminal server port directly through the network without David's
|
|
SerPortServer program in between. Also make sure that the port runs at
|
|
115KB when using this device.
|
|
|
|
Mark Koennecke, October 2001
|
|
|
|
Adaptiert auf neue DSP Software version, Mark Koennecke, August 2005
|
|
|
|
Fixed some bugs and added resetting of error conditions:
|
|
Mark Koennecke, May 2007
|
|
|
|
There is another scheme for resetting controller erros which might need
|
|
to be implemented:
|
|
1) switch the controller off
|
|
2) Write 0 to 0x21
|
|
3) switch on
|
|
4) drive to target
|
|
This reboots the controller. Lukas Tanner does not recommend to do this
|
|
automatically. This is why it is not implemented yet. This reboot anyway
|
|
is not as hard as a full power cycle.
|
|
|
|
Copyright: see copyright.h
|
|
----------------------------------------------------------------------------*/
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <time.h>
|
|
#include <math.h>
|
|
#include <assert.h>
|
|
#include <unistd.h>
|
|
#include <fortify.h>
|
|
#include <conman.h>
|
|
#include <servlog.h>
|
|
#include <fortify.h>
|
|
#include <strlutil.h>
|
|
|
|
#include "evdriver.h"
|
|
#include <network.h>
|
|
#include <rs232controller.h>
|
|
|
|
/*
|
|
error codes
|
|
*/
|
|
#define BADECHO -5100
|
|
/*
|
|
#define NOTCONNECTED -5200
|
|
#define TIMEOUT -5300
|
|
*/
|
|
|
|
/*
|
|
when waiting for results, the code loops at max MAXLOOP times
|
|
before doing a timeout. 100 corresponds to one second
|
|
*/
|
|
#define MAXLOOP 100
|
|
#define BADLOWLIM -5301
|
|
#define BADHIGHLIM -5302
|
|
#define DEVICERROR -5304
|
|
/*
|
|
packet header codes
|
|
*/
|
|
#define DSPWRITE 0x80
|
|
#define DSPREAD 0x0
|
|
|
|
#define ABS(x) (x < 0 ? -(x) : (x))
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
typedef struct {
|
|
mkChannel *pSock;
|
|
char *pHost;
|
|
int iPort;
|
|
int iError;
|
|
} SLSDriv, *pSLSDriv;
|
|
/*-------------------------------------------------------------------------
|
|
Code for data conversion from Lukas Tanner. The ULONG is system dependent,
|
|
it MUST describe a 32 bit value.
|
|
-------------------------------------------------------------------------*/
|
|
#define ULONG int
|
|
/***********************************************************************/
|
|
static ULONG double2DSPfloat(double input)
|
|
/***********************************************************************/
|
|
/* Konvertiert eine normale double Variable in ein 32bit DSP Float Format. */
|
|
{
|
|
ULONG output;
|
|
double mantissa;
|
|
int exponent;
|
|
|
|
if (input == 0) {
|
|
output = 0;
|
|
} else {
|
|
mantissa = 2 * (frexp(fabs(input), &exponent));
|
|
mantissa = ldexp(mantissa, 23);
|
|
exponent = exponent - 1 + 127;
|
|
if (exponent < 0) {
|
|
exponent = 0;
|
|
} else if (exponent > 0xFE) {
|
|
exponent = 0xFE;
|
|
}
|
|
exponent = exponent << 23;
|
|
output = ((ULONG) mantissa) & 0x7FFFFF;
|
|
output = output | ((ULONG) (exponent));
|
|
if (input < 0) {
|
|
output = output | 0x80000000;
|
|
}
|
|
}
|
|
return output;
|
|
}
|
|
|
|
/***********************************************************************/
|
|
static double DSPfloat2double(ULONG input)
|
|
/***********************************************************************/
|
|
/* Konvertiert eine Variable inder ein 32bit DSP Float Wert abgelegt ist,
|
|
in ein normales double Format
|
|
32bit IEEE Float => SEEEEEEEEMMMMMMMMMMMMMMMMMMMMMMM; S = Sign Bit
|
|
E = Exponent
|
|
M = Mantissa (23)*/
|
|
{
|
|
double output;
|
|
if ((input & 0x7FFFFF) == 0 && ((input >> 23) & 0xFF) == 0) {
|
|
output = 0;
|
|
} else {
|
|
output = ldexp(input & 0x7FFFFF, -23) + 1;
|
|
output = output * pow(-1, ((input >> 31) & 1));
|
|
output = output * ldexp(1, (((input >> 23) & 0xFF) - 127));
|
|
}
|
|
return output;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
static int communicateSLS(mkChannel * pSock, char msg[6], char reply[6])
|
|
{
|
|
long lVal = 0;
|
|
int iRet, i, address, status;
|
|
|
|
if (!pSock)
|
|
return NOTCONNECTED;
|
|
|
|
memset(reply, 0, 6);
|
|
address = (int) msg[1];
|
|
iRet = NETWrite(pSock, msg, 6);
|
|
if (iRet < 0) {
|
|
return iRet;
|
|
}
|
|
for (i = 0; i < MAXLOOP; i++) {
|
|
iRet = NETAvailable(pSock, 10);
|
|
if (iRet < 0) {
|
|
return iRet;
|
|
} else if (iRet == 1) {
|
|
status = NETRead(pSock, reply + lVal, 6 - lVal, -10);
|
|
if (status >= 0) {
|
|
lVal += status;
|
|
} else {
|
|
/*
|
|
* network read error
|
|
*/
|
|
return status;
|
|
}
|
|
if (lVal >= 6) {
|
|
return (int) lVal;
|
|
} else {
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
if ((int) reply[1] != address) {
|
|
return BADECHO;
|
|
}
|
|
return TIMEOUT;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
static int GetSLSPos(pEVDriver self, float *fPos)
|
|
{
|
|
pSLSDriv pMe = NULL;
|
|
int iRet, ival, err;
|
|
double dval;
|
|
char msg[6], reply[6];
|
|
long lVal;
|
|
|
|
assert(self);
|
|
pMe = (pSLSDriv) self->pPrivate;
|
|
assert(pMe);
|
|
|
|
memset(msg, 0, 6 * sizeof(char));
|
|
memset(reply, 0, 6 * sizeof(char));
|
|
msg[0] = DSPREAD; /* read request */
|
|
/* old address of mag current
|
|
msg[1] = 0x92;
|
|
*/
|
|
msg[1] = 0x9c; /* address of mag current */
|
|
iRet = communicateSLS(pMe->pSock, msg, reply);
|
|
if (iRet < 0) {
|
|
pMe->iError = iRet;
|
|
return 0;
|
|
}
|
|
memcpy(&ival, reply + 2, 4);
|
|
dval = DSPfloat2double(ival);
|
|
*fPos = (float) dval;
|
|
pMe->iError = 0;
|
|
|
|
/*
|
|
* try read error codes
|
|
*/
|
|
msg[1] = 0x29;
|
|
iRet = communicateSLS(pMe->pSock, msg, reply);
|
|
if (iRet < 0) {
|
|
pMe->iError = iRet;
|
|
return 0;
|
|
}
|
|
err = (int) reply[5];
|
|
if (err != 0) {
|
|
pMe->iError = -7000 - err;
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
static int SLSRun(pEVDriver self, float fVal)
|
|
{
|
|
pSLSDriv pMe = NULL;
|
|
int iRet, ival, i;
|
|
char msg[6], reply[6];
|
|
double min, max;
|
|
|
|
assert(self);
|
|
pMe = (pSLSDriv) self->pPrivate;
|
|
assert(pMe);
|
|
|
|
memset(msg, 0, 6 * sizeof(char));
|
|
memset(reply, 0, 6 * sizeof(char));
|
|
|
|
/*
|
|
* test high limit
|
|
*/
|
|
msg[0] = DSPREAD;
|
|
msg[1] = 0x76;
|
|
iRet = communicateSLS(pMe->pSock, msg, reply);
|
|
if (iRet <= 0) {
|
|
pMe->iError = iRet;
|
|
return iRet;
|
|
}
|
|
memcpy(&ival, reply + 2, 4);
|
|
max = DSPfloat2double(ival);
|
|
if (fVal > max) {
|
|
pMe->iError = BADHIGHLIM;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* test low limit
|
|
*/
|
|
msg[0] = DSPREAD;
|
|
msg[1] = 0x77;
|
|
iRet = communicateSLS(pMe->pSock, msg, reply);
|
|
if (iRet <= 0) {
|
|
pMe->iError = iRet;
|
|
return iRet;
|
|
}
|
|
memcpy(&ival, reply + 2, 4);
|
|
min = -ABS(DSPfloat2double(ival));
|
|
if (fVal < min) {
|
|
pMe->iError = BADLOWLIM;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* actual set the new value
|
|
*/
|
|
msg[0] = DSPWRITE;
|
|
msg[1] = 0x90;
|
|
ival = double2DSPfloat((double) fVal);
|
|
memcpy(msg + 2, &ival, 4);
|
|
iRet = communicateSLS(pMe->pSock, msg, reply);
|
|
if (iRet <= 0) {
|
|
pMe->iError = iRet;
|
|
return 0;
|
|
}
|
|
for (i = 1; i < 6; i++) {
|
|
if (msg[i] != reply[i]) {
|
|
pMe->iError = BADECHO;
|
|
return 0;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------*/
|
|
static void slsdspCodeToText(int code, char *text, int textlen)
|
|
{
|
|
switch (code) {
|
|
case 0x0:
|
|
strlcpy(text, "NO", textlen);
|
|
break;
|
|
case 0x1:
|
|
strlcpy(text, "DEVICE_STATE_ERROR", textlen);
|
|
break;
|
|
case 0x2:
|
|
strlcpy(text, "DEVICE_SUPERVISOR_DISABLED", textlen);
|
|
break;
|
|
case 0x3:
|
|
strlcpy(text, "COMMAND_ABORT", textlen);
|
|
break;
|
|
case 0x4:
|
|
strlcpy(text, "DATA_NOT_STORED", textlen);
|
|
break;
|
|
case 0x5:
|
|
strlcpy(text, "ERROR_ERASING_FLASH", textlen);
|
|
break;
|
|
case 0x6:
|
|
strlcpy(text, "COMMUNICATION_BREAK", textlen);
|
|
break;
|
|
case 0x7:
|
|
strlcpy(text, "INTERNAL_COMMUNICATION_ERROR", textlen);
|
|
break;
|
|
case 0x8:
|
|
strlcpy(text, "MASTER_CARD_ERROR", textlen);
|
|
break;
|
|
case 0x9:
|
|
strlcpy(text, "INTERNAL_BUFFER_FULL", textlen);
|
|
break;
|
|
case 0xa:
|
|
strlcpy(text, "WRONG_SECTOR", textlen);
|
|
break;
|
|
case 0xb:
|
|
strlcpy(text, "DATA_NOT_COPIED", textlen);
|
|
break;
|
|
case 0xc:
|
|
strlcpy(text, "WRONG_DOWNLOAD_PARAMETERS", textlen);
|
|
break;
|
|
case 0xd:
|
|
strlcpy(text, "DEVICE_PARAMETRIZATION_ERROR", textlen);
|
|
break;
|
|
case 0x10:
|
|
strlcpy(text, "TIMEOUT_DC_LINK_VOLTAGE", textlen);
|
|
break;
|
|
case 0x11:
|
|
strlcpy(text, "TIMEOUT_AUXILIARY_RELAY_ON", textlen);
|
|
break;
|
|
case 0x12:
|
|
strlcpy(text, "TIMEOUT_AUXILIARY_RELAY_OFF", textlen);
|
|
break;
|
|
case 0x13:
|
|
strlcpy(text, "TIMEOUT_MAIN_RELAY_ON", textlen);
|
|
break;
|
|
case 0x14:
|
|
strlcpy(text, "TIMEOUT_MAIN_RELAY_OFF", textlen);
|
|
break;
|
|
case 0x15:
|
|
strlcpy(text, "TIMEOUT_DATA_DOWNLOAD", textlen);
|
|
break;
|
|
case 0x20:
|
|
strlcpy(text, "INTERLOCK", textlen);
|
|
break;
|
|
case 0x21:
|
|
strlcpy(text, "MASTER_SWITCH", textlen);
|
|
break;
|
|
case 0x22:
|
|
strlcpy(text, "MAGNET_INTERLOCK", textlen);
|
|
break;
|
|
case 0x23:
|
|
strlcpy(text, "TEMPERATURE_TRANSFORMER", textlen);
|
|
break;
|
|
case 0x24:
|
|
strlcpy(text, "TEMPERATURE_RECTIFIER", textlen);
|
|
break;
|
|
case 0x25:
|
|
strlcpy(text, "TEMPERATURE_CONVERTER", textlen);
|
|
break;
|
|
case 0x26:
|
|
strlcpy(text, "CURRENT_TRANSDUCER", textlen);
|
|
break;
|
|
case 0x27:
|
|
strlcpy(text, "TEMPERATURE_POLARITY_SWITCH", textlen);
|
|
break;
|
|
case 0x28:
|
|
strlcpy(text, "POWER_SEMICONDUCTOR", textlen);
|
|
break;
|
|
case 0x29:
|
|
strlcpy(text, "MAIN_RELAY", textlen);
|
|
break;
|
|
case 0x2a:
|
|
strlcpy(text, "AD_CONVERTER_CARD", textlen);
|
|
break;
|
|
case 0x2b:
|
|
strlcpy(text, "POLARITY_SWITCH", textlen);
|
|
break;
|
|
case 0x2c:
|
|
strlcpy(text, "AUXILIARY_RELAY", textlen);
|
|
break;
|
|
case 0x2d:
|
|
strlcpy(text, "MASTER_SWITCH_T1", textlen);
|
|
break;
|
|
case 0x2e:
|
|
strlcpy(text, "MASTER_SWITCH_T2", textlen);
|
|
break;
|
|
case 0x2f:
|
|
strlcpy(text, "TEMPERATURE_MAGNET", textlen);
|
|
break;
|
|
case 0x30:
|
|
strlcpy(text, "WATER_MAGNET", textlen);
|
|
break;
|
|
case 0x31:
|
|
strlcpy(text, "WATER_RACK", textlen);
|
|
break;
|
|
case 0x40:
|
|
strlcpy(text, "LOAD_CURRENT_TOO_HIGH", textlen);
|
|
break;
|
|
case 0x41:
|
|
strlcpy(text, "DC_LINK_VOLTAGE_TOO_LOW", textlen);
|
|
break;
|
|
case 0x42:
|
|
strlcpy(text, "DC_LINK_VOLTAGE_TOO_HIGH", textlen);
|
|
break;
|
|
case 0x43:
|
|
strlcpy(text, "LOAD_VOLTAGE_TOO_HIGH", textlen);
|
|
break;
|
|
case 0x44:
|
|
strlcpy(text, "LOAD_CURRENT_RIPPLE_TOO_HIGH", textlen);
|
|
break;
|
|
case 0x45:
|
|
strlcpy(text, "DC_LINK_ISOLATION_NOT_OK", textlen);
|
|
break;
|
|
case 0x46:
|
|
strlcpy(text, "LOAD_ISOLATION_NOT_OK", textlen);
|
|
break;
|
|
case 0x47:
|
|
strlcpy(text, "LOAD_IMPEDANCE_OUT_OF_RANGE", textlen);
|
|
break;
|
|
case 0x48:
|
|
strlcpy(text, "SHUT_OFF_CURRENT_TOO_HIGH", textlen);
|
|
break;
|
|
case 0x49:
|
|
strlcpy(text, "LOAD_DC_CURRENT_TOO_HIGH", textlen);
|
|
break;
|
|
case 0x4a:
|
|
strlcpy(text, "CURRENT_I1A1_TOO_HIGH", textlen);
|
|
break;
|
|
case 0x4b:
|
|
strlcpy(text, "CURRENT_I1B1_TOO_HIGH", textlen);
|
|
break;
|
|
case 0x4c:
|
|
strlcpy(text, "CURRENT_I1A2_TOO_HIGH", textlen);
|
|
break;
|
|
case 0x4d:
|
|
strlcpy(text, "CURRENT_I1B2_TOO_HIGH", textlen);
|
|
break;
|
|
case 0x4e:
|
|
strlcpy(text, "CURRENT_I2A1_TOO_HIGH", textlen);
|
|
break;
|
|
case 0x4f:
|
|
strlcpy(text, "CURRENT_I2B1_TOO_HIGH", textlen);
|
|
break;
|
|
case 0x50:
|
|
strlcpy(text, "CURRENT_I2A2_TOO_HIGH", textlen);
|
|
break;
|
|
case 0x51:
|
|
strlcpy(text, "CURRENT_I2B2_TOO_HIGH", textlen);
|
|
break;
|
|
case 0x52:
|
|
strlcpy(text, "CURRENT_I3P_TOO_HIGH", textlen);
|
|
break;
|
|
case 0x53:
|
|
strlcpy(text, "CURRENT_I3N_TOO_HIGH", textlen);
|
|
break;
|
|
case 0x54:
|
|
strlcpy(text, "CURRENT_IE_TOO_HIGH", textlen);
|
|
break;
|
|
case 0x55:
|
|
strlcpy(text, "VOLTAGE_U1A_TOO_LOW", textlen);
|
|
break;
|
|
case 0x56:
|
|
strlcpy(text, "VOLTAGE_U1B_TOO_LOW", textlen);
|
|
break;
|
|
case 0x57:
|
|
strlcpy(text, "DIFF_CURRENT_I1A1_I1A2_TOO_HIGH", textlen);
|
|
break;
|
|
case 0x58:
|
|
strlcpy(text, "DIFF_CURRENT_I1B1_I1B2_TOO_HIGH", textlen);
|
|
break;
|
|
case 0x59:
|
|
strlcpy(text, "DIFF_CURRENT_I2A1_I2A2_TOO_HIGH", textlen);
|
|
break;
|
|
case 0x5a:
|
|
strlcpy(text, "DIFF_CURRENT_I2B1_I2B2_TOO_HIGH", textlen);
|
|
break;
|
|
case 0x5b:
|
|
strlcpy(text, "DIFF_CURRENT_I3P_I3N_TOO_HIGH", textlen);
|
|
break;
|
|
case 0x5c:
|
|
strlcpy(text, "CURRENT_I1A_TOO_HIGH", textlen);
|
|
break;
|
|
case 0x5d:
|
|
strlcpy(text, "CURRENT_I1B_TOO_HIGH", textlen);
|
|
break;
|
|
case 0x5e:
|
|
strlcpy(text, "CURRENT_I3A1_TOO_HIGH", textlen);
|
|
break;
|
|
case 0x5f:
|
|
strlcpy(text, "CURRENT_I3B1_TOO_HIGH", textlen);
|
|
break;
|
|
case 0x60:
|
|
strlcpy(text, "CURRENT_I3A2_TOO_HIGH", textlen);
|
|
break;
|
|
case 0x61:
|
|
strlcpy(text, "CURRENT_I3B2_TOO_HIGH", textlen);
|
|
break;
|
|
case 0x62:
|
|
strlcpy(text, "CURRENT_I4_TOO_HIGH", textlen);
|
|
break;
|
|
case 0x63:
|
|
strlcpy(text, "CURRENT_I5_TOO_HIGH", textlen);
|
|
break;
|
|
case 0x64:
|
|
strlcpy(text, "DIFF_CURRENT_I3A1_I3A2_TOO_HIGH", textlen);
|
|
break;
|
|
case 0x65:
|
|
strlcpy(text, "DIFF_CURRENT_I3B1_I3B2_TOO_HIGH", textlen);
|
|
break;
|
|
case 0x66:
|
|
strlcpy(text, "DIFF_CURRENT_I4_I5_TOO_HIGH", textlen);
|
|
break;
|
|
case 0x67:
|
|
strlcpy(text, "VOLTAGE_U3A_TOO_LOW", textlen);
|
|
break;
|
|
case 0x68:
|
|
strlcpy(text, "VOLTAGE_U3B_TOO_LOW", textlen);
|
|
break;
|
|
case 0x69:
|
|
strlcpy(text, "VOLTAGE_U1_TOO_LOW", textlen);
|
|
break;
|
|
case 0x6a:
|
|
strlcpy(text, "VOLTAGE_U3A_TOO_HIGH", textlen);
|
|
break;
|
|
case 0x6b:
|
|
strlcpy(text, "VOLTAGE_U3B_TOO_HIGH", textlen);
|
|
break;
|
|
case 0x6c:
|
|
strlcpy(text, "SPEED_ERROR_TOO_HIGH", textlen);
|
|
break;
|
|
case 0x70:
|
|
strlcpy(text, "MAIN_RELAY_A", textlen);
|
|
break;
|
|
case 0x71:
|
|
strlcpy(text, "MAIN_RELAY_B", textlen);
|
|
break;
|
|
case 0x72:
|
|
strlcpy(text, "POWER_SWITCH_A", textlen);
|
|
break;
|
|
case 0x73:
|
|
strlcpy(text, "POWER_SWITCH_B", textlen);
|
|
break;
|
|
case 0x74:
|
|
strlcpy(text, "MONITOR_TRAFO_A", textlen);
|
|
break;
|
|
case 0x75:
|
|
strlcpy(text, "MONITOR_TRAFO_B", textlen);
|
|
break;
|
|
case 0x76:
|
|
strlcpy(text, "TEMPERATURE_RECTIFIER_A", textlen);
|
|
break;
|
|
case 0x77:
|
|
strlcpy(text, "TEMPERATURE_RECTIFIER_B", textlen);
|
|
break;
|
|
case 0x78:
|
|
strlcpy(text, "TEMPERATURE_CONVERTER_A", textlen);
|
|
break;
|
|
case 0x79:
|
|
strlcpy(text, "TEMPERATURE_CONVERTER_B", textlen);
|
|
break;
|
|
case 0x7a:
|
|
strlcpy(text, "TEMPERATURE_CONVERTER_A1", textlen);
|
|
break;
|
|
case 0x7b:
|
|
strlcpy(text, "TEMPERATURE_CONVERTER_B1", textlen);
|
|
break;
|
|
case 0x7c:
|
|
strlcpy(text, "TEMPERATURE_CONVERTER_A2", textlen);
|
|
break;
|
|
case 0x7d:
|
|
strlcpy(text, "TEMPERATURE_CONVERTER_B2", textlen);
|
|
break;
|
|
case 0x7e:
|
|
strlcpy(text, "TEMPERATURE_TRANSFORMER_A", textlen);
|
|
break;
|
|
case 0x7f:
|
|
strlcpy(text, "TEMPERATURE_TRANSFORMER_B", textlen);
|
|
break;
|
|
case 0x80:
|
|
strlcpy(text, "WATER_RECTIFIER_A", textlen);
|
|
break;
|
|
case 0x81:
|
|
strlcpy(text, "WATER_RECTIFIER_B", textlen);
|
|
break;
|
|
case 0x82:
|
|
strlcpy(text, "WATER_CONVERTER_A", textlen);
|
|
break;
|
|
case 0x83:
|
|
strlcpy(text, "WATER_CONVERTER_B", textlen);
|
|
break;
|
|
case 0x84:
|
|
strlcpy(text, "WATER_CONVERTER_A1", textlen);
|
|
break;
|
|
case 0x85:
|
|
strlcpy(text, "WATER_CONVERTER_B1", textlen);
|
|
break;
|
|
case 0x86:
|
|
strlcpy(text, "WATER_CONVERTER_A2", textlen);
|
|
break;
|
|
case 0x87:
|
|
strlcpy(text, "WATER_CONVERTER_B2", textlen);
|
|
break;
|
|
case 0x88:
|
|
strlcpy(text, "WATER_TRANSFORMER_A", textlen);
|
|
break;
|
|
case 0x89:
|
|
strlcpy(text, "WATER_TRANSFORMER_B", textlen);
|
|
break;
|
|
case 0x8a:
|
|
strlcpy(text, "DOOR_A", textlen);
|
|
break;
|
|
case 0x8b:
|
|
strlcpy(text, "DOOR_B", textlen);
|
|
break;
|
|
case 0x8c:
|
|
strlcpy(text, "DOOR_C", textlen);
|
|
break;
|
|
case 0x8d:
|
|
strlcpy(text, "POWER_SEMICONDUCTOR_CONVERTER_A", textlen);
|
|
break;
|
|
case 0x8e:
|
|
strlcpy(text, "POWER_SEMICONDUCTOR_CONVERTER_B", textlen);
|
|
break;
|
|
case 0x8f:
|
|
strlcpy(text, "POWER_SEMICONDUCTOR_CONVERTER_A1", textlen);
|
|
break;
|
|
case 0x90:
|
|
strlcpy(text, "POWER_SEMICONDUCTOR_CONVERTER_B1", textlen);
|
|
break;
|
|
case 0x91:
|
|
strlcpy(text, "POWER_SEMICONDUCTOR_CONVERTER_A2", textlen);
|
|
break;
|
|
case 0x92:
|
|
strlcpy(text, "POWER_SEMICONDUCTOR_CONVERTER_B2", textlen);
|
|
break;
|
|
case 0x93:
|
|
strlcpy(text, "CURRENT_TRANSDUCER_I3P", textlen);
|
|
break;
|
|
case 0x94:
|
|
strlcpy(text, "CURRENT_TRANSDUCER_I3N", textlen);
|
|
break;
|
|
case 0x95:
|
|
strlcpy(text, "MAGNET_INTERLOCK_1", textlen);
|
|
break;
|
|
case 0x96:
|
|
strlcpy(text, "MAGNET_INTERLOCK_2", textlen);
|
|
break;
|
|
case 0x97:
|
|
strlcpy(text, "VENTILATOR", textlen);
|
|
break;
|
|
case 0x98:
|
|
strlcpy(text, "EMERGENCY_SWITCH", textlen);
|
|
break;
|
|
case 0x99:
|
|
strlcpy(text, "CAPACITOR_DISCHARGE_A_ON", textlen);
|
|
break;
|
|
case 0x9a:
|
|
strlcpy(text, "CAPACITOR_DISCHARGE_B_ON", textlen);
|
|
break;
|
|
case 0x9b:
|
|
strlcpy(text, "CURRENT_TRANSDUCER_I4", textlen);
|
|
break;
|
|
case 0x9c:
|
|
strlcpy(text, "CURRENT_TRANSDUCER_I5", textlen);
|
|
break;
|
|
case 0xb0:
|
|
strlcpy(text, "TIMEOUT_DC_LINK_VOLTAGE_PART_A", textlen);
|
|
break;
|
|
case 0xb1:
|
|
strlcpy(text, "TIMEOUT_DC_LINK_VOLTAGE_PART_B", textlen);
|
|
break;
|
|
case 0xb2:
|
|
strlcpy(text, "TIMEOUT_AUXILIARY_RELAY_A_ON", textlen);
|
|
break;
|
|
case 0xb3:
|
|
strlcpy(text, "TIMEOUT_AUXILIARY_RELAY_B_ON", textlen);
|
|
break;
|
|
case 0xb4:
|
|
strlcpy(text, "TIMEOUT_AUXILIARY_RELAY_A_OFF", textlen);
|
|
break;
|
|
case 0xb5:
|
|
strlcpy(text, "TIMEOUT_AUXILIARY_RELAY_B_OFF", textlen);
|
|
break;
|
|
case 0xb6:
|
|
strlcpy(text, "TIMEOUT_MAIN_RELAY_A_ON", textlen);
|
|
break;
|
|
case 0xb7:
|
|
strlcpy(text, "TIMEOUT_MAIN_RELAY_B_ON", textlen);
|
|
break;
|
|
case 0xb8:
|
|
strlcpy(text, "TIMEOUT_MAIN_RELAY_A_OFF", textlen);
|
|
break;
|
|
case 0xb9:
|
|
strlcpy(text, "TIMEOUT_MAIN_RELAY_B_OFF", textlen);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
static int SLSError(pEVDriver self, int *iCode, char *error, int iErrLen)
|
|
{
|
|
pSLSDriv pMe = NULL;
|
|
char *pPtr = NULL;
|
|
int i1, i2;
|
|
char pBueffel[132];
|
|
|
|
assert(self);
|
|
pMe = (pSLSDriv) self->pPrivate;
|
|
assert(pMe);
|
|
|
|
*iCode = pMe->iError;
|
|
if (*iCode < -7000) {
|
|
slsdspCodeToText(-(pMe->iError + 7000), error, iErrLen);
|
|
return 1;
|
|
}
|
|
|
|
|
|
switch (*iCode) {
|
|
case BADECHO:
|
|
strlcpy(error, "message sent and reply did not match", iErrLen);
|
|
break;
|
|
case NOTCONNECTED:
|
|
strlcpy(error, "Not connected to device", iErrLen);
|
|
break;
|
|
case TIMEOUT:
|
|
strlcpy(error, "Timeout waiting for response", iErrLen);
|
|
break;
|
|
case BADHIGHLIM:
|
|
strlcpy(error, "Device internal upper limit violated", iErrLen);
|
|
break;
|
|
case BADLOWLIM:
|
|
strlcpy(error, "Device internal lower limit violated", iErrLen);
|
|
break;
|
|
default:
|
|
getRS232Error(*iCode, error, iErrLen);
|
|
break;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
static int SLSSend(pEVDriver self, char *pCommand, char *pReply, int iLen)
|
|
{
|
|
pSLSDriv pMe = NULL;
|
|
int iRet, ival;
|
|
char msg[6], reply[6];
|
|
|
|
assert(self);
|
|
pMe = (pSLSDriv) self->pPrivate;
|
|
assert(pMe);
|
|
|
|
|
|
|
|
msg[0] = DSPWRITE;
|
|
msg[1] = 0x3c;
|
|
if (strcmp(pCommand, "off") == 0) {
|
|
/*
|
|
* ival = 0: ausschalten
|
|
*/
|
|
ival = 0;
|
|
memcpy(msg + 2, &ival, 4);
|
|
iRet = communicateSLS(pMe->pSock, msg, reply);
|
|
if (iRet <= 0) {
|
|
pMe->iError = iRet;
|
|
SLSError(self, &ival, pReply, iLen);
|
|
return 0;
|
|
} else {
|
|
strlcpy(pReply, "Done", iLen);
|
|
return 1;
|
|
}
|
|
} else if (strcmp(pCommand, "on") == 0) {
|
|
/*
|
|
* ival = 1: einschalten
|
|
*/
|
|
ival = 1;
|
|
memcpy(msg + 2, &ival, 4);
|
|
iRet = communicateSLS(pMe->pSock, msg, reply);
|
|
if (iRet <= 0) {
|
|
pMe->iError = iRet;
|
|
SLSError(self, &ival, pReply, iLen);
|
|
return 0;
|
|
} else {
|
|
strlcpy(pReply, "Done", iLen);
|
|
return 1;
|
|
}
|
|
} else {
|
|
strlcpy(pReply, "SLSMagnet only understands on or off on send", iLen);
|
|
return 0;
|
|
}
|
|
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
static int SLSInit(pEVDriver self)
|
|
{
|
|
pSLSDriv pMe = NULL;
|
|
int iRet, ival, i;
|
|
char msg[6], reply[6];
|
|
|
|
assert(self);
|
|
pMe = (pSLSDriv) self->pPrivate;
|
|
assert(pMe);
|
|
|
|
pMe->pSock = NULL;
|
|
pMe->pSock = NETConnect(pMe->pHost, pMe->iPort);
|
|
if (!pMe->pSock) {
|
|
return 0;
|
|
}
|
|
|
|
sleep(1);
|
|
|
|
/*
|
|
try to switch device on
|
|
*/
|
|
msg[0] = DSPWRITE;
|
|
msg[1] = 0x3c;
|
|
/*
|
|
* ival = 0: ausschalten
|
|
*/
|
|
ival = 1;
|
|
memcpy(msg + 2, &ival, 4);
|
|
iRet = communicateSLS(pMe->pSock, msg, reply);
|
|
if (iRet <= 0) {
|
|
pMe->iError = iRet;
|
|
return iRet;
|
|
}
|
|
for (i = 1; i < 6; i++) {
|
|
if (msg[i] != reply[i]) {
|
|
pMe->iError = BADECHO;
|
|
return BADECHO;
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
static int SLSClose(pEVDriver self)
|
|
{
|
|
pSLSDriv pMe = NULL;
|
|
int iRet, ival;
|
|
char msg[6], reply[6];
|
|
|
|
assert(self);
|
|
pMe = (pSLSDriv) self->pPrivate;
|
|
assert(pMe);
|
|
|
|
/*
|
|
msg[0] = DSPWRITE;
|
|
msg[1] = 0x3c;
|
|
ival = 0;
|
|
memcpy(msg+2, &ival,4);
|
|
iRet = communicateSLS(pMe->pSock,msg,reply);
|
|
*/
|
|
NETClosePort(pMe->pSock);
|
|
pMe->pSock = NULL;
|
|
return 1;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
static int SLSFix(pEVDriver self, int iError)
|
|
{
|
|
pSLSDriv pMe = NULL;
|
|
int iRet, i, ival;
|
|
char buffer[80];
|
|
char msg[6], reply[6];
|
|
float fVal = .0;
|
|
|
|
assert(self);
|
|
pMe = (pSLSDriv) self->pPrivate;
|
|
assert(pMe);
|
|
|
|
if (iError < -7000) {
|
|
/*
|
|
* This logic tries to reset the error code. Then it reads the
|
|
* error back. Serious errors persist and must be fixed by magnet
|
|
* technicians. But some can be cleared....
|
|
*/
|
|
msg[0] = DSPWRITE;
|
|
msg[1] = 0x29;
|
|
ival = double2DSPfloat((double) fVal);
|
|
memcpy(msg + 2, &ival, 4);
|
|
communicateSLS(pMe->pSock, msg, reply);
|
|
/*
|
|
* read again: if persists: this is really, really bad
|
|
*/
|
|
msg[0] = DSPREAD;
|
|
msg[1] = 0x29;
|
|
iRet = communicateSLS(pMe->pSock, msg, reply);
|
|
if (iRet < 0) {
|
|
return DEVFAULT;
|
|
}
|
|
ival = (int) reply[5];
|
|
if (ival == 0) {
|
|
return DEVREDO;
|
|
}
|
|
/*
|
|
* OK, clearing the error did not work, I try to reinitialize the
|
|
* socket because this helps sometimes.
|
|
*/
|
|
NETClosePort(pMe->pSock);
|
|
pMe->pSock = NULL;
|
|
pMe->pSock = NETConnect(pMe->pHost, pMe->iPort);
|
|
if (!pMe->pSock) {
|
|
return DEVFAULT;
|
|
}
|
|
sleep(1);
|
|
msg[0] = DSPREAD;
|
|
msg[1] = 0x29;
|
|
iRet = communicateSLS(pMe->pSock, msg, reply);
|
|
if (iRet < 0) {
|
|
return DEVFAULT;
|
|
}
|
|
ival = (int) reply[5];
|
|
if (ival == 0) {
|
|
return DEVREDO;
|
|
} else {
|
|
return DEVFAULT;
|
|
}
|
|
}
|
|
|
|
switch (iError) {
|
|
case BADHIGHLIM:
|
|
case BADLOWLIM:
|
|
return DEVFAULT;
|
|
break;
|
|
case BADECHO:
|
|
case TIMEOUT:
|
|
for (i = 0; i < 10; i++) {
|
|
iRet = NETAvailable(pMe->pSock, 0);
|
|
if (iRet == 1) {
|
|
NETRead(pMe->pSock, buffer, 70, -10);
|
|
}
|
|
}
|
|
return DEVREDO;
|
|
break;
|
|
default:
|
|
SLSClose(self);
|
|
iRet = SLSInit(self);
|
|
if (iRet) {
|
|
return DEVREDO;
|
|
} else {
|
|
return DEVFAULT;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
static int SLSHalt(pEVDriver * self)
|
|
{
|
|
assert(self);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
void KillSLS(void *pData)
|
|
{
|
|
pSLSDriv pMe = NULL;
|
|
|
|
pMe = (pSLSDriv) pData;
|
|
assert(pMe);
|
|
|
|
if (pMe->pHost) {
|
|
free(pMe->pHost);
|
|
}
|
|
free(pMe);
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
pEVDriver CreateSLSDriv(int argc, char *argv[])
|
|
{
|
|
pEVDriver pNew = NULL;
|
|
pSLSDriv pSim = NULL;
|
|
|
|
/* check for arguments */
|
|
if (argc < 2) {
|
|
return NULL;
|
|
}
|
|
|
|
pNew = CreateEVDriver(argc, argv);
|
|
pSim = (pSLSDriv) malloc(sizeof(SLSDriv));
|
|
memset(pSim, 0, sizeof(SLSDriv));
|
|
if (!pNew || !pSim) {
|
|
return NULL;
|
|
}
|
|
pNew->pPrivate = pSim;
|
|
pNew->KillPrivate = KillSLS;
|
|
|
|
pSim->pHost = strdup(argv[0]);
|
|
pSim->iPort = atoi(argv[1]);
|
|
|
|
/* initialise function pointers */
|
|
pNew->SetValue = SLSRun;
|
|
pNew->GetValue = GetSLSPos;
|
|
pNew->Send = SLSSend;
|
|
pNew->GetError = SLSError;
|
|
pNew->TryFixIt = SLSFix;
|
|
pNew->Init = SLSInit;
|
|
pNew->Close = SLSClose;
|
|
|
|
return pNew;
|
|
}
|