[QtMoko] GSM not turning on / registering

Michael Spacefalcon msokolov at ivan.Harhan.ORG
Tue May 20 07:27:51 CEST 2014


Nick <openmoko-community at njw.me.uk> wrote:

> In the meantime, I tried running the AT commands with socat, but 
> didn't get very far.

I've never used socat (I use my own tool, see below), so I don't have
much to comment on that part, but the transcript you've posted shows
that you managed to catch some of the modem's output while it was being
driven by QtMoko (perhaps stopping QtMoko doesn't power the modem off),
and this output contains a smoking gun:

> +CREG: 3

The +CREG unsolicited response from the modem indicates its registration
status, and looking up the meaning of status code 3 in GSM spec 07.07
tells us that it means "registration denied" - aha!  So the GSM radio
signal *is* present, but when your FR tries to register to the network
it hears, the network actively denies that registration!  Two
possibilities come to mind:

Possibility 1: AT&T GSM service went away (either a deliberate service
shutdown, or the tower simply went down for some random reason or
another, and they are in no hurry to fix it because it's 2G which is
only used by outlaws and freedom lovers like us), but T-Mobile GSM is
still present; your FR tries to register with the T-Mobile network,
but the latter rejects the AT&T SIM.

Possibility 2: AT&T GSM service is still there, and your FR is trying
to register to it because it's got an AT&T SIM, but AT&T has decided
to reject your FR for some truly nefarious reason, such as an IMEI ban
against an entire range of devices they don't like - I've read stories
on the web about AT&T specifically pulling such BS.

See below on my proposed method for distinguishing between these two
possibilities.

> %CSQ:  18, 99, 2

%CSQ is TI's non-standard extended version of the standard +CSQ command
and unsolicited response; the standard +CSQ response gives two numbers,
while %CSQ adds a third.  I don't fully understand the meaning of the
3rd number yet, but we can ignore it for now.  99 in the 2nd number
position is a placeholder meaning that the modem has no BER information,
but the 1st number is the RSSI: received signal strength indicator.
Numbers like 18 or 15 seen further in your transcript look good to me.

> +CIEV: 1, 3

Yet another way by which TI's modem implementation returns the RSSI,
apparently.

> The commands 'AT+COPS=?', 'ATE1', 'AT+CFUN=1', 'AT+CGMI' were 
> entered by me. I'm guessing I should have seen at least a 'OK' or 
> 'ERROR' message, so maybe I'm using socat incorrectly?

Because I am the kind of guy who finds it easier to write his own
program than to learn how to use one that already exists, I've been
using my own ad hack tool called engcons to talk AT commands to the
modem in my Neo FR.  The engcons.c source is appended at the end of
this post; you'll need to compile and run it on your FR.  Use it like
this:

# stop QtMoko
/etc/init.d/qtmoko-neo stop
# power-cycle the modem
echo 0 > /sys/bus/platform/devices/gta02-pm-gsm.0/power_on
echo 1 > /sys/bus/platform/devices/gta02-pm-gsm.0/power_on
# run engcons to talk AT commands
engcons /dev/ttySAC0 r115200

Once you do the above, you should be in a state where you can type AT
commands and see the expected responses.  Try AT+CGMI, AT+CGMM, AT+CGMR,
AT+CFUN=1, AT+COPS and AT+COPS=?, and post the results you get.

VLR,
SF

engcons.c source follows; this ad hack program was originally written
for some completely different purposes and thus contains a bunch of
crud that will make no sense, but I just reused what I already had
working.

/*
 * This utility is used at Harhan Engineering Co. to connect to
 * the console ports of various targets in the lab.  Most of the latter
 * are either MicroVAXen or our own designs inspired by the VAX/MicroVAX
 * console, and this program has a few nifty features specifically
 * intended for those consoles.
 *
 * Beyond simple pass-thru of bytes in both directions, the following
 * features are provided:
 *
 *   - logging
 *   - ^P sends a break
 *   - binary upload via X command
 *   - changing console baud rate on HEC MC68302 targets (not in this version)
 *
 * This is the POSIX termios version of the program; the original version
 * was for 4.3BSD UNIX.
 *
 * Author: Michael Sokolov, Harhan Engineering Co.
 * msokolov at ivan.Harhan.ORG
 */

#include <sys/param.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/errno.h>
#include <termios.h>
#include <ctype.h>
#include <stdio.h>
#include <strings.h>

extern int errno;

int mypid;
int tfd;
FILE *tfdF;

struct termios saved_termios, my_termios, target_termios;

int kbd_eol_state = 1;
FILE *logF;

static struct speedtab {
	int	num;
	speed_t	code;
} speed_table[] = {
	{300, B300},
	{1200, B1200},
	{2400, B2400},
	{4800, B4800},
	{9600, B9600},
	{19200, B19200},
	{38400, B38400},
	{57600, B57600},
	{115200, B115200},
	{0, 0}};

main(argc, argv)
	char **argv;
{
	int zero = 0;
	struct speedtab *spd;
	int speed, rtscts = 0;
	char *cp;

	if (argc < 2 || argc > 3) {
		fprintf(stderr, "usage: %s tty [baud]\n", argv[0]);
		exit(1);
	}
	tfd = open(argv[1], O_RDWR|O_NONBLOCK);
	if (tfd < 0) {
		perror(argv[1]);
		exit(1);
	}
	tfdF = fdopen(tfd, "w");
	if (!tfdF) {
		perror("fdopen");
		exit(1);
	}
	if (argc == 3) {
		cp = argv[2];
		if (*cp == 'r') {
			cp++;
			rtscts++;
		}
		speed = atoi(cp);
	} else
		speed = 9600;
	for (spd = speed_table; spd->num; spd++)
		if (spd->num == speed)
			break;
	if (!spd->num) {
		fprintf(stderr, "%s: invalid baud rate\n", argv[2]);
		exit(1);
	}
	target_termios.c_iflag = IGNBRK;
	target_termios.c_oflag = 0;
	target_termios.c_cflag = CLOCAL|HUPCL|CREAD|CS8;
	if (rtscts)
		target_termios.c_cflag |= CRTSCTS;
	target_termios.c_lflag = 0;
	target_termios.c_cc[VMIN] = 1;
	target_termios.c_cc[VTIME] = 0;
	cfsetispeed(&target_termios, spd->code);
	cfsetospeed(&target_termios, spd->code);
	if (tcsetattr(tfd, TCSAFLUSH, &target_termios) < 0) {
		perror("tcsetattr");
		exit(1);
	}
	ioctl(tfd, FIONBIO, &zero);

	tcgetattr(0, &saved_termios);
	bcopy(&saved_termios, &my_termios, sizeof(struct termios));
	cfmakeraw(&my_termios);
	my_termios.c_cc[VMIN] = 1;
	my_termios.c_cc[VTIME] = 0;
	tcsetattr(0, TCSAFLUSH, &my_termios);

	printf("Starting session\r\n");
	mainloop();
}

mainloop()
{
	char buf[BUFSIZ];
	fd_set fds, fds1;
	register int i, cc, max;

	FD_ZERO(&fds);
	FD_SET(0, &fds);
	FD_SET(tfd, &fds);
	max = tfd + 1;
	for (;;) {
		bcopy(&fds, &fds1, sizeof(fd_set));
		i = select(max, &fds1, NULL, NULL, NULL);
		if (i < 0) {
			if (errno == EINTR)
				continue;
			tcsetattr(0, TCSAFLUSH, &saved_termios);
			perror("select");
			exit(1);
		}
		if (FD_ISSET(0, &fds1)) {
			cc = read(0, buf, sizeof buf);
			if (cc <= 0)
				quit();
			if (cc == 1 && buf[0] == 0x10) {
				sendbreak();
				continue;
			}
			if (cc == 1 && buf[0] == '!' && kbd_eol_state) {
				local_command();
				continue;
			}
			i = buf[cc-1];
			kbd_eol_state = (i == '\r') || (i == '\n');
			write(tfd, buf, cc);
		}
		if (FD_ISSET(tfd, &fds1)) {
			cc = read(tfd, buf, sizeof buf);
			if (cc <= 0) {
				tcsetattr(0, TCSAFLUSH, &saved_termios);
				fprintf(stderr, "EOF/error on target tty\n");
				exit(1);
			}
			write(1, buf, cc);
			if (logF)
				log_output(buf, cc);
		}
	}
}

log_output(buf, cc)
	char *buf;
{
	register char *cp;
	register int c, i;

	for (cp = buf, i = 0; i < cc; i++) {
		c = *cp++;
		if (c != '\r')
			putc(c, logF);
	}
}

sendbreak()
{
	tcsendbreak(tfd, 0);
}

local_command()
{
	char buf[256];
	int cc;
	register char *cp, *np;

	tcsetattr(0, TCSAFLUSH, &saved_termios);
	write(1, ":", 1);
	cc = read(0, buf, sizeof(buf) - 1);
	if (cc <= 0)
		quit(0);
	buf[cc] = '\0';

	for (cp = buf; isspace(*cp); cp++)
		;
	if (!*cp)
		goto out;
	for (np = cp; *cp && !isspace(*cp); cp++)
		;
	if (*cp)
		*cp++ = '\0';
	if (!strcasecmp(np, "log"))
		lcmd_log(cp);
	else if (!strcasecmp(np, "flush"))
		lcmd_flush();
	else if (!strcasecmp(np, "upload"))
		lcmd_upload(cp);
	else if (!strcasecmp(np, "quit"))
		quit();
	else
		fprintf(stderr, "invalid command\n");

out:	tcsetattr(0, TCSAFLUSH, &my_termios);
	return(0);
}

lcmd_log(arg)
	register char *arg;
{
	register char *cp;

	while (isspace(*arg))
		arg++;
	for (cp = arg; isgraph(*cp); cp++)
		;
	*cp = '\0';
	if (!arg[0]) {			/* check logging status */
		printf("Logging is %s\n", logF ? "on" : "off");
		return;
	} else if (!strcmp(arg, "-")) {	/* turn off */
		if (logF) {
			fclose(logF);
			logF = NULL;
			printf("Logging stopped\n");
		}
		return;
	}
	/* must be a request to turn it on */
	if (logF) {
		fprintf(stderr, "Logging is already on\n");
		return;
	}
	logF = fopen(arg, "w");
	if (logF)
		printf("Started logging to %s\n", arg);
	else
		perror(arg);
	return;
}

lcmd_flush()
{
	if (logF)
		fflush(logF);
}

lcmd_upload(arg)
	char *arg;
{
	char *filename, *loadaddr;
	register char *cp;
	FILE *df;
	struct stat st;
	u_char chksum, byte;
	char buf[256];
	int cc, chevron_count;
	register int i;

	for (cp = arg; isspace(*cp); cp++)
		;
	if (!*cp) {
toofew:		fprintf(stderr, "too few arguments\n");
		return;
	}
	for (filename = cp; *cp && !isspace(*cp); cp++)
		;
	if (!*cp)
		goto toofew;
	*cp++ = '\0';
	while (isspace(*cp))
		cp++;
	if (!*cp)
		goto toofew;
	for (loadaddr = cp; *cp && !isspace(*cp); cp++)
		;
	if (*cp)
		*cp++ = '\0';

	df = fopen(filename, "r");
	if (!df) {
		perror("filename");
		exit(1);
	}
	fstat(fileno(df), &st);
	sprintf(buf, "X %s %X\r", loadaddr, st.st_size);
	chksum = 0;
	for (cp = buf; *cp != '\r'; cp++)
		chksum += *cp;
	cp++;
	*cp++ = ~chksum + 1;
	write(tfd, buf, cp - buf);

	/* wait for the target to get ready */
	for (chevron_count = 0; chevron_count < 3; ) {
		cc = read(tfd, buf, sizeof buf);
		if (cc <= 0) {
			fprintf(stderr, "EOF/error on target tty\n");
			exit(1);
		}
		write(1, buf, cc);
		if (logF)
			log_output(buf, cc);
		for (cp = buf, i = 0; i < cc; i++) {
			if (*cp++ == '>')
				chevron_count++;
			else
				chevron_count = 0;
		}
	}

	/* pump the data */
	for (chksum = 0; (i = getc(df)) != EOF; ) {
		putc(i, tfdF);
		chksum += i;
	}
	putc(~chksum + 1, tfdF);
	fflush(tfdF);

	/* done! */
	fclose(df);
}

quit()
{
	tcsetattr(0, TCSAFLUSH, &saved_termios);
	exit(0);
}



More information about the community mailing list