summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrandon Bayer <bbayer@multitech.com>2015-10-26 14:58:43 -0500
committerBrandon Bayer <bbayer@multitech.com>2015-11-06 13:49:06 -0600
commitbe01eb8a87f1582b1c15ec4e09a9a66770da87c5 (patch)
treed2044a650d334dca4aa2efb2521e3ecf887ac86b
parentab80a82e2e0f5ea7cdef0394f80e69b377fab779 (diff)
downloadsms-utils-be01eb8a87f1582b1c15ec4e09a9a66770da87c5.tar.gz
sms-utils-be01eb8a87f1582b1c15ec4e09a9a66770da87c5.tar.bz2
sms-utils-be01eb8a87f1582b1c15ec4e09a9a66770da87c5.zip
feat: sms support for CE910-DUAL, DE910-DUAL, LE910-SVG0.0.8
- PDU is used for everything except LE910-SVG sending - a bug in radio requires radio reboot to send more than 1 PDU sms
-rw-r--r--src/atcmd.c177
-rw-r--r--src/atcmd.h12
-rw-r--r--src/global.h1
-rw-r--r--src/pdu.h16
-rw-r--r--src/pdu_decode.c156
-rw-r--r--src/pdu_decode.h4
-rw-r--r--src/pdu_encode.c125
-rw-r--r--src/pdu_encode.h3
-rw-r--r--src/sms_list.c9
-rw-r--r--src/sms_main.c1
-rw-r--r--src/sms_send.c44
11 files changed, 500 insertions, 48 deletions
diff --git a/src/atcmd.c b/src/atcmd.c
index aad15e9..578554f 100644
--- a/src/atcmd.c
+++ b/src/atcmd.c
@@ -674,6 +674,51 @@ int atcmd_plus_cmgw_write(int fd, const char *msg, size_t msg_len)
return mem_index;
}
+int atcmd_plus_cmgw_write_text(int fd, const char *addr, int addr_type,
+ const char *status, const char *msg, size_t msg_len)
+{
+ char buf[ATCMD_LINE_SIZE];
+ int tmp;
+ int mem_index;
+
+ atcmd_printf(fd, "AT+CMGW");
+ if (addr) {
+ atcmd_printf(fd, "=\"%s\"", addr);
+ if (addr_type != SMS_ADDR_UNSPEC) {
+ atcmd_printf(fd, ",%d", addr_type);
+ if (status) {
+ atcmd_printf(fd, ",\"%s\"", status);
+ }
+ }
+ }
+ atcmd_write_str(fd, ATCMD_EOL);
+
+ tmp = atcmd_read_until(fd, buf, sizeof(buf), "> ");
+ if (tmp <= 0) {
+ log_debug("expected > start sequence but it was not received");
+ return -1;
+ }
+
+ tmp = atcmd_write(fd, msg, strlen(msg));
+ tmp = atcmd_write_str(fd, CONTROL_Z_STR);
+
+ tmp = atcmd_expect_line(fd, buf, sizeof(buf), "+CMGW: ");
+ if (tmp <= 0) {
+ log_debug("expected +CMGW: but it was not received");
+ return -1;
+ }
+
+ mem_index = atoi(buf + strlen("+CMGW: "));
+
+ tmp = atcmd_expect_line(fd, buf, sizeof(buf), "OK");
+ if (tmp <= 0) {
+ log_debug("expected OK but it was not received");
+ return -1;
+ }
+
+ return mem_index;
+}
+
int atcmd_plus_cmgs_write(int fd, const char *msg, size_t msg_len)
{
char buf[ATCMD_LINE_SIZE];
@@ -706,6 +751,38 @@ int atcmd_plus_cmgs_write(int fd, const char *msg, size_t msg_len)
return msg_ref;
}
+int atcmd_plus_cmgs_write_text(int fd, const char *addr, const char *msg, size_t msg_len)
+{
+ char buf[ATCMD_LINE_SIZE];
+ int tmp;
+ int msg_ref;
+
+ atcmd_writeline(fd, "AT+CMGS=\"%s\"", addr);
+ tmp = atcmd_read_until(fd, buf, sizeof(buf), "> ");
+ if (tmp <= 0) {
+ log_debug("expected > start sequence but it was not received");
+ return -1;
+ }
+
+ tmp = atcmd_write(fd, msg, strlen(msg));
+ tmp = atcmd_write_str(fd, CONTROL_Z_STR);
+
+ tmp = atcmd_expect_line(fd, buf, sizeof(buf), "+CMGS: ");
+ if (tmp <= 0) {
+ log_debug("expected +CMGS: but it was not received");
+ return -1;
+ }
+ msg_ref = atoi(buf + strlen("+CMGS: "));
+
+ tmp = atcmd_expect_line(fd, buf, sizeof(buf), "OK");
+ if (tmp <= 0) {
+ log_debug("expected OK but it was not received");
+ return -1;
+ }
+
+ return msg_ref;
+}
+
int atcmd_plus_cmss_write(int fd, int index, const char *addr, int addr_type)
{
char buf[ATCMD_LINE_SIZE];
@@ -774,16 +851,24 @@ int atcmd_response_foreach_line(int fd, atcmd_response_callback_t call, void *pr
}
int atcmd_plus_cpms_read(int fd, struct data_store *read_store,
- struct data_store *send_store, struct data_store *new_store)
+ struct data_store *send_store, struct data_store *new_store, const char *model)
{
char buf[ATCMD_LINE_SIZE];
char *save;
char *token;
int tmp;
int i;
+ int data_stores_size;
- struct data_store *data_stores[] = {read_store, send_store, new_store};
struct data_store *store;
+ struct data_store *data_stores[] = {read_store, send_store, new_store};
+
+ if (isCdmaTypeModel()) {
+ data_stores_size = 2;
+ }
+ else {
+ data_stores_size = 3;
+ }
atcmd_writeline(fd, "AT+CPMS?");
tmp = atcmd_expect_line(fd, buf, sizeof(buf), "+CPMS: ");
@@ -799,7 +884,7 @@ int atcmd_plus_cpms_read(int fd, struct data_store *read_store,
return -1;
}
- for (i = 0; i < ARRAY_SIZE(data_stores); i++) {
+ for (i = 0; i < data_stores_size; i++) {
store = data_stores[i];
token = atcmd_value_tok(&save);
@@ -844,7 +929,7 @@ int atcmd_plus_cpms_test(int fd, struct store_locations *read_loc,
int tmp;
int i, j;
- struct store_locations *locations[] = {read_loc, send_loc, new_loc};
+ struct store_locations *locations[] = {read_loc, send_loc, new_loc};
struct store_locations *loc;
atcmd_writeline(fd, "AT+CPMS=?");
@@ -901,13 +986,19 @@ int atcmd_plus_cpms_test(int fd, struct store_locations *read_loc,
}
int atcmd_plus_cpms_write(int fd, const char *read_name,
- const char *send_name, const char *new_name)
+ const char *send_name, const char *new_name, const char *model)
{
char buf[ATCMD_LINE_SIZE];
int tmp;
- atcmd_writeline(fd, "AT+CPMS=\"%s\",\"%s\",\"%s\"",
- read_name, send_name, new_name);
+ if (isCdmaTypeModel()) {
+ atcmd_writeline(fd, "AT+CPMS=\"%s\",\"%s\"", read_name, send_name);
+ }
+ else
+ {
+ atcmd_writeline(fd, "AT+CPMS=\"%s\",\"%s\",\"%s\"",
+ read_name, send_name, new_name);
+ }
tmp = atcmd_expect_line(fd, buf, sizeof(buf), "OK");
if (tmp <= 0) {
log_debug("expected OK but it was not received");
@@ -1110,6 +1201,48 @@ int atcmd_plus_cpbr_test(int fd, struct phonebook_store *store)
return 0;
}
+int atcmd_plus_gmm_read(int fd)
+{
+ char buf[ATCMD_LINE_SIZE];
+ char *save;
+ char *token;
+ int tmp;
+
+ atcmd_writeline(fd, "AT+GMM");
+ //Swallow extra "\r\n"
+ tmp = atcmd_readline(fd, buf, sizeof(buf));
+ if (tmp <= 0) {
+ log_debug("expected \\r\\n but it was not received");
+ return -1;
+ }
+
+ //Read model string
+ tmp = atcmd_readline(fd, buf, sizeof(buf));
+ if (tmp <= 0) {
+ log_debug("expected model but it was not received");
+ return -1;
+ }
+
+ save = buf;
+ token = atcmd_value_tok(&save);
+ if (!token) {
+ log_debug("atcmd_value_tok model");
+ return -1;
+ }
+ free(Global.core.model);
+ Global.core.model = strdup(token);
+
+ log_debug("model: %s", Global.core.model);
+
+ tmp = atcmd_expect_line(fd, buf, sizeof(buf), "OK");
+ if (tmp <= 0) {
+ log_debug("expected OK but it was not received");
+ return -1;
+ }
+
+ return 0;
+}
+
int atcmd_init(int fd, int read_timeout)
{
int tmp;
@@ -1158,6 +1291,12 @@ static int sms_atcmd_init(int fd)
return -1;
}
+ tmp = atcmd_plus_gmm_read(fd);
+ if (tmp < 0) {
+ log_error("failed to read radio model");
+ return -1;
+ }
+
tmp = atcmd_plus_cmgf_write(fd, SMS_PDU_MODE);
if (tmp < 0) {
return -1;
@@ -1167,10 +1306,18 @@ static int sms_atcmd_init(int fd)
memset(&send_store, 0, sizeof(send_store));
memset(&new_store, 0, sizeof(new_store));
+ if (!strcmp(Global.core.model, "CE910-DUAL") || !strcmp(Global.core.model, "DE910-DUAL")) {
+ log_info("Changing message storage locations to ME for CE/DE910-DUAL");
+ free(Global.core.msg_store_read);
+ free(Global.core.msg_store_send);
+ Global.core.msg_store_read = strdup("ME");
+ Global.core.msg_store_send = strdup("ME");
+ }
+
atcmd_plus_cpms_test(fd, &read_store.choices,
&send_store.choices, &new_store.choices);
atcmd_plus_cpms_read(fd, &read_store.selected,
- &send_store.selected, &new_store.selected);
+ &send_store.selected, &new_store.selected, Global.core.model);
if (Global.core.msg_store_read && Global.core.msg_store_send &&
Global.core.msg_store_new) {
@@ -1184,14 +1331,16 @@ static int sms_atcmd_init(int fd)
Global.core.msg_store_send);
return -1;
}
- if (!msg_store_choice(&new_store, Global.core.msg_store_new)) {
+
+ //Doesn't apply to CDMA type radios
+ if (!isCdmaTypeModel() && !msg_store_choice(&new_store, Global.core.msg_store_new)) {
log_error("message storage location %s is not a choice",
Global.core.msg_store_new);
return -1;
}
tmp = atcmd_plus_cpms_write(fd, Global.core.msg_store_read,
- Global.core.msg_store_send, Global.core.msg_store_new);
+ Global.core.msg_store_send, Global.core.msg_store_new, Global.core.model);
if (tmp < 0) {
return -1;
}
@@ -1255,3 +1404,11 @@ int sms_device_open(void)
return fd;
}
+
+int isCdmaTypeModel()
+{
+ return (!strcmp(Global.core.model, "LE910-SVG") ||
+ !strcmp(Global.core.model, "DE910-DUAL") ||
+ !strcmp(Global.core.model, "CE910-DUAL"));
+}
+
diff --git a/src/atcmd.h b/src/atcmd.h
index de6eeee..16b991f 100644
--- a/src/atcmd.h
+++ b/src/atcmd.h
@@ -62,10 +62,15 @@ int atcmd_v_write(int fd, int mode);
int atcmd_q_write(int fd, int mode);
int atcmd_plus_cmgf_write(int fd, int mode);
int atcmd_plus_cmgw_write(int fd, const char *msg, size_t msg_len);
+int atcmd_plus_cmgw_write_text(int fd, const char *addr, int addr_type,
+ const char *status, const char *msg, size_t msg_len);
int atcmd_plus_cmgs_write(int fd, const char *msg, size_t msg_len);
+int atcmd_plus_cmgs_write_text(int fd, const char *addr, const char *msg, size_t msg_len);
int atcmd_plus_cmss_write(int fd, int index, const char *addr, int addr_type);
int atcmd_plus_cmgd_write(int fd, int index);
+int isCdmaTypeModel();
+
#define STORE_NAME_LEN 2
#define STORE_NAME_SIZE (STORE_NAME_LEN + 1)
#define STORE_LOCATIONS_MAX 8
@@ -87,11 +92,11 @@ struct msg_store {
};
int atcmd_plus_cpms_read(int fd, struct data_store *read_store,
- struct data_store *send_store, struct data_store *new_store);
+ struct data_store *send_store, struct data_store *new_store, const char *model);
int atcmd_plus_cpms_test(int fd, struct store_locations *read_loc,
struct store_locations *send_loc, struct store_locations *new_loc);
int atcmd_plus_cpms_write(int fd, const char *read_name,
- const char *send_name, const char *new_name);
+ const char *send_name, const char *new_name, const char *model);
struct phonebook_store {
struct data_store selected;
@@ -105,9 +110,10 @@ struct phonebook_store {
int atcmd_plus_cpbs_read(int fd, struct data_store *store);
int atcmd_plus_cpbs_test(int fd, struct store_locations *loc);
int atcmd_plus_cpbs_write(int fd, const char *name);
-
int atcmd_plus_cpbr_test(int fd, struct phonebook_store *store);
+int atcmd_plus_gmm_read(int fd);
+
int atcmd_init(int fd, int read_timeout);
int sms_device_close(int fd);
int sms_device_open(void);
diff --git a/src/global.h b/src/global.h
index fe8f5c2..4248c64 100644
--- a/src/global.h
+++ b/src/global.h
@@ -29,6 +29,7 @@ struct global_core {
char *msg_store_send;
char *msg_store_new;
char *pb_store;
+ char *model;
char *editor;
char *edit_file;
diff --git a/src/pdu.h b/src/pdu.h
index 468687d..5f47e5e 100644
--- a/src/pdu.h
+++ b/src/pdu.h
@@ -18,6 +18,7 @@ extern char *strptime(const char *s, const char *format, struct tm *tm);
#define PDU_UD_SIZE (PDU_UD_7BIT_MAX + 1)
#define PDU_TIMESTAMP_LEN 14
+#define PDU_CDMA_TIMESTAMP_LEN 12
#define PDU_TIMESTAMP_SIZE (PDU_TIMESTAMP_LEN + 1)
#define GMT_OFFSET_LEN 2
#define GMT_OFFSET_IDX (PDU_TIMESTAMP_LEN - GMT_OFFSET_LEN)
@@ -45,10 +46,9 @@ enum {
};
enum {
- PDU_ALPHABET_DEFAULT = 0,
- PDU_ALPHABET_EIGHT = 1,
- PDU_ALPHABET_UCS2 = 2,
- PDU_ALPHABET_RESERVED = 3,
+ PDU_ALPHABET_DEFAULT = 0, //7-bit
+ PDU_ALPHABET_CDMA_DEFAULT = 2, //7-bit
+ PDU_ALPHABET_EIGHT = 4,
};
struct pdu_info {
@@ -71,8 +71,8 @@ struct pdu_info {
union {
uint8_t data_coding;
struct {
- uint8_t msg_class: 2;
- uint8_t alphabet: 2;
+ // uint8_t msg_class: 2;
+ uint8_t alphabet: 4;
uint8_t have_msg_class: 1;
uint8_t compressed: 1;
uint8_t unused: 2;
@@ -113,6 +113,10 @@ int pdu_user_data_read(int fd, struct pdu_info *pdu);
#define octet_align(n) ((((n) * 7) + ((-(n) * 7) & 7)) / 8)
+#define septet_idx(n) ((n) * 8 / 7)
+#define octet_align_cdma(n) septet_idx(n)
+
+
#define STRLEN_CHECK(str, len, ret) \
do { \
if (strnlen(str, len) < len) { \
diff --git a/src/pdu_decode.c b/src/pdu_decode.c
index cbc2009..2b9e44c 100644
--- a/src/pdu_decode.c
+++ b/src/pdu_decode.c
@@ -30,6 +30,7 @@
#include <ctype.h>
#include "config.h"
+#include "global.h"
#include "log.h"
#include "utils.h"
#include "pdu_decode.h"
@@ -82,6 +83,31 @@ int pdu_decode_timestamp(const char *pdu_str, struct tm *tm)
return PDU_TIMESTAMP_LEN;
}
+
+int pdu_decode_cdma_timestamp(const char *pdu_str, struct tm *tm)
+{
+ char buf[PDU_CDMA_TIMESTAMP_LEN + 1];
+ char *cp;
+ int off_upper;
+ int off_lower;
+ int off;
+
+ STRLEN_CHECK(pdu_str, PDU_CDMA_TIMESTAMP_LEN, -1);
+
+ memset(tm, 0, sizeof(*tm));
+ memset(buf, 0, sizeof(buf));
+
+ strncpy(buf, pdu_str, PDU_CDMA_TIMESTAMP_LEN);
+
+ cp = (char *) strptime(buf, "%y%m%d%H%M%S", tm);
+ if (!cp || *cp) {
+ log_error("timestamp could not be converted to tm");
+ return -1;
+ }
+
+ return PDU_CDMA_TIMESTAMP_LEN;
+}
+
int pdu_decode_addr(const char *pdu_str, struct pdu_addr *addr, int smsc)
{
const char *begin = pdu_str;
@@ -141,17 +167,21 @@ done:
}
#define octet_idx(n) octet_align(n)
+#define octet_cdma_idx(n) ((n+1) * 7 / 8)
#define decode_septet(buf, n) \
shiftl(bit_maskr(cycledown(n, 8)) & buf[octet_idx(n)], cycleup(n, 8)) | \
shiftr(bit_maskl(cycleup(n, 8), 8) & buf[octet_idx(n - 1)], cycledown(n - 1, 8))
-int pdu_decode_user_data(const char *pdu_str, struct pdu_info *pdu)
+#define decode_septet_cdma(buf, n) \
+shiftr(buf[octet_cdma_idx(n)], cycleup(n, 8) + 1) | \
+shiftl(buf[octet_cdma_idx(n) - 1], cycledown(n, 8)) & 0x7F
+
+int pdu_decode_user_data(const char *pdu_str, struct pdu_info *pdu, int *nr_octets)
{
const char *begin = pdu_str;
int tmp;
uint8_t octets[PDU_OCTETS_MAX + 1];
- int nr_octets;
int i;
STRLEN_CHECK(pdu_str, HEX_BYTE_LEN, -1);
@@ -176,7 +206,30 @@ int pdu_decode_user_data(const char *pdu_str, struct pdu_info *pdu)
pdu->user_data_len = PDU_UD_7BIT_MAX;
}
- nr_octets = octet_align(pdu->user_data_len);
+ *nr_octets = octet_align(pdu->user_data_len);
+ } else if (pdu->data_coding.general.alphabet == PDU_ALPHABET_CDMA_DEFAULT) {
+ log_debug("data coding alphabet is cdma default");
+
+ if (!strcmp(Global.core.model, "LE910-SVG")) {
+ if (pdu->user_data_len > PDU_UD_7BIT_MAX) {
+ log_warning("pdu contains invalid user-data-len: 0x%02X", pdu->user_data_len);
+ pdu->user_data_len = PDU_UD_7BIT_MAX;
+ }
+ }
+ else {
+ if (pdu->user_data_len > PDU_UD_8BIT_MAX) {
+ log_warning("pdu contains invalid user-data-len: 0x%02X", pdu->user_data_len);
+ pdu->user_data_len = PDU_UD_8BIT_MAX;
+ }
+ }
+
+ if (!strcmp(Global.core.model, "LE910-SVG")) {
+ *nr_octets = octet_align(pdu->user_data_len);
+ }
+ else {
+ *nr_octets = pdu->user_data_len;
+ pdu->user_data_len = octet_align_cdma(pdu->user_data_len);
+ }
} else if (pdu->data_coding.general.alphabet == PDU_ALPHABET_EIGHT) {
log_debug("data coding alphabet is eight");
@@ -186,19 +239,19 @@ int pdu_decode_user_data(const char *pdu_str, struct pdu_info *pdu)
pdu->user_data_len = PDU_UD_8BIT_MAX;
}
- nr_octets = pdu->user_data_len;
+ *nr_octets = pdu->user_data_len;
} else {
log_debug("data coding alphabet 0x%02X not implemented",
pdu->data_coding.general.alphabet);
return -1;
}
- STRLEN_CHECK(pdu_str, nr_octets * 2, -1);
+ STRLEN_CHECK(pdu_str, *nr_octets * 2, -1);
log_debug("user-data-len: 0x%02X", pdu->user_data_len);
- log_debug("nr_octets: 0x%02X", nr_octets);
+ log_debug("nr_octets: 0x%02X", *nr_octets);
- for (i = 0; i < nr_octets; i++) {
+ for (i = 0; i < *nr_octets; i++) {
octets[i] = hex_byte_decode(pdu_str);
pdu_str += HEX_BYTE_LEN;
}
@@ -222,6 +275,32 @@ int pdu_decode_user_data(const char *pdu_str, struct pdu_info *pdu)
pdu->user_data[i] = decode_septet(octets, i);
}
pdu->user_data[i] = '\0';
+ } else if (pdu->data_coding.general.alphabet == PDU_ALPHABET_CDMA_DEFAULT) {
+ // Keep UDH for concatenated SMS.
+ // Otherwise it is impossible to process correctly concatenated SMS.
+ i = 0;
+ if (pdu->type.user_data_header) {
+ for (i = 0; i <= octets[0]; ++i) {
+ pdu->user_data[i] = octets[i];
+ }
+ i = octets[0] + 1; // Set message text start after UDH.
+ // Process octets padding for 7-bit encoding.
+ if (0 != (i * 8) % 7) {
+ pdu->user_data[i] = 0; // set padding data to 0;
+ i++;
+ }
+ }
+ for (; i < pdu->user_data_len; i++) {
+ pdu->user_data[i] = decode_septet_cdma(octets, i);
+ log_debug("DECODE: i: %d octet: 0x%02X --> data: 0x%02X", i, octets[i], pdu->user_data[i]);
+ }
+ //Remove padded byte for data length of 7 characters if not LE910-SVG
+ if (strcmp(Global.core.model, "LE910-SVG") && pdu->user_data[i-1] == 0) {
+ log_debug("Removing padded char");
+ i--;
+ pdu->user_data_len--;
+ }
+ pdu->user_data[i] = '\0';
} else {
for (i = 0; i < pdu->user_data_len; i++) {
pdu->user_data[i] = octets[i];
@@ -237,6 +316,7 @@ int pdu_decode(const char *pdu_str, struct pdu_info *pdu)
const char *begin = pdu_str;
const char *msg_begin;
int tmp;
+ int nr_octets;
memset(pdu, 0, sizeof(*pdu));
@@ -341,7 +421,7 @@ int pdu_decode(const char *pdu_str, struct pdu_info *pdu)
pdu_str += tmp;
}
- tmp = pdu_decode_user_data(pdu_str, pdu);
+ tmp = pdu_decode_user_data(pdu_str, pdu, &nr_octets);
DECODE_FAIL(tmp < 0, "user-data", -1);
pdu_str += tmp;
}
@@ -352,3 +432,63 @@ int pdu_decode(const char *pdu_str, struct pdu_info *pdu)
return pdu_str - begin;
}
+
+
+int pdu_decode_cdma(const char *pdu_str, struct pdu_info *pdu)
+{
+ const char *begin = pdu_str;
+ const char *msg_begin;
+ int tmp;
+ int nr_octets;
+
+ memset(pdu, 0, sizeof(*pdu));
+
+ //Destination address
+ tmp = pdu_decode_addr(pdu_str, &pdu->addr, 1);
+ DECODE_FAIL(tmp < 0, "addr", -1);
+ pdu_str += tmp;
+
+ msg_begin = pdu_str;
+
+ STRLEN_CHECK(pdu_str, HEX_BYTE_LEN, -1);
+
+ //Timestamp
+ tmp = pdu_decode_cdma_timestamp(pdu_str, &pdu->timestamp);
+ DECODE_FAIL(tmp < 0, "timestamp", -1);
+ pdu_str += tmp;
+
+ //Teleservice ID
+ tmp = hex_byte_decode(pdu_str);
+ DECODE_FAIL(tmp < 0, "tele-id-1", -1);
+ pdu_str += HEX_BYTE_LEN;
+ log_debug("tele-id-1: 0x%02X", tmp);
+
+ tmp = hex_byte_decode(pdu_str);
+ DECODE_FAIL(tmp < 0, "tele-id-2", -1);
+ pdu_str += HEX_BYTE_LEN;
+ log_debug("tele-id-2: 0x%02X", tmp);
+
+ //Priority
+ tmp = hex_byte_decode(pdu_str);
+ DECODE_FAIL(tmp < 0, "priority", -1);
+ pdu_str += HEX_BYTE_LEN;
+ log_debug("priority: 0x%02X", tmp);
+
+ //Data coding scheme
+ tmp = hex_byte_decode(pdu_str);
+ DECODE_FAIL(tmp < 0, "data-coding-scheme", -1);
+ pdu_str += HEX_BYTE_LEN;
+ pdu->data_coding.data_coding = tmp;
+ log_debug("data-coding-scheme: 0x%02X", pdu->data_coding.data_coding);
+
+ //User Data
+ tmp = pdu_decode_user_data(pdu_str, pdu, &nr_octets);
+ DECODE_FAIL(tmp < 0, "user-data", -1);
+ pdu_str += tmp;
+
+ pdu->msg_len = 6 + nr_octets;
+
+ log_debug("msg_len: %d", pdu->msg_len);
+
+ return pdu_str - begin;
+}
diff --git a/src/pdu_decode.h b/src/pdu_decode.h
index 004c8ad..c39f232 100644
--- a/src/pdu_decode.h
+++ b/src/pdu_decode.h
@@ -4,9 +4,11 @@
#include "pdu.h"
int pdu_decode_timestamp(const char *pdu_str, struct tm *tm);
+int pdu_decode_cdma_timestamp(const char *pdu_str, struct tm *tm);
int pdu_decode_addr(const char *pdu_str, struct pdu_addr *addr, int smsc);
-int pdu_decode_user_data(const char *pdu_str, struct pdu_info *pdu);
+int pdu_decode_user_data(const char *pdu_str, struct pdu_info *pdu, int *nr_octets);
int pdu_decode(const char *pdu_str, struct pdu_info *pdu);
+int pdu_decode_cdma(const char *pdu_str, struct pdu_info *pdu);
#endif /* ~__PDU_DECODE_H */
diff --git a/src/pdu_encode.c b/src/pdu_encode.c
index 30cb4a9..1bb7e4d 100644
--- a/src/pdu_encode.c
+++ b/src/pdu_encode.c
@@ -39,6 +39,8 @@ do { \
} \
} while (0)
+#define CEIL(X) ((X-(int)(X)) > 0 ? (int)(X+1) : (int)(X))
+
int pdu_encode_timestamp(char *pdu_str, size_t len, struct tm *tm)
{
int tmp;
@@ -75,7 +77,7 @@ int pdu_encode_timestamp(char *pdu_str, size_t len, struct tm *tm)
strpad(pdu_str, PDU_TIMESTAMP_LEN, 'F');
nibble_swap(pdu_str, PDU_TIMESTAMP_LEN);
- log_debug("%s", pdu_str);
+ log_debug("encode_timestamp: %s", pdu_str);
return PDU_TIMESTAMP_LEN;
}
@@ -86,7 +88,17 @@ int pdu_encode_addr(char *pdu_str, size_t len, struct pdu_addr *addr, int smsc)
int addr_len;
int tmp;
- addr_len = strlen(addr->addr);
+ if (isCdmaTypeModel()) {
+ //CDMA length is # of bytes including address type
+ //Ex: Type: 80 #: 9132074666 --> 80 19 23 70 64 66 => 6 bytes
+ addr_len = 1; //1 byte for address type
+ addr_len += CEIL(strlen(addr->addr) / 2); //Number of hex bytes
+ }
+ else {
+ //GSM length is # of digits in converted number
+ //Ex: Type: 81 #: 9132074666 --> 1923706466 => 10 digits
+ addr_len = strlen(addr->addr);
+ }
if (smsc) {
if (addr_len) {
@@ -136,18 +148,20 @@ done:
return pdu_str - begin;
}
-#define septet_idx(n) ((n) * 8 / 7)
+
#define encode_octet(buf, n) \
shiftr(bit_maskl(cycledown(n, 7) + 1, 7) & buf[septet_idx(n)], cycleup(n, 7)) | \
shiftl(bit_maskr(cycleup(n, 7) + 1) & buf[septet_idx(n) + 1], cycledown(n, 7) + 1)
-int pdu_encode_user_data(char *pdu_str, size_t len, struct pdu_info *pdu)
+#define encode_cdma_octet(buf, n) \
+shiftl(buf[septet_idx(n)], cycleup(n, 7) + 1) | shiftr(buf[septet_idx(n) + 1], cycledown(n, 7))
+
+int pdu_encode_user_data(char *pdu_str, size_t len, struct pdu_info *pdu, int *nr_octets)
{
char *begin = pdu_str;
int tmp;
uint8_t octets[PDU_OCTETS_MAX];
- int nr_octets;
int i;
if (pdu->data_coding.general.unused) {
@@ -157,9 +171,11 @@ int pdu_encode_user_data(char *pdu_str, size_t len, struct pdu_info *pdu)
}
if (pdu->data_coding.general.alphabet == PDU_ALPHABET_DEFAULT) {
- log_debug("data coding alphabet is default");
+ log_debug("data coding alphabet is default (7-bit)");
} else if (pdu->data_coding.general.alphabet == PDU_ALPHABET_EIGHT) {
log_debug("data coding alphabet is eight");
+ } else if (pdu->data_coding.general.alphabet == PDU_ALPHABET_CDMA_DEFAULT) {
+ log_debug("data coding alphabet is CDMA default (7-bit)");
} else {
log_debug("data coding alphabet 0x%02X not implemented",
pdu->data_coding.general.alphabet);
@@ -172,23 +188,35 @@ int pdu_encode_user_data(char *pdu_str, size_t len, struct pdu_info *pdu)
return -1;
}
- nr_octets = octet_align(pdu->user_data_len);
- for (i = 0; i < nr_octets; i++) {
+ *nr_octets = octet_align(pdu->user_data_len);
+ for (i = 0; i < *nr_octets; i++) {
octets[i] = encode_octet(pdu->user_data, i);
}
+ } else if (pdu->data_coding.general.alphabet == PDU_ALPHABET_CDMA_DEFAULT) {
+ if (pdu->user_data_len > PDU_UD_7BIT_MAX) {
+ log_error("string exceeds 7-bit data max length");
+ return -1;
+ }
+
+ //CDMA ENCODING
+ *nr_octets = octet_align(pdu->user_data_len);
+ pdu->user_data_len = *nr_octets;
+ for (i = 0; i < *nr_octets; i++) {
+ octets[i] = encode_cdma_octet(pdu->user_data, i);
+ }
} else {
if (pdu->user_data_len > PDU_UD_8BIT_MAX) {
log_error("string exceeds 8-bit data max length");
return -1;
}
- nr_octets = pdu->user_data_len;
+ *nr_octets = pdu->user_data_len;
for (i = 0; i < pdu->user_data_len; i++) {
octets[i] = pdu->user_data[i];
}
}
- if (len < nr_octets * 2 + HEX_BYTE_LEN + 1) {
+ if (len < *nr_octets * 2 + HEX_BYTE_LEN + 1) {
log_error("buffer is not large enough to hold user-data");
return -1;
}
@@ -198,15 +226,15 @@ int pdu_encode_user_data(char *pdu_str, size_t len, struct pdu_info *pdu)
pdu_str += tmp;
len -= tmp;
- for (i = 0; i < nr_octets; i++) {
+ for (i = 0; i < *nr_octets; i++) {
hex_byte_encode(pdu_str, len, octets[i]);
pdu_str += HEX_BYTE_LEN;
}
- len -= nr_octets * 2;
+ len -= *nr_octets * 2;
pdu_str[i] = '\0';
log_debug("user-data-len: 0x%02X", pdu->user_data_len);
- log_debug("nr_octets: 0x%02X", nr_octets);
+ log_debug("nr_octets: 0x%02X", *nr_octets);
return pdu_str - begin;
}
@@ -216,6 +244,7 @@ int pdu_encode(char *pdu_str, size_t len, struct pdu_info *pdu)
char *begin = pdu_str;
char *msg_begin = pdu_str;
int tmp;
+ int nr_octets;
tmp = pdu_encode_addr(pdu_str, len, &pdu->smsc_addr, 1);
ENCODE_FAIL(tmp < 0, "smsc-addr", -1);
@@ -293,7 +322,7 @@ int pdu_encode(char *pdu_str, size_t len, struct pdu_info *pdu)
pdu_str += tmp;
}
- tmp = pdu_encode_user_data(pdu_str, len, pdu);
+ tmp = pdu_encode_user_data(pdu_str, len, pdu, &nr_octets);
ENCODE_FAIL(tmp < 0, "user-data", -1);
len -= tmp;
pdu_str += tmp;
@@ -305,3 +334,71 @@ int pdu_encode(char *pdu_str, size_t len, struct pdu_info *pdu)
return pdu_str - begin;
}
+
+int pdu_encode_cdma(char *pdu_str, size_t len, struct pdu_info *pdu)
+{
+ char *begin = pdu_str;
+ char *msg_begin = pdu_str;
+ int tmp;
+ int nr_octets;
+
+ //Set pdu encoding for CDMA
+ pdu->data_coding.general.alphabet = PDU_ALPHABET_CDMA_DEFAULT;
+
+ //Destination address
+ tmp = pdu_encode_addr(pdu_str, len, &pdu->addr, 0);
+ ENCODE_FAIL(tmp < 0, "addr", -1);
+ len -= tmp;
+ pdu_str += tmp;
+
+ //Callback address (Always 00 because it's empty)
+ tmp = hex_byte_encode(pdu_str, len, 0);
+ ENCODE_FAIL(tmp != HEX_BYTE_LEN, "callback-addr-len", -1);
+ pdu_str += tmp;
+ len -= tmp;
+
+ //Teleservice ID (always 1002)
+ tmp = hex_byte_encode(pdu_str, len, 16);
+ ENCODE_FAIL(tmp != HEX_BYTE_LEN, "tele-id-1", -1);
+ pdu_str += tmp;
+ len -= tmp;
+ tmp = hex_byte_encode(pdu_str, len, 2);
+ ENCODE_FAIL(tmp != HEX_BYTE_LEN, "tele-id-2", -1);
+ pdu_str += tmp;
+ len -= tmp;
+
+ //Priority (always 00 for normal)
+ tmp = hex_byte_encode(pdu_str, len, 0);
+ ENCODE_FAIL(tmp != HEX_BYTE_LEN, "priority", -1);
+ pdu_str += tmp;
+ len -= tmp;
+
+ switch (pdu->type.msg_type) {
+ case PDU_MTI_REPORT:
+ log_error("msg_type PDU_MTI_REPORT not supported!");
+ return 0;
+
+ case PDU_MTI_DELIVER:
+ log_debug("msg_type: PDU_MTI_DELIVER");
+ case PDU_MTI_SUBMIT:
+ log_debug("msg_type: PDU_MTI_SUBMIT");
+
+ //add data coding scheme
+ tmp = hex_byte_encode(pdu_str, len, pdu->data_coding.data_coding);
+ ENCODE_FAIL(tmp != HEX_BYTE_LEN, "data-coding-scheme", -1);
+ len -= tmp;
+ pdu_str += tmp;
+
+
+ tmp = pdu_encode_user_data(pdu_str, len, pdu, &nr_octets);
+ ENCODE_FAIL(tmp < 0, "user-data", -1);
+ len -= tmp;
+ pdu_str += tmp;
+ }
+
+ // pdu->msg_len = (pdu_str - msg_begin) / 2;
+ pdu->msg_len = 6 + nr_octets;
+ log_debug("msg-len: %d", pdu->msg_len);
+
+ return pdu_str - begin;
+}
diff --git a/src/pdu_encode.h b/src/pdu_encode.h
index 246ea3d..8ff79a3 100644
--- a/src/pdu_encode.h
+++ b/src/pdu_encode.h
@@ -5,8 +5,9 @@
int pdu_encode_timestamp(char *pdu_str, size_t len, struct tm *tm);
int pdu_encode_addr(char *pdu_str, size_t len, struct pdu_addr *addr, int smsc);
-int pdu_encode_user_data(char *pdu_str, size_t len, struct pdu_info *pdu);
+int pdu_encode_user_data(char *pdu_str, size_t len, struct pdu_info *pdu, int *nr_octets);
int pdu_encode(char *pdu_str, size_t len, struct pdu_info *pdu);
+int pdu_encode_cdma(char *pdu_str, size_t len, struct pdu_info *pdu);
#endif /* ~__PDU_ENCODE_H */
diff --git a/src/sms_list.c b/src/sms_list.c
index 0ccec15..dcad3fe 100644
--- a/src/sms_list.c
+++ b/src/sms_list.c
@@ -279,7 +279,14 @@ static int list_info_callback(char *buf, size_t len, void *data)
msg = list_entry(list_info->msg_list.prev, typeof(*msg), list);
if (msg->len > 0) {
- err = pdu_decode(buf, &msg->pdu);
+ if (isCdmaTypeModel()) {
+ log_debug("using CDMA pdu decoding");
+ err = pdu_decode_cdma(buf, &msg->pdu);
+ }
+ else {
+ log_debug("using GSM pdu decoding");
+ err = pdu_decode(buf, &msg->pdu);
+ }
if (err < 0) {
log_warning("pdu decode failed: %d", err);
}
diff --git a/src/sms_main.c b/src/sms_main.c
index 1bf74fa..e91aaba 100644
--- a/src/sms_main.c
+++ b/src/sms_main.c
@@ -59,6 +59,7 @@ static int global_init(void)
Global.core.msg_store_send = strdup("SM");
Global.core.msg_store_new = strdup("SM");
Global.core.pb_store = strdup("SM");
+ Global.core.model = strdup("UNKNOWNMODEL");
Global.core.editor = strdup("vi");
Global.core.edit_file = strdup("${HOME}/.smsmsg");
diff --git a/src/sms_send.c b/src/sms_send.c
index 8ed7ebb..3933786 100644
--- a/src/sms_send.c
+++ b/src/sms_send.c
@@ -224,8 +224,25 @@ static int do_send(int fd, struct send_options *options, int argc, char **argv)
printf("preparing for send...\n");
}
+ //LE910-SVG SMS SEND WORKAROUND
+ if (!strcmp(Global.core.model, "LE910-SVG")) {
+ log_info("setting text mode for LE910-SVG");
+ tmp = atcmd_plus_cmgf_write(fd, SMS_TEXT_MODE);
+ if (tmp < 0) {
+ log_error("failed to set text mode for sending with LE910-SVG");
+ return false;
+ }
+ }
+
if (options->cmgw_first) {
- tmp = pdu_encode(buf, sizeof(buf), &pdu);
+ if (isCdmaTypeModel()) {
+ log_debug("using CDMA pdu encoding for cmgw");
+ tmp = pdu_encode_cdma(buf, sizeof(buf), &pdu);
+ }
+ else {
+ log_debug("using GSM pdu encoding for cmgw");
+ tmp = pdu_encode(buf, sizeof(buf), &pdu);
+ }
if (tmp < 0) {
log_error("pdu encode failed");
return false;
@@ -235,7 +252,13 @@ static int do_send(int fd, struct send_options *options, int argc, char **argv)
printf("writing message to memory\n");
}
- mem_index = atcmd_plus_cmgw_write(fd, buf, pdu.msg_len);
+ //LE910-SVG SMS SEND WORKAROUND
+ if (!strcmp(Global.core.model, "LE910-SVG")) {
+ mem_index = atcmd_plus_cmgw_write_text(fd, NULL, SMS_ADDR_UNSPEC, NULL, pdu.user_data, pdu.user_data_len);
+ }
+ else {
+ mem_index = atcmd_plus_cmgw_write(fd, buf, pdu.msg_len);
+ }
if (mem_index < 0) {
log_error("write message to memory failed");
return false;
@@ -275,14 +298,27 @@ static int do_send(int fd, struct send_options *options, int argc, char **argv)
continue;
}
} else {
- tmp = pdu_encode(buf, sizeof(buf), &pdu);
+ if (isCdmaTypeModel()) {
+ log_debug("using CDMA pdu encoding for cmgs");
+ tmp = pdu_encode_cdma(buf, sizeof(buf), &pdu);
+ }
+ else {
+ log_debug("using GSM pdu encoding for cmgs");
+ tmp = pdu_encode(buf, sizeof(buf), &pdu);
+ }
if (tmp < 0) {
printf("sending message to %s failed\n", argv[i]);
failed++;
continue;
}
- tmp = atcmd_plus_cmgs_write(fd, buf, pdu.msg_len);
+ //LE910-SVG SMS SEND WORKAROUND
+ if (!strcmp(Global.core.model, "LE910-SVG")) {
+ tmp = atcmd_plus_cmgs_write_text(fd, pdu.addr.addr, pdu.user_data, pdu.user_data_len);
+ }
+ else {
+ tmp = atcmd_plus_cmgs_write(fd, buf, pdu.msg_len);
+ }
if (tmp < 0) {
printf("sending message to %s failed\n", argv[i]);
failed++;