summaryrefslogtreecommitdiff
path: root/src/atcmd.c
diff options
context:
space:
mode:
authorJames Maki <jmaki@multitech.com>2010-04-23 11:58:20 -0500
committerJames Maki <jmaki@multitech.com>2010-04-23 11:58:20 -0500
commit14fb44b17123b27e562379f51b75ee889982688d (patch)
tree3c2344f5c42396ab839638ee12f7c2f66a2656cb /src/atcmd.c
downloadsms-utils-14fb44b17123b27e562379f51b75ee889982688d.tar.gz
sms-utils-14fb44b17123b27e562379f51b75ee889982688d.tar.bz2
sms-utils-14fb44b17123b27e562379f51b75ee889982688d.zip
initial commit
Diffstat (limited to 'src/atcmd.c')
-rw-r--r--src/atcmd.c1087
1 files changed, 1087 insertions, 0 deletions
diff --git a/src/atcmd.c b/src/atcmd.c
new file mode 100644
index 0000000..10470c1
--- /dev/null
+++ b/src/atcmd.c
@@ -0,0 +1,1087 @@
+/*
+ * AT Command Utilities (and terminal stuff for now)
+ *
+ * Copyright (C) 2010 by Multi-Tech Systems
+ *
+ * Author: James Maki <jmaki@multitech.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#define _GNU_SOURCE
+
+#define __ATCMD_C 1
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <errno.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <string.h>
+
+#include "global.h"
+#include "log.h"
+#include "utils.h"
+#include "atcmd.h"
+#include "sms_utils.h"
+
+static const struct baud_map __baud_map[] = {
+ {B300, 300},
+ {B600, 600},
+ {B1200, 1200},
+ {B1800, 1800},
+ {B2400, 2400},
+ {B4800, 4800},
+ {B9600, 9600},
+ {B19200, 19200},
+ {B38400, 38400},
+ {B57600, 57600},
+ {B115200, 115200},
+ {B230400, 230400},
+ {B460800, 460800},
+ {B921600, 921600},
+};
+
+speed_t value_to_baud(speed_t value)
+{
+ int n = ARRAY_SIZE(__baud_map);
+ int i;
+
+ for (i = 0; i < n; ++i) {
+ if (__baud_map[i].value == value) {
+ return __baud_map[i].baud;
+ }
+ }
+
+ log_warning("baud rate not valid: %lu", (unsigned long) value);
+
+ return (speed_t) -1;
+}
+
+int rts_get(int fd)
+{
+ int err;
+ int status;
+
+ err = ioctl(fd, TIOCMGET, &status);
+ if (err < 0) {
+ return -1;
+ }
+ return status & TIOCM_RTS ? 1 : 0;
+}
+
+int dtr_get(int fd)
+{
+ int err;
+ int status;
+
+ err = ioctl(fd, TIOCMGET, &status);
+ if (err < 0) {
+ return -1;
+ }
+ return status & TIOCM_DTR ? 1 : 0;
+}
+
+int cts_get(int fd)
+{
+ int err;
+ int status;
+
+ err = ioctl(fd, TIOCMGET, &status);
+ if (err < 0) {
+ return -1;
+ }
+ return status & TIOCM_CTS ? 1 : 0;
+}
+
+int dsr_get(int fd)
+{
+ int err;
+ int status;
+
+ err = ioctl(fd, TIOCMGET, &status);
+ if (err < 0) {
+ return -1;
+ }
+ return status & TIOCM_DSR ? 1 : 0;
+}
+
+int cd_get(int fd)
+{
+ int err;
+ int status;
+
+ err = ioctl(fd, TIOCMGET, &status);
+ if (err < 0) {
+ return -1;
+ }
+ return status & TIOCM_CD ? 1 : 0;
+}
+
+int ri_get(int fd)
+{
+ int err;
+ int status;
+
+ err = ioctl(fd, TIOCMGET, &status);
+ if (err < 0) {
+ return -1;
+ }
+ return status & TIOCM_RI ? 1 : 0;
+}
+
+int line_signal_set(int fd, int signal, int value)
+{
+ int err;
+ int status;
+
+ err = ioctl(fd, TIOCMGET, &status);
+ if (err < 0) {
+ return -1;
+ }
+
+ if (value) {
+ status &= ~signal;
+ } else {
+ status |= signal;
+ }
+
+ err = ioctl(fd, TIOCMSET, &status);
+ if (err < 0) {
+ return -1;
+ }
+
+ return status;
+}
+
+int rts_set(int fd, int value)
+{
+ return line_signal_set(fd, TIOCM_RTS, value);
+}
+
+int dtr_set(int fd, int value)
+{
+ return line_signal_set(fd, TIOCM_DTR, value);
+}
+
+int tty_configure(int fd, speed_t baud_rate)
+{
+ int err;
+ struct termios params;
+
+ err = tcgetattr(fd, &params);
+ if (err < 0) {
+ log_error("tcgetattr failed: %m");
+ return -1;
+ }
+
+ cfmakeraw(&params);
+ cfsetspeed(&params, baud_rate);
+
+ err = tcsetattr(fd, TCSANOW, &params);
+ if (err < 0) {
+ log_error("tcsetattr failed: %m");
+ return -1;
+ }
+
+ return 0;
+}
+
+int tty_open(const char *dev, speed_t baud_rate)
+{
+ int fd;
+
+ fd = open(dev, O_RDWR | O_NOCTTY);
+ if (fd < 0) {
+ log_error("failed to open %s: %m", dev);
+ return fd;
+ }
+
+ if (!isatty(fd)) {
+ log_error("%s is not a tty device", dev);
+ close(fd);
+ return -1;
+ }
+
+ tty_configure(fd, baud_rate);
+ tcflush(fd, TCIOFLUSH);
+
+ log_debug("rts: %d", rts_get(fd));
+ log_debug("dtr: %d", dtr_get(fd));
+ log_debug("cts: %d", cts_get(fd));
+ log_debug("dsr: %d", dsr_get(fd));
+ log_debug("cd: %d", cd_get(fd));
+ log_debug("ri: %d", ri_get(fd));
+
+ return fd;
+}
+
+int tty_set_read_timeout(int fd, int timeout)
+{
+ int err;
+ struct termios params;
+
+ err = tcgetattr(fd, &params);
+ if (err < 0) {
+ log_error("tcgetattr failed: %m");
+ return -1;
+ }
+
+ if (timeout < 0) {
+ params.c_cc[VTIME] = 0;
+ params.c_cc[VMIN] = 0;
+ } else if (timeout == 0) {
+ params.c_cc[VTIME] = 0;
+ params.c_cc[VMIN] = 1;
+ } else {
+ params.c_cc[VTIME] = (timeout + 50) / 100;
+ params.c_cc[VMIN] = 0;
+ }
+
+ err = tcsetattr(fd, TCSANOW, &params);
+ if (err < 0) {
+ log_error("tcsetattr failed: %m");
+ return -1;
+ }
+
+ return 0;
+}
+
+int tty_close(int fd)
+{
+ tcflush(fd, TCIOFLUSH);
+ return close(fd);
+}
+
+int atcmd_read(int fd, char *buf, size_t len)
+{
+ int err;
+
+ err = read(fd, buf, len);
+ if (!err) {
+ log_notice("read timeout");
+ } else if (err < 0) {
+ log_error("read failed: %m");
+ }
+
+ return err;
+}
+
+int atcmd_read_until(int fd, char *buf, size_t len, const char *stop)
+{
+ int err;
+ char c;
+ ssize_t total = 0;
+ size_t stop_len = strlen(stop);
+
+ if (!stop_len) {
+ BUG("specify a stop string");
+ }
+
+ while (1) {
+ err = atcmd_read(fd, &c, 1);
+ if (err <= 0) {
+ buf[total] = '\0';
+ return err;
+ }
+
+ if (total < len - 1) {
+ buf[total++] = c;
+ }
+
+ if (stop_len <= total && c == stop[stop_len - 1] &&
+ !memcmp(buf + (total - stop_len), stop, stop_len)) {
+ buf[total] = '\0';
+ break;
+ }
+
+ if (total >= len - 1) {
+ buf[total] = '\0';
+ log_notice("buffer exceeded before finding stop sequence");
+ log_notice("buffer so far: %s", buf);
+ return -1;
+ }
+ }
+
+ debug_buffer("read:", buf, strlen(buf));
+
+ return total;
+}
+
+int atcmd_readline(int fd, char *buf, size_t len)
+{
+ int tmp;
+
+ tmp = atcmd_read_until(fd, buf, len, ATCMD_RESPONSE_EOL);
+ if (tmp <= 0) {
+ log_debug("atcmd_read_until failed with %d", tmp);
+ return tmp;
+ }
+
+ buf = strpbrk(buf, ATCMD_RESPONSE_EOL);
+ if (buf) {
+ *buf = '\0';
+ }
+
+ return tmp;
+}
+
+int atcmd_expect_line(int fd, char *buf, size_t len, const char *expect)
+{
+ int tmp;
+
+ while (1) {
+ tmp = atcmd_readline(fd, buf, len);
+ if (tmp <= 0) {
+ *buf = '\0';
+ log_debug("atcmd_readline failed");
+ return tmp;
+ }
+
+ if (strstr(buf, expect)) {
+ return tmp;
+ } else if (!strcmp(buf, "OK")) {
+ log_error("expected %s but got %s", expect, buf);
+ return -1;
+ } else if (!strcmp(buf, "ERROR")) {
+ log_error("expected %s but got %s", expect, buf);
+ return -1;
+ } else if (!strncmp(buf, "+CMS ERROR: ", sizeof("+CMS ERROR: ") - 1)) {
+ log_error("expected %s but got %s", expect, buf);
+ return -1;
+ }
+ }
+
+ return -1;
+}
+
+int atcmd_write(int fd, const char *buf, size_t len)
+{
+ int err;
+
+ debug_buffer("writing:", buf, len);
+
+ err = full_write(fd, buf, len);
+ if (err < 0) {
+ log_error("full_write failed: %m");
+ }
+ return err;
+}
+
+int atcmd_write_str(int fd, const char *buf)
+{
+ return atcmd_write(fd, buf, strlen(buf));
+}
+
+int atcmd_vprintf(int fd, char *fmt, va_list ap)
+{
+ char *buf;
+ int err;
+
+ err = vasprintf(&buf, fmt, ap);
+ if (err < 0) {
+ log_error("out of memory");
+ return err;
+ }
+
+ err = atcmd_write_str(fd, buf);
+ if (err < 0) {
+ log_debug("atcmd_write failed");
+ }
+ free(buf);
+
+ return err;
+}
+
+int atcmd_printf(int fd, char *fmt, ...)
+{
+ va_list ap;
+ int err;
+
+ va_start(ap, fmt);
+ err = atcmd_vprintf(fd, fmt, ap);
+ if (err < 0) {
+ log_debug("atcmd_write failed");
+ }
+ va_end(ap);
+
+ return err;
+}
+
+int atcmd_writeline(int fd, char *fmt, ...)
+{
+ va_list ap;
+ int err;
+ int total = 0;
+
+ va_start(ap, fmt);
+ err = atcmd_vprintf(fd, fmt, ap);
+ va_end(ap);
+ if (err < 0) {
+ log_debug("atcmd_vprintf failed");
+ return err;
+ }
+ total += err;
+
+ err = atcmd_write_str(fd, ATCMD_EOL);
+ if (err < 0) {
+ log_debug("atcmd_write_str failed");
+ return err;
+ }
+ total += err;
+
+ return total;
+}
+
+/**
+ * atcmd_value_tok - Tokenize an AT compound value.
+ * @str: The compound value to tokenize.
+ *
+ * Return: A pointer to the next token is returned and @str is updated for the next
+ * call. Returns NULL on error or when there are no more tokens.
+ *
+ */
+char *atcmd_value_tok(char **str)
+{
+ char *next;
+ char *begin;
+
+ begin = *str;
+ if (!begin || !*begin) {
+ return NULL;
+ }
+
+ begin += strspn(begin, " \t");
+
+ if (*begin == '\"') {
+ next = ++begin;
+
+ next = strchr(next, '\"');
+ if (!next) {
+ log_notice("unterminated string");
+ return NULL;
+ }
+ *next++ = '\0';
+
+ next = strchr(next, ',');
+ if (next) {
+ *next++ = '\0';
+ }
+ } else if (*begin == '(') {
+ next = ++begin;
+
+ next = strchr(next, ')');
+ if (!next) {
+ log_notice("unterminated group");
+ return NULL;
+ }
+ *next++ = '\0';
+
+ next = strchr(next, ',');
+ if (next) {
+ *next++ = '\0';
+ }
+ } else {
+ next = begin;
+
+ next = strchr(next, ',');
+ if (next) {
+ *next++ = '\0';
+ }
+
+ strrstrip(begin);
+ }
+
+ *str = next;
+
+ return begin;
+}
+
+/**
+ * atcmd_response_brk - Break an AT command response info line in half.
+ * @str: The response info line to break in half
+ *
+ * expected format: "<key>: <value>". <value> can be the empty string.
+ *
+ * Return: A pointer to <key> is returned. @str is set to <value>.
+ *
+ */
+char *atcmd_response_brk(char **str)
+{
+ char *next;
+ char *begin;
+
+ begin = *str;
+ if (!begin || !*begin) {
+ return NULL;
+ }
+
+ begin += strspn(begin, " \t");
+
+ next = begin;
+
+ next = strstr(next, ": ");
+ if (!next) {
+ log_notice("separator \": \" not found");
+ return NULL;
+ }
+ *next++ = '\0';
+ next += strspn(next, " \t");
+
+ *str = next;
+
+ return begin;
+}
+
+int atcmd_e_write(int fd, int mode)
+{
+ char buf[ATCMD_LINE_SIZE];
+ int tmp;
+
+ atcmd_writeline(fd, "ATE%d", mode);
+ 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_plus_cmgf_write(int fd, int mode)
+{
+ char buf[ATCMD_LINE_SIZE];
+ int tmp;
+
+ atcmd_writeline(fd, "AT+CMGF=%d", mode);
+ 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_plus_cmgw_write(int fd, const char *msg, size_t msg_len)
+{
+ char buf[ATCMD_LINE_SIZE];
+ int tmp;
+ int mem_index;
+
+ atcmd_writeline(fd, "AT+CMGW=%d", msg_len);
+ 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];
+ int tmp;
+ int msg_ref;
+
+ atcmd_writeline(fd, "AT+CMGS=%d", msg_len);
+ 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];
+ int tmp;
+ int msg_ref;
+
+ atcmd_printf(fd, "AT+CMSS=%d", index);
+ if (addr) {
+ atcmd_printf(fd, ",\"%s\"", addr);
+ if (addr_type != SMS_ADDR_UNSPEC) {
+ atcmd_printf(fd, ",%d", addr_type);
+ }
+ }
+ atcmd_write_str(fd, ATCMD_EOL);
+
+ tmp = atcmd_expect_line(fd, buf, sizeof(buf), "+CMSS: ");
+ if (tmp <= 0) {
+ log_debug("expected +CMSS: but it was not received");
+ return -1;
+ }
+
+ msg_ref = atoi(buf + strlen("+CMSS: "));
+
+ 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_cmgd_write(int fd, int index)
+{
+ char buf[ATCMD_LINE_SIZE];
+ int tmp;
+
+ atcmd_writeline(fd, "AT+CMGD=%d", index);
+ 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_response_foreach_line(int fd, atcmd_response_callback_t call, void *prv)
+{
+ char buf[ATCMD_LINE_SIZE];
+ int tmp;
+
+ while (1) {
+ tmp = atcmd_readline(fd, buf, sizeof(buf));
+ if (tmp <= 0) {
+ return -1;
+ }
+
+ tmp = call(buf, strlen(buf), prv);
+ if (tmp) {
+ return tmp;
+ }
+ }
+
+ return -1;
+}
+
+int atcmd_plus_cpms_read(int fd, struct data_store *read_store,
+ struct data_store *send_store, struct data_store *new_store)
+{
+ char buf[ATCMD_LINE_SIZE];
+ char *save;
+ char *token;
+ int tmp;
+ int i;
+
+ struct data_store *data_stores[] = {read_store, send_store, new_store};
+ struct data_store *store;
+
+ atcmd_writeline(fd, "AT+CPMS?");
+ tmp = atcmd_expect_line(fd, buf, sizeof(buf), "+CPMS: ");
+ if (tmp <= 0) {
+ log_debug("expected +CPMS: but it was not received");
+ return -1;
+ }
+
+ save = buf;
+ token = atcmd_response_brk(&save);
+ if (!token) {
+ log_debug("atcmd_response_brk failed");
+ return -1;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(data_stores); i++) {
+ store = data_stores[i];
+
+ token = atcmd_value_tok(&save);
+ if (!token) {
+ return -1;
+ }
+ strncpy(store->name, token, STORE_NAME_LEN);
+
+ token = atcmd_value_tok(&save);
+ if (!token) {
+ return -1;
+ }
+ store->used = atoi(token);
+
+ token = atcmd_value_tok(&save);
+ if (!token) {
+ return -1;
+ }
+ store->max = atoi(token);
+
+ log_debug("name[%d]: %s", i, store->name);
+ log_debug("used[%d]: %d", i, store->used);
+ log_debug("max[%d]: %d", i, store->max);
+ }
+
+ 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_plus_cpms_test(int fd, struct store_locations *read_loc,
+ struct store_locations *send_loc, struct store_locations *new_loc)
+{
+ char buf[ATCMD_LINE_SIZE];
+ char *save;
+ char *token;
+ char *choices;
+ int tmp;
+ int i, j;
+
+ struct store_locations *locations[] = {read_loc, send_loc, new_loc};
+ struct store_locations *loc;
+
+ atcmd_writeline(fd, "AT+CPMS=?");
+ tmp = atcmd_expect_line(fd, buf, sizeof(buf), "+CPMS: ");
+ if (tmp <= 0) {
+ log_debug("expected +CPMS: but it was not received");
+ return -1;
+ }
+
+ save = buf;
+ token = atcmd_response_brk(&save);
+ if (!token) {
+ log_debug("atcmd_response_brk failed");
+ return -1;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(locations); i++) {
+ loc = locations[i];
+
+ token = atcmd_value_tok(&save);
+ if (!token) {
+ break;
+ }
+
+ choices = token;
+ for (j = 0; j < STORE_LOCATIONS_MAX; j++) {
+ token = atcmd_value_tok(&choices);
+ if (!token) {
+ break;
+ }
+
+ strncpy(loc->names[j], token, STORE_NAME_LEN);
+
+ log_debug("loc[%d] choice[%d]: %s", i, j, token);
+
+ loc->nr_locations++;
+ }
+ }
+
+ 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_plus_cpms_write(int fd, const char *read_name,
+ const char *send_name, const char *new_name)
+{
+ char buf[ATCMD_LINE_SIZE];
+ int tmp;
+
+ 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");
+ return -1;
+ }
+
+ return 0;
+}
+
+int atcmd_plus_cpbs_read(int fd, struct data_store *store)
+{
+ char buf[ATCMD_LINE_SIZE];
+ char *save;
+ char *token;
+ int tmp;
+
+ atcmd_writeline(fd, "AT+CPBS?");
+ tmp = atcmd_expect_line(fd, buf, sizeof(buf), "+CPBS: ");
+ if (tmp <= 0) {
+ log_debug("expected +CPBS: but it was not received");
+ return -1;
+ }
+
+ save = buf;
+ token = atcmd_response_brk(&save);
+ if (!token) {
+ log_debug("atcmd_response_brk failed");
+ return -1;
+ }
+
+ token = atcmd_value_tok(&save);
+ if (!token) {
+ log_debug("atcmd_value_tok name");
+ return -1;
+ }
+ strncpy(store->name, token, STORE_NAME_LEN);
+
+ token = atcmd_value_tok(&save);
+ if (!token) {
+ log_debug("atcmd_value_tok used");
+ return -1;
+ }
+ store->used = atoi(token);
+
+ token = atcmd_value_tok(&save);
+ if (!token) {
+ log_debug("atcmd_value_tok max");
+ return -1;
+ }
+ store->max = atoi(token);
+
+ log_debug("name: %s", store->name);
+ log_debug("used: %d", store->used);
+ log_debug("max: %d", store->max);
+
+ 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_plus_cpbs_test(int fd, struct store_locations *loc)
+{
+ char buf[ATCMD_LINE_SIZE];
+ char *save;
+ char *token;
+ char *choices;
+ int tmp;
+ int i;
+
+ atcmd_writeline(fd, "AT+CPBS=?");
+ tmp = atcmd_expect_line(fd, buf, sizeof(buf), "+CPBS: ");
+ if (tmp <= 0) {
+ log_debug("expected +CPBS: but it was not received");
+ return -1;
+ }
+
+ save = buf;
+ token = atcmd_response_brk(&save);
+ if (!token) {
+ log_debug("atcmd_response_brk failed");
+ return -1;
+ }
+
+ token = atcmd_value_tok(&save);
+ if (!token) {
+ log_debug("atcmd_value_tok group");
+ return -1;
+ }
+
+ choices = token;
+ for (i = 0; i < STORE_LOCATIONS_MAX; i++) {
+ token = atcmd_value_tok(&choices);
+ if (!token) {
+ break;
+ }
+
+ strncpy(loc->names[i], token, STORE_NAME_LEN);
+
+ log_debug("choice[%d]: %s", i, token);
+
+ loc->nr_locations++;
+ }
+
+ 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_plus_cpbs_write(int fd, const char *name)
+{
+ char buf[ATCMD_LINE_SIZE];
+ int tmp;
+
+ atcmd_writeline(fd, "AT+CPBS=\"%s\"", name);
+ 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_plus_cpbr_test(int fd, struct phonebook_store *store)
+{
+ char buf[ATCMD_LINE_SIZE];
+ char *save;
+ char *range;
+ char *token;
+ int tmp;
+
+ atcmd_writeline(fd, "AT+CPBR=?");
+ tmp = atcmd_expect_line(fd, buf, sizeof(buf), "+CPBR: ");
+ if (tmp <= 0) {
+ log_debug("expected +CPBR: but it was not received");
+ return -1;
+ }
+
+ save = buf;
+ token = atcmd_response_brk(&save);
+ if (!token) {
+ log_debug("atcmd_response_brk failed");
+ return -1;
+ }
+
+ token = atcmd_value_tok(&save);
+ if (!token) {
+ log_debug("atcmd_value_tok start");
+ return -1;
+ }
+
+ range = token;
+ token = atcmd_value_tok(&range);
+ if (!token) {
+ log_debug("atcmd_value_tok range");
+ return -1;
+ }
+
+ range = strchr(token, '-');
+ if (!range) {
+ log_debug("break range");
+ return -1;
+ }
+ store->index_min = atoi(token);
+ store->index_max = atoi(range + 1);
+
+ token = atcmd_value_tok(&save);
+ if (!token) {
+ log_debug("atcmd_value_tok addr_max");
+ return -1;
+ }
+ store->addr_max = atoi(token);
+
+ token = atcmd_value_tok(&save);
+ if (!token) {
+ log_debug("atcmd_value_tok name_max");
+ return -1;
+ }
+ store->name_max = atoi(token);
+
+ log_debug("index_min: %d", store->index_min);
+ log_debug("index_max: %d", store->index_max);
+ log_debug("addr_max: %d", store->addr_max);
+ log_debug("name_max: %d", store->name_max);
+
+ 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)
+{
+ char buf[ATCMD_LINE_SIZE];
+ int tmp;
+
+ tmp = tty_set_read_timeout(fd, read_timeout);
+ if (tmp < 0) {
+ return tmp;
+ }
+
+ atcmd_writeline(fd, "ATV1");
+ tmp = atcmd_expect_line(fd, buf, sizeof(buf), "OK");
+ if (tmp <= 0) {
+ log_debug("expected OK but it was not received");
+ return -1;
+ }
+
+ tmp = atcmd_e_write(fd, 0);
+ if (tmp < 0) {
+ return tmp;
+ }
+
+ struct msg_store read_store;
+ struct msg_store send_store;
+ struct msg_store new_store;
+
+ memset(&read_store, 0, sizeof(read_store));
+ memset(&send_store, 0, sizeof(send_store));
+ memset(&new_store, 0, sizeof(new_store));
+
+ 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);
+ if (Global.core.msg_store_read && Global.core.msg_store_send &&
+ Global.core.msg_store_new) {
+ atcmd_plus_cpms_write(fd, Global.core.msg_store_read,
+ Global.core.msg_store_send, Global.core.msg_store_new);
+ }
+
+ return 0;
+}