From e284d5f09b3114526a502e8c1f4e7f8b4a22b833 Mon Sep 17 00:00:00 2001 From: Douglas Clowes Date: Thu, 8 Mar 2007 16:25:30 +1100 Subject: [PATCH] Improve timeout handling, implement list command and all print remaining items r1615 | dcl | 2007-03-08 16:25:30 +1100 (Thu, 08 Mar 2007) | 2 lines --- site_ansto/safetyplc.c | 225 ++++++++++++++++++++++++++++++----------- 1 file changed, 165 insertions(+), 60 deletions(-) diff --git a/site_ansto/safetyplc.c b/site_ansto/safetyplc.c index f35471e6..f04bb4ca 100644 --- a/site_ansto/safetyplc.c +++ b/site_ansto/safetyplc.c @@ -6,6 +6,7 @@ */ #include +#include #include #include "network.h" #include "multichan.h" @@ -47,13 +48,15 @@ struct __SafetyPLCController { int iGetOut; int iValue; pNWTimer nw_tmr; /* NetWait timer handle */ + int timeout; + struct timeval tvSend; }; typedef struct __command Command, *pCommand; typedef int (*CommandCallback)(void* ctx, const char* resp, int resp_len); struct __command { - pMultiChan unit; + pSafetyPLCController plc; int cstate; int lstate; char* out_buf; @@ -72,10 +75,11 @@ static int PLC_Tx(void* ctx) pCommand myCmd = (pCommand) ctx; if (myCmd) { - iRet = MultiChanWrite(myCmd->unit, myCmd->out_buf, myCmd->out_len); + gettimeofday(&myCmd->plc->tvSend, NULL); /* refresh */ + iRet = MultiChanWrite(myCmd->plc->mcc, myCmd->out_buf, myCmd->out_len); /* TODO handle errors */ if (iRet < 0) { /* TODO: EOF */ - iRet = MultiChanReconnect(myCmd->unit); + iRet = MultiChanReconnect(myCmd->plc->mcc); if (iRet == 0) return 0; } @@ -127,13 +131,14 @@ static int PLC_Rx(void* ctx, int rxchar) return iRet; } -int PLC_SendCmd(pMultiChan unit, +static int PLC_SendCmd(pSafetyPLCController self, char* command, int cmd_len, CommandCallback callback, void* context, int rsp_len) { pCommand myCmd = NULL; - assert(unit); + assert(self); + assert(self->mcc); myCmd = (pCommand) malloc(sizeof(Command)); assert(myCmd); memset(myCmd, 0, sizeof(Command)); @@ -156,8 +161,9 @@ int PLC_SendCmd(pMultiChan unit, memset(myCmd->inp_buf, 0, rsp_len + 1); } myCmd->inp_len = rsp_len; - myCmd->unit = unit; - return MultiChanEnque(unit, myCmd, PLC_Tx, PLC_Rx); + myCmd->plc = self; + gettimeofday(&self->tvSend, NULL); /* refresh */ + return MultiChanEnque(self->mcc, myCmd, PLC_Tx, PLC_Rx); } static void PLC_Notify(void* context, int event) @@ -213,75 +219,172 @@ static int MyTimerCallback(void* context, int mode) { pSafetyPLCController self = (pSafetyPLCController) context; if (self->iGetOut) { + struct timeval now; + gettimeofday(&now, NULL); /* TODO error handling */ - if (--self->iGetOut) + if (((now.tv_sec - self->tvSend.tv_sec) * 1000 + + (now.tv_usec / 1000) + - (self->tvSend.tv_usec / 1000)) < self->timeout) return 1; DMC2280MotionControl = -1; } - self->iGetOut = 100; - PLC_SendCmd(self->mcc, "READ", 4, - GetCallback, self, 132); + self->iGetOut = 1; + PLC_SendCmd(self, "READ", 4, GetCallback, self, 132); return 1; } +static int PLC_Print(SConnection *pCon, SicsInterp *pSics, + void *pData, char *name, char *param) +{ + char line[132]; + pSafetyPLCController self = (pSafetyPLCController) pData; + if (strcasecmp(param, "key") == 0) { + char* state = "unknown(low)"; + if ((self->iValue & KEY_BOTH_BITS) == KEY_BOTH_BITS) + state = "invalid(high)"; + else if (self->iValue & KEY_ENABLED_BIT) + state = "enabled"; + else if (self->iValue & KEY_DISABLED_BIT) + state = "disabled"; + snprintf(line, 132, "%s.Key = %s", name, state); + SCWrite(pCon, line, eStatus); + return OKOK; + } + if (strcasecmp(param, "secondary") == 0) { + char* state = "unknown(low)"; + if ((self->iValue & SEC_BOTH_BITS) == SEC_BOTH_BITS) + state = "invalid(high)"; + if (self->iValue & SEC_OPENED_BIT) + state = "opened"; + else if (self->iValue & SEC_CLOSED_BIT) + state = "closed"; + snprintf(line, 132, "%s.Secondary = %s", name, state); + SCWrite(pCon, line, eStatus); + return OKOK; + } + if (strcasecmp(param, "tertiary") == 0) { + char* state = "unknown(low)"; + if ((self->iValue & TER_BOTH_BITS) == TER_BOTH_BITS) + state = "invalid(high)"; + if (self->iValue & TER_OPENED_BIT) + state = "opened"; + else if (self->iValue & TER_CLOSED_BIT) + state = "closed"; + snprintf(line, 132, "%s.Tertiary = %s", name, state); + SCWrite(pCon, line, eStatus); + return OKOK; + } + if (strcasecmp(param, "motioncontrol") == 0) { + char* state = "unknown(low)"; + if ((self->iValue & MOTOR_BOTH_BITS) == MOTOR_BOTH_BITS) + state = "invalid(high)"; + else if (self->iValue & MOTOR_ENABLED_BIT) + state = "enabled"; + else if (self->iValue & MOTOR_DISABLED_BIT) + state = "disabled"; + snprintf(line, 132, "%s.MotionControl = %s", name, state); + SCWrite(pCon, line, eStatus); + return OKOK; + } + if (strcasecmp(param, "access") == 0) { + char* state = "unknown(low)"; + if ((self->iValue & ACCESS_BOTH_BITS) == ACCESS_BOTH_BITS) + state = "invalid(high)"; + else if (self->iValue & ACCESS_LOCKED_BIT) + state = "locked"; + else if (self->iValue & ACCESS_UNLOCKED_BIT) + state = "unlocked"; + snprintf(line, 132, "%s.Access = %s", name, state); + SCWrite(pCon, line, eStatus); + return OKOK; + } + if (strcasecmp(param, "dc") == 0) { + char* state = "false"; + if (self->iValue & DC_POWEROK_BIT) + state = "true"; + snprintf(line, 132, "%s.DC = %s", name, state); + SCWrite(pCon, line, eStatus); + return OKOK; + } + if (strcasecmp(param, "exit") == 0) { + char* state = "false"; + if (self->iValue & EXIT_INPROGRESS_BIT) + state = "true"; + snprintf(line, 132, "%s.Exit = %s", name, state); + SCWrite(pCon, line, eStatus); + return OKOK; + } + if (strcasecmp(param, "trip") == 0) { + char* state = "false"; + if (self->iValue & SAFETY_TRIPPED_BIT) + state = "true"; + snprintf(line, 132, "%s.Trip = %s", name, state); + SCWrite(pCon, line, eStatus); + return OKOK; + } + if (strcasecmp(param, "fault") == 0) { + char* state = "false"; + if (self->iValue & SAFETY_MALFUNCTION_BIT) + state = "true"; + snprintf(line, 132, "%s.Fault = %s", name, state); + SCWrite(pCon, line, eStatus); + return OKOK; + } + if (strcasecmp(param, "operate") == 0) { + char* state = "false"; + if (self->iValue & TER_OPERATE_BIT) + state = "true"; + snprintf(line, 132, "%s.Operate = %s", name, state); + SCWrite(pCon, line, eStatus); + return OKOK; + } + if (strcasecmp(param, "relay") == 0) { + char* state = "false"; + if (self->iValue & RELAY_ENABLED_BIT) + state = "true"; + snprintf(line, 132, "%s.Relay = %s", name, state); + SCWrite(pCon, line, eStatus); + return OKOK; + } + if (strcasecmp(param, "ready") == 0) { + char* state = "false"; + if (self->iValue & INST_READY_BIT) + state = "true"; + snprintf(line, 132, "%s.Ready = %s", name, state); + SCWrite(pCon, line, eStatus); + return OKOK; + } + return 0; +} + static int PLC_Action(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]) { char line[132]; pSafetyPLCController self = (pSafetyPLCController) pData; if (argc == 1) { - snprintf(line, 132, "%s.iValue = %06x", argv[0], self->iValue & 0xffffff); + snprintf(line, 132, "%s.iValue = %06X", argv[0], self->iValue & 0xffffff); SCWrite(pCon, line, eStatus); return OKOK; } else if (argc == 2) { if (strcmp(argv[1], "list") == 0) { + PLC_Print(pCon, pSics, pData, argv[0], "key"); + PLC_Print(pCon, pSics, pData, argv[0], "secondary"); + PLC_Print(pCon, pSics, pData, argv[0], "tertiary"); + PLC_Print(pCon, pSics, pData, argv[0], "motioncontrol"); + PLC_Print(pCon, pSics, pData, argv[0], "access"); + PLC_Print(pCon, pSics, pData, argv[0], "dc"); + PLC_Print(pCon, pSics, pData, argv[0], "exit"); + PLC_Print(pCon, pSics, pData, argv[0], "trip"); + PLC_Print(pCon, pSics, pData, argv[0], "fault"); + PLC_Print(pCon, pSics, pData, argv[0], "operate"); + PLC_Print(pCon, pSics, pData, argv[0], "relay"); + PLC_Print(pCon, pSics, pData, argv[0], "ready"); return OKOK; } - if (strcmp(argv[1], "motioncontrol") == 0) { - char* state = "unknown"; - if ((self->iValue & MOTOR_BOTH_BITS) == MOTOR_BOTH_BITS) - state = "invalid"; - else if (self->iValue & MOTOR_ENABLED_BIT) - state = "enabled"; - else if (self->iValue & MOTOR_DISABLED_BIT) - state = "disabled"; - snprintf(line, 132, "%s.MotionControl = %s", argv[0], state); - SCWrite(pCon, line, eStatus); + if (PLC_Print(pCon, pSics, pData, argv[0], argv[1])) return OKOK; - } - else if (strcmp(argv[1], "secondary") == 0) { - char* state = "unknown"; - if ((self->iValue & SEC_BOTH_BITS) == SEC_BOTH_BITS) - state = "invalid"; - if (self->iValue & SEC_OPENED_BIT) - state = "opened"; - else if (self->iValue & SEC_CLOSED_BIT) - state = "closed"; - snprintf(line, 132, "%s.Secondary = %s", argv[0], state); - SCWrite(pCon, line, eStatus); - return OKOK; - } - else if (strcmp(argv[1], "tertiary") == 0) { - char* state = "unknown"; - if ((self->iValue & TER_BOTH_BITS) == TER_BOTH_BITS) - state = "invalid"; - if (self->iValue & TER_OPENED_BIT) - state = "opened"; - else if (self->iValue & TER_CLOSED_BIT) - state = "closed"; - snprintf(line, 132, "%s.Tertiary = %s", argv[0], state); - SCWrite(pCon, line, eStatus); - return OKOK; - } - else if (strcmp(argv[1], "instrument") == 0) { - char* state = "unready"; - if (self->iValue & INST_READY_BIT) - state = "ready"; - snprintf(line, 132, "%s.Instrument = %s", argv[0], state); - SCWrite(pCon, line, eStatus); - return OKOK; - } } /* TODO: handle private stuff */ return MultiChanAction(pCon, pSics, self->mcc, argc, argv); @@ -308,11 +411,13 @@ static pSafetyPLCController PLC_Create(const char* pName, int port) static int PLC_Init(pSafetyPLCController self) { /* TODO: Init the controller */ - if (self->nw_tmr == NULL) - NetWatchRegisterTimerPeriodic(&self->nw_tmr, - 1000, 100, - MyTimerCallback, - self); + if (self->nw_tmr != NULL) + NetWatchRemoveTimer(self->nw_tmr); + NetWatchRegisterTimerPeriodic(&self->nw_tmr, + 1000, 100, + MyTimerCallback, + self); + self->timeout=30000; return 1; }