aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMagnus Reftel <magnus.xm.reftel@stericsson.com>2011-05-20 16:06:50 +0200
committerSverre Vegge <sverre.vegge@stericsson.com>2011-07-25 09:45:01 +0200
commit97a8222f0d97fb87cd8f7f20f380d84fc763277e (patch)
treef205fb33d8dde7bb967c32554b1a09325ef0acff
parentd72ffc1a1bba365e84e5b4685d2d1bca25787fa3 (diff)
downloadu300-97a8222f0d97fb87cd8f7f20f380d84fc763277e.tar.gz
AT channel: handle command without response prefix
Added at_send_command_with_echo, which can be used for sending AT commands that have responses without prefixes. There is a race condition in at_send_command_multiline etc. with such AT commands that can only be avoided by having echo on while sending the command, which is what at_send_command_with_echo does. Signed-off-by: Sverre Vegge <sverre.vegge@stericsson.com>
-rw-r--r--atchannel.c60
-rw-r--r--atchannel.h15
-rw-r--r--u300-ril-information.c3
3 files changed, 75 insertions, 3 deletions
diff --git a/atchannel.c b/atchannel.c
index 5e3d666..7df2117 100644
--- a/atchannel.c
+++ b/atchannel.c
@@ -97,6 +97,9 @@ struct atcontext {
int readerClosed;
int timeoutMsec;
+
+ bool waitingForEcho;
+ const char* command;
};
static struct atcontext *s_defaultAtContext = NULL;
@@ -428,6 +431,17 @@ static void processLine(const char *line)
handleUnsolicited(line);
break;
+ case ECHOED:
+ if (ac->waitingForEcho) {
+ if (strcmp(line, ac->command) == 0) {
+ ac->waitingForEcho = false;
+ } else {
+ handleUnsolicited(line);
+ }
+ } else {
+ addIntermediate(line);
+ }
+ break;
default: /* This should never be reached */
LOGE("Unsupported AT command type %d", ac->type);
@@ -1038,6 +1052,8 @@ static int at_send_command_full_nolock(const char *command,
ac->type = type;
ac->responsePrefix = responsePrefix;
ac->smsPDU = smspdu;
+ ac->waitingForEcho = true; /* Only actually used when type is ECHOED */
+ ac->command = command;
ac->response = (ATResponse *) calloc(1, sizeof(ATResponse));
assert(ac->response != NULL);
@@ -1162,6 +1178,50 @@ int at_send_command(const char *command, ATResponse **pp_outResponse)
return err;
}
+int at_send_command_with_echo(const char *command, ATResponse **pp_outResponse)
+{
+ int err;
+ int ate0_err;
+
+ struct atcontext *ac = getAtContext();
+
+ if (0 != pthread_equal(ac->tid_reader, pthread_self()))
+ /* Cannot be called from reader thread. */
+ return AT_ERROR_INVALID_THREAD;
+
+ pthread_mutex_lock(&ac->commandmutex);
+
+ err = at_send_command_full_nolock("ATE1", NO_RESULT, NULL, NULL,
+ ac->timeoutMsec, pp_outResponse);
+ if (err < 0 || (pp_outResponse != NULL && *pp_outResponse != NULL
+ && (*pp_outResponse)->success == 0))
+ goto exit;
+
+ if (pp_outResponse) {
+ at_response_free(*pp_outResponse);
+ *pp_outResponse = NULL;
+ }
+
+ err = at_send_command_full_nolock(command, ECHOED, NULL, NULL,
+ ac->timeoutMsec, pp_outResponse);
+ if (err < 0 || (pp_outResponse != NULL && *pp_outResponse != NULL
+ && (*pp_outResponse)->success == 0))
+ goto exit;
+
+ ate0_err = at_send_command_full_nolock("ATE0", ECHOED, NULL, NULL,
+ ac->timeoutMsec, NULL);
+ if (ate0_err == AT_ERROR_TIMEOUT)
+ err = ate0_err;
+
+exit:
+ pthread_mutex_unlock(&ac->commandmutex);
+
+ if (err == AT_ERROR_TIMEOUT && ac->onTimeout != NULL)
+ ac->onTimeout();
+
+ return err;
+}
+
int at_send_command_with_timeout(const char *command,
ATResponse **pp_outResponse,
long long timeoutMsec)
diff --git a/atchannel.h b/atchannel.h
index 56fffa0..b3511e3 100644
--- a/atchannel.h
+++ b/atchannel.h
@@ -198,8 +198,10 @@ typedef enum {
NO_RESULT, /* No intermediate response expected. */
NUMERIC, /* A single intermediate response starting with a 0-9. */
SINGLELINE, /* A single intermediate response starting with a prefix. */
- MULTILINE /* Multiple line intermediate response
+ MULTILINE, /* Multiple line intermediate response
starting with a prefix. */
+ ECHOED, /* One or more lines, without prefixes. Requires
+ echo to be on while sending the command. */
} ATCommandType;
/** A singly-linked list of intermediate responses. */
@@ -274,6 +276,17 @@ int at_handshake();
int at_send_command(const char *command, ATResponse **pp_outResponse);
+/* Send an AT command with echo-aware response handling.
+ *
+ * This function will enable echo before sending the command, and disable it
+ * afterwards. This means that if echo was already enabled, echo may be
+ * disabled on return.
+ *
+ * The default timeout is used for each individual command, so this function
+ * may return successfully after up to three times the default timeout.
+ */
+int at_send_command_with_echo(const char *command, ATResponse **pp_outResponse);
+
int at_send_command_with_timeout(const char *command,
ATResponse **pp_outResponse,
long long timeoutMsec);
diff --git a/u300-ril-information.c b/u300-ril-information.c
index d32ec2d..82f1fb8 100644
--- a/u300-ril-information.c
+++ b/u300-ril-information.c
@@ -325,8 +325,7 @@ void requestBasebandVersion(void *data, size_t datalen, RIL_Token t)
ATLine *atline;
char *line;
- /* TODO: Check if we really should pass an empty string here */
- err = at_send_command_multiline("AT+CGMR", "", &atresponse);
+ err = at_send_command_with_echo("AT+CGMR", &atresponse);
if (err < 0 ||
atresponse->success == 0 || atresponse->p_intermediates == NULL)