- SECoP protocol for scriptcontext

This commit is contained in:
2018-05-07 13:53:51 +02:00
parent da2b8c13d4
commit 19b3c71274
15 changed files with 288 additions and 27 deletions

10
ascon.c
View File

@ -150,9 +150,11 @@ static void AsconConnect(Ascon * a)
ret = CreateSocketAdress(&adr, a->hostport, port); ret = CreateSocketAdress(&adr, a->hostport, port);
*colon = ':'; *colon = ':';
if (ret == 0) { if (ret == 0) {
a->ip = 0;
AsconError(a, "bad host specification", 0); AsconError(a, "bad host specification", 0);
return; return;
} }
a->ip = adr.sin_addr.s_addr;
oldopts = fcntl(a->fd, F_GETFL, 0); oldopts = fcntl(a->fd, F_GETFL, 0);
fcntl(a->fd, F_SETFL, oldopts | O_NONBLOCK); fcntl(a->fd, F_SETFL, oldopts | O_NONBLOCK);
ret = ret =
@ -853,6 +855,14 @@ char *AsconHostport(Ascon *a)
return a->hostport; return a->hostport;
} }
unsigned long AsconIP(Ascon *a)
{
if (a==NULL) {
return 0;
}
return a->ip;
}
double AsconGetSetTimeout(Ascon *a, double timeout, int setmode) { double AsconGetSetTimeout(Ascon *a, double timeout, int setmode) {
if (setmode) { if (setmode) {
a->timeout = timeout; a->timeout = timeout;

View File

@ -109,6 +109,13 @@ int AsconLastState(Ascon *a);
*/ */
char *AsconHostport(Ascon *a); char *AsconHostport(Ascon *a);
/**
* \brief return IP address
* \param a The Ascon to query
* \return the IP address
*/
unsigned long AsconIP(Ascon *a);
/** /**
* \brief set or get timeout * \brief set or get timeout
* \param a the Ascon * \param a the Ascon

View File

@ -65,6 +65,7 @@ struct Ascon {
char *sendTerminator; /**< terminator for sending messages */ char *sendTerminator; /**< terminator for sending messages */
char *replyTerminator; /**< (std) terminator list for reply. NULL is the special case CR, LF or CR/LF */ char *replyTerminator; /**< (std) terminator list for reply. NULL is the special case CR, LF or CR/LF */
char *hostport; /**< host:port to connect */ char *hostport; /**< host:port to connect */
in_addr_t ip; /**< the ip address */
pDynString errmsg; /**< error message */ pDynString errmsg; /**< error message */
double start; /**< unix time when read was started */ double start; /**< unix time when read was started */
int noResponse; /**< no response expected */ int noResponse; /**< no response expected */

View File

@ -72,9 +72,12 @@
* chksum-crc: simple 8bit checksum * chksum-crc: simple 8bit checksum
*/ */
#define SIMULATE_ERROR 0
static int simulate_error = 0;
typedef enum {intType, hexType, floatType, strType, typedef enum {intType, hexType, floatType, strType,
skipType, codeType, checkType, crcType, skipType, codeType, checkType, crcType,
dumpType, endType, errorType} BinDataType; // items on this line stay at end dumpType, endType, errorType} BinDataType; /* items on this line stay at end */
typedef enum {modbusCrc, kellerCrc, rsportCrc, syconCrc, chksumCrc} CrcAlgorithm; typedef enum {modbusCrc, kellerCrc, rsportCrc, syconCrc, chksumCrc} CrcAlgorithm;
@ -83,7 +86,8 @@ typedef struct {
CrcAlgorithm algo; CrcAlgorithm algo;
int crcStart; int crcStart;
pDynString inp; pDynString inp;
char *nextFmt; // position of next format token char *nextFmt; /* position of next format token */
char *readFmt; /* position of first read format */
pDynString result; pDynString result;
int expectedChars; int expectedChars;
BinDataType type; BinDataType type;
@ -94,6 +98,8 @@ typedef struct {
int syconState; int syconState;
unsigned char chksum; unsigned char chksum;
pDynString data; pDynString data;
int try_again_count;
int try_again_max;
} BinPrivate; } BinPrivate;
#define MAXDUMP 999 #define MAXDUMP 999
@ -383,6 +389,15 @@ void BinShuffle(char *input, int order) {
break; break;
} }
} }
/*----------------------------------------------------------------------------*/
void BinResetWrite(Ascon *a) {
BinPrivate *p = a->private;
p->nextFmt = p->readFmt;
a->wrPos = 0;
a->lineCount = 0;
a->state = AsconWriting;
}
/*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
int BinHandler(Ascon *a) { int BinHandler(Ascon *a) {
int res; int res;
@ -408,6 +423,7 @@ int BinHandler(Ascon *a) {
/* exchange buffers */ /* exchange buffers */
dyn = p->inp; dyn = p->inp;
p->inp = a->wrBuffer; p->inp = a->wrBuffer;
p->try_again_count = p->try_again_max;
a->wrBuffer = dyn; a->wrBuffer = dyn;
DynStringClear(dyn); DynStringClear(dyn);
str = GetCharArray(p->inp); str = GetCharArray(p->inp);
@ -530,7 +546,8 @@ int BinHandler(Ascon *a) {
BinToSycon(dyn); BinToSycon(dyn);
} }
p->nextFmt = str + pos; p->readFmt = str + pos;
p->nextFmt = p->readFmt;
p->type = hexType; /* initialize to anything < dumpType */ p->type = hexType; /* initialize to anything < dumpType */
do { do {
res = BinReadItem(a); res = BinReadItem(a);
@ -540,15 +557,11 @@ int BinHandler(Ascon *a) {
return 1; return 1;
} }
} while (res == 1); } while (res == 1);
p->nextFmt = str + pos; BinResetWrite(a);
a->wrPos = 0;
if (GetDynStringLength(a->wrBuffer) == 0) { if (GetDynStringLength(a->wrBuffer) == 0) {
/* prevent to swallow "garbage" */ /* prevent to swallow "garbage" */
a->state = AsconWriteDone; a->state = AsconWriteDone;
} else {
a->state = AsconWriting;
} }
a->lineCount = 0;
return 1; return 1;
case AsconReadStart: case AsconReadStart:
DynStringClear(p->result); DynStringClear(p->result);
@ -558,10 +571,16 @@ int BinHandler(Ascon *a) {
break; break;
case AsconReading: case AsconReading:
res = AsconBaseHandler(a); res = AsconBaseHandler(a);
if (a->state == AsconTimeout && p->try_again_count > 0) {
p->try_again_count--;
DynStringCopy(a->errmsg, "timeout");
BinResetWrite(a);
return 0;
}
if (res == 0) { if (res == 0) {
if (GetDynStringLength(a->rdBuffer) == 0) { if (GetDynStringLength(a->rdBuffer) == 0) {
/* wait for the first byte - or timeout */ /* wait for the first byte - or timeout */
return res; return 0;
} }
if (p->type >= dumpType) { if (p->type >= dumpType) {
l = GetDynStringLength(a->rdBuffer); l = GetDynStringLength(a->rdBuffer);
@ -578,15 +597,23 @@ int BinHandler(Ascon *a) {
DynStringConcat(a->errmsg, GetCharArray(p->result)); DynStringConcat(a->errmsg, GetCharArray(p->result));
a->state = AsconFailed; a->state = AsconFailed;
} else { } else {
if (p->try_again_count != p->try_again_max) {
Log(INFO, "com", "sock0:recovered from (%s) after: %s", GetCharArray(a->errmsg), GetCharArray(p->inp));
}
a->state = AsconReadDone; a->state = AsconReadDone;
} }
/* exchange buffers */ /* exchange buffers */
dyn = a->rdBuffer; dyn = a->rdBuffer;
a->rdBuffer = p->result; a->rdBuffer = p->result;
p->result = dyn; p->result = dyn;
if (a->state == AsconFailed && p->try_again_count > 0) {
p->try_again_count--;
BinResetWrite(a);
return 0;
}
return 1; return 1;
} }
return res; return 0;
} }
if (p->crcAlgorithm == syconCrc) { if (p->crcAlgorithm == syconCrc) {
switch (p->syconState) { switch (p->syconState) {
@ -745,13 +772,23 @@ int BinHandler(Ascon *a) {
p->expectedChars--; p->expectedChars--;
if ((unsigned char)a->lastChar != p->iValue) { if ((unsigned char)a->lastChar != p->iValue) {
i = GetDynStringLength(a->rdBuffer) - 1; i = GetDynStringLength(a->rdBuffer) - 1;
snprintf(item, sizeof item, "BINERR: response[%d]==%2.2x != %2.2x ", i, (unsigned char)a->lastChar, (unsigned char)p->iValue); snprintf(item, sizeof item, "BINERR: [%d]==%2.2x != %2.2x ", i, (unsigned char)a->lastChar, (unsigned char)p->iValue);
DynStringCopy(a->errmsg, item); DynStringCopy(a->errmsg, item);
p->type = errorType; p->type = errorType;
p->dumpFrom = 0; p->dumpFrom = 0;
/* skip to end */ /* skip to end */
p->nextFmt = ""; p->nextFmt = "";
} }
#if SIMULATE_ERROR > 0
if (p->try_again_max > 0 && simulate_error++ > SIMULATE_ERROR) {
DynStringCopy(a->errmsg, "simulate ");
p->type = errorType;
p->dumpFrom = 0;
/* skip to end */
p->nextFmt = "";
simulate_error = 0;
}
#endif
} }
if (p->expectedChars <= 0) { if (p->expectedChars <= 0) {
BinReadItem(a); BinReadItem(a);
@ -773,6 +810,7 @@ static int BinInit(Ascon * a, SConnection * con, int argc, char *argv[])
{ {
BinPrivate *p; BinPrivate *p;
/* args: 2 <protocol>, 3 <timeout>, 4 <try_again_max>
/* argv[2] may be modbus-crc (default), keller-crc, rsport-crc or sycon-crc */ /* argv[2] may be modbus-crc (default), keller-crc, rsport-crc or sycon-crc */
if (argc < 2) { if (argc < 2) {
@ -807,6 +845,12 @@ static int BinInit(Ascon * a, SConnection * con, int argc, char *argv[])
} else { } else {
a->timeout = 2.0; /* sec */ a->timeout = 2.0; /* sec */
} }
if (argc > 4) {
p->try_again_max = atoi(argv[4]);
} else {
p->try_again_max = 0;
}
return 1; return 1;
} }

View File

@ -580,6 +580,10 @@ char *DevHostport(DevSer *devser) {
return AsconHostport(devser->ascon); return AsconHostport(devser->ascon);
} }
unsigned long DevIP(DevSer *devser) {
return AsconIP(devser->ascon);
}
char *DevStatus(DevSer *devser) { char *DevStatus(DevSer *devser) {
char *str, *pos; char *str, *pos;
static char buf[64]; static char buf[64];

View File

@ -203,6 +203,13 @@ void DevAsconStatistics(DevSer *self, double *avg,
*/ */
char *DevHostport(DevSer *devser); char *DevHostport(DevSer *devser);
/**
* \brief return IP address
* \param a The device serializer to query
* \return the IP address
*/
unsigned long DevIP(DevSer *devser);
/** /**
* \brief return status of device server ("offline", "unconnected", "") * \brief return status of device server ("offline", "unconnected", "")
* \param devser The device serializer to query * \param devser The device serializer to query

View File

@ -121,17 +121,17 @@ int Drive(SConnection * pCon, SicsInterp * pInter, char *name, float fNew)
if (iRet == DEVINT) { if (iRet == DEVINT) {
if (SCGetInterrupt(pCon) == eAbortOperation) { if (SCGetInterrupt(pCon) == eAbortOperation) {
SCSetInterrupt(pCon, eContinue); SCSetInterrupt(pCon, eContinue);
snprintf(pBueffel, 511, "Driving %s aborted at %9.3f", name, fPos); snprintf(pBueffel, 511, "Driving %s aborted at %.6g", name, fPos);
SCWrite(pCon, pBueffel, eError); SCWrite(pCon, pBueffel, eError);
} }
return 0; return 0;
} else if (iRet == DEVDONE) { } else if (iRet == DEVDONE) {
snprintf(pBueffel, 511, "Driving %s to %9.3f done", name, fPos); snprintf(pBueffel, 511, "Driving %s to %.6g done", name, fPos);
SCWrite(pCon, pBueffel, eValue); SCWrite(pCon, pBueffel, eValue);
return 1; return 1;
} else { } else {
snprintf(pBueffel, 511, snprintf(pBueffel, 511,
"Driving %s finished with problems, position: %9.3f", name, "Driving %s finished with problems, position: %.6g", name,
fPos); fPos);
SCWrite(pCon, pBueffel, eValue); SCWrite(pCon, pBueffel, eValue);
return 1; return 1;
@ -341,7 +341,7 @@ int DriveWrapper(SConnection * pCon, SicsInterp * pSics, void *pData,
/* print positions */ /* print positions */
for (i = 1; i < argc; i += 2) { for (i = 1; i < argc; i += 2) {
snprintf(pBueffel,511, "New %s position: %9.3f", argv[i], snprintf(pBueffel,511, "New %s position: %.6g", argv[i],
findPosition(pSics, pCon, argv[i])); findPosition(pSics, pCon, argv[i]));
SCWrite(pCon, pBueffel, eValue); SCWrite(pCon, pBueffel, eValue);
} }

View File

@ -133,13 +133,19 @@ int AnalyzeCommand(char *command) {
Tcl_SplitList(NULL, command, &argc, &argv); Tcl_SplitList(NULL, command, &argc, &argv);
arg0 = 0; arg0 = 0;
if (argc > 0 && strcmp(argv[0], "fulltransact") == 0) { if (argc > 0 && (strcmp(argv[0], "fulltransact") == 0
|| strcmp(argv[0], "transact") == 0)) {
arg0 = 1; arg0 = 1;
} }
if (argc <= arg0 + 1) { if (argc <= arg0 + 1) {
writable = 0; /* single word -> guess read only */ writable = 0; /* single word -> guess read only */
goto Free; goto Free;
} }
if (strcmp(argv[arg0], "sicsdescriptor") == 0
|| strcmp(argv[arg0], "_tcl") == 0) {
writable = 0;
goto Free;
}
pDes = FindCommandDescriptor(pServ->pSics, argv[arg0]); pDes = FindCommandDescriptor(pServ->pSics, argv[arg0]);
if (pDes == NULL) goto Free; if (pDes == NULL) goto Free;
if (pDes->parNode == NULL && GetDescriptorKey(pDes, "pardef") == NULL) goto Free; if (pDes->parNode == NULL && GetDescriptorKey(pDes, "pardef") == NULL) goto Free;

View File

@ -31,7 +31,8 @@ static hdbCallbackReturn LoggerUpdateCallback(pHdb node,
value = *(mm->v); value = *(mm->v);
time(&now); time(&now);
if (now > LoggerLastTime(logger)) { /* never write more than once per second */ /* testwise >= */
if (now >= LoggerLastTime(logger)) { /* never write more than once per second */
if (GetHdbProp(node, "geterror") == NULL) { if (GetHdbProp(node, "geterror") == NULL) {
str = formatValue(value, node); str = formatValue(value, node);
LoggerWrite(logger, time(NULL), LoggerPeriod(logger), GetCharArray(str)); LoggerWrite(logger, time(NULL), LoggerPeriod(logger), GetCharArray(str));

View File

@ -45,7 +45,8 @@ SOBJ = network.o ifile.o conman.o SCinter.o splitter.o passwd.o \
singlenb.o simindex.o simidx.o uselect.o singletas.o motorsec.o \ singlenb.o simindex.o simidx.o uselect.o singletas.o motorsec.o \
rwpuffer.o asynnet.o background.o countersec.o hdbtable.o velosec.o \ rwpuffer.o asynnet.o background.o countersec.o hdbtable.o velosec.o \
histmemsec.o sansbc.o sicsutil.o strlutil.o genbinprot.o trace.o\ histmemsec.o sansbc.o sicsutil.o strlutil.o genbinprot.o trace.o\
singlebinb.o taskobj.o sctcomtask.o tasmono.o multicountersec.o lscprot.o \ singlebinb.o taskobj.o sctcomtask.o tasmono.o multicountersec.o\
lscprot.o secopprot.o\
messagepipe.o sicsget.o remoteobject.o pmacprot.o charbychar.o binprot.o \ messagepipe.o sicsget.o remoteobject.o pmacprot.o charbychar.o binprot.o \
cnvrt.o tclClock.o tclDate.o tclUnixTime.o stack_trace.o logv2.o outcode.o cnvrt.o tclClock.o tclDate.o tclUnixTime.o stack_trace.o logv2.o outcode.o

2
ofac.c
View File

@ -52,6 +52,7 @@ static void InitGeneral(void)
INIT(AddPMACProtocoll); INIT(AddPMACProtocoll);
INIT(AddCharByCharProtocoll); INIT(AddCharByCharProtocoll);
INIT(AddLscProtocol); INIT(AddLscProtocol);
INIT(AddSecopProtocol);
INIT(MakeTrace); INIT(MakeTrace);
INIT(InitTaskOBJ); INIT(InitTaskOBJ);
INIT(RemoteObjectInit); INIT(RemoteObjectInit);
@ -121,6 +122,7 @@ static void InitIniCommands(SicsInterp * pInter)
PCMD("SICSType", SICSType); PCMD("SICSType", SICSType);
PCMD("Sics_Exitus", SicsExit); PCMD("Sics_Exitus", SicsExit);
PCMD("silent", SICSSilent); PCMD("silent", SICSSilent);
PCMD("json2tcl", SICSjson2tcl);
PCMD("status", UserStatus); PCMD("status", UserStatus);
PCMD("TclReplaceDrivable", TclReplaceDrivable); PCMD("TclReplaceDrivable", TclReplaceDrivable);
PCMD("transact", TransactAction); PCMD("transact", TransactAction);

View File

@ -43,7 +43,6 @@
#include <assert.h> #include <assert.h>
#include <ctype.h> #include <ctype.h>
#include <math.h> #include <math.h>
#include <tcl.h>
#include "fortify.h" #include "fortify.h"
#include "sics.h" #include "sics.h"
#include "fupa.h" #include "fupa.h"
@ -579,3 +578,66 @@ int SICSSilent(SConnection *pCon, SicsInterp *pSics, void *pData,
free(cmd); free(cmd);
return 1; return 1;
} }
/*------------------------------------------------------------------------*/
Tcl_Obj *json2tcl(struct json_object *jobj) {
char buf[100];
int i, len;
Tcl_Obj **list;
Tcl_Obj *dict, *kobj, *vobj;
Tcl_Obj *val;
const char *key;
const char *str;
switch (json_object_get_type(jobj)) {
case json_type_boolean:
return Tcl_NewBooleanObj(json_object_get_boolean(jobj));
case json_type_int:
return Tcl_NewLongObj(json_object_get_int(jobj));
case json_type_double:
return Tcl_NewDoubleObj(json_object_get_double(jobj));
case json_type_string:
str = json_object_get_string(jobj);
return Tcl_NewStringObj((char *)str, json_object_get_string_len(jobj));
case json_type_array:
len = json_object_array_length(jobj);
list = calloc(sizeof *list, len);
for (i=0; i<len; i++) {
list[i] = json2tcl(json_object_array_get_idx(jobj, i));
if (!list[i]) return NULL;
}
return Tcl_NewListObj(len, list);
case json_type_object:
dict = Tcl_NewDictObj();
if (!dict) return NULL;
json_object_object_foreach(jobj, key, val) {
kobj = Tcl_NewStringObj(key, strlen(key));
vobj = json2tcl(val);
if (kobj && vobj) {
Tcl_DictObjPut(NULL, dict, kobj, vobj);
}
}
return dict;
}
return Tcl_NewStringObj("None", 4);
}
/*------------------------------------------------------------------------*/
int SICSjson2tcl(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]) {
json_object *jobj;
assert(pCon);
assert(pSics);
if (argc != 2) {
SCWrite(pCon, "ERROR: should be: json2tcl <string>", eError);
return 0;
}
jobj = json_tokener_parse(argv[1]);
if (!jobj) {
SCWrite(pCon, "ERROR: no valid JSON", eError);
return 0;
}
/* the result is written only to the interpreter, no output to the client */
Tcl_SetObjResult(pSics->pTcl, json2tcl(jobj));
json_object_put(jobj);
return 1;
}

View File

@ -10,6 +10,9 @@
#ifndef SICSSCRIPT #ifndef SICSSCRIPT
#define SICSSCRIPT #define SICSSCRIPT
#include <tcl.h>
#include <json-c/json.h>
/* -------------------------- Interrupts -----------------------------------*/ /* -------------------------- Interrupts -----------------------------------*/
int GetSICSInterrupt(SConnection * pCon, SicsInterp * pSics, void *pData, int GetSICSInterrupt(SConnection * pCon, SicsInterp * pSics, void *pData,
int argc, char *argv[]); int argc, char *argv[]);
@ -51,4 +54,9 @@ int SICSDescriptor(SConnection * pCon, SicsInterp * pSics, void *pData,
/*----------------------------------------------------------------------*/ /*----------------------------------------------------------------------*/
int SICSSilent(SConnection *pCon, SicsInterp *pSics, void *pData, int SICSSilent(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]); int argc, char *argv[]);
/*----------------------------------------------------------------------*/
Tcl_Obj *json2tcl(struct json_object *jobj);
/*----------------------------------------------------------------------*/
int SICSjson2tcl(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
#endif #endif

View File

@ -283,7 +283,11 @@ int SctCommand(SConnection * con, SicsInterp * sics, void *object,
if (argc == 3) { if (argc == 3) {
node = FindHdbNode(NULL, argv[2], con); node = FindHdbNode(NULL, argv[2], con);
} }
if (node) {
GetHdbPath(node->mama, value, sizeof value); GetHdbPath(node->mama, value, sizeof value);
} else {
value[0] = 0;
}
/* returns an empty string on error */ /* returns an empty string on error */
SCWrite(con, value, eValue); SCWrite(con, value, eValue);
return 1; return 1;
@ -1733,6 +1737,22 @@ static int SctHostport(pSICSOBJ ccmd, SConnection * con,
return 1; return 1;
} }
static int SctIpAddress(pSICSOBJ ccmd, SConnection * con,
Hdb * cmdNode, Hdb * par[], int nPar)
{
SctController *c;
uint32_t ip;
c = (SctController *) ccmd->pPrivate;
ip = DevIP(c->devser);
SCPrintf(con, eValue, "%d.%d.%d.%d",
(int)(ip & 0xff),
(int)((ip >> 8) & 0xff),
(int)((ip >> 16) & 0xff),
(int)((ip >> 24) & 0xff));
return 1;
}
static int SctTimeout(pSICSOBJ ccmd, SConnection * con, static int SctTimeout(pSICSOBJ ccmd, SConnection * con,
Hdb * cmdNode, Hdb * par[], int nPar) Hdb * cmdNode, Hdb * par[], int nPar)
{ {
@ -1909,7 +1929,7 @@ static int SctMakeController(SConnection * con, SicsInterp * sics,
assert(controller); assert(controller);
controller->debugConn = NULL; controller->debugConn = NULL;
ccmd = MakeSICSOBJv(objName, "SctController", HIPNONE, usSpy); ccmd = MakeSICSOBJv(objName, "SctController", HIPTEXT, usSpy);
controller->node = ccmd->objectNode; controller->node = ccmd->objectNode;
controller->conn = SCCreateDummyConnection(pServ->pSics); controller->conn = SCCreateDummyConnection(pServ->pSics);
@ -2006,6 +2026,9 @@ static int SctMakeController(SConnection * con, SicsInterp * sics,
cmd = AddSICSHdbPar(controller->node, cmd = AddSICSHdbPar(controller->node,
"hostport", usSpy, MakeSICSFunc(SctHostport)); "hostport", usSpy, MakeSICSFunc(SctHostport));
cmd = AddSICSHdbPar(controller->node,
"ip", usSpy, MakeSICSFunc(SctIpAddress));
cmd = AddSICSHdbPar(controller->node, cmd = AddSICSHdbPar(controller->node,
"status", usSpy, MakeSICSFunc(SctStatus)); "status", usSpy, MakeSICSFunc(SctStatus));

85
secopprot.c Normal file
View File

@ -0,0 +1,85 @@
#include <errno.h>
#include <tcl.h>
#include <json-c/json.h>
#include "ascon.h"
#include "ascon.i"
#include "script.h"
/*
* protocol for SECoP
*
* Markus Zolliker June 2017
*/
/*----------------------------------------------------------------------------*/
int SecopProtHandler(Ascon *a) {
int ret;
char *result;
char *space;
char *json;
Tcl_Obj *tcllist[3], *tclobj;
int l;
struct json_object *jobj;
switch (a->state) {
case AsconWriting:
/* do not skip garbage (might be a message!) */
l = GetDynStringLength(a->wrBuffer) - a->wrPos;
ret = AsconWriteChars(a->fd, GetCharArray(a->wrBuffer) + a->wrPos, l);
if (ret < 0) {
AsconError(a, "ASC4", errno); /* sets state to AsconFailed */
} else {
a->wrPos += ret;
if (a->wrPos >= GetDynStringLength(a->wrBuffer)) {
a->state = AsconWriteDone;
}
}
return 1;
case AsconWriteStart:
if (GetDynStringLength(a->wrBuffer) == 0) {
/* do not send empty message */
a->state = AsconWriteDone;
return 1;
}
break;
}
ret = AsconStdHandler(a);
switch (a->state) {
case AsconReading:
if (ret) {
if (a->timeout < 1) {
/* extend timeout to 1 sec during a message */
a->start = DoubleTime() + 1 - a->timeout;
}
}
break;
case AsconReadDone:
result = GetCharArray(a->rdBuffer);
space = strchr(result, ' ');
if (space) {
json = strchr(space+1, ' ');
if (json) {
json++;
jobj = json_tokener_parse(json);
if (jobj) {
tcllist[0] = Tcl_NewStringObj(result, space - result);
tcllist[1] = Tcl_NewStringObj(space + 1, json - space - 2);
tcllist[2] = json2tcl(jobj);
tclobj = Tcl_NewListObj(3, tcllist);
DynStringCopy(a->rdBuffer, Tcl_GetString(tclobj));
json_object_put(jobj); /* free jobj */
}
}
}
}
return ret;
}
/*----------------------------------------------------------------------------*/
void AddSecopProtocol() {
static AsconProtocol secopprot;
secopprot.name = "SECoP";
secopprot.handler = SecopProtHandler;
secopprot.init = AsconStdInit;
AsconInsertProtocol(&secopprot);
}