summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlaforge <laforge@99fdad57-331a-0410-800a-d7fa5415bdb3>2006-10-24 13:07:08 +0000
committerlaforge <laforge@99fdad57-331a-0410-800a-d7fa5415bdb3>2006-10-24 13:07:08 +0000
commit23dfcf4ff925f61bcb2c3bdd712ff0f70bde4fcb (patch)
tree97c62e6b7bc73cd4be3961ed2a253504381841c3
parent3c4d2776058a440bb8d406cd85783898c14b2403 (diff)
- clean up header files (all in include/gmsd now)
- finish vendor plugin support - add call progress indicator and signal quality unsolicited support to vendor_ti.c git-svn-id: http://svn.openmoko.org/trunk/src/target/gsm@120 99fdad57-331a-0410-800a-d7fa5415bdb3
-rw-r--r--include/gsmd/atcmd.h17
-rw-r--r--include/gsmd/gsmd.h88
-rw-r--r--include/gsmd/select.h (renamed from src/gsmd/select.h)10
-rw-r--r--include/gsmd/unsolicited.h18
-rw-r--r--include/gsmd/usock.h41
-rw-r--r--include/gsmd/vendorplugin.h27
-rw-r--r--src/gsmd/Makefile.am3
-rw-r--r--src/gsmd/atcmd.c10
-rw-r--r--src/gsmd/atcmd.h13
-rw-r--r--src/gsmd/gsmd.c24
-rw-r--r--src/gsmd/gsmd.h84
-rw-r--r--src/gsmd/log.c2
-rw-r--r--src/gsmd/select.c5
-rw-r--r--src/gsmd/unsolicited.c58
-rw-r--r--src/gsmd/unsolicited.h9
-rw-r--r--src/gsmd/usock.c117
-rw-r--r--src/gsmd/usock.h16
-rw-r--r--src/gsmd/vendor.c39
-rw-r--r--src/gsmd/vendor_ti.c91
-rw-r--r--src/gsmd/vendorplugin.h4
-rw-r--r--src/libgsmd/libgsmd.c6
-rw-r--r--src/libgsmd/libgsmd_network.c4
-rw-r--r--src/util/atcmd.c2
-rw-r--r--src/util/event.c15
24 files changed, 525 insertions, 178 deletions
diff --git a/include/gsmd/atcmd.h b/include/gsmd/atcmd.h
new file mode 100644
index 0000000..0d6c62a
--- /dev/null
+++ b/include/gsmd/atcmd.h
@@ -0,0 +1,17 @@
+#ifndef __GSMD_ATCMD_H
+#define __GSMD_ATCMD_H
+
+#ifdef __GSMD__
+
+#include <gsmd/gsmd.h>
+
+typedef int atcmd_cb_t(struct gsmd_atcmd *cmd, void *ctx, char *resp);
+
+extern struct gsmd_atcmd *atcmd_fill(const char *cmd, int rlen, atcmd_cb_t *cb, void *ctx, u_int16_t id);
+extern int atcmd_submit(struct gsmd *g, struct gsmd_atcmd *cmd);
+extern int atcmd_init(struct gsmd *g, int sockfd);
+extern void atcmd_drain(int fd);
+
+#endif /* __GSMD__ */
+
+#endif
diff --git a/include/gsmd/gsmd.h b/include/gsmd/gsmd.h
index f5b61d5..9b99a15 100644
--- a/include/gsmd/gsmd.h
+++ b/include/gsmd/gsmd.h
@@ -1,4 +1,92 @@
#ifndef _GSMD_H
#define _GSMD_H
+#ifdef __GSMD__
+
+#include <sys/types.h>
+
+#include <common/linux_list.h>
+
+#include <gsmd/vendorplugin.h>
+#include <gsmd/select.h>
+
+/* Refer to 3GPP TS 07.07 v 7.8.0, Chapter 4.1 */
+#define LGSM_ATCMD_F_EXTENDED 0x01 /* as opposed to basic */
+#define LGSM_ATCMD_F_PARAM 0x02 /* as opposed to action */
+
+struct gsmd_atcmd {
+ struct llist_head list;
+ void *ctx;
+ int (*cb)(struct gsmd_atcmd *cmd, void *ctx, char *resp);
+ char *resp;
+ int32_t ret;
+ u_int32_t buflen;
+ u_int16_t id;
+ u_int8_t flags;
+ char buf[];
+};
+
+enum llparse_state {
+ LLPARSE_STATE_IDLE, /* idle, not parsing a response */
+ LLPARSE_STATE_IDLE_CR, /* CR before response (V1) */
+ LLPARSE_STATE_IDLE_LF, /* LF before response (V1) */
+ LLPARSE_STATE_RESULT, /* within result payload */
+ LLPARSE_STATE_RESULT_CR, /* CR after result */
+ LLPARSE_STATE_ERROR, /* something went wrong */
+ /* ... idle again */
+};
+
+/* we can't take any _single_ response bigger than this: */
+#define LLPARSE_BUF_SIZE 256
+
+struct llparser {
+ enum llparse_state state;
+ unsigned int len;
+ unsigned int flags;
+ void *ctx;
+ int (*cb)(const char *buf, int len, void *ctx);
+ char *cur;
+ char buf[LLPARSE_BUF_SIZE];
+};
+
+struct gsmd;
+
+#define GSMD_FLAG_V0 0x0001 /* V0 responses to be expected from TA */
+
+struct gsmd {
+ unsigned int flags;
+ struct gsmd_fd gfd_uart;
+ struct gsmd_fd gfd_sock;
+ struct llparser llp;
+ struct llist_head users;
+ struct llist_head pending_atcmds; /* our busy gsmd_atcmds */
+ struct llist_head busy_atcmds; /* our busy gsmd_atcmds */
+ struct gsmd_vendor_plugin *vendorpl;
+};
+
+struct gsmd_user {
+ struct llist_head list; /* our entry in the global list */
+ struct llist_head finished_ucmds; /* our busy gsmd_ucmds */
+ struct gsmd *gsmd;
+ struct gsmd_fd gfd; /* the socket */
+ u_int32_t subscriptions; /* bitmaks of subscribed event groups */
+};
+
+#define GSMD_DEBUG 1 /* debugging information */
+#define GSMD_INFO 3
+#define GSMD_NOTICE 5 /* abnormal/unexpected condition */
+#define GSMD_ERROR 7 /* error condition, requires user action */
+#define GSMD_FATAL 8 /* fatal, program aborted */
+
+extern int gsmdlog_init(const char *path);
+/* write a message to the daemons' logfile */
+void __gsmd_log(int level, const char *file, int line, const char *function, const char *message, ...);
+/* macro for logging including filename and line number */
+#define gsmd_log(level, format, args ...) \
+ __gsmd_log(level, __FILE__, __LINE__, __FUNCTION__, format, ## args)
+
+#define DEBUGP(x, args ...) gsmd_log(GSMD_DEBUG, x, ## args)
+
+#endif /* __GSMD__ */
+
#endif /* _GSMD_H */
diff --git a/src/gsmd/select.h b/include/gsmd/select.h
index c734eb6..b75c338 100644
--- a/src/gsmd/select.h
+++ b/include/gsmd/select.h
@@ -1,6 +1,8 @@
#ifndef __GSMD_SELECT_H
#define __GSMD_SELECT_H
+#ifdef __GSMD__
+
#include <common/linux_list.h>
#define GSMD_FD_READ 0x0001
@@ -15,8 +17,10 @@ struct gsmd_fd {
void *data; /* void * to pass to callback */
};
-int gsmd_register_fd(struct gsmd_fd *ufd);
-void gsmd_unregister_fd(struct gsmd_fd *ufd);
-int gsmd_select_main(void);
+extern int gsmd_register_fd(struct gsmd_fd *ufd);
+extern void gsmd_unregister_fd(struct gsmd_fd *ufd);
+extern int gsmd_select_main(void);
+
+#endif /* __GSMD__ */
#endif
diff --git a/include/gsmd/unsolicited.h b/include/gsmd/unsolicited.h
new file mode 100644
index 0000000..e7f17c5
--- /dev/null
+++ b/include/gsmd/unsolicited.h
@@ -0,0 +1,18 @@
+#ifndef __GSMD_UNSOLICITED_H
+#define __GSMD_UNSOLICITED_H
+
+#ifdef __GSMD__
+
+#include <gsmd/gsmd.h>
+
+struct gsmd_unsolicit {
+ const char *prefix;
+ int (*parse)(char *unsol, int len, const char *param, struct gsmd *gsmd);
+};
+
+extern int unsolicited_parse(struct gsmd *g, char *buf, int len, const char *param);
+extern int generate_event_from_cme(struct gsmd *g, unsigned int cme_error);
+
+#endif /* __GSMD__ */
+
+#endif
diff --git a/include/gsmd/usock.h b/include/gsmd/usock.h
index 2eaa6cf..94e8c37 100644
--- a/include/gsmd/usock.h
+++ b/include/gsmd/usock.h
@@ -53,6 +53,9 @@ enum gsmd_msg_phone {
enum gsmd_msg_network {
GSMD_NETWORK_REGISTER = 1,
+ GSMD_NETWORK_SIGQ_GET = 2,
+ GSMD_NETWORK_VMAIL_GET = 3,
+ GSMD_NETWORK_VMAIL_SET = 4,
};
/* Length from 3GPP TS 04.08, Clause 10.5.4.7 */
@@ -61,7 +64,17 @@ enum gsmd_msg_network {
struct gsmd_addr {
u_int8_t type;
char number[GSMD_ADDR_MAXLEN+1];
-};
+} __attribute__ ((packed));
+
+struct gsmd_signal_quality {
+ u_int8_t rssi;
+ u_int8_t ber;
+} __attribute__ ((packed));
+
+struct gsmd_voicemail {
+ u_int8_t enable;
+ struct gsmd_addr addr;
+} __attribute__ ((packed));
struct gsmd_evt_auxdata {
union {
@@ -89,6 +102,9 @@ struct gsmd_evt_auxdata {
struct {
u_int8_t tz;
} timezone;
+ struct {
+ struct gsmd_signal_quality sigq;
+ } signal;
} u;
} __attribute__((packed));
@@ -103,4 +119,27 @@ struct gsmd_msg_hdr {
} __attribute__((packed));
+#ifdef __GSMD__
+
+#include <common/linux_list.h>
+
+#include <gsmd/usock.h>
+#include <gsmd/gsmd.h>
+
+struct gsmd_user;
+
+struct gsmd_ucmd {
+ struct llist_head list;
+ struct gsmd_msg_hdr hdr;
+ char buf[];
+} __attribute__ ((packed));
+
+extern int usock_init(struct gsmd *g);
+extern void usock_cmd_enqueue(struct gsmd_ucmd *ucmd, struct gsmd_user *gu);
+extern struct gsmd_ucmd *usock_build_event(u_int8_t type, u_int8_t subtype, u_int8_t len);
+extern int usock_evt_send(struct gsmd *gsmd, struct gsmd_ucmd *ucmd, u_int32_t evt);
+
+#endif /* __GSMD__ */
+
#endif
+
diff --git a/include/gsmd/vendorplugin.h b/include/gsmd/vendorplugin.h
new file mode 100644
index 0000000..c3843b2
--- /dev/null
+++ b/include/gsmd/vendorplugin.h
@@ -0,0 +1,27 @@
+#ifndef _GSMD_VENDORPLUGIN_H
+#define _GSMD_VENDORPLUGIN_H
+
+#ifdef __GSMD__
+
+#include <common/linux_list.h>
+#include <gsmd/gsmd.h>
+
+struct gsmd;
+struct gsmd_unsolicit;
+
+struct gsmd_vendor_plugin {
+ struct llist_head list;
+ unsigned char *name;
+ unsigned int num_unsolicit;
+ const struct gsmd_unsolicit *unsolicit;
+ int (*detect)(struct gsmd *g);
+ int (*initsettings)(struct gsmd *g);
+};
+
+extern int gsmd_vendor_plugin_register(struct gsmd_vendor_plugin *pl);
+extern void gsmd_vendor_plugin_unregister(struct gsmd_vendor_plugin *pl);
+extern int gsmd_vendor_plugin_find(struct gsmd *g);
+
+#endif /* __GSMD__ */
+
+#endif
diff --git a/src/gsmd/Makefile.am b/src/gsmd/Makefile.am
index 2d62662..d720a4c 100644
--- a/src/gsmd/Makefile.am
+++ b/src/gsmd/Makefile.am
@@ -3,7 +3,8 @@ AM_CFLAGS = -std=gnu99
bin_PROGRAMS = gsmd
-gsmd_SOURCES = gsmd.c atcmd.c select.c vendor_ti.c usock.c unsolicited.c log.c
+gsmd_SOURCES = gsmd.c atcmd.c select.c vendor.c usock.c unsolicited.c log.c \
+ vendor_ti.c
#gsmd_LDADD = ../libgsmd/libgsmd.la
#gsmd_LDFLAGS = -dynamic
diff --git a/src/gsmd/atcmd.c b/src/gsmd/atcmd.c
index 53120f4..7f95465 100644
--- a/src/gsmd/atcmd.c
+++ b/src/gsmd/atcmd.c
@@ -8,11 +8,13 @@
#include <sys/types.h>
#include <common/linux_list.h>
-#include <gsmd/ts0707.h>
#include "gsmd.h"
-#include "atcmd.h"
-#include "unsolicited.h"
+
+#include <gsmd/ts0707.h>
+#include <gsmd/gsmd.h>
+#include <gsmd/atcmd.h>
+#include <gsmd/unsolicited.h>
/* libgsmd / gsmd AT command interpreter / parser / constructor
* (C) 2006 by Harald Welte <hwelte@hmw-consulting.de>
@@ -179,7 +181,7 @@ static int ml_parse(const char *buf, int len, void *ctx)
* TBD
*/
- if (buf[0] == '+') {
+ if (buf[0] == '+' || buf[0] == '%') {
/* an extended response */
const char *colon = strchr(buf, ':');
if (!colon) {
diff --git a/src/gsmd/atcmd.h b/src/gsmd/atcmd.h
deleted file mode 100644
index 1e4cdfb..0000000
--- a/src/gsmd/atcmd.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef __GSMD_ATCMD_H
-#define __GSMD_ATCMD_H
-
-#include "gsmd.h"
-
-typedef int atcmd_cb_t(struct gsmd_atcmd *cmd, void *ctx, char *resp);
-
-struct gsmd_atcmd *atcmd_fill(const char *cmd, int rlen, atcmd_cb_t *cb, void *ctx, u_int16_t id);
-int atcmd_submit(struct gsmd *g, struct gsmd_atcmd *cmd);
-int atcmd_init(struct gsmd *g, int sockfd);
-void atcmd_drain(int fd);
-
-#endif
diff --git a/src/gsmd/gsmd.c b/src/gsmd/gsmd.c
index 9595d4b..c56e74c 100644
--- a/src/gsmd/gsmd.c
+++ b/src/gsmd/gsmd.c
@@ -12,13 +12,13 @@
#include <sys/types.h>
#include <sys/stat.h>
-#include <gsmd/gsmd.h>
-
#include "gsmd.h"
-#include "atcmd.h"
-#include "select.h"
-#include "usock.h"
-#include "vendorplugin.h"
+
+#include <gsmd/gsmd.h>
+#include <gsmd/atcmd.h>
+#include <gsmd/select.h>
+#include <gsmd/usock.h>
+#include <gsmd/vendorplugin.h>
static int gsmd_test_atcb(struct gsmd_atcmd *cmd, void *ctx, char *resp)
{
@@ -26,7 +26,7 @@ static int gsmd_test_atcb(struct gsmd_atcmd *cmd, void *ctx, char *resp)
return 0;
}
-static int gsmd_simplecmd(struct gsmd *gsmd, char *cmdtxt)
+int gsmd_simplecmd(struct gsmd *gsmd, char *cmdtxt)
{
struct gsmd_atcmd *cmd;
cmd = atcmd_fill(cmdtxt, strlen(cmdtxt)+1, &gsmd_test_atcb, NULL, 0);
@@ -43,7 +43,10 @@ int gsmd_initsettings(struct gsmd *gsmd)
rc |= gsmd_simplecmd(gsmd, "ATE0V1");
rc |= gsmd_simplecmd(gsmd, "AT+CRC=1;+CREG=2;+CMEE=1;+CLIP=1;+COLP=1;+CTZR=1;+CFUN=1");
- return rc;
+ if (gsmd->vendorpl && gsmd->vendorpl->initsettings)
+ return gsmd->vendorpl->initsettings(gsmd);
+ else
+ return rc;
}
struct bdrt {
@@ -199,6 +202,11 @@ int main(int argc, char **argv)
setsid();
}
+ /* FIXME: do this dynamically */
+ ticalypso_init();
+
+ gsmd_vendor_plugin_find(&g);
+
gsmd_initsettings(&g);
while (1) {
diff --git a/src/gsmd/gsmd.h b/src/gsmd/gsmd.h
deleted file mode 100644
index c67e15e..0000000
--- a/src/gsmd/gsmd.h
+++ /dev/null
@@ -1,84 +0,0 @@
-#ifndef __GSMD_H
-#define __GSMD_H
-
-#include <sys/types.h>
-
-#include <common/linux_list.h>
-
-#include "select.h"
-
-/* Refer to 3GPP TS 07.07 v 7.8.0, Chapter 4.1 */
-#define LGSM_ATCMD_F_EXTENDED 0x01 /* as opposed to basic */
-#define LGSM_ATCMD_F_PARAM 0x02 /* as opposed to action */
-
-struct gsmd_atcmd {
- struct llist_head list;
- void *ctx;
- int (*cb)(struct gsmd_atcmd *cmd, void *ctx, char *resp);
- char *resp;
- int32_t ret;
- u_int32_t buflen;
- u_int16_t id;
- u_int8_t flags;
- char buf[];
-};
-
-enum llparse_state {
- LLPARSE_STATE_IDLE, /* idle, not parsing a response */
- LLPARSE_STATE_IDLE_CR, /* CR before response (V1) */
- LLPARSE_STATE_IDLE_LF, /* LF before response (V1) */
- LLPARSE_STATE_RESULT, /* within result payload */
- LLPARSE_STATE_RESULT_CR, /* CR after result */
- LLPARSE_STATE_ERROR, /* something went wrong */
- /* ... idle again */
-};
-
-/* we can't take any _single_ response bigger than this: */
-#define LLPARSE_BUF_SIZE 256
-
-struct llparser {
- enum llparse_state state;
- unsigned int len;
- unsigned int flags;
- void *ctx;
- int (*cb)(const char *buf, int len, void *ctx);
- char *cur;
- char buf[LLPARSE_BUF_SIZE];
-};
-
-#define GSMD_FLAG_V0 0x0001 /* V0 responses to be expected from TA */
-
-struct gsmd {
- unsigned int flags;
- struct gsmd_fd gfd_uart;
- struct gsmd_fd gfd_sock;
- struct llparser llp;
- struct llist_head users;
- struct llist_head pending_atcmds; /* our busy gsmd_atcmds */
- struct llist_head busy_atcmds; /* our busy gsmd_atcmds */
-};
-
-struct gsmd_user {
- struct llist_head list; /* our entry in the global list */
- struct llist_head finished_ucmds; /* our busy gsmd_ucmds */
- struct gsmd *gsmd;
- struct gsmd_fd gfd; /* the socket */
- u_int32_t subscriptions; /* bitmaks of subscribed event groups */
-};
-
-#define GSMD_DEBUG 1 /* debugging information */
-#define GSMD_INFO 3
-#define GSMD_NOTICE 5 /* abnormal/unexpected condition */
-#define GSMD_ERROR 7 /* error condition, requires user action */
-#define GSMD_FATAL 8 /* fatal, program aborted */
-
-extern int gsmdlog_init(const char *path);
-/* write a message to the daemons' logfile */
-void __gsmd_log(int level, const char *file, int line, const char *function, const char *message, ...);
-/* macro for logging including filename and line number */
-#define gsmd_log(level, format, args ...) \
- __gsmd_log(level, __FILE__, __LINE__, __FUNCTION__, format, ## args)
-
-#define DEBUGP(x, args ...) gsmd_log(GSMD_DEBUG, x, ## args)
-
-#endif /* __GSMD_H */
diff --git a/src/gsmd/log.c b/src/gsmd/log.c
index af58c6d..a601e69 100644
--- a/src/gsmd/log.c
+++ b/src/gsmd/log.c
@@ -11,6 +11,8 @@
#include "gsmd.h"
+#include <gsmd/gsmd.h>
+
static FILE *logfile;
static FILE syslog_dummy;
static int loglevel;
diff --git a/src/gsmd/select.c b/src/gsmd/select.c
index fc9647f..159b560 100644
--- a/src/gsmd/select.c
+++ b/src/gsmd/select.c
@@ -19,7 +19,10 @@
#include <fcntl.h>
#include <common/linux_list.h>
-#include "select.h"
+
+#include "gsmd.h"
+
+#include <gsmd/select.h>
static int maxfd = 0;
static LLIST_HEAD(gsmd_fds);
diff --git a/src/gsmd/unsolicited.c b/src/gsmd/unsolicited.c
index e97f478..57a4e59 100644
--- a/src/gsmd/unsolicited.c
+++ b/src/gsmd/unsolicited.c
@@ -5,14 +5,14 @@
#include <string.h>
#include <sys/types.h>
+#include "gsmd.h"
+
#include <gsmd/usock.h>
#include <gsmd/event.h>
#include <gsmd/ts0707.h>
+#include <gsmd/unsolicited.h>
-#include "gsmd.h"
-#include "usock.h"
-
-static struct gsmd_ucmd *build_event(u_int8_t type, u_int8_t subtype, u_int8_t len)
+struct gsmd_ucmd *usock_build_event(u_int8_t type, u_int8_t subtype, u_int8_t len)
{
struct gsmd_ucmd *ucmd = malloc(sizeof(*ucmd)+len);
@@ -38,7 +38,7 @@ static struct gsmd_ucmd *ucmd_copy(const struct gsmd_ucmd *orig)
return copy;
}
-static int usock_evt_send(struct gsmd *gsmd, struct gsmd_ucmd *ucmd, u_int32_t evt)
+int usock_evt_send(struct gsmd *gsmd, struct gsmd_ucmd *ucmd, u_int32_t evt)
{
struct gsmd_user *gu;
int num_sent = 0;
@@ -65,7 +65,7 @@ static int ring_parse(char *buf, int len, const char *param,
struct gsmd *gsmd)
{
/* FIXME: generate ring event */
- struct gsmd_ucmd *ucmd = build_event(GSMD_MSG_EVENT, GSMD_EVT_IN_CALL,
+ struct gsmd_ucmd *ucmd = usock_build_event(GSMD_MSG_EVENT, GSMD_EVT_IN_CALL,
sizeof(struct gsmd_evt_auxdata));
struct gsmd_evt_auxdata *aux;
if (!ucmd)
@@ -80,7 +80,7 @@ static int ring_parse(char *buf, int len, const char *param,
static int cring_parse(char *buf, int len, const char *param, struct gsmd *gsmd)
{
- struct gsmd_ucmd *ucmd = build_event(GSMD_MSG_EVENT, GSMD_EVT_IN_CALL,
+ struct gsmd_ucmd *ucmd = usock_build_event(GSMD_MSG_EVENT, GSMD_EVT_IN_CALL,
sizeof(struct gsmd_evt_auxdata));
struct gsmd_evt_auxdata *aux;
if (!ucmd)
@@ -114,7 +114,7 @@ static int creg_parse(char *buf, int len, const char *param,
struct gsmd *gsmd)
{
const char *comma = strchr(param, ',');
- struct gsmd_ucmd *ucmd = build_event(GSMD_MSG_EVENT, GSMD_EVT_NETREG,
+ struct gsmd_ucmd *ucmd = usock_build_event(GSMD_MSG_EVENT, GSMD_EVT_NETREG,
sizeof(struct gsmd_evt_auxdata));
struct gsmd_evt_auxdata *aux;
if (!ucmd)
@@ -124,11 +124,11 @@ static int creg_parse(char *buf, int len, const char *param,
aux->u.netreg.state = atoi(param);
if (comma) {
/* we also have location area code and cell id to parse (hex) */
- aux->u.netreg.lac = atoi(comma+1);
+ aux->u.netreg.lac = strtoul(comma+2, NULL, 16);
comma = strchr(comma+1, ',');
if (!comma)
return -EINVAL;
- aux->u.netreg.ci = atoi(comma+1);
+ aux->u.netreg.ci = strtoul(comma+2, NULL, 16);
}
return usock_evt_send(gsmd, ucmd, GSMD_EVT_NETREG);
@@ -140,7 +140,7 @@ static int ccwa_parse(char *buf, int len, const char *param,
{
const char *token;
unsigned int type;
- struct gsmd_ucmd *ucmd = build_event(GSMD_MSG_EVENT, GSMD_EVT_CALL_WAIT,
+ struct gsmd_ucmd *ucmd = usock_build_event(GSMD_MSG_EVENT, GSMD_EVT_CALL_WAIT,
sizeof(struct gsmd_addr));
struct gsmd_addr *gaddr;
@@ -205,7 +205,7 @@ static int cgreg_parse(char *buf, int len, const char *param,
static int clip_parse(char *buf, int len, const char *param,
struct gsmd *gsmd)
{
- struct gsmd_ucmd *ucmd = build_event(GSMD_MSG_EVENT, GSMD_EVT_IN_CLIP,
+ struct gsmd_ucmd *ucmd = usock_build_event(GSMD_MSG_EVENT, GSMD_EVT_IN_CLIP,
sizeof(struct gsmd_evt_auxdata));
struct gsmd_evt_auxdata *aux;
const char *comma = strchr(param, ',');
@@ -232,7 +232,7 @@ static int clip_parse(char *buf, int len, const char *param,
static int colp_parse(char *buf, int len, const char *param,
struct gsmd *gsmd)
{
- struct gsmd_ucmd *ucmd = build_event(GSMD_MSG_EVENT, GSMD_EVT_OUT_COLP,
+ struct gsmd_ucmd *ucmd = usock_build_event(GSMD_MSG_EVENT, GSMD_EVT_OUT_COLP,
sizeof(struct gsmd_evt_auxdata));
struct gsmd_evt_auxdata *aux;
const char *comma = strchr(param, ',');
@@ -257,7 +257,7 @@ static int colp_parse(char *buf, int len, const char *param,
static int ctzv_parse(char *buf, int len, const char *param,
struct gsmd *gsmd)
{
- struct gsmd_ucmd *ucmd = build_event(GSMD_MSG_EVENT, GSMD_EVT_TIMEZONE,
+ struct gsmd_ucmd *ucmd = usock_build_event(GSMD_MSG_EVENT, GSMD_EVT_TIMEZONE,
sizeof(struct gsmd_evt_auxdata));
struct gsmd_evt_auxdata *aux;
int tz;
@@ -278,11 +278,6 @@ static int ctzv_parse(char *buf, int len, const char *param,
return usock_evt_send(gsmd, ucmd, GSMD_EVT_TIMEZONE);
}
-struct gsmd_unsolicit {
- const char *prefix;
- int (*parse)(char *unsol, int len, const char *param, struct gsmd *gsmd);
-};
-
static const struct gsmd_unsolicit gsm0707_unsolicit[] = {
{ "RING", &ring_parse },
{ "+CRING", &cring_parse },
@@ -310,7 +305,29 @@ static const struct gsmd_unsolicit gsm0707_unsolicit[] = {
int unsolicited_parse(struct gsmd *g, char *buf, int len, const char *param)
{
int i, rc;
+ struct gsmd_vendor_plugin *vpl = g->vendorpl;
+
+ /* call vendor-specific unsolicited code parser */
+ if (vpl && vpl->num_unsolicit) {
+ for (i = 0; i < vpl->num_unsolicit; i++) {
+ const char *colon;
+ if (strncmp(buf, vpl->unsolicit[i].prefix,
+ strlen(vpl->unsolicit[i].prefix)))
+ continue;
+
+ colon = strchr(buf, ':') + 2;
+ if (colon > buf+len)
+ colon = NULL;
+
+ rc = vpl->unsolicit[i].parse(buf, len, colon, g);
+ if (rc < 0)
+ gsmd_log(GSMD_ERROR, "error %d during parse of "
+ "unsolicied response `%s'\n", rc, buf);
+ return rc;
+ }
+ }
+ /* call generic unsolicited code parser */
for (i = 0; i < ARRAY_SIZE(gsm0707_unsolicit); i++) {
const char *colon;
if (strncmp(buf, gsm0707_unsolicit[i].prefix,
@@ -328,7 +345,6 @@ int unsolicited_parse(struct gsmd *g, char *buf, int len, const char *param)
return rc;
}
- /* FIXME: call vendor-specific unsolicited code parser */
gsmd_log(GSMD_NOTICE, "no parser for unsolicited response `%s'\n", buf);
return -ENOENT;
@@ -382,7 +398,7 @@ int generate_event_from_cme(struct gsmd *g, unsigned int cme_error)
ARRAY_SIZE(errors_creating_events)))
return 0;
- gu = build_event(GSMD_MSG_EVENT, GSMD_EVT_PIN, sizeof(*eaux));
+ gu = usock_build_event(GSMD_MSG_EVENT, GSMD_EVT_PIN, sizeof(*eaux));
if (!gu)
return -1;
eaux = ((void *)gu) + sizeof(*gu);
diff --git a/src/gsmd/unsolicited.h b/src/gsmd/unsolicited.h
deleted file mode 100644
index fb99e1b..0000000
--- a/src/gsmd/unsolicited.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef __GSMD_UNSOLICITED_H
-#define __GSMD_UNSOLICITED_H
-
-#include "gsmd.h"
-
-int unsolicited_parse(struct gsmd *g, const char *buf, int len, const char *param);
-int generate_event_from_cme(struct gsmd *g, unsigned int cme_error);
-
-#endif
diff --git a/src/gsmd/usock.c b/src/gsmd/usock.c
index 76be1aa..42f8099 100644
--- a/src/gsmd/usock.c
+++ b/src/gsmd/usock.c
@@ -7,13 +7,13 @@
#include <sys/socket.h>
#include <sys/un.h>
+#include "gsmd.h"
+
#include <gsmd/gsmd.h>
#include <gsmd/usock.h>
-
-#include "gsmd.h"
-#include "select.h"
-#include "atcmd.h"
-#include "usock.h"
+#include <gsmd/select.h>
+#include <gsmd/atcmd.h>
+#include <gsmd/usock.h>
void usock_cmd_enqueue(struct gsmd_ucmd *ucmd, struct gsmd_user *gu)
{
@@ -169,16 +169,123 @@ static int usock_rcv_phone(struct gsmd_user *gu, struct gsmd_msg_hdr *gph,
return atcmd_submit(gu->gsmd, cmd);
}
+static int network_vmail_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp)
+{
+ struct gsmd_user *gu = ctx;
+ struct gsmd_voicemail *vmail;
+ struct gsmd_ucmd *ucmd = malloc(sizeof(*ucmd)+sizeof(*vmail));
+ char *comma;
+
+ DEBUGP("entering(cmd=%p, gu=%p)\n", cmd, gu);
+
+ if (!ucmd)
+ return -ENOMEM;
+
+ /* FIXME: pass error values back somehow */
+ ucmd->hdr.version = GSMD_PROTO_VERSION;
+ ucmd->hdr.msg_type = GSMD_MSG_NETWORK;
+ ucmd->hdr.len = sizeof(*vmail);
+ ucmd->hdr.id = cmd->id;
+
+ if (cmd->buf[7] == '=') {
+ /* response to set command */
+ ucmd->hdr.msg_subtype = GSMD_NETWORK_VMAIL_SET;
+ /* FIXME: */
+ return 0;
+ } else {
+ /* response to get command */
+ char *tok = strtok(resp, ",");
+ if (!tok)
+ goto out_free_einval;
+ ucmd->hdr.msg_subtype = GSMD_NETWORK_VMAIL_GET;
+ vmail->enable = atoi(tok);
+
+ tok = strtok(NULL, ",");
+ if (!tok)
+ goto out_free_einval;
+ strncpy(vmail->addr.number, tok, GSMD_ADDR_MAXLEN);
+ vmail->addr.number[GSMD_ADDR_MAXLEN] = '\0';
+
+ tok = strtok(NULL, ",");
+ if (!tok)
+ goto out_free_einval;
+ vmail->addr.type = atoi(tok);
+ }
+
+ usock_cmd_enqueue(ucmd, gu);
+
+ return 0;
+
+out_free_einval:
+ gsmd_log(GSMD_ERROR, "can't understand voicemail response\n");
+ free(ucmd);
+ return -EINVAL;
+}
+
+static struct gsmd_ucmd *gsmd_ucmd_fill(int len, u_int8_t msg_type, u_int8_t msg_subtype,
+ u_int16_t id)
+{
+ struct gsmd_ucmd *ucmd;
+
+ ucmd = malloc(sizeof(*ucmd)+len);
+ if (!ucmd)
+ return NULL;
+
+ ucmd->hdr.version = GSMD_PROTO_VERSION;
+ ucmd->hdr.msg_type = msg_type;
+ ucmd->hdr.msg_subtype = msg_subtype;
+ ucmd->hdr.len = len;
+ ucmd->hdr.id = id;
+
+ return ucmd;
+}
+
+static int network_sigq_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp)
+{
+ struct gsmd_user *gu = ctx;
+ struct gsmd_signal_quality *gsq;
+ struct gsmd_ucmd *ucmd;
+ char *comma;
+
+ ucmd = gsmd_ucmd_fill(sizeof(*gsq), GSMD_MSG_NETWORK,
+ GSMD_NETWORK_SIGQ_GET, 0);
+ if (!ucmd)
+ return -ENOMEM;
+
+ gsq = (struct gsmd_signal_quality *) ucmd->buf;
+ gsq->rssi = atoi(resp);
+ comma = strchr(resp, ',');
+ if (!comma) {
+ free(ucmd);
+ return -EIO;
+ }
+ gsq->ber = atoi(comma+1);
+
+ usock_cmd_enqueue(ucmd, gu);
+
+ return 0;
+}
+
static int usock_rcv_network(struct gsmd_user *gu, struct gsmd_msg_hdr *gph,
int len)
{
struct gsmd_atcmd *cmd;
+ struct gsmd_voicemail *vmail = (struct gsmd_voicemail *) gph->data;
switch (gph->msg_subtype) {
case GSMD_NETWORK_REGISTER:
cmd = atcmd_fill("AT+COPS", 9+1,
&null_cmd_cb, gu, 0);
break;
+ case GSMD_NETWORK_VMAIL_GET:
+ cmd = atcmd_fill("AT+CSVM?", 8+1, &network_vmail_cb, gu, 0);
+ break;
+ case GSMD_NETWORK_VMAIL_SET:
+ cmd = atcmd_fill("AT+CSVM=", 8+1, &network_vmail_cb, gu, 0);
+ break;
+ case GSMD_NETWORK_SIGQ_GET:
+ cmd = atcmd_fill("AT+CSQ", 6+1, &network_sigq_cb, gu, 0);
+ break;
default:
return -EINVAL;
}
diff --git a/src/gsmd/usock.h b/src/gsmd/usock.h
deleted file mode 100644
index efa0f34..0000000
--- a/src/gsmd/usock.h
+++ /dev/null
@@ -1,16 +0,0 @@
-#ifndef __GSMD_USOCK_H
-#define __GSMD_USOCK_H
-
-#include <gsmd/usock.h>
-
-struct gsmd_ucmd {
- struct llist_head list;
- struct gsmd_msg_hdr hdr;
- char buf[];
-} __attribute__ ((packed));
-
-extern int usock_init(struct gsmd *g);
-extern void usock_cmd_enqueue(struct gsmd_ucmd *ucmd, struct gsmd_user *gu);
-
-#endif
-
diff --git a/src/gsmd/vendor.c b/src/gsmd/vendor.c
new file mode 100644
index 0000000..d577e98
--- /dev/null
+++ b/src/gsmd/vendor.c
@@ -0,0 +1,39 @@
+#include <errno.h>
+
+#include <common/linux_list.h>
+
+#include "gsmd.h"
+
+#include <gsmd/gsmd.h>
+#include <gsmd/vendorplugin.h>
+
+static LLIST_HEAD(vendorpl_list);
+
+int gsmd_vendor_plugin_register(struct gsmd_vendor_plugin *pl)
+{
+ llist_add(&pl->list, &vendorpl_list);
+
+ return 0;
+}
+
+void gsmd_vendor_plugin_unregister(struct gsmd_vendor_plugin *pl)
+{
+ llist_del(&pl->list);
+}
+
+int gsmd_vendor_plugin_find(struct gsmd *g)
+{
+ struct gsmd_vendor_plugin *pl;
+
+ if (g->vendorpl)
+ return -EEXIST;
+
+ llist_for_each_entry(pl, &vendorpl_list, list) {
+ if (pl->detect(g) == 1) {
+ g->vendorpl = pl;
+ return 1;
+ }
+ }
+
+ return 0;
+}
diff --git a/src/gsmd/vendor_ti.c b/src/gsmd/vendor_ti.c
index ac67b92..53ca7ed 100644
--- a/src/gsmd/vendor_ti.c
+++ b/src/gsmd/vendor_ti.c
@@ -5,6 +5,15 @@
#include <string.h>
#include <errno.h>
+#include "gsmd.h"
+
+#include <gsmd/gsmd.h>
+#include <gsmd/usock.h>
+#include <gsmd/event.h>
+#include <gsmd/vendorplugin.h>
+#include <gsmd/unsolicited.h>
+
+#if 0
#include "vendorplugin.h"
static int
@@ -31,8 +40,60 @@ ti_setopt(struct gsmd *gh, int optname, const void *optval, int optlen)
}
}
-static int ti_parseunsolicit(struct gsmd *gh)
+#endif
+
+
+static int csq_parse(char *buf, int len, char *param,
+ struct gsmd *gsmd)
+{
+ char *tok;
+ struct gsmd_evt_auxdata *aux;
+ struct gsmd_ucmd *ucmd = usock_build_event(GSMD_MSG_EVENT, GSMD_EVT_SIGNAL,
+ sizeof(*aux));
+
+ DEBUGP("entering csq_parse param=`%s'\n", param);
+ if (!ucmd)
+ return -EINVAL;
+
+
+ aux = (struct gsmd_evt_auxdata *) ucmd->buf;
+ tok = strtok(param, ",");
+ if (!tok)
+ goto out_free_io;
+
+ aux->u.signal.sigq.rssi = atoi(tok);
+
+ tok = strtok(NULL, ",");
+ if (!tok)
+ goto out_free_io;
+
+ aux->u.signal.sigq.ber = atoi(tok);
+
+ DEBUGP("sending EVT_SIGNAL\n");
+ usock_evt_send(gsmd, ucmd, GSMD_EVT_SIGNAL);
+
+ return 0;
+
+out_free_io:
+ free(ucmd);
+ return -EIO;
+}
+
+static int cpri_parse(char *buf, int len, const char *param, struct gsmd *gsmd)
+{
+
+}
+
+static int cpi_parse(char *buf, int len, const char *param, struct gsmd *gsmd)
{
+
+}
+
+static const struct gsmd_unsolicit ticalypso_unsolicit[] = {
+ { "\%CSQ", &csq_parse }, /* Signal Quality */
+ { "\%CPRI", &cpri_parse }, /* Ciphering Indication */
+ { "\%CPI", &cpi_parse }, /* Call Progress Information */
+
/* FIXME: parse all the below and generate the respective events */
/* %CPROAM: CPHS Home Country Roaming Indicator */
@@ -43,11 +104,29 @@ static int ti_parseunsolicit(struct gsmd *gh)
/* %CPKY: Press Key */
/* %CMGRS: Message Retransmission Service */
/* %CGEV: reports GPRS network events */
- return -EINVAL;
+};
+
+static int ticalypso_detect(struct gsmd *g)
+{
+ /* FIXME: do actual detection of vendor if we have multiple vendors */
+ return 1;
}
-struct gsmd_vendorspecific ti_vendorspec = {
- .getopt = &ti_getopt,
- .setopt = &ti_setopt,
- .parse_unsolicit = &ti_parseunsolicit,
+static int ticalypso_initsettings(struct gsmd *g)
+{
+ return gsmd_simplecmd(g, "AT\%CPI=3;\%CPRI=1;\%CSQ=1");
+}
+
+static struct gsmd_vendor_plugin plugin_ticalypso = {
+ .name = "TI Calypso",
+ .num_unsolicit = ARRAY_SIZE(ticalypso_unsolicit),
+ .unsolicit = &ticalypso_unsolicit,
+ .detect = &ticalypso_detect,
+ .initsettings = &ticalypso_initsettings,
};
+
+/* FIXME: this will be _init() when we make this a plugin */
+int ticalypso_init(void)
+{
+ return gsmd_vendor_plugin_register(&plugin_ticalypso);
+}
diff --git a/src/gsmd/vendorplugin.h b/src/gsmd/vendorplugin.h
index b8be9ba..62546ba 100644
--- a/src/gsmd/vendorplugin.h
+++ b/src/gsmd/vendorplugin.h
@@ -1,6 +1,8 @@
#ifndef __GSMD_VENDORPLUG_H
#define __GSMD_VENDORPLUG_H
+#ifdef __GSMD__
+
#include "gsmd.h"
/* gsmd vendor-specific plugin */
@@ -26,4 +28,6 @@ struct gsmd_vendorspecific {
/* ciphering indications */
+#endif /* __GSMD__ */
+
#endif
diff --git a/src/libgsmd/libgsmd.c b/src/libgsmd/libgsmd.c
index 7f936e8..8dde4b6 100644
--- a/src/libgsmd/libgsmd.c
+++ b/src/libgsmd/libgsmd.c
@@ -82,9 +82,11 @@ int lgsm_handle_packet(struct lgsm_handle *lh, char *buf, int len)
handler = lh->handler[gmh->msg_type];
if (handler)
- handler(lh, gmh);
- else
+ return handler(lh, gmh);
+ else {
fprintf(stderr, "unable to handle packet type=%u\n", gmh->msg_type);
+ return 0;
+ }
}
int lgsm_register_handler(struct lgsm_handle *lh, int type, lgsm_msg_handler *handler)
diff --git a/src/libgsmd/libgsmd_network.c b/src/libgsmd/libgsmd_network.c
index ae104b8..73bc895 100644
--- a/src/libgsmd/libgsmd_network.c
+++ b/src/libgsmd/libgsmd_network.c
@@ -16,3 +16,7 @@ int lgsm_netreg_register(struct lgsm_handle *lh, int oper)
return lgsm_send_simple(lh, GSMD_MSG_NETWORK, GSMD_NETWORK_REGISTER);
}
+int lgsm_signal_quality(struct lgsm_handle *lh)
+{
+ return lgsm_send_simple(lh, GSMD_MSG_NETWORK, GSMD_NETWORK_SIGQ_GET);
+}
diff --git a/src/util/atcmd.c b/src/util/atcmd.c
index 6cf9aa7..61f7032 100644
--- a/src/util/atcmd.c
+++ b/src/util/atcmd.c
@@ -44,6 +44,8 @@ int atcmd_main(struct lgsm_handle *lgsmh)
break;
}
rc = lgsm_handle_packet(lgsmh, buf, rc);
+ if (rc < 0)
+ printf("ERROR processing packet: %d(%s)\n", rc, strerror(rc));
}
if (FD_ISSET(0, &readset)) {
/* we've received something on stdin. send it as passthrough
diff --git a/src/util/event.c b/src/util/event.c
index 0f09d47..bff895d 100644
--- a/src/util/event.c
+++ b/src/util/event.c
@@ -6,14 +6,14 @@
static int incall_handler(struct lgsm_handle *lh, int evt, struct gsmd_evt_auxdata *aux)
{
- printf("EVENT: Incoming call type=%u!\n", aux->u.call.type);
+ printf("EVENT: Incoming call type = %u\n", aux->u.call.type);
return 0;
}
static int clip_handler(struct lgsm_handle *lh, int evt, struct gsmd_evt_auxdata *aux)
{
- printf("EVENT: Incoming call clip=`%s'\n", aux->u.clip.addr.number);
+ printf("EVENT: Incoming call clip = %s\n", aux->u.clip.addr.number);
return 0;
}
@@ -41,15 +41,21 @@ static int netreg_handler(struct lgsm_handle *lh, int evt, struct gsmd_evt_auxda
}
if (aux->u.netreg.lac)
- printf("LocationAreaCode=0x%04X ", aux->u.netreg.lac);
+ printf("LocationAreaCode = 0x%04X ", aux->u.netreg.lac);
if (aux->u.netreg.ci)
- printf("CellID=0x%04X ", aux->u.netreg.ci);
+ printf("CellID = 0x%04X ", aux->u.netreg.ci);
printf("\n");
return 0;
}
+static int sigq_handler(struct lgsm_handle *lh, int evt, struct gsmd_evt_auxdata *aux)
+{
+ printf("EVENT: Signal Quality: %u\n", aux->u.signal.sigq.rssi);
+ return 0;
+}
+
int event_init(struct lgsm_handle *lh)
{
int rc;
@@ -57,6 +63,7 @@ int event_init(struct lgsm_handle *lh)
rc = lgsm_evt_handler_register(lh, GSMD_EVT_IN_CALL, &incall_handler);
rc |= lgsm_evt_handler_register(lh, GSMD_EVT_IN_CLIP, &clip_handler);
rc |= lgsm_evt_handler_register(lh, GSMD_EVT_NETREG, &netreg_handler);
+ rc |= lgsm_evt_handler_register(lh, GSMD_EVT_SIGNAL, &sigq_handler);
return rc;
}
personal git repositories of Harald Welte. Your mileage may vary