E1550 cusd error ira gsm

e1550 cusd error ira gsm

When I connected the modem to my PC it was immediately recognized as both an USB Drive and an GSM modem. Grepping through dmesg revealed. Mon Sep 28 sprers.eu chat[]: abort on (ERROR) sprers.eu uhttpd[]: ussd at_wcusd: got «+CUSD: 0. I haven't seen this behaviour with Huawei modems but I have seen it with some ZTE models. Have a look at the AT+CSCS command.

E1550 cusd error ira gsm - agree, very

Recently, while cleaning my flat, I found an old Huawei E USB modem. I planed to throw it away, but then I reminded myself that this simple device, as virtually all modems, supports a primitive text based interface known as “AT commands”. And so I started thinking about spending a few hours of my time sending AT commands and figuring out what is actually possible. This post is the result of this few hours of hacking. Enjoy!

When I connected the modem to my PC it was immediately recognized as both an USB Drive and an GSM modem. Grepping through revealed that three serial port terminals where created at , and :

To be honest I expected only a single file…

Running command on returned some useful information, including baud rate:

before an option name means that this option is disabled. Explanations for all options can be found in . For example means that the characters that we are writing, are not visible on the screen. That is not very comfortable but can be changed easily (you can try it yourself in bash by executing to disable and to enable echo).

To connect to I used :

We need to create a configuration first. For some reason was not able to save it’s config file in my home directory and insisted on saving it into and so I have to run it with :

Configuring is like a journey to 80s, entire UI is text based: minicom main menu First we need to go into “Serial port setup” section: minicom serial port setting and change “Serial Device” to (to do this press A, change the field value and press either Enter to save or Escape to cancel). Then we need to change baud rate (press E): minicom baud rate setting On this screen press C and then Enter. Next we need to go into “Screen and Keyboard” section and enable echo (press Q) and then Enter: minicom screen and keyboard settings We need to enable local echo (on the minicom side) because, as indicated the serial port itself does not support it.

Then we need to return to the main menu (press Enter) and select “Save setup as…” option. I saved my config under name. Then we should choose “Exit from Minicom”. If you chose “Exit” use Ctrl+A followed by X to exit.

Now we can start without :

and execute our first AT command which is just . The modem should respons with if everything works: minicom working

To find out what options are supported by my modem, I googled for “huawei e at command interface specification” and found a PDF document describing supported AT commands. By the way AT commands are de facto standard and could be used with any modem.

TIP: To exit press Ctrl+A followed by X (must be upper case).

WARNING: In the following sections I assume that we inserted a working SIM card into the modem.

Obtaining information from the modem

We can obtain a lot of information about our modem and the SIM card just by running AT commands. For example we may ask the modem for its phone number:

(“NUMER WLASNY” is “MY OWN NUMBER” in Polish), or for its IMEI number:

To read a modem flag or a setting we need to run a command in format. For example to obtain the character set used by the modem we send command:

To check what values are acceptable for this flag we run a command in format:

And to set flag/setting value we execute a command in format like :

Network signal strength can be checked using command:

The response has format . Signal strength varies from 31 (very good) to 0 (very poor / lack of signal). In my case bit error rate is not supported (99) by the modem.

command allows us to check the current network and to get a list of the present networks:

Sending USSD codes

USSD codes (short codes) like “*#” are quite useful, we can use them to check money amount on our account or to change the current tariff. Let’s see how to send them using AT commands. First hurdle to overcome is the encoding used while sending an USSD code. By default the codes must be encoded using GSM7Bit encoding, which is not related to 7-bit ASCII in any way. I couldn’t find any online encoder/decoder for this encoding, but fortunatelly I found a pice of code that does exactly what we want: sprers.eu And so I added a method and pasted the code to sprers.eu to obtain an online converter. You can see the final, “paste ready” code here.

Encoding in GSM7Bit gives us . Now we may issue our USSD request using command:

(first value in the request) means that we want to see the response, (the last value) is the encoding type that we are using.

Next we need to use our GSM7Bit decoder to obtain plain text from the network response (in Polish):

Sending and receiving SMS

Our next step will be to send and to receive an SMS:

Before we send a message we must switch to the text mode, which can be done by issuing command. The default mode is the PDU mode, which requires creating and parsing PDU binary frames.

To send an SMS command is used. After executing , a command prompt () will appear allowing us to write our message. When we are done we press Ctrl+Z, few seconds later the message will be delivered.

To list received and sent messages we can use command:

Remember to run this command in the text mode (), otherwise you will see hex encoded binary PDU frames.

First value in the row is the message index (). We may use this index to either read the message:

or to remove it:

Playing with the phone book entries

command can be used to read SIM card phone book entries:

returns supported range of indexes (; some of them may be empty), max. phone number length () and max. entry name length (). Using this information we may read phone book entries using command. When the phone number starts with its type is otherwise its type is .

Adding a phone book entry is very simple:

The same command can be used to remove a phone book entry:

RING RING RING

AT commands can also be used to make and receive phone calls. Voice is send/received in WAVE format. Unfortunately I cannot obtain even a simplest notification from my modem.

result == 1))+ return -1;++ if (p_out != NULL)+ *p_out = (char)result;+ else+ return -1;++ return ret;+}++int at_tok_nextstr(char **p_cur, char **p_out)+{+ if (*p_cur == NULL)+ return -1;++ *p_out = nextTok(p_cur);+ if (*p_out == NULL)+ return -1;++ return 0;+}++/** Returns 1 on "has more tokens" and 0 if not. */+int at_tok_hasmore(char **p_cur)+{+ return ! (*p_cur == NULL **p_cur == '\0');+}++/** *p_out returns count of given character (needle) in given string (p_in). */+int at_tok_charcounter(char *p_in, char needle, int *p_out)+{+ char *p_cur = p_in;+ int num_found = 0;++ if (p_in == NULL)+ return -1;++ while (*p_cur != '\0') {+ if (*p_cur == needle) {+ num_found++;+ }++ p_cur++;+ }++ *p_out = num_found;+ return 0;+}
+++ b/huaweigeneric-ril/at_tok.h
@@ -0,0 +1,31 @@
1+/* //device/system/reference-ril/at_tok.h
2+**
3+** Copyright , The Android Open Source Project
4+**
5+** Licensed under the Apache License, Version (the "License");
6+** you may not use this file except in compliance with the License.
7+** You may obtain a copy of the License at
8+**
9+** sprers.eu
10+**
11+** Unless required by applicable law or agreed to in writing, software
12+** distributed under the License is distributed on an "AS IS" BASIS,
13+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+** See the License for the specific language governing permissions and
15+** limitations under the License.
16+*/
17+
18+#ifndef AT_TOK_H
19+#define AT_TOK_H 1
20+
21+int at_tok_start(char **p_cur);
22+int at_tok_nextint(char **p_cur, int *p_out);
23+int at_tok_nexthexint(char **p_cur, int *p_out);
24+
25+int at_tok_nextbool(char **p_cur, char *p_out);
26+int at_tok_nextstr(char **p_cur, char **out);
27+
28+int at_tok_hasmore(char **p_cur);
29+
30+int at_tok_charcounter(char *p_in, char needle, int *p_out);
31+#endif
+++ b/huaweigeneric-ril/atchannel.c
@@ -0,0 +1, @@
1+/* //device/system/reference-ril/atchannel.c
2+**
3+** Copyright , The Android Open Source Project
4+**
5+** Licensed under the Apache License, Version (the "License");
6+** you may not use this file except in compliance with the License.
7+** You may obtain a copy of the License at
8+**
9+** sprers.eu
10+**
11+** Unless required by applicable law or agreed to in writing, software
12+** distributed under the License is distributed on an "AS IS" BASIS,
13+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+** See the License for the specific language governing permissions and
15+** limitations under the License.
16+*/
17+
18+#include "atchannel.h"
19+#include "at_tok.h"
20+
21+#include <stdio.h>
22+#include <string.h>
23+#include <pthread.h>
24+#include <ctype.h>
25+#include <stdlib.h>
26+#include <errno.h>
27+#include <fcntl.h>
28+#include <sys/time.h>
29+#include <time.h>
30+#include <unistd.h>
31+#include <stdarg.h>
32+
33+#include <poll.h>
34+
35+#define LOG_NDEBUG 0
36+#define LOG_TAG "AT"
37+#include <utils/Log.h>
38+
39+#ifdef HAVE_ANDROID_OS
40+/* For IOCTL's */
41+#include <linux/omap_csmi.h>
42+#endif /*HAVE_ANDROID_OS*/
43+
44+#include "misc.h"
45+
46+#define MAX_AT_RESPONSE (8 * )
47+#define HANDSHAKE_RETRY_COUNT 8
48+#define HANDSHAKE_TIMEOUT_MSEC
49+#define DEFAULT_AT_TIMEOUT_MSEC (3 * 60 * )
50+#define BUFFSIZE
51+
52+struct atcontext {
53+ pthread_t tid_reader;
54+ int fd; /* fd of the AT channel. */
55+ int readerCmdFds[2];
56+ int isInitialized;
57+ ATUnsolHandler unsolHandler;
58+
59+ /* For input buffering. */
60+ char ATBuffer[MAX_AT_RESPONSE+1];
61+ char *ATBufferCur;
62+
63+ int readCount;
64+
65+ /*
66+ * For current pending command, these are protected by commandmutex.
67+ *
68+ * The mutex and cond struct is memset in the getAtChannel() function,
69+ * so no initializer should be needed.
70+ */
71+ pthread_mutex_t requestmutex;
72+ pthread_mutex_t commandmutex;
73+ pthread_cond_t requestcond;
74+ pthread_cond_t commandcond;
75+
76+ ATCommandType type;
77+ const char *responsePrefix;
78+ const char *smsPDU;
79+ ATResponse *response;
80+
81+ void (*onTimeout)(void);
82+ void (*onReaderClosed)(void);
83+ int readerClosed;
84+
85+ int timeoutMsec;
86+};
87+
88+static struct atcontext *s_defaultAtContext = NULL;
89+static va_list empty = {0};
90+
91+static pthread_key_t key;
92+static pthread_once_t key_once = PTHREAD_ONCE_INIT;
93+
94+static int writeCtrlZ (const char *s);
95+static int writeline (const char *s);
96+static void onReaderClosed(void);
97+
98+static void make_key(void)
99+{
+ (void) pthread_key_create(&key, NULL);
+}
+
+/**
+ * Set the atcontext pointer. Useful for sub-threads that needs to hold
+ * the same state information.
+ *
+ * The caller IS responsible for freeing any memory already allocated
+ * for any previous atcontexts.
+ */
+static void setAtContext(struct atcontext *ac)
+{
+ (void) pthread_once(&key_once, make_key);
+ (void) pthread_setspecific(key, ac);
+}
+
+static void ac_free(void)
+{
+ struct atcontext *ac = NULL;
+ (void) pthread_once(&key_once, make_key);
+ if ((ac = (struct atcontext *) pthread_getspecific(key)) != NULL) {
+ free(ac);
+ LOGD("%s() freed current thread AT context", __func__);
+ } else {
+ LOGW("%s() No AT context exist for current thread, cannot free it",
+ __func__);
+ }
+}
+
+static int initializeAtContext(void)
+{
+ struct atcontext *ac = NULL;
+
+ if (pthread_once(&key_once, make_key)) {
+ LOGE("%s() Pthread_once failed!", __func__);
+ goto error;
+ }
+
+ ac = (struct atcontext *)pthread_getspecific(key);
+
+ if (ac == NULL) {
+ ac = (struct atcontext *) malloc(sizeof(struct atcontext));
+ if (ac == NULL) {
+ LOGE("%s() Failed to allocate memory", __func__);
+ goto error;
+ }
+
+ memset(ac, 0, sizeof(struct atcontext));
+
+ ac->fd = -1;
+ ac->readerCmdFds[0] = -1;
+ ac->readerCmdFds[1] = -1;
+ ac->ATBufferCur = ac->ATBuffer;
+
+ if (pipe(ac->readerCmdFds)) {
+ LOGE("%s() Failed to create pipe: %s", __func__, strerror(errno));
+ goto error;
+ }
+
+ pthread_mutex_init(&ac->commandmutex, NULL);
+ pthread_mutex_init(&ac->requestmutex, NULL);
+ pthread_cond_init(&ac->requestcond, NULL);
+ pthread_cond_init(&ac->commandcond, NULL);
+
+ ac->timeoutMsec = DEFAULT_AT_TIMEOUT_MSEC;
+
+ if (pthread_setspecific(key, ac)) {
+ LOGE("%s() Calling pthread_setspecific failed!", __func__);
+ goto error;
+ }
+ }
+
+ LOGI("Initialized new AT Context!");
+
+ return 0;
+
+error:
+ LOGE("%s() Failed initializing new AT Context!", __func__);
+ free(ac);
+ return -1;
+}
+
+static struct atcontext *getAtContext(void)
+{
+ struct atcontext *ac = NULL;
+
+ (void) pthread_once(&key_once, make_key);
+
+ if ((ac = (struct atcontext *) pthread_getspecific(key)) == NULL) {
+ if (s_defaultAtContext) {
+ LOGW("WARNING! external thread use default AT Context");
+ ac = s_defaultAtContext;
+ } else {
+ LOGE("WARNING! %s() called from external thread with "
+ "no defaultAtContext set!! This IS a bug! "
+ "A crash is probably nearby!", __func__);
+ }
+ }
+
+ return ac;
+}
+
+/**
+ * This function will make the current at thread the default channel,
+ * meaning that calls from a thread that is not a queuerunner will
+ * be executed in this context.
+ */
+void at_make_default_channel(void)
+{
+ struct atcontext *ac = getAtContext();
+
+ if (ac->isInitialized)
+ s_defaultAtContext = ac;
+}
+
+#if AT_DEBUG
+void AT_DUMP(const char* prefix, const char* buff, int len)
+{
+ if (len < 0)
+ len = strlen(buff);
+ LOGD("%.*s", len, buff);
+}
+#endif
+
+#ifndef HAVE_ANDROID_OS
+int pthread_cond_timeout_np(pthread_cond_t *cond,
+ pthread_mutex_t * mutex,
+ unsigned msecs)
+{
+ struct timespec ts;
+ clock_gettime(CLOCK_REALTIME, &ts);
+
+ sprers.eu_sec += msecs / ;
+ sprers.eu_nsec += (msecs % ) * ;
+ return pthread_cond_timedwait(cond, mutex, &ts);
+}
+#endif /*HAVE_ANDROID_OS*/
+
+static void sleepMsec(long long msec)
+{
+ struct timespec ts;
+ int err;
+
+ sprers.eu_sec = (msec / );
+ sprers.eu_nsec = (msec % ) * * ;
+
+ do {
+ err = nanosleep (&ts, &ts);
+ } while (err < 0 && errno == EINTR);
+}
+
+
+
+/** Add an intermediate response to sp_response. */
+static void addIntermediate(const char *line)
+{
+ ATLine *p_new;
+ struct atcontext *ac = getAtContext();
+
+ p_new = (ATLine *) malloc(sizeof(ATLine));
+
+ p_new->line = strdup(line);
+
+ /* Note: This adds to the head of the list, so the list will
+ be in reverse order of lines received. the order is flipped
+ again before passing on to the command issuer. */
+ p_new->p_next = ac->response->p_intermediates;
+ ac->response->p_intermediates = p_new;
+}
+
+
+/**
+ * Returns 1 if line is a final response indicating error.
+ * See annex B.
+ * WARNING: NO CARRIER and others are sometimes unsolicited.
+ */
+static const char * s_finalResponsesError[] = {
+ "ERROR",
+ "+CMS ERROR:",
+ "+CME ERROR:",
+ "NO CARRIER", /* Sometimes! */
+ "NO ANSWER",
+ "NO DIALTONE",
+};
+
+static int isFinalResponseError(const char *line)
+{
+ size_t i;
+
+ for (i = 0 ; i < NUM_ELEMS(s_finalResponsesError) ; i++) {
+ if (strStartsWith(line, s_finalResponsesError[i])) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * Returns 1 if line is a final response indicating success.
+ * See annex B.
+ * WARNING: NO CARRIER and others are sometimes unsolicited.
+ */
+static const char * s_finalResponsesSuccess[] = {
+ "OK",
+ "CONNECT" /* Some stacks start up data on another channel. */
+};
+static int isFinalResponseSuccess(const char *line)
+{
+ size_t i;
+
+ for (i = 0 ; i < NUM_ELEMS(s_finalResponsesSuccess) ; i++) {
+ if (strStartsWith(line, s_finalResponsesSuccess[i])) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * Returns 1 if line is the first line in (what will be) a two-line
+ * SMS unsolicited response.
+ */
+static const char * s_smsUnsoliciteds[] = {
+ "+CMT:",
+ "+CDS:",
+ "+CBM:"
+};
+static int isSMSUnsolicited(const char *line)
+{
+ size_t i;
+
+ for (i = 0 ; i < NUM_ELEMS(s_smsUnsoliciteds) ; i++) {
+ if (strStartsWith(line, s_smsUnsoliciteds[i])) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+
+/** Assumes s_commandmutex is held. */
+static void handleFinalResponse(const char *line)
+{
+ struct atcontext *ac = getAtContext();
+
+ ac->response->finalResponse = strdup(line);
+