From be174b78167bf9f2b77901b4b318606144a5ae58 Mon Sep 17 00:00:00 2001 From: laforge Date: Fri, 17 Aug 2007 08:31:21 +0000 Subject: From: Andrzej Zaborowski Date: Fri, 27 Jul 2007 19:39:15 +0200 Subject: [PATCH] Cell Broadcast message decoding and presentation in libgsmd-tool. This time Cell Broadcast is tested to work, I should have made tests earlier. Now I'm correctly getting a CB message with the human readable name of the city and district when I'm connecting. In the previous patches the CB PDU was not being decoded at all. git-svn-id: http://svn.openmoko.org/trunk/src/target/gsm@2723 99fdad57-331a-0410-800a-d7fa5415bdb3 --- include/gsmd/sms.h | 5 ++- include/gsmd/usock.h | 42 +++++++++++++++++++ include/libgsmd/sms.h | 1 + src/gsmd/sms_cb.c | 42 ++++++++----------- src/gsmd/sms_pdu.c | 29 ++++++++++++-- src/libgsmd/libgsmd_sms.c | 14 +++++++ src/util/event.c | 100 +++++++++++++++++++++++++++++++++++++++++++++- 7 files changed, 202 insertions(+), 31 deletions(-) diff --git a/include/gsmd/sms.h b/include/gsmd/sms.h index b48ce5d..c5ee0d8 100644 --- a/include/gsmd/sms.h +++ b/include/gsmd/sms.h @@ -8,10 +8,13 @@ int sms_cb_init(struct gsmd *gsmd); int sms_cb_network_init(struct gsmd *gsmd); -#define MAX_PDU_SIZE 180 +#define SMS_MAX_PDU_SIZE 180 +#define CBM_MAX_PDU_SIZE 88 +#define CBM_MAX_PDU_PAGES 15 int sms_pdu_make_smssubmit(char *dest, const struct gsmd_sms_submit *src); int sms_pdu_to_msg(struct gsmd_sms_list *dst, const u_int8_t *src, int pdulen, int len); +int cbs_pdu_to_msg(struct gsmd_cbm *dst, u_int8_t *src, int pdulen, int len); int usock_rcv_sms(struct gsmd_user *gu, struct gsmd_msg_hdr *gph, int len); int usock_rcv_cb(struct gsmd_user *gu, struct gsmd_msg_hdr *gph, int len); diff --git a/include/gsmd/usock.h b/include/gsmd/usock.h index 18ffa5e..ce5c25e 100644 --- a/include/gsmd/usock.h +++ b/include/gsmd/usock.h @@ -365,6 +365,48 @@ struct gsmd_sms_storage { struct __gsmd_sms_storage mem[3]; } __attribute__ ((packed)); +/* Refer to GSM 03.41 subclause 9.3.1 - note: this indicates display mode too */ +enum gsmd_geographical_scope { + GSMD_SCOPE_CELL_WIDE_OPER = 0, + GSMD_SCOPE_PLMN_WIDE, + GSMD_SCOPE_LOC_AREA_WIDE, + GSMD_SCOPE_CELL_WIDE, +}; + +enum gsmd_language { + GSMD_LANG_GERMAN = 0, + GSMD_LANG_ENGLISH, + GSMD_LANG_ITALIAN, + GSMD_LANG_FRENCH, + GSMD_LANG_SPANISH, + GSMD_LANG_DUTCH, + GSMD_LANG_SWEDISH, + GSMD_LANG_DANISH, + GSMD_LANG_PORTUGUESE, + GSMD_LANG_FINNISH, + GSMD_LANG_NORWEGIAN, + GSMD_LANG_GREEK, + GSMD_LANG_TURKISH, + GSMD_LANG_HUNGARIAN, + GSMD_LANG_POLISH, + GSMD_LANG_UNSPECIFIED, +}; + +/* Refer to GSM 03.41 subclause 9.3 */ +struct gsmd_cbm { + struct { + enum gsmd_geographical_scope scope; + int msg_code; + int update_num; + } serial; + u_int16_t msg_id; + enum gsmd_language language; + u_int8_t coding_scheme; + int pages; + int page; + u_int8_t data[82]; +}; + /* Refer to GSM 07.07 subclause 8.12 */ struct gsmd_phonebook_readrg { u_int8_t index1; diff --git a/include/libgsmd/sms.h b/include/libgsmd/sms.h index 69363e7..3ada62d 100644 --- a/include/libgsmd/sms.h +++ b/include/libgsmd/sms.h @@ -90,6 +90,7 @@ extern int packing_7bit_character(const char *src, struct lgsm_sms *dest); /* Packing of 7-bit characters, refer to GSM 03.38 subclause 6.1.2.1.1 */ extern int unpacking_7bit_character(const struct gsmd_sms *src, char *dest); +extern int cbm_unpacking_7bit_character(const char *src, char *dest); /* Refer to 3GPP TS 11.11 Annex B */ extern int packing_UCS2_80(char *src, char *dest); diff --git a/src/gsmd/sms_cb.c b/src/gsmd/sms_cb.c index 1ae337e..0ffe563 100644 --- a/src/gsmd/sms_cb.c +++ b/src/gsmd/sms_cb.c @@ -67,7 +67,7 @@ static int sms_list_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp) struct gsmd_ucmd *ucmd; struct gsmd_sms_list msg; int i, idx, stat, len, cr; - u_int8_t pdu[MAX_PDU_SIZE]; + u_int8_t pdu[SMS_MAX_PDU_SIZE]; if (cmd->ret && cmd->ret != -255) return 0; @@ -86,7 +86,7 @@ static int sms_list_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp) msg.stat = stat; msg.is_last = (cmd->ret == 0); for (i = 0; resp[cr] >= '0' && resp[cr + 1] >= '0' && - i < MAX_PDU_SIZE; i ++) { + i < SMS_MAX_PDU_SIZE; i ++) { if (sscanf(resp + cr, "%2hhX", &pdu[i]) < 1) { gsmd_log(GSMD_DEBUG, "malformed input (%i)\n", i); return -EINVAL; @@ -115,7 +115,7 @@ static int sms_read_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp) struct gsmd_ucmd *ucmd; struct gsmd_sms_list msg; int i, stat, len, cr; - u_int8_t pdu[MAX_PDU_SIZE]; + u_int8_t pdu[SMS_MAX_PDU_SIZE]; if (cmd->ret) return 0; @@ -134,7 +134,7 @@ static int sms_read_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp) msg.stat = stat; msg.is_last = 1; for (i = 0; resp[cr] >= '0' && resp[cr + 1] >= '0' && - i < MAX_PDU_SIZE; i ++) { + i < SMS_MAX_PDU_SIZE; i ++) { if (sscanf(resp + cr, "%2hhX", &pdu[i]) < 1) { gsmd_log(GSMD_DEBUG, "malformed input (%i)\n", i); return -EINVAL; @@ -475,7 +475,7 @@ static int cmti_parse(char *buf, int len, const char *param, struct gsmd *gsmd) static int cmt_parse(char *buf, int len, const char *param, struct gsmd *gsmd) { /* TODO: TEXT mode */ - u_int8_t pdu[MAX_PDU_SIZE]; + u_int8_t pdu[SMS_MAX_PDU_SIZE]; const char *comma = strchr(param, ','); char *cr; int i; @@ -502,7 +502,8 @@ static int cmt_parse(char *buf, int len, const char *param, struct gsmd *gsmd) } cr ++; - for (i = 0; cr[0] >= '0' && cr[1] >= '0' && i < MAX_PDU_SIZE; i ++) { + for (i = 0; cr[0] >= '0' && cr[1] >= '0' && i < SMS_MAX_PDU_SIZE; + i ++) { if (sscanf(cr, "%2hhX", &pdu[i]) < 1) { gsmd_log(GSMD_DEBUG, "malformed input (%i)\n", i); talloc_free(ucmd); @@ -531,11 +532,6 @@ static int cbmi_parse(char *buf, int len, const char *param, struct gsmd *gsmd) if (!ucmd) return -ENOMEM; - ucmd->hdr.version = GSMD_PROTO_VERSION; - ucmd->hdr.msg_type = GSMD_MSG_EVENT; - ucmd->hdr.msg_subtype = GSMD_EVT_IN_CBM; - ucmd->hdr.len = sizeof(*aux); - aux = (struct gsmd_evt_auxdata *) ucmd->buf; if (sscanf(param, "\"%2[A-Z]\",%i", memstr, &aux->u.cbm.index) < 2) { talloc_free(ucmd); @@ -551,20 +547,20 @@ static int cbmi_parse(char *buf, int len, const char *param, struct gsmd *gsmd) static int cbm_parse(char *buf, int len, const char *param, struct gsmd *gsmd) { /* TODO: TEXT mode */ - u_int8_t pdu[MAX_PDU_SIZE]; + u_int8_t pdu[CBM_MAX_PDU_SIZE]; char *cr; int i; struct gsmd_evt_auxdata *aux; - struct gsmd_sms_list *msg; + struct gsmd_cbm *msg; struct gsmd_ucmd *ucmd = usock_build_event(GSMD_MSG_EVENT, GSMD_EVT_IN_CBM, sizeof(struct gsmd_evt_auxdata) + - sizeof(struct gsmd_sms_list)); + sizeof(struct gsmd_cbm)); if (!ucmd) return -ENOMEM; aux = (struct gsmd_evt_auxdata *) ucmd->buf; - msg = (struct gsmd_sms_list *) aux->data; + msg = (struct gsmd_cbm *) aux->data; len = strtoul(param, &cr, 10); if (cr[0] != '\n') { @@ -573,7 +569,8 @@ static int cbm_parse(char *buf, int len, const char *param, struct gsmd *gsmd) } cr ++; - for (i = 0; cr[0] >= '0' && cr[1] >= '0' && i < MAX_PDU_SIZE; i ++) { + for (i = 0; cr[0] >= '0' && cr[1] >= '0' && i < CBM_MAX_PDU_SIZE; + i ++) { if (sscanf(cr, "%2hhX", &pdu[i]) < 1) { gsmd_log(GSMD_DEBUG, "malformed input (%i)\n", i); talloc_free(ucmd); @@ -583,7 +580,7 @@ static int cbm_parse(char *buf, int len, const char *param, struct gsmd *gsmd) } aux->u.cbm.inlined = 1; - if (sms_pdu_to_msg(msg, pdu, len, i)) { + if (cbs_pdu_to_msg(msg, pdu, len, i)) { gsmd_log(GSMD_DEBUG, "malformed PDU\n"); talloc_free(ucmd); return -EINVAL; @@ -617,7 +614,7 @@ static int cdsi_parse(char *buf, int len, const char *param, struct gsmd *gsmd) static int cds_parse(char *buf, int len, const char *param, struct gsmd *gsmd) { /* TODO: TEXT mode */ - u_int8_t pdu[MAX_PDU_SIZE]; + u_int8_t pdu[SMS_MAX_PDU_SIZE]; char *cr; int i; struct gsmd_evt_auxdata *aux; @@ -639,7 +636,8 @@ static int cds_parse(char *buf, int len, const char *param, struct gsmd *gsmd) } cr ++; - for (i = 0; cr[0] >= '0' && cr[1] >= '0' && i < MAX_PDU_SIZE; i ++) { + for (i = 0; cr[0] >= '0' && cr[1] >= '0' && i < SMS_MAX_PDU_SIZE; + i ++) { if (sscanf(cr, "%2hhX", &pdu[i]) < 1) { gsmd_log(GSMD_DEBUG, "malformed input (%i)\n", i); talloc_free(ucmd); @@ -714,11 +712,5 @@ int sms_cb_network_init(struct gsmd *gsmd) */ ret |= gsmd_simplecmd(gsmd, "AT+CNMI=2,1,2,1,0"); - /* Store into ME/TA and notify */ - ret |= gsmd_simplecmd(gsmd, "AT+CSBS=1"); - - /* Store into ME/TA and notify */ - ret |= gsmd_simplecmd(gsmd, "AT+CSDS=2"); - return ret; } diff --git a/src/gsmd/sms_pdu.c b/src/gsmd/sms_pdu.c index c9b9327..665fdcb 100644 --- a/src/gsmd/sms_pdu.c +++ b/src/gsmd/sms_pdu.c @@ -26,6 +26,7 @@ #include #include +#include static int sms_number_bytelen(u_int8_t type, u_int8_t len) { @@ -50,7 +51,7 @@ static int sms_data_bytelen(u_int8_t data_coding_scheme, u_int8_t len) return 0; } -static int sms_address2ascii(struct gsmd_addr *dst, u_int8_t *src) +static int sms_address2ascii(struct gsmd_addr *dst, const u_int8_t *src) { int i; @@ -80,7 +81,7 @@ static int sms_address2ascii(struct gsmd_addr *dst, u_int8_t *src) } int sms_pdu_to_msg(struct gsmd_sms_list *dst, - u_int8_t *src, int pdulen, int len) + const u_int8_t *src, int pdulen, int len) { int i, vpf; if (len < 1 || len < 1 + src[0] + pdulen || pdulen < 1) @@ -200,7 +201,7 @@ int sms_pdu_to_msg(struct gsmd_sms_list *dst, } /* Refer to GSM 03.40 subclause 9.2.3.3, for SMS-SUBMIT */ -int sms_pdu_make_smssubmit(char *dest, struct gsmd_sms_submit *src) +int sms_pdu_make_smssubmit(char *dest, const struct gsmd_sms_submit *src) { /* FIXME: ALPHANUMERIC encoded addresses can be longer than 13B */ u_int8_t header[15 + GSMD_ADDR_MAXLEN]; @@ -259,3 +260,25 @@ int sms_pdu_make_smssubmit(char *dest, struct gsmd_sms_submit *src) return pos + len; } + +/* Refer to GSM 03.41 subclause 9.3 */ +int cbs_pdu_to_msg(struct gsmd_cbm *dst, u_int8_t *src, int pdulen, int len) +{ + if (len != pdulen || len != CBM_MAX_PDU_SIZE) + return 1; + + dst->serial.scope = (src[0] >> 6) & 3; + dst->serial.msg_code = ((src[0] << 4) | (src[1] >> 4)) & 0x3ff; + dst->serial.update_num = src[1] & 0xf; + + dst->msg_id = (src[2] << 8) | src[3]; + + dst->language = src[4] & 0xf; + dst->coding_scheme = ((src[4] >> 4) & 3) << 2; + + dst->pages = src[5] & 0xf; + dst->page = src[5] >> 4; + + memcpy(dst->data, src + 6, len - 6); + return 0; +} diff --git a/src/libgsmd/libgsmd_sms.c b/src/libgsmd/libgsmd_sms.c index 72723c0..22d7dbf 100644 --- a/src/libgsmd/libgsmd_sms.c +++ b/src/libgsmd/libgsmd_sms.c @@ -283,6 +283,20 @@ int unpacking_7bit_character(const struct gsmd_sms *src, char *dest) return i; } +int cbm_unpacking_7bit_character(const char *src, char *dest) +{ + int i; + u_int8_t ch = 1; + + for (i = 0; i < 93 && ch; i ++) + *(dest ++) = ch = + ((src[(i * 7 + 7) >> 3] << (7 - ((i * 7 + 7) & 7))) | + (src[(i * 7) >> 3] >> ((i * 7) & 7))) & 0x7f; + *dest = '\0'; + + return i; +} + /* Refer to 3GPP TS 11.11 Annex B */ int packing_UCS2_80(char *src, char *dest) { diff --git a/src/util/event.c b/src/util/event.c index f98c7da..a206bbc 100644 --- a/src/util/event.c +++ b/src/util/event.c @@ -34,10 +34,104 @@ static int incall_handler(struct lgsm_handle *lh, int evt, struct gsmd_evt_auxda return 0; } -static int insms_handler(struct lgsm_handle *lh, int evt, struct gsmd_evt_auxdata *aux) +static int insms_handler(struct lgsm_handle *lh, int evt, + struct gsmd_evt_auxdata *aux) { - printf("EVENT: Incoming SMS stored at location %i\n", aux->u.sms.index); + struct gsmd_sms_list *sms; + char payload[GSMD_SMS_DATA_MAXLEN]; + if (aux->u.sms.inlined) { + sms = (struct gsmd_sms_list *) aux->data; + printf("EVENT: Incoming SMS from/to %s%s, at %i%i-%i%i-%i%i " + "%i%i:%i%i:%i%i, GMT%c%i\n", + ((sms->addr.type & __GSMD_TOA_TON_MASK) == + GSMD_TOA_TON_INTERNATIONAL) ? "+" : "", + sms->addr.number, + sms->time_stamp[0] & 0xf, + sms->time_stamp[0] >> 4, + sms->time_stamp[1] & 0xf, + sms->time_stamp[1] >> 4, + sms->time_stamp[2] & 0xf, + sms->time_stamp[2] >> 4, + sms->time_stamp[3] & 0xf, + sms->time_stamp[3] >> 4, + sms->time_stamp[4] & 0xf, + sms->time_stamp[4] >> 4, + sms->time_stamp[5] & 0xf, + sms->time_stamp[5] >> 4, + (sms->time_stamp[6] & 8) ? '-' : '+', + (((sms->time_stamp[6] << 4) | + (sms->time_stamp[6] >> 4)) & 0x3f) >> 2); + if (sms->payload.coding_scheme == ALPHABET_DEFAULT) { + unpacking_7bit_character(&sms->payload, payload); + printf("\"%s\"\n", payload); + } else if (sms->payload.coding_scheme == ALPHABET_8BIT) + printf("8-bit encoded data\n"); + else if (sms->payload.coding_scheme == ALPHABET_UCS2) + printf("Unicode-16 encoded text\n"); + } else + printf("EVENT: Incoming SMS stored at location %i\n", + aux->u.sms.index); + return 0; +} + +static int incbm_handler(struct lgsm_handle *lh, int evt, + struct gsmd_evt_auxdata *aux) +{ + struct gsmd_cbm *msg; + char payload[95]; + static const char *scope_name[] = { + [GSMD_SCOPE_CELL_WIDE_OPER] = "immediate-display cell", + [GSMD_SCOPE_PLMN_WIDE] = "PLMN", + [GSMD_SCOPE_LOC_AREA_WIDE] = "Location Area", + [GSMD_SCOPE_CELL_WIDE] = "cell", + }; + static const char *lang_name[] = { + [GSMD_LANG_GERMAN] = "German", + [GSMD_LANG_ENGLISH] = "English", + [GSMD_LANG_ITALIAN] = "Italian", + [GSMD_LANG_FRENCH] = "French", + [GSMD_LANG_SPANISH] = "Spanish", + [GSMD_LANG_DUTCH] = "Dutch", + [GSMD_LANG_SWEDISH] = "Swedish", + [GSMD_LANG_DANISH] = "Danish", + [GSMD_LANG_PORTUGUESE] = "Portuguese", + [GSMD_LANG_FINNISH] = "Finnish", + [GSMD_LANG_NORWEGIAN] = "Norwegian", + [GSMD_LANG_GREEK] = "Greek", + [GSMD_LANG_TURKISH] = "Turkish", + [GSMD_LANG_HUNGARIAN] = "Hungarian", + [GSMD_LANG_POLISH] = "Polish", + [GSMD_LANG_UNSPECIFIED] = "an unspecified language", + }; + if (aux->u.cbm.inlined) { + msg = (struct gsmd_cbm *) aux->data; + printf("EVENT: Incoming %s-wide Cell Broadcast message in " + "%s (page %i of %i)\n", + scope_name[msg->serial.scope], + lang_name[msg->language], + msg->page, msg->pages); + + if (msg->coding_scheme == ALPHABET_DEFAULT) { + cbm_unpacking_7bit_character(msg->data, payload); + printf("\"%s\"\n", payload); + } else if (msg->coding_scheme == ALPHABET_8BIT) + printf("8-bit encoded data\n"); + else if (msg->coding_scheme == ALPHABET_UCS2) + printf("Unicode-16 encoded text\n"); + } else + printf("EVENT: Incoming Cell Broadcast message stored at " + "location %i\n", aux->u.cbm.index); + return 0; +} +static int inds_handler(struct lgsm_handle *lh, int evt, + struct gsmd_evt_auxdata *aux) +{ + if (aux->u.ds.inlined) + printf("EVENT: Incoming Status Report\n"); + else + printf("EVENT: Incoming Status Report stored at location %i\n", + aux->u.ds.index); return 0; } @@ -139,6 +233,8 @@ 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_IN_SMS, &insms_handler); + rc |= lgsm_evt_handler_register(lh, GSMD_EVT_IN_CBM, &incbm_handler); + rc |= lgsm_evt_handler_register(lh, GSMD_EVT_IN_DS, &inds_handler); rc |= lgsm_evt_handler_register(lh, GSMD_EVT_OUT_COLP, &colp_handler); rc |= lgsm_evt_handler_register(lh, GSMD_EVT_NETREG, &netreg_handler); rc |= lgsm_evt_handler_register(lh, GSMD_EVT_SIGNAL, &sigq_handler); -- cgit v1.2.3