- reworked states (removed substate)
- leave handler after every character read
This commit is contained in:
118
ascon.c
118
ascon.c
@ -65,15 +65,23 @@ double DoubleTime(void)
|
||||
void AsconError(Ascon *a, char *msg, int errorno)
|
||||
{
|
||||
static char *stateText[]={
|
||||
"state 0", "state 1", "state 2", "notConnected",
|
||||
"connect", "start connect", "connect finished", "connect failed",
|
||||
"write", "start write", "write finished", "write failed",
|
||||
"read", "start read", "read finished", "read failed",
|
||||
"state 16", "state 17", "state 18", "idle"
|
||||
"not connected",
|
||||
"connect start",
|
||||
"connecting",
|
||||
"connect done",
|
||||
"write start",
|
||||
"writing",
|
||||
"write done",
|
||||
"read start",
|
||||
"reading",
|
||||
"read done",
|
||||
"idle",
|
||||
"failed",
|
||||
"timeout"
|
||||
};
|
||||
char *state;
|
||||
|
||||
if (a->state < 0 || a->state > 19) {
|
||||
if (a->state < 0 || a->state >= AsconMaxState) {
|
||||
state = "bad state";
|
||||
} else {
|
||||
state = stateText[a->state];
|
||||
@ -92,7 +100,7 @@ void AsconError(Ascon *a, char *msg, int errorno)
|
||||
DynStringConcat(a->errmsg, msg);
|
||||
DynStringConcat(a->errmsg, ")");
|
||||
}
|
||||
a->state |= AsconFailed;
|
||||
a->state = AsconFailed;
|
||||
}
|
||||
|
||||
static void AsconConnect(Ascon * a)
|
||||
@ -144,7 +152,7 @@ static void AsconConnect(Ascon * a)
|
||||
ret =
|
||||
connect(a->fd, (struct sockaddr *) &adr, sizeof(struct sockaddr_in));
|
||||
if (ret < 0) {
|
||||
switch(errno) {
|
||||
switch (errno) {
|
||||
case EINPROGRESS:
|
||||
case EALREADY:
|
||||
case EISCONN:
|
||||
@ -359,11 +367,7 @@ int AsconStdHandler(Ascon * a)
|
||||
l = GetDynStringLength(a->wrBuffer) - a->wrPos;
|
||||
ret = AsconWriteChars(a->fd, GetCharArray(a->wrBuffer) + a->wrPos, l);
|
||||
if (ret < 0) {
|
||||
AsconError(a, "ASC4", errno);
|
||||
/*
|
||||
* Ooops: which state shall we go to after a write fail?
|
||||
* This seems to retry.
|
||||
*/
|
||||
AsconError(a, "ASC4", errno); /* sets state to AsconFailed */
|
||||
} else {
|
||||
a->wrPos += ret;
|
||||
if (a->wrPos >= GetDynStringLength(a->wrBuffer)) {
|
||||
@ -378,7 +382,7 @@ int AsconStdHandler(Ascon * a)
|
||||
break;
|
||||
case AsconReading:
|
||||
ret = AsconReadChar(a->fd, &chr);
|
||||
while (ret > 0) {
|
||||
if (ret > 0) {
|
||||
a->start = DoubleTime();
|
||||
|
||||
if (a->replyTerminator != NULL) {
|
||||
@ -413,23 +417,20 @@ int AsconStdHandler(Ascon * a)
|
||||
}
|
||||
a->readState = 0;
|
||||
}
|
||||
ret = AsconReadChar(a->fd, &chr);
|
||||
}
|
||||
if (ret < 0) {
|
||||
/* EINTR means we shall retry */
|
||||
if (errno != EINTR && errno != EAGAIN) {
|
||||
AsconError(a, "ASC5", errno);
|
||||
}
|
||||
AsconError(a, "ASC5", errno);
|
||||
return 1;
|
||||
}
|
||||
if (a->state == AsconReadDone) {
|
||||
DynStringConcatChar(a->rdBuffer, '\0');
|
||||
} else {
|
||||
if (a->timeout > 0) {
|
||||
if (DoubleTime() - a->start > a->timeout) {
|
||||
AsconError(a, "no response", 0);
|
||||
a->state = AsconTimeout;
|
||||
}
|
||||
} else if (ret > 0) {
|
||||
return 0; /* characater read: recycle */
|
||||
}
|
||||
if (a->timeout > 0) {
|
||||
if (DoubleTime() - a->start > a->timeout) {
|
||||
AsconError(a, "no response", 0);
|
||||
a->state = AsconTimeout;
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -539,21 +540,22 @@ void AsconDisconnect(Ascon * a)
|
||||
|
||||
AsconStatus AsconTask(Ascon * a)
|
||||
{
|
||||
int result;
|
||||
double now;
|
||||
|
||||
while (a->handler(a)) {
|
||||
|
||||
while (1) {
|
||||
result = a->handler(a);
|
||||
switch (a->state) {
|
||||
case AsconReading:
|
||||
case AsconWriting:
|
||||
return AsconPending;
|
||||
case AsconNotConnected:
|
||||
return AsconOffline;
|
||||
break;
|
||||
case AsconConnecting:
|
||||
return AsconUnconnected;
|
||||
case AsconConnectDone:
|
||||
a->state = AsconIdle;
|
||||
return AsconReady;
|
||||
case AsconWriteDone:
|
||||
if (a->noResponse) {
|
||||
a->state = AsconIdle;
|
||||
return AsconReady;
|
||||
}
|
||||
a->state = AsconReadStart;
|
||||
@ -562,39 +564,39 @@ AsconStatus AsconTask(Ascon * a)
|
||||
a->state = AsconIdle;
|
||||
a->responseValid = 1;
|
||||
return AsconReady;
|
||||
case AsconConnecting:
|
||||
return AsconUnconnected;
|
||||
default:
|
||||
switch (a->state % 4) {
|
||||
case AsconOnTheWay:
|
||||
case AsconStart:
|
||||
return AsconPending;
|
||||
case AsconFailed:
|
||||
if (a->state == AsconTimeout) {
|
||||
a->state = AsconIdle;
|
||||
} else {
|
||||
close(a->fd);
|
||||
lastClose = DoubleTime();
|
||||
a->fd = -1;
|
||||
a->state = AsconConnectStart;
|
||||
}
|
||||
|
||||
return AsconFailure;
|
||||
case AsconFinished:
|
||||
if (a->state < AsconConnectFailed) {
|
||||
return AsconUnconnected;
|
||||
}
|
||||
return AsconReady;
|
||||
case AsconIdle:
|
||||
return AsconReady;
|
||||
case AsconTimeout:
|
||||
a->state = AsconIdle;
|
||||
return AsconFailure;
|
||||
case AsconFailed:
|
||||
now = DoubleTime();
|
||||
if (a->fd > 0) {
|
||||
close(a->fd);
|
||||
lastClose = now;
|
||||
a->fd = -1;
|
||||
}
|
||||
if (now > a->lastReconnect + a->reconnectInterval) {
|
||||
a->lastReconnect = now;
|
||||
a->state = AsconConnectStart;
|
||||
}
|
||||
return AsconFailure;
|
||||
default:
|
||||
if (result) {
|
||||
return AsconPending;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return AsconIdle;
|
||||
}
|
||||
|
||||
int AsconWrite(Ascon * a, char *command, int noResponse)
|
||||
{
|
||||
if (a->state <= AsconConnectFailed || a->state % 4 < AsconFinished)
|
||||
if (a->state != AsconIdle) {
|
||||
/* this might happen if a script is sending after an error */
|
||||
return 0;
|
||||
}
|
||||
|
||||
DynStringCopy(a->wrBuffer, command);
|
||||
a->noResponse = noResponse;
|
||||
a->state = AsconWriteStart;
|
||||
@ -609,9 +611,9 @@ char *AsconRead(Ascon * a)
|
||||
a->noResponse = 0;
|
||||
return "";
|
||||
}
|
||||
if (a->state % 4 == AsconFailed) {
|
||||
if (a->state != AsconIdle) {
|
||||
a->state = AsconIdle;
|
||||
return "";
|
||||
return "programming error in devser.c/ascon.c";
|
||||
}
|
||||
if (a->responseValid) {
|
||||
a->responseValid = 0;
|
||||
|
Reference in New Issue
Block a user