- reworked states (removed substate)

- leave handler after every character read
This commit is contained in:
zolliker
2009-02-25 14:44:26 +00:00
parent 2006a2cf7d
commit 2fd07071d9
2 changed files with 81 additions and 80 deletions

118
ascon.c
View File

@ -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;