diff --git a/ascon.c b/ascon.c index 42906fb7..b0d6c609 100644 --- a/ascon.c +++ b/ascon.c @@ -284,14 +284,15 @@ int AsconWriteChars(int fd, char *data, int length) if (length <= 0) return 0; - /* - { int i; - for (i=0; inoResponse = noResponse; a->state = AsconWriteStart; a->responseValid = 0; - AsconTask(a); - return 1; + return AsconTask(a); } char *AsconRead(Ascon * a) diff --git a/binprot.c b/binprot.c index f65511ae..e07992e6 100644 --- a/binprot.c +++ b/binprot.c @@ -22,8 +22,18 @@ * a number converted according to the choosen format, i1 is default * int changing the format to byte integers * hex changing the format to hexadecimal (1 byte at a time) - * float changing the format to 4 byte ieee float - * crc send crc + * float changing the format to 4 byte ieee float + * order : + * 0: normal (may be omitted) + * 1: exchange bytes within words + * 2: exchange words + * 3: invert order + * str string nul terminated or with exactly n characters + * (encode space by underscore) + * crc send crc + * is the type of crc + * (m: modbus, k: keller, r: rs_port, s: sycon, c: checksum) + * index from where to start counting (default 0) * * and formatItem is one of the follwing * @@ -38,11 +48,14 @@ * if is omitted, = 1 is assumed * hex convert 1 byte to hexadecimal coded integer * and append it to the response - * float convert 4 bytes from ieee float - * and append the number to the response + * float convert 4 bytes from ieee float ( see above) + * str string (length n or nul terminated) + * (spaces are encoded by underscore) * dump read all bytes in read buffer as hex (only for tests) - * crc check crc (if wrong, "badCRC" is added to the response) - * + * crc check crc (if wrong, "badCRC" is added to the response) + * is the type of crc + * (m: modbus, k: keller, r: rs_port, s: sycon, c: checksum) + * index from where to start counting (default 0) * multiple items in the response are space separated * * Usage example: Modbus read (float) @@ -58,25 +71,50 @@ * chksum-crc: simple 8bit checksum */ -typedef enum {intType, hexType, floatType, skipType, codeType, checkType, - crcType, dumpType, endType, errorType} BinDataType; -// dumpType, endType, errorType must be the last items +typedef enum {intType, hexType, floatType, strType, + skipType, codeType, checkType, crcType, + dumpType, endType, errorType} BinDataType; // items on this line stay at end typedef enum {modbusCrc, kellerCrc, rsportCrc, syconCrc, chksumCrc} CrcAlgorithm; typedef struct { CrcAlgorithm crcAlgorithm; + CrcAlgorithm algo; + int crcStart; pDynString inp; char *nextFmt; // position of next format token pDynString result; int expectedChars; BinDataType type; + int order; + int done; long iValue; int dumpFrom; int syconState; unsigned char chksum; + pDynString data; } BinPrivate; +#define MAXDUMP 999 +#define NUL_TERMINATED 9999 + +/*----------------------------------------------------------------------------*/ +static int parseAlgo(char *inp, BinPrivate *p) { + int index = 0; + + p->algo = p->crcAlgorithm; + switch (*inp) { + case 'm': p->algo = modbusCrc; break; + case 'k': p->algo = kellerCrc; break; + case 'r': p->algo = rsportCrc; break; + case 's': p->algo = syconCrc; break; + case 'c': p->algo = chksumCrc; break; + } + while (*inp > '9') inp++; + sscanf(inp, "%d", &index); + return index; +} + /*----------------------------------------------------------------------------*/ static int calc_crc(char *inp, int inpLen) { @@ -156,25 +194,66 @@ static int calc_chksum(char *inp, int inpLen) return crc; } +/*----------------------------------------------------------------------------*/ +int BinGetItem(char *str, char *item, size_t item_size) { + int cntcurly = 0; + char *p, *res; + int l; + + p = str; + while (*p == ' ') p++; + if (*p == '{') { + cntcurly++; + p++; + } + if (!*p) return -1; + res = p; + while (*p) { + if (*p == '{') { + cntcurly++; + } else if (*p == '}') { + cntcurly--; + if (cntcurly == 0) { + l = p - str - 1; + break; + } + } else if (*p == ' ' && cntcurly == 0) { + break; + } + p++; + } + l = p - res; + if (l >= item_size) { + l = item_size - 1; + } + strncpy(item, res, l); + item[l] = '\0'; + return p - str; +} + /*----------------------------------------------------------------------------*/ int BinReadItem(Ascon *a) { BinPrivate *p = a->private; char item[32]; int valen; int size; - - if (sscanf(p->nextFmt, "%30s%n", item, &valen) <= 0) { + CrcAlgorithm algo; + + valen = BinGetItem(p->nextFmt, item, sizeof item); + if (valen < 0) { if (p->type < dumpType) { p->dumpFrom = GetDynStringLength(a->rdBuffer); p->type = endType; } - p->expectedChars = 999; + p->expectedChars = MAXDUMP; return 0; } - if (strcasecmp(item, "crc") == 0) { + if (strncasecmp(item, "crc", 3) == 0) { p->type = crcType; - if (p->crcAlgorithm == chksumCrc) { + p->expectedChars = 2; + p->crcStart = parseAlgo(item + 3, p); + if (p->algo == chksumCrc) { p->expectedChars = 1; } else { p->expectedChars = 2; @@ -187,9 +266,22 @@ int BinReadItem(Ascon *a) { p->expectedChars = size; p->type = intType; p->iValue = 0; - } else if (strcasecmp(item, "float") == 0) { + } else if (strncasecmp(item, "float", 5) == 0) { + p->order = 0; + sscanf(item + 5, "%d", &p->order); p->expectedChars = 4; p->type = floatType; + DynStringClear(p->data); + } else if (strncasecmp(item, "str", 3) == 0) { + size = 1; + sscanf(item + 3, "%d", &size); + if (size == 0) { + size = NUL_TERMINATED; + } + p->expectedChars = size; + p->type = strType; + p->done = 0; + DynStringClear(p->data); } else if (strcasecmp(item, "hex") == 0) { p->expectedChars = 1; p->type = hexType; @@ -205,12 +297,17 @@ int BinReadItem(Ascon *a) { p->type = skipType; } else { p->iValue = 0; - if (1 == sscanf(item, "%ld", &p->iValue)) { - p->expectedChars = 1; - p->type = checkType; + if (strncasecmp(item, "0x", 2) == 0) { + if (1 != sscanf(item + 2, "%lx", &p->iValue)) { + return -1; + } } else { - return -1; + if (1 != sscanf(item, "%ld", &p->iValue)) { + return -1; + } } + p->expectedChars = 1; + p->type = checkType; } p->nextFmt += valen; return 1; @@ -265,17 +362,39 @@ void BinToSycon(pDynString dyn) { free(str); } +/*----------------------------------------------------------------------------*/ +void BinShuffle(char *input, int order) { + /* order may be 0: no shuffle, 1: change within words, 2: change words, 3: invert*/ + char ch; + + switch (order) { + case 1: + ch = input[0]; input[0] = input[1]; input[1] = ch; + ch = input[2]; input[2] = input[3]; input[3] = ch; + break; + case 2: + ch = input[0]; input[0] = input[2]; input[2] = ch; + ch = input[1]; input[1] = input[3]; input[3] = ch; + break; + case 3: + ch = input[0]; input[0] = input[3]; input[3] = ch; + ch = input[1]; input[1] = input[2]; input[2] = ch; + break; + } +} /*----------------------------------------------------------------------------*/ int BinHandler(Ascon *a) { int res; char *str; int len; - int i, l, pos; + int i, l, ls, pos; + int start; unsigned int crc; pDynString dyn; char item[32]; char data[8]; int size; + int order; int valen; BinDataType type; long iValue; @@ -293,44 +412,52 @@ int BinHandler(Ascon *a) { str = GetCharArray(p->inp); len = GetDynStringLength(p->inp); l = 0; - size = 1; type = intType; for (pos = 0; pos < len; ) { - if (sscanf(str + pos, "%30s%n", item, &valen) <= 0) { + valen = BinGetItem(str + pos, item, sizeof item); + if (valen < 0) { BinError(a, "missing '/'"); return 1; } pos += valen; if (strcasecmp(item, "/") == 0) { break; - } else if (strcasecmp(item, "crc") == 0) { - switch (p->crcAlgorithm) { + } else if (strncasecmp(item, "crc", 3) == 0) { + start = parseAlgo(item + 3, p); + switch (p->algo) { case kellerCrc: - crc = calc_crc(GetCharArray(dyn), l); + crc = calc_crc(GetCharArray(dyn)+start, l-start); DynStringConcatChar(dyn, crc / 256); DynStringConcatChar(dyn, crc % 256); break; case modbusCrc: - crc = calc_crc(GetCharArray(dyn), l); + crc = calc_crc(GetCharArray(dyn)+start, l-start); DynStringConcatChar(dyn, crc % 256); DynStringConcatChar(dyn, crc / 256); break; case chksumCrc: - crc = calc_chksum(GetCharArray(dyn), l); + crc = calc_chksum(GetCharArray(dyn)+start, l-start); DynStringConcatChar(dyn, crc % 256); break; case rsportCrc: - crc = calc_crc8(GetCharArray(dyn), l); + crc = calc_crc8(GetCharArray(dyn)+start, l-start); DynStringConcatChar(dyn, crc); break; } } else if (strncasecmp(item, "int", 3) == 0) { + size = 1; sscanf(item + 3, "%d", &size); type = intType; } else if (strcasecmp(item, "hex") == 0) { type = hexType; - } else if (strcasecmp(item, "float") == 0) { + } else if (strncasecmp(item, "float", 5) == 0) { + order = 0; + sscanf(item + 5, "%d", &order); type = floatType; + } else if (strncasecmp(item, "str", 3) == 0) { + size = NUL_TERMINATED; + sscanf(item + 3, "%d", &size); + type = strType; } else { switch (type) { case intType: @@ -339,6 +466,9 @@ int BinHandler(Ascon *a) { BinError(a, "invalid integer"); return 1; } + if (iValue < 0) { + printf("%ld\n", iValue); + } uValue = iValue; for (i = size - 1; i >= 0; i--) { if (i < sizeof data) { @@ -362,6 +492,7 @@ int BinHandler(Ascon *a) { return 1; } DynStringConcatChar(dyn, (iValue & 255)); + l += 1; break; case floatType: res = sscanf(item, "%lf", &fValue); @@ -370,12 +501,26 @@ int BinHandler(Ascon *a) { return 1; } double2ieee(fValue, data); - DynStringConcatChar(dyn, data[0]); - DynStringConcatChar(dyn, data[1]); - DynStringConcatChar(dyn, data[2]); - DynStringConcatChar(dyn, data[3]); + BinShuffle(data, order); + DynStringConcatBytes(dyn, data, 4); l += 4; break; + case strType: + ls = strlen(item); + if (ls > size) { + item[size] = '\0'; + } + DynStringConcat(dyn, item); + if (size == NUL_TERMINATED) { + DynStringConcatChar(dyn, 0); + l += ls + 1; + } else { + for (i = ls; i < size; i++) { + DynStringConcatChar(dyn, 0); + } + l += size; + } + break; } } } @@ -530,21 +675,42 @@ int BinHandler(Ascon *a) { DynStringConcat(p->result, item); } break; - case floatType: /* does not work with sycon when stuffed */ + case floatType: p->expectedChars--; + DynStringConcatChar(p->data, a->lastChar); if (p->expectedChars <= 0) { - str = GetCharArray(a->rdBuffer) + GetDynStringLength(a->rdBuffer) - 4; - fValue = ieee2double(str); + char *shuffle = GetCharArray(p->data); + BinShuffle(shuffle, p->order); + fValue = ieee2double(shuffle); snprintf(item, sizeof item, "%.7g ", fValue); DynStringConcat(p->result, item); } break; + case strType: + if (a->lastChar) { + if (!p->done) { + DynStringConcatChar(p->data, a->lastChar); + } + } else { + p->done = 1; + if (p->expectedChars == NUL_TERMINATED) { + DynStringConcat(p->result, GetCharArray(p->data)); + p->expectedChars = 0; + break; + } + } + p->expectedChars--; + if (p->expectedChars <= 0) { + DynStringConcat(p->result, GetCharArray(p->data)); + break; + } + break; case crcType: p->expectedChars--; if (p->expectedChars <= 0) { str = GetCharArray(a->rdBuffer); l = GetDynStringLength(a->rdBuffer); - switch (p->crcAlgorithm) { + switch (p->algo) { case syconCrc: /* ignore crc check */ /* subtract CRC char (undo the addition) and subtract crc higher four bits */ p->chksum -= a->lastChar + (a->lastChar & 0x0f); @@ -554,7 +720,7 @@ int BinHandler(Ascon *a) { } break; case chksumCrc: - if (calc_chksum(str, l-1) != (unsigned char)str[l-1]) { + if (calc_chksum(str+p->crcStart, l-1-p->crcStart) != (unsigned char)str[l-1]) { DynStringConcat(p->result, "badCRC "); } break; @@ -565,7 +731,7 @@ int BinHandler(Ascon *a) { /* fall through */ case modbusCrc: case rsportCrc: - if (calc_crc(str, l) != 0) { + if (calc_crc(str+p->crcStart, l-p->crcStart) != 0) { DynStringConcat(p->result, "badCRC "); } } @@ -576,8 +742,10 @@ int BinHandler(Ascon *a) { break; case checkType: p->expectedChars--; - if ((a->lastChar & 255) != p->iValue) { - DynStringCopy(a->errmsg, "BINERR: mismatch "); + if ((unsigned char)a->lastChar != p->iValue) { + 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); + DynStringCopy(a->errmsg, item); p->type = errorType; p->dumpFrom = 0; /* skip to end */ @@ -596,6 +764,7 @@ static void BinPrivateKill(void *pVoid) { BinPrivate *p = pVoid; DeleteDynString(p->inp); DeleteDynString(p->result); + DeleteDynString(p->data); free(p); } @@ -631,6 +800,7 @@ static int BinInit(Ascon * a, SConnection * con, int argc, char *argv[]) a->hostport = strdup(argv[1]); p->inp = CreateDynString(60,63); p->result = CreateDynString(60,63); + p->data = CreateDynString(60,63); if (argc > 3) { a->timeout = atof(argv[3]); } else { diff --git a/devser.c b/devser.c index 4df8bb74..2baf4755 100644 --- a/devser.c +++ b/devser.c @@ -76,26 +76,17 @@ static void DevFreeActionList(DevAction * actions) } } -static double nextTime(double due, - double lastInterval, - double now, - double interval) { - double base; - /* nextTime gives the next possible time according to the - * following rules: - * (1) result > now - * (2) result is a multiple of interval - * (3) result >= due OR result >= due - lastInterval + interval - */ - if (interval > lastInterval) { - base = due - lastInterval * 0.01; - } else { - base = due - lastInterval + interval * 0.99; - } - if (now > base) { - base = now; - } - return (floor(base / interval) + 1) * interval; +static double nextDue(double due, double now, double interval) { + /* calculate next due value. the phase is rounded to usec in order to + prevent phase drifts by summed rounding errors + */ + double p; /* phase */ + + if (interval <= 0) return now; + if (now < due) return due; + + p = round(fmod(due, interval)*1e6)/1e6; + return p + interval * floor((due-p)/interval + (now-due)/interval + 1.000001); } @@ -124,7 +115,7 @@ static DevAction *DevNextAction(DevSer * devser) action->timeDue = now; } else { /* increase timeDue according to interval */ - action->timeDue = nextTime(0, 0, now, action->interval); + action->timeDue = nextDue(action->timeDue, now, action->interval); } prio = action->prio; @@ -243,9 +234,9 @@ int DevQueueTask(void *ds) action = DevNextAction(devser); } + StartAscon(devser); + devser->status = AsconTask(devser->ascon); while (action != NULL) { - StartAscon(devser); - devser->status = AsconTask(devser->ascon); AsconLog(devser); if (devser->status >= AsconFailure) { replyData = AsconGetError(devser->ascon); @@ -272,7 +263,11 @@ int DevQueueTask(void *ds) } sendData = action->hdl(action->data, replyData, (devser->status != AsconReady)); if (sendData != NULL) { - AsconWrite(devser->ascon, sendData, 0); + devser->status = AsconWrite(devser->ascon, sendData, 0); + if (devser->status >= AsconFailure) { + replyData = AsconGetError(devser->ascon); + continue; + } LogStart(devser); return 1; } @@ -284,6 +279,8 @@ int DevQueueTask(void *ds) devser->current = NULL; } action = DevNextAction(devser); + StartAscon(devser); + devser->status = AsconTask(devser->ascon); } return 1; } @@ -391,8 +388,8 @@ int DevUnschedule(DevSer * devser, void *callData, return cnt; } -int DevSchedule(DevSer * devser, void *actionData, - DevPrio prio, double interval, +int DevScheduleS(DevSer * devser, void *actionData, + DevPrio prio, double interval, double start, DevActionHandler * hdl, DevActionMatch * matchFunc, DevKillActionData * killFunc, DevInfoFunc * infoFunc) { @@ -454,6 +451,7 @@ int DevSchedule(DevSer * devser, void *actionData, action->kill = killFunc; action->infoFunc = infoFunc; action->timeDue = 0; + action->interval = 0; ret = 1; } @@ -468,22 +466,31 @@ int DevSchedule(DevSer * devser, void *actionData, if (interval < 0) { /* case "queued" */ action->interval = -1.0; } else { /* case "scheduled" */ - if (action->timeDue == 0) { /* not yet scheduled: do it immediately */ - action->timeDue = DoubleTime(); - } else { /* calculate next time */ - action->timeDue = nextTime(action->timeDue, action->interval, - DoubleTime(), interval); - } + /* nextDue calculates the next due date after the last call + however, it returns the 'start' value + - when this is a new action and start > 0 + - when the presumed last call time is bigger the 'start' value + */ + action->timeDue = nextDue(start, action->timeDue - action->interval, interval); action->interval = interval; } return ret; /* when 0, actionData was killed */ } +int DevSchedule(DevSer * devser, void *actionData, + DevPrio prio, double interval, + DevActionHandler * hdl, DevActionMatch * matchFunc, + DevKillActionData * killFunc, DevInfoFunc * infoFunc) +{ + return DevScheduleS(devser, actionData, prio, interval, 0.0, + hdl, matchFunc, killFunc, infoFunc); +} + int DevQueue(DevSer * devser, void *actionData, DevPrio prio, DevActionHandler * hdl, DevActionMatch * matchFunc, DevKillActionData * killFunc, DevInfoFunc *infoFunc) { - return DevSchedule(devser, actionData, prio, -1.0, hdl + return DevScheduleS(devser, actionData, prio, -1.0, 0.0, hdl , matchFunc, killFunc, infoFunc); } @@ -559,7 +566,7 @@ char * DevList(DevSer * devser) { DynStringConcat(result, str); free(str); } else { - snprintf(text, sizeof text, "%8.8lx", (unsigned long)action->data); + snprintf(text, sizeof text, "%p", action->data); DynStringConcat(result, text); } DynStringConcat(result, "\n"); diff --git a/logger.c b/logger.c index b281b718..454a6317 100644 --- a/logger.c +++ b/logger.c @@ -1,5 +1,5 @@ /*--------------------------------------------------------------------------- -Logger.c +logger.c Markus Zolliker, Sept 2004 ---------------------------------------------------------------------------- @@ -20,6 +20,7 @@ static Logger *list; static time_t lastLife = 0; static time_t lastWritten = 0; static time_t omitCheck = 0; + /*--------------------------------------------------------------------------*/ char *LoggerName(Logger * log) { diff --git a/scriptcontext.c b/scriptcontext.c index 18f5beec..7fd1a653 100644 --- a/scriptcontext.c +++ b/scriptcontext.c @@ -338,13 +338,16 @@ int SctCallInContext(SConnection * con, char *script, Hdb * node, char *result = NULL; int iRet = 1; int verbose = controller->verbose; + char path[MAX_HDB_PATH]; PushContext(node, controller); if (verbose) { - SCPrintf(con, eLog, "%6.3f script: %s", secondsOfMinute(), script); + GetHdbPath(node, path, sizeof path); + SCPrintf(con, eLog, "%6.3f script: (on %s) %s", secondsOfMinute(), path, script); } if (controller->fd != NULL) { - fprintf(controller->fd,"%6.3f script: %s\n", secondsOfMinute(), script); + GetHdbPath(node, path, sizeof path); + fprintf(controller->fd,"%6.3f script: (on %s) %s\n", secondsOfMinute(), path, script); } MacroPush(con); @@ -551,7 +554,7 @@ static char *SctActionHandler(void *actionData, char *lastReply, l = blank - origScript; } else { l = strlen(origScript); - } + } snprintf(eprop, sizeof eprop, "error_in_%.*s", (int)l, origScript); emsg = GetHdbProp(node, eprop); cnt = 0; @@ -877,12 +880,13 @@ static hdbCallbackReturn SctActionCallback(Hdb * node, void *userData, * solution is to requeue the node. */ SCDeleteConnection(data->conCtx); + } else { + data->syncid = SyncedIncr(0); } data->conCtx = SCCopyConnection(con); data->answered = 0; data->inMacro = SCinMacro(con); tracePar(node->name,"Queued %s to %s",node->name, GetCharArray(text)); - data->syncid = SyncedIncr(0); data->busy = 1; DevQueue(data->controller->devser, data, prio, SctWriteHandler, SctMatch, SctEndData, SctDataInfo); @@ -980,7 +984,7 @@ static void SctKillCBData(void *d) } int SctAddPollNode(SctController * controller, Hdb * node, double interval, - DevPrio prio, char *action) + double start, DevPrio prio, char *action) { SctData *data; hdbCallback *cb; @@ -1003,7 +1007,7 @@ int SctAddPollNode(SctController * controller, Hdb * node, double interval, data->name = strdup(action); data->syncid = SyncedIncr(0); - if (DevSchedule(controller->devser, data, prio, interval, + if (DevScheduleS(controller->devser, data, prio, interval, start, SctActionHandler, SctMatch, SctKillData, SctDataInfo)) { return 1; } else { @@ -1016,15 +1020,17 @@ static int SctPollCmd(pSICSOBJ ccmd, SConnection * con, { Hdb *node; SctController *controller; - double interval; + double interval, start; char *path; DevPrio prio; char *action; char *prioText; - + char *intervalText; + int ii; + if (nPar < 1) { SCPrintf(con, eError, - "ERROR: should be: %s poll ( )", + "ERROR: should be: %s poll ( )", ccmd->objectNode->name); return 0; } @@ -1043,15 +1049,16 @@ static int SctPollCmd(pSICSOBJ ccmd, SConnection * con, return 0; } action = ParText(cmdNode, "action", nPar, "read"); + start = ParValue(cmdNode, "start", nPar, 0.0); - if (SctAddPollNode(controller, node, interval, prio, action)) { + if (SctAddPollNode(controller, node, interval, start, prio, action)) { SCPrintf(con, eValue, - "%s poll registered on %s (%g sec, %s prio)", - action, path, interval, prioText); + "%s poll registered on %s (%g sec, %s prio, %g start)", + action, path, interval, prioText, start); } else { SCPrintf(con, eValue, - "%s poll on %s changed to %g sec, %s prio", - action, path, interval, prioText); + "%s poll on %s changed to %g sec, %s prio, %g start", + action, path, interval, prioText, start); } return 1; } @@ -1922,6 +1929,7 @@ static int SctMakeController(SConnection * con, SicsInterp * sics, AddSICSHdbPar(cmd, "interval", usMugger, MakeHdbFloat(5.0)); AddSICSHdbPar(cmd, "prio", usMugger, MakeHdbText("read")); AddSICSHdbPar(cmd, "action", usMugger, MakeHdbText("read")); + AddSICSHdbPar(cmd, "start", usMugger, MakeHdbFloat(0.0)); cmd = AddSICSHdbPar(controller->node, "unpoll", usMugger, MakeSICSFunc(SctUnpollCmd));