Finally opening the serial line correctly

This commit is contained in:
Pierre Pronchery 2010-04-24 15:26:11 +00:00
parent 61aab8b3cd
commit fbb0fda16b
2 changed files with 99 additions and 33 deletions

129
src/gsm.c
View File

@ -21,6 +21,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <errno.h>
#include <glib.h> #include <glib.h>
#include "phone.h" #include "phone.h"
#include "gsm.h" #include "gsm.h"
@ -161,10 +162,10 @@ int gsm_modem_call(GSM * gsm, char const * number)
#endif #endif
if(!_is_number(number)) if(!_is_number(number))
return 1; return 1;
len = sizeof(cmd) + strlen(number) + 1; len = sizeof(cmd) + strlen(number) + 2;
if((buf = malloc(len)) == NULL) if((buf = malloc(len)) == NULL)
return phone_error(NULL, "malloc", 1); return phone_error(NULL, "malloc", 1);
snprintf(buf, len, "%s%s\n", cmd, number); snprintf(buf, len, "%s%s\r\n", cmd, number);
ret = gsm_modem_queue(gsm, buf); ret = gsm_modem_queue(gsm, buf);
free(buf); free(buf);
return ret; return ret;
@ -174,7 +175,7 @@ int gsm_modem_call(GSM * gsm, char const * number)
/* gsm_modem_hangup */ /* gsm_modem_hangup */
int gsm_modem_hangup(GSM * gsm) int gsm_modem_hangup(GSM * gsm)
{ {
return gsm_modem_queue(gsm, "ATH\n"); return gsm_modem_queue(gsm, "\r\nATH\r\n");
} }
@ -202,7 +203,8 @@ int gsm_modem_queue(GSM * gsm, char const * command)
/* gsm_modem_reset */ /* gsm_modem_reset */
int gsm_modem_reset(GSM * gsm) int gsm_modem_reset(GSM * gsm)
{ {
return gsm_modem_queue(gsm, "ATZ\n"); /* FIXME queue commands in sequence and prepend this one to the list */
return gsm_modem_queue(gsm, "\r\nATZ\r\n");
} }
@ -272,50 +274,91 @@ static int _is_number(char const * number)
/* callbacks */ /* callbacks */
/* on_reset */ /* on_reset */
static int _reset_do(GSM * gsm); static int _reset_do(GSM * gsm, int fd);
static gboolean _on_reset(gpointer data) static gboolean _on_reset(gpointer data)
{ {
GSM * gsm = data; GSM * gsm = data;
int fd;
GError * error = NULL;
gsm->source = 0; gsm->source = 0;
if(_reset_do(gsm) != 0) if((fd = open(gsm->device, O_RDWR | O_NONBLOCK)) < 0)
return phone_error(NULL, "open", 1);
if(_reset_do(gsm, fd) != 0)
{ {
phone_error(NULL, gsm->device, 0); close(fd);
if(gsm->retry > 0) if(gsm->retry > 0)
gsm->source = g_timeout_add(gsm->retry, _on_reset, gsm); gsm->source = g_timeout_add(gsm->retry, _on_reset, gsm);
return FALSE;
} }
gsm->channel = g_io_channel_unix_new(fd);
if((g_io_channel_set_encoding(gsm->channel, NULL, &error))
!= G_IO_STATUS_NORMAL)
/* XXX ugly */
fprintf(stderr, "ERROR: %s() g_io_channel_set_encoding\n",
__func__);
g_io_channel_set_buffered(gsm->channel, FALSE);
gsm->rd_io = g_io_add_watch(gsm->channel, G_IO_IN, _on_watch_read, gsm);
gsm_modem_reset(gsm);
return FALSE; return FALSE;
} }
static int _reset_do(GSM * gsm) static int _reset_do(GSM * gsm, int fd)
{ {
int fd; struct stat st;
int fl; int fl;
struct termios tios; struct termios term;
if((fd = open(gsm->device, O_RDWR | O_NONBLOCK)) < 0) #ifdef DEBUG
return 1; fprintf(stderr, "DEBUG: %s(%d)\n", __func__, fd);
fl = fcntl(fd, F_GETFL);
if(fcntl(fd, F_SETFL, fl & ~O_NONBLOCK) == -1
|| tcgetattr(fd, &tios) != 0)
#ifdef DEBUG /* ignore errors here */
;
#else
return 1;
#endif #endif
tios.c_ispeed = gsm->baudrate; if(flock(fd, LOCK_EX | LOCK_NB) != 0)
tios.c_ospeed = gsm->baudrate; return phone_error(NULL, "flock", 1);
if(tcsetattr(fd, TCSANOW, &tios) != 0) if(fstat(fd, &st) != 0)
return phone_error(NULL, "fstat", 1);
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s(%d) mode 0%o\n", __func__, fd, st.st_mode);
#endif
if(st.st_mode & S_IFCHR) /* character special */
{ {
#ifndef DEBUG /* ignore errors here as well */ if(tcgetattr(fd, &term) != 0)
close(fd); return phone_error(NULL, "tcgetattr", 1);
return 1; switch(gsm->baudrate) /* XXX rewrite this a nicer way */
#endif {
case 4800:
term.c_cflag = B4800;
break;
case 9600:
term.c_cflag = B9600;
break;
case 19200:
term.c_cflag = B19200;
break;
case 38400:
term.c_cflag = B38400;
break;
case 115200:
term.c_cflag = B115200;
break;
default:
errno = EINVAL;
return phone_error(NULL, "baudrate", 1);
} }
gsm->channel = g_io_channel_unix_new(fd); term.c_cflag |= CS8;
gsm->rd_io = g_io_add_watch(gsm->channel, G_IO_IN, _on_watch_read, gsm); term.c_cflag |= CREAD;
gsm_modem_reset(gsm); term.c_cflag |= CLOCAL;
term.c_iflag = (IGNPAR | IGNBRK);
term.c_lflag = 0;
term.c_oflag = 0;
term.c_cc[VMIN] = 1;
term.c_cc[VTIME] = 0;
if(tcsetattr(fd, TCSAFLUSH, &term) != 0)
return phone_error(NULL, "tcsetattr", 1);
}
fl = fcntl(fd, F_GETFL, 0);
if(fcntl(fd, F_SETFL, fl & ~O_NONBLOCK) == -1)
return phone_error(NULL, "fcntl", 1);
return 0; return 0;
} }
@ -331,22 +374,28 @@ static gboolean _on_watch_read(GIOChannel * source, GIOCondition condition,
GIOStatus status; GIOStatus status;
#ifdef DEBUG #ifdef DEBUG
fprintf(stderr, "DEBUG: %s()\n", __func__); fprintf(stderr, "DEBUG: %s(%d)\n", __func__, condition);
#endif #endif
if(condition != G_IO_IN || source != gsm->channel) if(condition != G_IO_IN || source != gsm->channel)
return FALSE; return FALSE;
/* FIXME really implement */ /* FIXME really implement */
status = g_io_channel_read_chars(source, buf, sizeof(buf), &cnt, status = g_io_channel_read_chars(source, buf, sizeof(buf), &cnt,
&error); &error);
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s() cnt=%lu\n", __func__, cnt);
#endif
switch(status) switch(status)
{ {
case G_IO_STATUS_NORMAL: case G_IO_STATUS_NORMAL:
break; break;
case G_IO_STATUS_ERROR: case G_IO_STATUS_ERROR:
/* XXX report error, do not break */ /* XXX report error, do not break */
fprintf(stderr, "%s%s\n", "phone: read: ",
error->message);
case G_IO_STATUS_EOF: case G_IO_STATUS_EOF:
default: /* should not happen... */ default: /* should not happen... */
gsm_reset(gsm, 1000); if(gsm->retry > 0)
gsm_reset(gsm, gsm->retry);
return FALSE; return FALSE;
} }
/* FIXME parse and interpret the output */ /* FIXME parse and interpret the output */
@ -369,12 +418,18 @@ static gboolean _on_watch_write(GIOChannel * source, GIOCondition condition,
GIOStatus status; GIOStatus status;
char * p; char * p;
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s(%d)\n", __func__, condition);
#endif
if(condition != G_IO_OUT || source != gsm->channel) if(condition != G_IO_OUT || source != gsm->channel)
return FALSE; return FALSE;
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s() write %zu\n", __func__, gsm->wr_buf_cnt);
#endif
status = g_io_channel_write_chars(source, gsm->wr_buf, gsm->wr_buf_cnt, status = g_io_channel_write_chars(source, gsm->wr_buf, gsm->wr_buf_cnt,
&cnt, &error); &cnt, &error);
#ifdef DEBUG #ifdef DEBUG
fprintf(stderr, "DEBUG: %s() \"", __func__); fprintf(stderr, "DEBUG: %s() wrote %lu \"", __func__, cnt);
fwrite(gsm->wr_buf, sizeof(*gsm->wr_buf), cnt, stderr); fwrite(gsm->wr_buf, sizeof(*gsm->wr_buf), cnt, stderr);
fputs("\"\n", stderr); fputs("\"\n", stderr);
#endif #endif
@ -391,8 +446,16 @@ static gboolean _on_watch_write(GIOChannel * source, GIOCondition condition,
break; break;
case G_IO_STATUS_ERROR: case G_IO_STATUS_ERROR:
/* XXX report error, do not break */ /* XXX report error, do not break */
#ifdef DEBUG
perror("phone: write");
#else
fprintf(stderr, "%s%s\n", "phone: write: ",
error->message);
#endif
case G_IO_STATUS_EOF:
default: /* should not happen... */ default: /* should not happen... */
gsm_reset(gsm, 1000); if(gsm->retry > 0)
gsm_reset(gsm, gsm->retry);
return FALSE; return FALSE;
} }
if(gsm->wr_buf_cnt > 0) /* there is more data to write */ if(gsm->wr_buf_cnt > 0) /* there is more data to write */

View File

@ -51,6 +51,9 @@ Phone * phone_new(char const * device, unsigned int baudrate)
GtkWidget * vbox; GtkWidget * vbox;
GtkWidget * widget; GtkWidget * widget;
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s(\"%s\", %u)\n", __func__, device, baudrate);
#endif
if((phone = malloc(sizeof(*phone))) == NULL) if((phone = malloc(sizeof(*phone))) == NULL)
return NULL; return NULL;
if(device == NULL) if(device == NULL)