From 9da5f8409c85637361d7bc69b721f6d9d3087b7b Mon Sep 17 00:00:00 2001
From: Uros Majstorovic <majstor@majstor.org>
Date: Wed, 4 Sep 2024 21:07:29 +0200
Subject: esp32 cellular modem driver fix

---
 fw/esp32/components/eos/at_cmd.c         |   3 +
 fw/esp32/components/eos/cell.c           |   2 +-
 fw/esp32/components/eos/cell_modem.c     |  10 +-
 fw/esp32/components/eos/cell_pcm.c       |  38 +++-
 fw/esp32/components/eos/cell_pdp.c       |   8 +-
 fw/esp32/components/eos/cell_sms.c       | 340 +++++++++++++++++------------
 fw/esp32/components/eos/cell_ussd.c      |  55 ++---
 fw/esp32/components/eos/cell_voice.c     |  27 ++-
 fw/esp32/components/eos/gsm.c            | 352 +++++++++++++++++--------------
 fw/esp32/components/eos/gsm_cp.c         |  22 +-
 fw/esp32/components/eos/include/at_cmd.h |   1 +
 fw/esp32/components/eos/include/cell.h   |  19 +-
 fw/esp32/components/eos/include/eos.h    |  10 +-
 fw/esp32/components/eos/include/gsm.h    |  37 ++--
 14 files changed, 539 insertions(+), 385 deletions(-)

(limited to 'fw/esp32')

diff --git a/fw/esp32/components/eos/at_cmd.c b/fw/esp32/components/eos/at_cmd.c
index 37de990..a1c329e 100644
--- a/fw/esp32/components/eos/at_cmd.c
+++ b/fw/esp32/components/eos/at_cmd.c
@@ -29,6 +29,9 @@ static SemaphoreHandle_t mutex;
 
 static char at_buf[EOS_CELL_UART_SIZE_BUF];
 
+/* should be used from net cell handlers only! */
+char at_cmd_buf[AT_SIZE_CMD_BUF];
+
 void at_init(void) {
     memset(&urc_list, 0, sizeof(ATURCList));
 
diff --git a/fw/esp32/components/eos/cell.c b/fw/esp32/components/eos/cell.c
index 2584884..d34172e 100644
--- a/fw/esp32/components/eos/cell.c
+++ b/fw/esp32/components/eos/cell.c
@@ -117,7 +117,7 @@ static void cell_handler(unsigned char type, unsigned char *buffer, uint16_t len
     xSemaphoreGive(mutex);
 
     if (buf == NULL) {
-        ESP_LOGE(TAG, "Cell message NOT handled: %2x", type);
+        if (len) ESP_LOGE(TAG, "Cell message NOT handled: %2x", buffer[0]);
         return;
     }
 
diff --git a/fw/esp32/components/eos/cell_modem.c b/fw/esp32/components/eos/cell_modem.c
index 26be56e..b279db1 100644
--- a/fw/esp32/components/eos/cell_modem.c
+++ b/fw/esp32/components/eos/cell_modem.c
@@ -64,9 +64,9 @@ static uint8_t RTC_NOINIT_ATTR uart_mode;
 static uint8_t uart_mode_next = EOS_CELL_UART_MODE_NONE;
 static SemaphoreHandle_t uart_mutex;
 
-static char ppp_apn[EOS_CELL_PDP_SIZE_APN];
-static char ppp_usr[EOS_CELL_PDP_SIZE_USR];
-static char ppp_pwd[EOS_CELL_PDP_SIZE_PWD];
+static char ppp_apn[EOS_CELL_PDP_SIZE_APN + 1];
+static char ppp_usr[EOS_CELL_PDP_SIZE_USR + 1];
+static char ppp_pwd[EOS_CELL_PDP_SIZE_PWD + 1];
 static SemaphoreHandle_t ppp_mutex;
 
 static ppp_pcb *ppp_handle;
@@ -150,7 +150,7 @@ static void uart_data_read(uint8_t mode) {
 
                 buf = eos_net_alloc();
                 buf[0] = EOS_CELL_MTYPE_DEV | EOS_CELL_MTYPE_UART_DATA;
-                _rd = eos_modem_read(buf + 1, MIN(bsize - rd, EOS_NET_MTU - 1), 100);
+                _rd = eos_modem_read(buf + 1, MIN(bsize - rd, EOS_NET_SIZE_BUF - 1), 100);
                 eos_net_send(EOS_NET_MTYPE_CELL, buf, _rd + 1);
                 rd += _rd;
             } while (rd != bsize);
@@ -594,7 +594,7 @@ static int ppp_resume(void) {
 
 static int ppp_setup(void) {
     int r;
-    char cmd[64];
+    char cmd[EOS_CELL_PDP_SIZE_APN + 32];
     int cmd_len;
 
     cmd_len = snprintf(cmd, sizeof(cmd), "AT+CGDCONT=1,\"IP\",\"%s\"\r", ppp_apn);
diff --git a/fw/esp32/components/eos/cell_pcm.c b/fw/esp32/components/eos/cell_pcm.c
index 0648be7..b993021 100644
--- a/fw/esp32/components/eos/cell_pcm.c
+++ b/fw/esp32/components/eos/cell_pcm.c
@@ -59,23 +59,42 @@ static void i2s_event_task(void *pvParameters) {
                     unsigned char _type;
                     unsigned char *buf;
 
+                    if (!pcm_active) {
+                        if (hold_buf) {
+                            eos_net_free(hold_buf);
+                            hold_buf = NULL;
+                        }
+                        break;
+                    }
+
                     // Event of I2S receiving data
                     if (!hold_cnt) {
-
                         buf = eos_net_alloc();
                         buf[0] = EOS_CELL_MTYPE_VOICE | EOS_CELL_MTYPE_VOICE_PCM;
                         bytes_r = eos_cell_pcm_read(buf + 1, PCM_MIC_WM);
+                        if (bytes_r < 0) {
+                            ESP_LOGE(TAG, "*** I2S READ ERROR ***");
+                            eos_net_free(buf);
+                            break;
+                        }
                         eos_net_send(EOS_NET_MTYPE_CELL, buf, bytes_r + 1);
                     } else {
-                        hold_cnt--;
                         if (hold_buf == NULL) {
                             hold_buf = eos_net_alloc();
                             hold_buf[0] = EOS_CELL_MTYPE_VOICE | EOS_CELL_MTYPE_VOICE_PCM;
+                            hold_bytes_r = 0;
+                        }
+                        if (1 + hold_bytes_r + PCM_MIC_WM <= EOS_NET_SIZE_BUF) {
+                            bytes_r = eos_cell_pcm_read(hold_buf + 1 + hold_bytes_r, PCM_MIC_WM);
+                            if (bytes_r < 0) {
+                                ESP_LOGE(TAG, "*** I2S READ ERROR ***");
+                                break;
+                            }
+                            hold_bytes_r += bytes_r;
                         }
-                        if (1 + hold_bytes_r + PCM_MIC_WM <= EOS_NET_MTU) hold_bytes_r += eos_cell_pcm_read(hold_buf + 1 + hold_bytes_r, PCM_MIC_WM);
+                        hold_cnt--;
                         if (hold_cnt == 0) {
                             eos_net_send(EOS_NET_MTYPE_CELL, hold_buf, hold_bytes_r + 1);
-                            hold_bytes_r = 0;
                             hold_buf = NULL;
                         }
                     }
@@ -87,10 +106,16 @@ static void i2s_event_task(void *pvParameters) {
                     xSemaphoreGive(mutex);
 
                     if (buf) {
-                        i2s_write(I2S_NUM_0, (const void *)buf, bytes_e, &bytes_w, portMAX_DELAY);
+                        esp_err_t ret;
+
+                        ret = i2s_write(I2S_NUM_0, (const void *)buf, bytes_e, &bytes_w, 1000 / portTICK_RATE_MS);
                         xSemaphoreTake(mutex, portMAX_DELAY);
                         eos_bufq_push(&pcm_buf_q, buf);
                         xSemaphoreGive(mutex);
+                        if (ret != ESP_OK) {
+                            ESP_LOGE(TAG, "*** I2S WRITE ERROR ***");
+                            break;
+                        }
                     }
                     break;
                 }
@@ -172,11 +197,12 @@ void eos_cell_pcm_init(void) {
 ssize_t eos_cell_pcm_read(unsigned char *data, size_t size) {
     static unsigned char buf[PCM_SIZE_BUF];
     size_t bytes_r;
+    esp_err_t ret;
     int i;
 
     if (size > PCM_MIC_WM) return EOS_ERR;
 
-    esp_err_t ret = i2s_read(I2S_NUM_0, (void *)buf, size * 4, &bytes_r, portMAX_DELAY);
+    ret = i2s_read(I2S_NUM_0, (void *)buf, size * 4, &bytes_r, 1000 / portTICK_RATE_MS);
     if (ret != ESP_OK) return EOS_ERR;
 
     for (i=0; i<size/2; i++) {
diff --git a/fw/esp32/components/eos/cell_pdp.c b/fw/esp32/components/eos/cell_pdp.c
index fc4739a..d04b66b 100644
--- a/fw/esp32/components/eos/cell_pdp.c
+++ b/fw/esp32/components/eos/cell_pdp.c
@@ -13,16 +13,14 @@ void eos_cell_pdp_handler(unsigned char mtype, unsigned char *buffer, uint16_t b
         case EOS_CELL_MTYPE_PDP_SET_USR:
         case EOS_CELL_MTYPE_PDP_SET_PWD: {
             char *arg;
-            size_t arg_len;
 
             buffer++;
             buf_len--;
 
             arg = (char *)buffer;
-            arg_len = strnlen(arg, buf_len);
-            if (arg_len == buf_len) break;
-            if (arg_len >= EOS_CELL_PDP_SIZE_ARG) break;
+            if (buf_len > EOS_CELL_PDP_SIZE_ARG) break;
 
+            buffer[buf_len] = '\0';
             switch (mtype) {
                 case EOS_CELL_MTYPE_PDP_SET_APN: {
                     eos_ppp_set_apn(arg);
@@ -66,7 +64,7 @@ void eos_cell_pdp_handler(unsigned char mtype, unsigned char *buffer, uint16_t b
                 }
             }
 
-            eos_net_reply(EOS_NET_MTYPE_CELL, buffer, 1 + strlen(arg));
+            eos_net_reply(EOS_NET_MTYPE_CELL, buffer, strlen(arg) + 1);
             break;
         }
 
diff --git a/fw/esp32/components/eos/cell_sms.c b/fw/esp32/components/eos/cell_sms.c
index ac710f9..f1f8b33 100644
--- a/fw/esp32/components/eos/cell_sms.c
+++ b/fw/esp32/components/eos/cell_sms.c
@@ -15,170 +15,213 @@
 
 static const char *TAG = "EOS SMS";
 
-static char cmd[256];
+static char _pdu_in[2048];
+static char _pdu_out[2048];
 
-static char pdu[4096];
-static int pdu_len;
+extern char *at_cmd_buf;
 
-static uint8_t udh[GSM_UDH_SIZE];
-static int udh_len;
+static ssize_t sms_encode(unsigned char *buffer, uint16_t buf_len, char *pdu, size_t pdu_size) {
+    ucp_t ch;
+    size_t pdu_len;
+    ssize_t rv;
+    int i;
 
-static uint8_t msg[GSM_MSG_SIZE];
-static int msg_len;
-static uint8_t msg_enc;
+    char *addr;
+    uint8_t addr_type;
+    size_t addr_len;
+
+    uint8_t txt[GSM_UD_SIZE];
+    size_t txt_len;
+
+    uint16_t flags;
+
+    if (buf_len < 2) return EOS_ERR_SIZE;
+    flags = buffer[0] << 8;
+    flags |= buffer[1];
+    buffer += 2;
+    buf_len -= 2;
+
+    if (buf_len < 2) return EOS_ERR_SIZE;
+    switch (buffer[0]) {
+        case EOS_CELL_SMS_ADDRTYPE_INTL:
+            addr_type = GSM_EXT | GSM_TON_INTERNATIONAL | GSM_NPI_TELEPHONE;
+            break;
+
+        case EOS_CELL_SMS_ADDRTYPE_OTHER:
+            addr_type = GSM_EXT | GSM_TON_UNKNOWN | GSM_NPI_TELEPHONE;
+            break;
+
+        default:
+            return EOS_ERR;
+    }
+    addr_len = buffer[1];
+    addr = (char *)buffer + 2;
 
-static char orig_addr[GSM_ADDR_SIZE];
-static int orig_addr_len;
-static uint8_t orig_addr_type;
+    if (buf_len < 2 + addr_len) return EOS_ERR_SIZE;
+    buffer += 2 + addr_len;
+    buf_len -= 2 + addr_len;
 
-static char smsc_addr[GSM_ADDR_SIZE];
-static int smsc_addr_len;
-static uint8_t smsc_addr_type;
+    i = 0;
+    txt_len = 0;
+    while (i < buf_len) {
+        int _rv;
+
+        if (buf_len - i < 4) {
+            _rv = utf8_len_str(buffer + i);
+            if (_rv < 0) return EOS_ERR;
+            if (buf_len - i < _rv) return EOS_ERR_SIZE;
+        }
 
-static char smsc_timestamp[GSM_TS_SIZE];
+        _rv = utf8_dec(buffer + i, &ch);
+        if (_rv < 0) return EOS_ERR;
+        if (ch >= 0xffff) return EOS_ERR;
+        i += _rv;
 
-uint16_t flags;
+        _rv = gsm_ucs2_to_7bit((char *)txt + txt_len, sizeof(txt) - txt_len, ch);
+        if (_rv < 0) return EOS_ERR;
+        txt_len += _rv;
+    }
+
+    if (pdu_size < 2) return EOS_ERR_SIZE;
+    pdu_putc(pdu, 0);
 
-static int sms_decode(unsigned char *buf, uint16_t *_len) {
-    int i, j, rv;
-    uint16_t len = 0;
-    uint8_t smsc_info, smsc_info_len;
+    rv = gsm_sms_enc(pdu + 2, pdu_size - 2, addr, addr_len, addr_type, NULL, 0, txt, txt_len, GSM_ENC_7BIT, flags);
+    if (rv < 0) return EOS_ERR;
+    pdu_len = rv + 2;
+
+    return pdu_len;
+}
 
-    if (pdu_len < 2) return EOS_ERR;
-    smsc_info = pdu_getc(pdu);
+static ssize_t sms_decode(char *pdu, size_t pdu_len, unsigned char *buf, uint16_t buf_size) {
+    uint16_t buf_len = 0;
+    ssize_t rv;
+    int i, j;
+
+    char smsc_addr[GSM_ADDR_SIZE];
+    size_t smsc_addr_len;
+    uint8_t smsc_info, smsc_info_len, smsc_addr_type;
+
+    char orig_addr[GSM_ADDR_SIZE];
+    size_t orig_addr_len;
+    uint8_t orig_addr_type;
+
+    uint8_t udh[GSM_UDH_SIZE];
+    size_t udh_len;
+
+    uint8_t txt[GSM_UD_SIZE];
+    size_t txt_len;
+    uint8_t txt_enc;
+
+    char smsc_timestamp[GSM_TS_SIZE];
+    uint16_t flags;
+
+    if (pdu_len < 2) return EOS_ERR_SIZE;
+    rv = pdu_getc(pdu, &smsc_info);
+    if (rv < 0) return rv;
     smsc_info_len = 2 * (smsc_info + 1);
-    if (pdu_len < smsc_info_len) return EOS_ERR;
+    if (pdu_len < smsc_info_len) return EOS_ERR_SIZE;
 
     if (smsc_info > 1) {
-        pdu_putc((smsc_info - 1) * 2, pdu);
+        /* SMSC address - currently not used */
+        pdu_putc(pdu, (smsc_info - 1) * 2);
         rv = gsm_addr_dec(pdu, pdu_len, smsc_addr, &smsc_addr_len, &smsc_addr_type);
         if (rv < 0) smsc_addr_len = 0;
     }
 
-    rv = gsm_sms_dec(pdu + smsc_info_len, pdu_len - smsc_info_len, orig_addr, &orig_addr_len, &orig_addr_type, udh, &udh_len, msg, &msg_len, smsc_timestamp, &msg_enc, &flags);
-    if (rv == GSM_ERR_NOT_SUPPORTED) ESP_LOGE(TAG, "Message not supported: %s", pdu);
-    if (rv < 0) return rv;
-    if (msg_enc == GSM_ENC_8BIT) return EOS_ERR;
+    rv = gsm_sms_dec(pdu + smsc_info_len, pdu_len - smsc_info_len, orig_addr, &orig_addr_len, &orig_addr_type, udh, &udh_len, txt, &txt_len, &txt_enc, smsc_timestamp, &flags);
+    if ((rv == GSM_ERR_NOTSUPPORTED) || (txt_enc == GSM_ENC_8BIT)) {
+        ESP_LOGE(TAG, "Message not supported: %s", pdu);
+        return EOS_ERR_NOTSUPPORTED;
+    }
+    if (rv < 0) return EOS_ERR;
 
+    if (buf_size < buf_len + 2) return EOS_ERR_SIZE;
     buf[0] = flags >> 8;
     buf[1] = flags;
-    len += 2;
+    buf_len += 2;
 
-    memcpy(buf + len, smsc_timestamp, GSM_TS_SIZE);
-    len += GSM_TS_SIZE;
+    if (buf_size < buf_len + GSM_TS_SIZE) return EOS_ERR_SIZE;
+    memcpy(buf + buf_len, smsc_timestamp, GSM_TS_SIZE);
+    buf_len += GSM_TS_SIZE;
 
     if ((orig_addr_type & GSM_TON) == GSM_TON_ALPHANUMERIC) {
-        buf[len] = EOS_CELL_SMS_ADDRTYPE_ALPHA;
-        buf[len + 1] = 0;
-        len += 2;
+        if (buf_size < buf_len + 2) return EOS_ERR_SIZE;
+        buf[buf_len] = EOS_CELL_SMS_ADDRTYPE_ALPHA;
+        buf[buf_len + 1] = 0;
+        buf_len += 2;
 
         i = 0;
         j = 0;
         while (i < orig_addr_len) {
             uint16_t ch;
+            int _rv;
 
-            rv = gsm_7bit_to_ucs2((char *)orig_addr + i, orig_addr_len - i, &ch);
-            if (rv < 0) return EOS_ERR;
-            i += rv;
-            rv = utf8_enc(ch, buf + len + j);
-            if (rv < 0) return EOS_ERR;
-            j += rv;
+            _rv = gsm_7bit_to_ucs2((char *)orig_addr + i, orig_addr_len - i, &ch);
+            if (_rv < 0) return EOS_ERR;
+            i += _rv;
+
+            if (buf_size - buf_len - j < 4) {
+                _rv = utf8_len_ch(ch);
+                if (_rv < 0) return EOS_ERR;
+                if (buf_size - buf_len - j < _rv) return EOS_ERR_SIZE;
+            }
+
+            _rv = utf8_enc(ch, buf + buf_len + j);
+            if (_rv < 0) return EOS_ERR;
+            j += _rv;
         }
-        buf[len - 1] = j;
-        len += j;
+        buf[buf_len - 1] = j;
+        buf_len += j;
     } else {
-        buf[len] = ((orig_addr_type & GSM_TON) == GSM_TON_INTERNATIONAL) ? EOS_CELL_SMS_ADDRTYPE_INTL : EOS_CELL_SMS_ADDRTYPE_OTHER;
-        buf[len + 1] = orig_addr_len;
-        len += 2;
-        memcpy(buf + len, orig_addr, orig_addr_len);
-        len += orig_addr_len;
+        if (buf_size < buf_len + 2) return EOS_ERR_SIZE;
+        buf[buf_len] = ((orig_addr_type & GSM_TON) == GSM_TON_INTERNATIONAL) ? EOS_CELL_SMS_ADDRTYPE_INTL : EOS_CELL_SMS_ADDRTYPE_OTHER;
+        buf[buf_len + 1] = orig_addr_len;
+        buf_len += 2;
+
+        if (buf_size < buf_len + orig_addr_len) return EOS_ERR_SIZE;
+        memcpy(buf + buf_len, orig_addr, orig_addr_len);
+        buf_len += orig_addr_len;
     }
 
     i = 0;
     j = 0;
-    while (i < msg_len) {
-        utf32_t ch;
+    while (i < txt_len) {
+        ucp_t ch;
+        int _rv;
 
-        if (msg_enc == GSM_ENC_7BIT) {
+        if (txt_enc == GSM_ENC_7BIT) {
             uint16_t _ch;
 
-            rv = gsm_7bit_to_ucs2((char *)msg + i, msg_len - i, &_ch);
+            _rv = gsm_7bit_to_ucs2((char *)txt + i, txt_len - i, &_ch);
+            if (_rv < 0) return EOS_ERR;
             ch = _ch;
         } else {
-            if (((msg_len - i) < 4) && (utf16_len(msg + i) > 2)) {
-                rv = EOS_ERR;
-            } else {
-                rv = utf16_dec(msg + i, &ch);
+            if (txt_len - i < 2) return EOS_ERR_SIZE;
+            if (txt_len - i < 4) {
+                _rv = utf16_len_str(txt + i);
+                if (_rv < 0) return EOS_ERR;
+                if (txt_len - i < _rv) return EOS_ERR_SIZE;
             }
+            _rv = utf16_dec(txt + i, &ch);
+            if (_rv < 0) return EOS_ERR;
         }
-        if (rv < 0) return EOS_ERR;
-        i += rv;
+        i += _rv;
 
-        rv = utf8_enc(ch, buf + len + j);
-        if (rv < 0) return EOS_ERR;
-        j += rv;
-    }
-    buf[len + j] = '\0';
-    len += j + 1;
-    *_len = len;
-
-    return EOS_OK;
-}
-
-static int sms_encode(unsigned char *buffer, uint16_t len) {
-    utf32_t ch;
-    int i, rv;
-    char *addr;
-    uint8_t addr_type;
-    int addr_len;
-
-    if (len < 2) return EOS_ERR;
-    flags = buffer[0] << 8;
-    flags |= buffer[1];
-    buffer += 2;
-    len -= 2;
-
-    if (len < 2) return EOS_ERR;
-    switch (buffer[0]) {
-        case EOS_CELL_SMS_ADDRTYPE_INTL:
-            addr_type = GSM_EXT | GSM_TON_INTERNATIONAL | GSM_NPI_TELEPHONE;
-            break;
-
-        case EOS_CELL_SMS_ADDRTYPE_OTHER:
-            addr_type = GSM_EXT | GSM_TON_UNKNOWN | GSM_NPI_TELEPHONE;
-            break;
-
-        default:
-            return EOS_ERR;
-    }
-    addr_len = buffer[1];
-    addr = (char *)buffer + 2;
-
-    if (len < 2 + addr_len) return EOS_ERR;
-    buffer += 2 + addr_len;
-    len -= 2 + addr_len;
-
-    i = 0;
-    msg_len = 0;
-    while (i < len) {
-        rv = utf8_dec(buffer + i, &ch);
-        if (rv < 0) return EOS_ERR;
-        if (ch >= 0xffff) return EOS_ERR;
-        i += rv;
+        if (buf_size - buf_len - j < 4) {
+            _rv = utf8_len_ch(ch);
+            if (_rv < 0) return EOS_ERR;
+            if (buf_size - buf_len - j < _rv) return EOS_ERR_SIZE;
+        }
 
-        rv = gsm_ucs2_to_7bit(ch, (char *)msg + msg_len, sizeof(msg) - msg_len);
-        if (rv < 0) return EOS_ERR;
-        msg_len += rv;
+        _rv = utf8_enc(ch, buf + buf_len + j);
+        if (_rv < 0) return EOS_ERR;
+        j += _rv;
     }
+    if (buf_size < buf_len + j + 1) return EOS_ERR_SIZE;
+    buf[buf_len + j] = '\0';
+    buf_len += j + 1;
 
-    pdu_putc(0, pdu);
-    rv = gsm_sms_enc(addr, addr_len, addr_type, NULL, 0, msg, msg_len, GSM_ENC_7BIT, flags, pdu + 2, sizeof(pdu) - 4);
-    if (rv < 0) return EOS_ERR;
-    pdu_len = rv;
-    pdu[pdu_len + 2] = CTRL_Z;
-    pdu[pdu_len + 3] = '\0';
-
-    return EOS_OK;
+    return buf_len;
 }
 
 void eos_cell_sms_handler(unsigned char mtype, unsigned char *buffer, uint16_t buf_len) {
@@ -190,34 +233,40 @@ void eos_cell_sms_handler(unsigned char mtype, unsigned char *buffer, uint16_t b
         case EOS_CELL_MTYPE_SMS_LIST: {
             if (buf_len < 1) return;
 
-            rv = snprintf(cmd, sizeof(cmd), "AT+CMGL=%d\r", buffer[0]);
-            if ((rv < 0) || (rv >= sizeof(cmd))) return;
+            rv = snprintf(at_cmd_buf, AT_SIZE_CMD_BUF, "AT+CMGL=%d\r", buffer[0]);
+            if ((rv < 0) || (rv >= AT_SIZE_CMD_BUF)) return;
 
             rv = eos_modem_take(1000);
             if (rv) return;
 
-            at_cmd(cmd);
+            at_cmd(at_cmd_buf);
             do {
                 unsigned char *buf;
-                uint16_t len;
+                uint16_t buf_len;
+
+                char *pdu = _pdu_in;
+                size_t pdu_size = sizeof(_pdu_in);
+                size_t pdu_len;
+                ssize_t _rv;
 
                 rv = at_expect("^\\+CMGL: [0-9]+,[0-9],.*,[0-9]+$", "^OK", 1000);
                 if (rv) break;
 
-                rv = eos_modem_readln(pdu, sizeof(pdu), 1000);
+                rv = eos_modem_readln(pdu, pdu_size, 1000);
                 if (rv) break;
 
                 pdu_len = strlen(pdu);
 
                 buf = eos_net_alloc();
                 buf[0] = EOS_CELL_MTYPE_SMS | EOS_CELL_MTYPE_SMS_LIST_ITEM;
-                rv = sms_decode(buf + 1, &len);
-                if (rv) {
+                _rv = sms_decode(pdu, pdu_len, buf + 1, EOS_NET_SIZE_BUF - 1);
+                if (_rv < 0) {
                     eos_net_free(buf);
                     continue;
                 }
 
-                eos_net_send(EOS_NET_MTYPE_CELL, buf, len + 1);
+                buf_len = _rv;
+                eos_net_send(EOS_NET_MTYPE_CELL, buf, buf_len + 1);
             } while (1);
 
             eos_modem_give();
@@ -227,16 +276,26 @@ void eos_cell_sms_handler(unsigned char mtype, unsigned char *buffer, uint16_t b
         case EOS_CELL_MTYPE_SMS_MSG: {
             char b[4];
 
-            rv = sms_encode(buffer, buf_len);
-            if (rv) return;
+            char *pdu = _pdu_in;
+            size_t pdu_size = sizeof(_pdu_in);
+            size_t pdu_len;
+            ssize_t _rv;
+
+            _rv = sms_encode(buffer, buf_len, pdu, pdu_size);
+            if (_rv < 0) return;
 
-            rv = snprintf(cmd, sizeof(cmd), "AT+CMGS=%d\r", pdu_len / 2);
-            if ((rv < 0) || (rv >= sizeof(cmd))) return;
+            pdu_len = _rv;
+            if (pdu_size < pdu_len + 2) return;
+            pdu[pdu_len] = CTRL_Z;
+            pdu[pdu_len + 1] = '\0';
+
+            rv = snprintf(at_cmd_buf, AT_SIZE_CMD_BUF, "AT+CMGS=%d\r", pdu_len / 2);
+            if ((rv < 0) || (rv >= AT_SIZE_CMD_BUF)) return;
 
             rv = eos_modem_take(1000);
             if (rv) return;
 
-            at_cmd(cmd);
+            at_cmd(at_cmd_buf);
             // wait for: '> ' (0d 0a 3e 20)
             eos_modem_read(b, 4, 1000);
             at_cmd(pdu);
@@ -250,10 +309,16 @@ void eos_cell_sms_handler(unsigned char mtype, unsigned char *buffer, uint16_t b
 }
 
 static void sms_received_handler(char *urc, regmatch_t m[]) {
+    char cmd[32];
     unsigned char *buf;
-    uint16_t len;
+    uint16_t buf_len;
     int ref, rv;
 
+    char *pdu = _pdu_out;
+    size_t pdu_size = sizeof(_pdu_out);
+    size_t pdu_len;
+    ssize_t _rv;
+
     sscanf(urc + m[1].rm_so, "%d", &ref);
 
     rv = snprintf(cmd, sizeof(cmd), "AT+CMGR=%d\r", ref);
@@ -264,7 +329,7 @@ static void sms_received_handler(char *urc, regmatch_t m[]) {
     rv = at_expect("^\\+CMGR: [0-9],.*,[0-9]+$", "^ERROR", 1000);
     if (rv) return;
 
-    rv = eos_modem_readln(pdu, sizeof(pdu), 1000);
+    rv = eos_modem_readln(pdu, pdu_size, 1000);
     if (rv) return;
 
     pdu_len = strlen(pdu);
@@ -273,13 +338,14 @@ static void sms_received_handler(char *urc, regmatch_t m[]) {
 
     buf = eos_net_alloc();
     buf[0] = EOS_CELL_MTYPE_SMS | EOS_CELL_MTYPE_SMS_MSG;
-    rv = sms_decode(buf + 1, &len);
-    if (rv) {
+    _rv = sms_decode(pdu, pdu_len, buf + 1, EOS_NET_SIZE_BUF - 1);
+    if (_rv < 0) {
         eos_net_free(buf);
         return;
     }
 
-    eos_net_send(EOS_NET_MTYPE_CELL, buf, len + 1);
+    buf_len = _rv;
+    eos_net_send(EOS_NET_MTYPE_CELL, buf, buf_len + 1);
 }
 
 void eos_cell_sms_init(void) {
diff --git a/fw/esp32/components/eos/cell_ussd.c b/fw/esp32/components/eos/cell_ussd.c
index 976fd51..375025f 100644
--- a/fw/esp32/components/eos/cell_ussd.c
+++ b/fw/esp32/components/eos/cell_ussd.c
@@ -11,8 +11,7 @@
 
 static const char *TAG = "EOS USSD";
 
-static char cmd[256];
-static int cmd_len;
+extern char *at_cmd_buf;
 
 void eos_cell_ussd_handler(unsigned char mtype, unsigned char *buffer, uint16_t buf_len) {
     int rv;
@@ -21,16 +20,16 @@ void eos_cell_ussd_handler(unsigned char mtype, unsigned char *buffer, uint16_t
     buf_len--;
     switch (mtype) {
         case EOS_CELL_MTYPE_USSD_REQUEST: {
-            if (buf_len > EOS_CELL_MAX_USSD_STR) return;
+            if (buf_len > EOS_CELL_USSD_SIZE_REQ) return;
 
             buffer[buf_len] = '\0';
-            cmd_len = snprintf(cmd, sizeof(cmd), "AT+CUSD=1,\"%s\",15\r", buffer);
-            if ((cmd_len < 0) || (cmd_len >= sizeof(cmd))) return;
+            rv = snprintf(at_cmd_buf, AT_SIZE_CMD_BUF, "AT+CUSD=1,\"%s\",15\r", buffer);
+            if ((rv < 0) || (rv >= AT_SIZE_CMD_BUF)) return;
 
             rv = eos_modem_take(1000);
             if (rv) return;
 
-            at_cmd(cmd);
+            at_cmd(at_cmd_buf);
             rv = at_expect("^OK", "^ERROR", 1000);
 
             eos_modem_give();
@@ -56,11 +55,6 @@ static void ussd_reply_handler(char *urc, regmatch_t m[]) {
     uint16_t len;
     char *_buf;
     size_t _len;
-    regex_t re;
-    regmatch_t match[2];
-
-    rv = regcomp(&re, ".*(\",[0-9]+)$", REG_EXTENDED);
-    if (rv) return;
 
     sscanf(urc + m[1].rm_so, "%1d", &rep);
 
@@ -69,15 +63,27 @@ static void ussd_reply_handler(char *urc, regmatch_t m[]) {
     buf[1] = rep;
     len = 2;
 
-    rv = EOS_OK;
+    if (m[2].rm_so == -1) {
+        eos_net_send(EOS_NET_MTYPE_CELL, buf, len);
+        return;
+    }
+
     _buf = (char *)buf + len;
-    strcpy(_buf, urc + m[2].rm_so);
+    _len = m[2].rm_eo - m[2].rm_so - 2;
+    if (_len > EOS_NET_SIZE_BUF - len) {
+        eos_net_free(buf);
+        return;
+    }
+    memcpy(_buf, urc + m[2].rm_so + 2, _len);
+    len += _len;
+
+    rv = EOS_OK;
     do {
-        if (regexec(&re, _buf, 2, match, 0) == 0) {
-            ESP_LOGI(TAG, "MATCH:%ld %s", match[1].rm_so, _buf);
-            _buf[match[1].rm_so] = '\0';
-            _len = strlen(_buf);
-            len += _len + 1;
+        char *end;
+
+        end = strchr(_buf, '"');
+        if (end) {
+            len += end - _buf;
             break;
         } else {
             _len = strlen(_buf);
@@ -85,20 +91,19 @@ static void ussd_reply_handler(char *urc, regmatch_t m[]) {
             _buf += _len + 1;
             len += _len + 1;
         }
-        rv = eos_modem_readln(_buf, EOS_NET_MTU - len, 1000);
+        rv = eos_modem_readln(_buf, EOS_NET_SIZE_BUF - len, 1000);
         if (rv) break;
     } while (1);
 
     if (rv) {
         ESP_LOGE(TAG, "error");
         eos_net_free(buf);
-    } else {
-        eos_net_send(EOS_NET_MTYPE_CELL, buf, len);
+        return;
     }
-    regfree(&re);
+
+    eos_net_send(EOS_NET_MTYPE_CELL, buf, len);
 }
 
 void eos_cell_ussd_init(void) {
-    at_urc_insert("\\+CUSD: ([0-9]),\"(.*)", ussd_reply_handler, REG_EXTENDED);
-
-}
\ No newline at end of file
+    at_urc_insert("^\\+CUSD: ([0-9])(,\".*)?", ussd_reply_handler, REG_EXTENDED);
+}
diff --git a/fw/esp32/components/eos/cell_voice.c b/fw/esp32/components/eos/cell_voice.c
index 7a9b823..2a7bb18 100644
--- a/fw/esp32/components/eos/cell_voice.c
+++ b/fw/esp32/components/eos/cell_voice.c
@@ -13,8 +13,7 @@
 #include "at_cmd.h"
 #include "cell.h"
 
-static char cmd[256];
-static int cmd_len;
+extern char *at_cmd_buf;
 
 void eos_cell_voice_handler(unsigned char mtype, unsigned char *buffer, uint16_t buf_len) {
     int rv;
@@ -23,17 +22,17 @@ void eos_cell_voice_handler(unsigned char mtype, unsigned char *buffer, uint16_t
     buf_len--;
     switch (mtype) {
         case EOS_CELL_MTYPE_VOICE_DIAL: {
-            if (buf_len > EOS_CELL_MAX_DIAL_STR) return;
+            if (buf_len > EOS_CELL_SIZE_PHNUM) return;
 
             buffer[buf_len] = '\0';
-            cmd_len = snprintf(cmd, sizeof(cmd), "ATD%s;\r", buffer);
-            if ((cmd_len < 0) || (cmd_len >= sizeof(cmd))) return;
+            rv = snprintf(at_cmd_buf, AT_SIZE_CMD_BUF, "ATD%s;\r", buffer);
+            if ((rv < 0) || (rv >= AT_SIZE_CMD_BUF)) return;
 
             rv = eos_modem_take(1000);
             if (rv) return;
 
-            at_cmd(cmd);
-            rv = at_expect("^OK", "^ERROR", 1000);
+            at_cmd(at_cmd_buf);
+            rv = at_expect("^OK", "^(ERROR|\\+CME ERROR: [0-9]+)", 1000);
 
             eos_modem_give();
             eos_cell_pcm_start();
@@ -45,7 +44,7 @@ void eos_cell_voice_handler(unsigned char mtype, unsigned char *buffer, uint16_t
             if (rv) return;
 
             at_cmd("ATA\r");
-            rv = at_expect("^OK", "^NO CARRIER", 1000);
+            // Response will be picked up by urc handler
 
             eos_modem_give();
             eos_cell_pcm_start();
@@ -59,7 +58,7 @@ void eos_cell_voice_handler(unsigned char mtype, unsigned char *buffer, uint16_t
             if (rv) return;
 
             at_cmd("AT+CHUP\r");
-            rv = at_expect("^OK", "^ERROR", 1000);
+            // Response will be picked up by urc handler
 
             eos_modem_give();
             break;
@@ -87,7 +86,7 @@ static void ring_handler(char *urc, regmatch_t m[]) {
         regoff_t num_len;
 
         num_len = match[1].rm_eo - match[1].rm_so;
-        if (num_len > EOS_CELL_MAX_DIAL_STR) {
+        if (num_len > EOS_CELL_SIZE_PHNUM) {
             eos_net_free(buf);
             return;
         }
@@ -124,10 +123,6 @@ static void miss_handler(char *urc, regmatch_t m[]) {
 static void call_begin_handler(char *urc, regmatch_t m[]) {
     unsigned char *buf;
 
-    buf = eos_net_alloc();
-    buf[0] = EOS_CELL_MTYPE_VOICE | EOS_CELL_MTYPE_VOICE_BEGIN;
-    eos_net_send(EOS_NET_MTYPE_CELL, buf, 1);
-
     vTaskDelay(100 / portTICK_PERIOD_MS);
     at_cmd("AT+CECH=0x0000\r");
     at_expect("^OK", "^ERROR", 1000);
@@ -144,6 +139,10 @@ static void call_begin_handler(char *urc, regmatch_t m[]) {
     at_cmd("AT+CECRX=0\r");
     at_expect("^OK", "^ERROR", 1000);
     */
+
+    buf = eos_net_alloc();
+    buf[0] = EOS_CELL_MTYPE_VOICE | EOS_CELL_MTYPE_VOICE_BEGIN;
+    eos_net_send(EOS_NET_MTYPE_CELL, buf, 1);
 }
 
 static void call_end_handler(char *urc, regmatch_t m[]) {
diff --git a/fw/esp32/components/eos/gsm.c b/fw/esp32/components/eos/gsm.c
index 920e121..551dc2c 100644
--- a/fw/esp32/components/eos/gsm.c
+++ b/fw/esp32/components/eos/gsm.c
@@ -1,36 +1,30 @@
-#include <stdlib.h>
-#include <string.h>
 #include <stdio.h>
 
 #include "gsm.h"
 
 #define DIVC(x,y)                   ((x) / (y) + ((x) % (y) != 0))
 
-uint8_t pdu_getc(char *pdu) {
-    int ch;
-
-    sscanf(pdu, "%2X", &ch);
-    return ch;
-}
-
-void pdu_putc(uint8_t ch, char *pdu) {
+size_t pdu_putc(char *pdu, uint8_t ch) {
     char b[3];
 
     sprintf(b, "%.2X", ch);
     *pdu = b[0];
     *(pdu + 1) = b[1];
+
+    return 2;
 }
 
-void pdu_gets(char *pdu, uint8_t *s, int s_len) {
-    int i, ch;
+ssize_t pdu_getc(char *pdu, uint8_t *ch) {
+    int rv, _ch;
 
-    for (i=0; i<s_len; i++) {
-        sscanf(pdu + 2 * i, "%2X", &ch);
-        s[i] = ch;
-    }
+    rv = sscanf(pdu, "%2X", &_ch);
+    if (rv != 1) return GSM_ERR;
+
+    *ch = _ch;
+    return 2;
 }
 
-void pdu_puts(uint8_t *s, int s_len, char *pdu) {
+size_t pdu_puts(char *pdu, uint8_t *s, size_t s_len) {
     int i;
     char b[3];
 
@@ -39,6 +33,108 @@ void pdu_puts(uint8_t *s, int s_len, char *pdu) {
         *(pdu + 2 * i) = b[0];
         *(pdu + 2 * i + 1) = b[1];
     }
+
+    return s_len * 2;
+}
+
+ssize_t pdu_gets(char *pdu, uint8_t *s, size_t s_len) {
+    int i, rv, _ch;
+
+    for (i=0; i<s_len; i++) {
+        rv = sscanf(pdu + 2 * i, "%2X", &_ch);
+        if (rv != 1) return GSM_ERR;
+        s[i] = _ch;
+    }
+
+    return s_len * 2;
+}
+
+size_t pdu_7bit_enc(char *pdu, char *text, size_t text_len, int padb) {
+    uint8_t carry = 0;
+    size_t pdu_len = 0;
+    int i = 0, shc = 0;
+
+    if (!text_len) return 0;
+
+    if (padb) {
+        shc = 7 - padb;
+    } else {
+        carry = *text;
+        i++;
+    }
+
+    while (i < text_len) {
+        pdu_putc(pdu + pdu_len, carry | (*(text + i) << (7 - shc)));
+        pdu_len += 2;
+
+        shc++;
+        shc = shc % 7;
+        if (!shc) {
+            i++;
+            if (i == text_len) return pdu_len;
+        }
+
+        carry = *(text + i) >> shc;
+        i++;
+    }
+    pdu_putc(pdu + pdu_len, carry);
+    pdu_len += 2;
+
+    return pdu_len;
+}
+
+ssize_t pdu_7bit_dec(char *pdu, char *text, size_t text_len, int padb) {
+    uint8_t ch;
+    uint8_t carry = 0;
+    int i = 0, shc = 0;
+    size_t pdu_len = 0;
+    ssize_t rv;
+
+    if (!text_len) return 0;
+
+    if (padb) {
+        rv = pdu_getc(pdu, &ch);
+        if (rv < 0) return rv;
+        pdu_len += 2;
+
+        if (padb == 1) {
+            *text = ch >> 1;
+            i++;
+        } else {
+            carry = ch >> padb;
+            shc = 8 - padb;
+        }
+    }
+
+    while (i < text_len) {
+        rv = pdu_getc(pdu + pdu_len, &ch);
+        if (rv < 0) return rv;
+        pdu_len += 2;
+
+        *(text + i) = ((ch << shc) | carry) & 0x7f;
+        carry = ch >> (7 - shc);
+        i++;
+
+        shc++;
+        shc = shc % 7;
+        if (!shc && (i < text_len)) {
+            *(text + i) = carry;
+            carry = 0;
+            i++;
+        }
+    }
+
+    return pdu_len;
+}
+
+void gsm_dcs_enc(uint8_t enc, uint16_t flags, uint8_t *dcs) {
+    *dcs = enc;
+    if (flags & GSM_FLAG_CLASS) {
+        *dcs |= GSM_DCS_CLASS_IND;
+        *dcs |= (flags >> 8) & GSM_DCS_CLASS;
+    }
+    if (flags & GSM_FLAG_COMPRESS) *dcs |= GSM_DCS_COMPRESS_IND;
+    if (flags & GSM_FLAG_DELETE) *dcs |= GSM_DCS_DELETE_IND;
 }
 
 void gsm_dcs_dec(uint8_t dcs, uint8_t *enc, uint16_t *flags) {
@@ -78,17 +174,7 @@ void gsm_dcs_dec(uint8_t dcs, uint8_t *enc, uint16_t *flags) {
     }
 }
 
-void gsm_dcs_enc(uint8_t enc, uint16_t flags, uint8_t *dcs) {
-    *dcs = enc;
-    if (flags & GSM_FLAG_CLASS) {
-        *dcs |= GSM_DCS_CLASS_IND;
-        *dcs |= (flags >> 8) & GSM_DCS_CLASS;
-    }
-    if (flags & GSM_FLAG_COMPRESS) *dcs |= GSM_DCS_COMPRESS_IND;
-    if (flags & GSM_FLAG_DELETE) *dcs |= GSM_DCS_DELETE_IND;
-}
-
-int gsm_ts_enc(char *ts, char *pdu, int pdu_size) {
+ssize_t gsm_ts_enc(char *pdu, size_t pdu_size, char *ts) {
     uint8_t tz;
     int tz_hh, tz_mm;
 
@@ -117,13 +203,14 @@ int gsm_ts_enc(char *ts, char *pdu, int pdu_size) {
     tz = (tz / 10) | ((tz % 10) << 4);
     if (ts[19] == '-') tz |= 0x08;
 
-    pdu_putc(tz, pdu + 12);
+    pdu_putc(pdu + 12, tz);
 
     return 14;
 }
 
-int gsm_ts_dec(char *pdu, int pdu_len, char *ts) {
+ssize_t gsm_ts_dec(char *pdu, size_t pdu_len, char *ts) {
     uint8_t tz;
+    ssize_t rv;
 
     if (pdu_len < 14) return GSM_ERR_SIZE;
 
@@ -147,7 +234,9 @@ int gsm_ts_dec(char *pdu, int pdu_len, char *ts) {
     ts[17] = pdu[11];   // ss
     ts[18] = pdu[10];
 
-    tz = pdu_getc(pdu + 12);
+    rv = pdu_getc(pdu + 12, &tz);
+    if (rv < 0) return rv;
+
     if (tz & 0x08) {
         ts[19] = '-';
         tz = tz & ~0x08;
@@ -160,80 +249,8 @@ int gsm_ts_dec(char *pdu, int pdu_len, char *ts) {
     return 14;
 }
 
-int gsm_7bit_enc(char *text, int text_len, char *pdu, int padb) {
-    uint8_t carry = 0;
-    int i = 0, pdu_len = 0, shc = 0;
-
-    if (!text_len) return 0;
-
-    if (padb) {
-        shc = 7 - padb;
-    } else {
-        carry = *text;
-        i++;
-    }
-
-    while (i < text_len) {
-        pdu_putc(carry | (*(text + i) << (7 - shc)), pdu + pdu_len);
-        pdu_len += 2;
-
-        shc++;
-        shc = shc % 7;
-        if (!shc) {
-            i++;
-            if (i == text_len) return pdu_len;
-        }
-
-        carry = *(text + i) >> shc;
-        i++;
-    }
-    pdu_putc(carry, pdu + pdu_len);
-    pdu_len += 2;
-
-    return pdu_len;
-}
-
-int gsm_7bit_dec(char *pdu, char *text, int text_len, int padb) {
-    uint8_t ch;
-    uint8_t carry = 0;
-    int i = 0, pdu_len = 0, shc = 0;
-
-    if (!text_len) return 0;
-
-    if (padb) {
-        ch = pdu_getc(pdu);
-        pdu_len += 2;
-        if (padb == 1) {
-            *text = ch >> 1;
-            i++;
-        } else {
-            carry = ch >> padb;
-            shc = 8 - padb;
-        }
-    }
-
-    while (i < text_len) {
-        ch = pdu_getc(pdu + pdu_len);
-        pdu_len += 2;
-
-        *(text + i) = ((ch << shc) | carry) & 0x7f;
-        carry = ch >> (7 - shc);
-        i++;
-
-        shc++;
-        shc = shc % 7;
-        if (!shc && (i < text_len)) {
-            *(text + i) = carry;
-            carry = 0;
-            i++;
-        }
-    }
-
-    return pdu_len;
-}
-
-int gsm_addr_enc(char *addr, int addr_len, uint8_t addr_type, char *pdu, int pdu_size) {
-    int _pdu_len;
+ssize_t gsm_addr_enc(char *pdu, size_t pdu_size, char *addr, size_t addr_len, uint8_t addr_type) {
+    size_t _pdu_len;
 
     addr_type |= GSM_EXT;
 
@@ -243,17 +260,17 @@ int gsm_addr_enc(char *addr, int addr_len, uint8_t addr_type, char *pdu, int pdu
         _pdu_len = 4 + DIVC(_addr_len, 2) * 2;
         if (pdu_size < _pdu_len) return GSM_ERR_SIZE;
 
-        pdu_putc(_addr_len, pdu);
-        pdu_putc(addr_type, pdu + 2);
-        gsm_7bit_enc(addr, addr_len, pdu, 0);
+        pdu_putc(pdu, _addr_len);
+        pdu_putc(pdu + 2, addr_type);
+        pdu_7bit_enc(pdu + 4, addr, addr_len, 0);
     } else {
         int i;
 
         _pdu_len = 4 + DIVC(addr_len, 2) * 2;
         if (pdu_size < _pdu_len) return GSM_ERR_SIZE;
 
-        pdu_putc(addr_len, pdu);
-        pdu_putc(addr_type, pdu + 2);
+        pdu_putc(pdu, addr_len);
+        pdu_putc(pdu + 2, addr_type);
         for (i=0; i<addr_len / 2; i++) {
             pdu[4 + 2 * i] = addr[2 * i + 1];
             pdu[4 + 2 * i + 1] = addr[2 * i];
@@ -267,16 +284,22 @@ int gsm_addr_enc(char *addr, int addr_len, uint8_t addr_type, char *pdu, int pdu
     return _pdu_len;
 }
 
-int gsm_addr_dec(char *pdu, int pdu_len, char *addr, int *addr_len, uint8_t *addr_type) {
-    int _pdu_len;
+ssize_t gsm_addr_dec(char *pdu, size_t pdu_len, char *addr, size_t *addr_len, uint8_t *addr_type) {
+    uint8_t pdu_ch;
+    size_t _pdu_len;
+    ssize_t rv;
 
     if (pdu_len < 4) return GSM_ERR_SIZE;
 
-    *addr_len = pdu_getc(pdu);
-    *addr_type = pdu_getc(pdu + 2);
+    rv = pdu_getc(pdu, &pdu_ch);
+    if (rv < 0) return rv;
+    rv = pdu_getc(pdu + 2, addr_type);
+    if (rv < 0) return rv;
+
+    *addr_len = pdu_ch;
     if (*addr_len > GSM_ADDR_SIZE) return GSM_ERR_SIZE;
 
-    if (!(*addr_type & GSM_EXT)) return GSM_ERR;
+    if (!(*addr_type & GSM_EXT)) return GSM_ERR_NOTSUPPORTED;
 
     _pdu_len = 4 + DIVC(*addr_len, 2) * 2;
     if (pdu_len < _pdu_len) return GSM_ERR_SIZE;
@@ -284,7 +307,8 @@ int gsm_addr_dec(char *pdu, int pdu_len, char *addr, int *addr_len, uint8_t *add
     if ((*addr_type & GSM_TON) == GSM_TON_ALPHANUMERIC) {
         *addr_len = (*addr_len * 4) / 7;
 
-        gsm_7bit_dec(pdu + 4, addr, *addr_len, 0);
+        rv = pdu_7bit_dec(pdu + 4, addr, *addr_len, 0);
+        if (rv < 0) return rv;
     } else {
         int i;
 
@@ -300,13 +324,14 @@ int gsm_addr_dec(char *pdu, int pdu_len, char *addr, int *addr_len, uint8_t *add
     return _pdu_len;
 }
 
-int gsm_sms_enc(char *addr, int addr_len, uint8_t addr_type, uint8_t *udh, int udh_len, uint8_t *msg, int msg_len, uint8_t enc, uint16_t flags, char *pdu, int pdu_size) {
-    int rv, _pdu_len = 0;
+ssize_t gsm_sms_enc(char *pdu, size_t pdu_size, char *addr, size_t addr_len, uint8_t addr_type, uint8_t *udh, size_t udh_len, uint8_t *txt, size_t txt_len, uint8_t enc, uint16_t flags) {
+    size_t _pdu_len = 0;
     uint8_t mti;
     uint8_t mr;
     uint8_t pid;
     uint8_t dcs;
     uint8_t udl;
+    ssize_t rv;
 
     mti = GSM_MTI_SUBMIT;
     if (udh_len) mti |= GSM_UDHI;
@@ -315,11 +340,11 @@ int gsm_sms_enc(char *addr, int addr_len, uint8_t addr_type, uint8_t *udh, int u
     mr = 0;
 
     if (pdu_size < 4) return GSM_ERR_SIZE;
-    pdu_putc(mti, pdu);
-    pdu_putc(mr, pdu + 2);
+    pdu_putc(pdu, mti);
+    pdu_putc(pdu + 2, mr);
     _pdu_len += 4;
 
-    rv = gsm_addr_enc(addr, addr_len, addr_type, pdu + _pdu_len, pdu_size - _pdu_len);
+    rv = gsm_addr_enc(pdu + _pdu_len, pdu_size - _pdu_len, addr, addr_len, addr_type);
     if (rv < 0) return rv;
     _pdu_len += rv;
 
@@ -329,10 +354,10 @@ int gsm_sms_enc(char *addr, int addr_len, uint8_t addr_type, uint8_t *udh, int u
     } else {
         pid = GSM_PID_DEFAULT;
     }
-    pid = 37;
-    pdu_putc(pid, pdu + _pdu_len);
     gsm_dcs_enc(enc, flags, &dcs);
-    pdu_putc(dcs, pdu + _pdu_len + 2);
+
+    pdu_putc(pdu + _pdu_len, pid);
+    pdu_putc(pdu + _pdu_len + 2, dcs);
     _pdu_len += 4;
 
     if (enc == GSM_ENC_7BIT) {
@@ -343,55 +368,57 @@ int gsm_sms_enc(char *addr, int addr_len, uint8_t addr_type, uint8_t *udh, int u
             udh_blen = 8 * (udh_len + 1);
             padb = DIVC(udh_blen, 7) * 7 - udh_blen;
         }
-        udl = DIVC(udh_blen, 7) + msg_len;
+        udl = DIVC(udh_blen, 7) + txt_len;
 
         if (pdu_size < _pdu_len + (DIVC(udl * 7, 8) + 1) * 2) return GSM_ERR_SIZE;
-        pdu_putc(udl, pdu + _pdu_len);
+        pdu_putc(pdu + _pdu_len, udl);
         _pdu_len += 2;
 
         if (udh_len) {
-            pdu_putc(udh_len, pdu + _pdu_len);
-            pdu_puts(udh, udh_len, pdu + _pdu_len + 2);
+            pdu_putc(pdu + _pdu_len, udh_len);
+            pdu_puts(pdu + _pdu_len + 2, udh, udh_len);
             _pdu_len += (udh_len + 1) * 2;
         }
 
-        rv = gsm_7bit_enc((char *)msg, msg_len, pdu + _pdu_len, padb);
+        rv = pdu_7bit_enc(pdu + _pdu_len, (char *)txt, txt_len, padb);
         if (rv < 0) return rv;
         _pdu_len += rv;
     } else {
-        udl = msg_len + (udh_len ? udh_len + 1 : 0);
+        udl = txt_len + (udh_len ? udh_len + 1 : 0);
 
         if (pdu_size < _pdu_len + (udl + 1) * 2) return GSM_ERR_SIZE;
-        pdu_putc(udl, pdu + _pdu_len);
+        pdu_putc(pdu + _pdu_len, udl);
         _pdu_len += 2;
 
         if (udh_len) {
-            pdu_putc(udh_len, pdu + _pdu_len);
-            pdu_puts(udh, udh_len, pdu + _pdu_len + 2);
+            pdu_putc(pdu + _pdu_len, udh_len);
+            pdu_puts(pdu + _pdu_len + 2, udh, udh_len);
             _pdu_len += (udh_len + 1) * 2;
         }
 
-        pdu_puts(msg, msg_len, pdu + _pdu_len);
-        _pdu_len += msg_len * 2;
+        pdu_puts(pdu + _pdu_len, txt, txt_len);
+        _pdu_len += txt_len * 2;
     }
 
     return _pdu_len;
 }
 
-int gsm_sms_dec(char *pdu, int pdu_len, char *addr, int *addr_len, uint8_t *addr_type, uint8_t *udh, int *udh_len, uint8_t *msg, int *msg_len, char *ts, uint8_t *enc, uint16_t *flags) {
-    int rv, _pdu_len = 0;
+ssize_t gsm_sms_dec(char *pdu, size_t pdu_len, char *addr, size_t *addr_len, uint8_t *addr_type, uint8_t *udh, size_t *udh_len, uint8_t *txt, size_t *txt_len, uint8_t *enc, char *ts, uint16_t *flags) {
+    size_t _pdu_len = 0;
     uint8_t mti;
     uint8_t pid;
     uint8_t dcs;
     uint8_t udl;
+    ssize_t rv;
 
     *enc = 0xff;
     *flags = 0;
     if (pdu_len < 2) return GSM_ERR_SIZE;
-    mti = pdu_getc(pdu);
+    rv = pdu_getc(pdu, &mti);
+    if (rv < 0) return rv;
     _pdu_len += 2;
 
-    if ((mti & GSM_MTI) != GSM_MTI_DELIVER) return GSM_ERR_NOT_SUPPORTED;
+    if ((mti & GSM_MTI) != GSM_MTI_DELIVER) return GSM_ERR_NOTSUPPORTED;
     if (mti & GSM_SRI) *flags |= GSM_FLAG_STATUS_REPORT;
     if (mti & GSM_RP) *flags |= GSM_FLAG_REPLY_PATH;
 
@@ -400,13 +427,15 @@ int gsm_sms_dec(char *pdu, int pdu_len, char *addr, int *addr_len, uint8_t *addr
     _pdu_len += rv;
 
     if (pdu_len < _pdu_len + 4) return GSM_ERR_SIZE;
-    pid = pdu_getc(pdu + _pdu_len);
+    rv = pdu_getc(pdu + _pdu_len, &pid);
+    if (rv < 0) return rv;
     if (pid == GSM_PID_TYPE0) {
         *flags |= GSM_FLAG_TYPE0;
     } else if (pid != GSM_PID_DEFAULT) {
-        return GSM_ERR_NOT_SUPPORTED;
+        return GSM_ERR_NOTSUPPORTED;
     }
-    dcs = pdu_getc(pdu + _pdu_len + 2);
+    rv = pdu_getc(pdu + _pdu_len + 2, &dcs);
+    if (rv < 0) return rv;
     gsm_dcs_dec(dcs, enc, flags);
     _pdu_len += 4;
 
@@ -415,7 +444,8 @@ int gsm_sms_dec(char *pdu, int pdu_len, char *addr, int *addr_len, uint8_t *addr
     _pdu_len += rv;
 
     if (pdu_len < _pdu_len + 2) return GSM_ERR_SIZE;
-    udl = pdu_getc(pdu + _pdu_len);
+    rv = pdu_getc(pdu + _pdu_len, &udl);
+    if (rv < 0) return rv;
     _pdu_len += 2;
 
     if ((mti & GSM_UDHI) && (udl == 0)) return GSM_ERR;
@@ -428,46 +458,58 @@ int gsm_sms_dec(char *pdu, int pdu_len, char *addr, int *addr_len, uint8_t *addr
         if (pdu_len < _pdu_len + DIVC(udl * 7, 8) * 2) return GSM_ERR_SIZE;
 
         if (mti & GSM_UDHI) {
-            *udh_len = pdu_getc(pdu + _pdu_len);
+            uint8_t pdu_ch;
+
+            rv = pdu_getc(pdu + _pdu_len, &pdu_ch);
+            if (rv < 0) return rv;
+
+            *udh_len = pdu_ch;
             udh_blen = 8 * (*udh_len + 1);
             padb = DIVC(udh_blen, 7) * 7 - udh_blen;
 
             if (udl * 7 < udh_blen) return GSM_ERR;
             if (*udh_len > GSM_UDH_SIZE) return GSM_ERR_SIZE;
 
-            pdu_gets(pdu + _pdu_len + 2, udh, *udh_len);
+            rv = pdu_gets(pdu + _pdu_len + 2, udh, *udh_len);
+            if (rv < 0) return rv;
             _pdu_len += (*udh_len + 1) * 2;
         } else {
             *udh_len = 0;
         }
 
-        *msg_len = udl - DIVC(udh_blen, 7);
-        if (*msg_len > GSM_UD_SIZE) return GSM_ERR_SIZE;
+        *txt_len = udl - DIVC(udh_blen, 7);
+        if (*txt_len > GSM_UD_SIZE) return GSM_ERR_SIZE;
 
-        rv = gsm_7bit_dec(pdu + _pdu_len, (char *)msg, *msg_len, padb);
+        rv = pdu_7bit_dec(pdu + _pdu_len, (char *)txt, *txt_len, padb);
         if (rv < 0) return rv;
         _pdu_len += rv;
     } else {
         if (pdu_len < _pdu_len + udl * 2) return GSM_ERR_SIZE;
 
         if (mti & GSM_UDHI) {
-            *udh_len = pdu_getc(pdu + _pdu_len);
+            uint8_t pdu_ch;
 
+            rv = pdu_getc(pdu + _pdu_len, &pdu_ch);
+            if (rv < 0) return rv;
+
+            *udh_len = pdu_ch;
             if (udl < *udh_len + 1) return GSM_ERR;
             if (*udh_len > GSM_UDH_SIZE) return GSM_ERR_SIZE;
 
-            pdu_gets(pdu + _pdu_len + 2, udh, *udh_len);
+            rv = pdu_gets(pdu + _pdu_len + 2, udh, *udh_len);
+            if (rv < 0) return rv;
             _pdu_len += (*udh_len + 1) * 2;
         } else {
             *udh_len = 0;
         }
 
-        *msg_len = udl - (*udh_len ? *udh_len + 1 : 0);
-        if (*msg_len > GSM_UD_SIZE) return GSM_ERR_SIZE;
-        if ((*enc == GSM_ENC_UCS2) && ((*msg_len % 2) != 0)) return GSM_ERR;
+        *txt_len = udl - (*udh_len ? *udh_len + 1 : 0);
+        if (*txt_len > GSM_UD_SIZE) return GSM_ERR_SIZE;
+        if ((*enc == GSM_ENC_UCS2) && ((*txt_len % 2) != 0)) return GSM_ERR;
 
-        pdu_gets(pdu + _pdu_len, msg, *msg_len);
-        _pdu_len += *msg_len * 2;
+        rv = pdu_gets(pdu + _pdu_len, txt, *txt_len);
+        if (rv < 0) return rv;
+        _pdu_len += *txt_len * 2;
     }
 
     return _pdu_len;
diff --git a/fw/esp32/components/eos/gsm_cp.c b/fw/esp32/components/eos/gsm_cp.c
index 508aa54..5478a8f 100644
--- a/fw/esp32/components/eos/gsm_cp.c
+++ b/fw/esp32/components/eos/gsm_cp.c
@@ -1,5 +1,3 @@
-#include <stdint.h>
-
 #include "gsm.h"
 
 #define UCS2_SUPL_SIZE  11
@@ -60,9 +58,9 @@ static const uint16_t ucs2_to_gsm7_supl[UCS2_SUPL_SIZE][2] = {
     {0x20ac, 0x1b65}
 };
 
-int gsm_ucs2_to_7bit(uint16_t ucs2, char *gsm7, int gsm7_size) {
+int gsm_ucs2_to_7bit(char *gsm7, size_t gsm7_size, uint16_t ucs2) {
     uint16_t ch = 0xffff;
-    int ret = 0;
+    int rv = 0;
 
     if (gsm7_size < 1) return GSM_ERR_SIZE;
 
@@ -83,28 +81,28 @@ int gsm_ucs2_to_7bit(uint16_t ucs2, char *gsm7, int gsm7_size) {
         if (gsm7_size < 2) return GSM_ERR_SIZE;
         *gsm7 = 0x1b;
         gsm7++;
-        ret++;
+        rv++;
     }
     *gsm7 = ch & 0x7f;
-    ret++;
+    rv++;
 
-    return ret;
+    return rv;
 }
 
-int gsm_7bit_to_ucs2(char *gsm7, int gsm7_len, uint16_t *ucs2) {
-    int ret;
+int gsm_7bit_to_ucs2(char *gsm7, size_t gsm7_len, uint16_t *ucs2) {
+    int rv;
 
     if (gsm7_len < 1) return GSM_ERR_SIZE;
     if (*gsm7 != 0x1b) {
         *ucs2 = gsm7_to_ucs2[*gsm7 & 0x7f];
-        ret = 1;
+        rv = 1;
     } else {
         if (gsm7_len < 2) return GSM_ERR_SIZE;
         gsm7++;
-        ret = 2;
+        rv = 2;
         *ucs2 = gsm7e_to_ucs2[*gsm7 & 0x7f];
     }
     if (*ucs2 == 0xffff) return GSM_ERR;
 
-    return ret;
+    return rv;
 }
diff --git a/fw/esp32/components/eos/include/at_cmd.h b/fw/esp32/components/eos/include/at_cmd.h
index 2d0813e..9dd355b 100644
--- a/fw/esp32/components/eos/include/at_cmd.h
+++ b/fw/esp32/components/eos/include/at_cmd.h
@@ -6,6 +6,7 @@
 #define AT_SIZE_PATTERN     64
 
 #define AT_SIZE_URC_LIST    32
+#define AT_SIZE_CMD_BUF     256
 
 typedef void (*at_urc_cb_t) (char *, regmatch_t[]);
 
diff --git a/fw/esp32/components/eos/include/cell.h b/fw/esp32/components/eos/include/cell.h
index af2dda8..cb9f49c 100644
--- a/fw/esp32/components/eos/include/cell.h
+++ b/fw/esp32/components/eos/include/cell.h
@@ -55,19 +55,24 @@
 #define EOS_CELL_SMS_ADDRTYPE_ALPHA     2
 #define EOS_CELL_SMS_ADDRTYPE_OTHER     3
 
-#define EOS_CELL_PDP_SIZE_APN           64
-#define EOS_CELL_PDP_SIZE_USR           64
-#define EOS_CELL_PDP_SIZE_PWD           64
-#define EOS_CELL_PDP_SIZE_ARG           64
+#define EOS_CELL_SIZE_PHNUM             16
+
+#define EOS_CELL_SMS_SIZE_ADDR          20
+#define EOS_CELL_SMS_SIZE_TS            25
+#define EOS_CELL_SMS_SIZE_TXT           160
+
+#define EOS_CELL_USSD_SIZE_REQ          128
+
+#define EOS_CELL_PDP_SIZE_APN           63
+#define EOS_CELL_PDP_SIZE_USR           63
+#define EOS_CELL_PDP_SIZE_PWD           63
+#define EOS_CELL_PDP_SIZE_ARG           63
 
 #define EOS_CELL_UART_MODE_NONE         0
 #define EOS_CELL_UART_MODE_ATCMD        1
 #define EOS_CELL_UART_MODE_PPP          2
 #define EOS_CELL_UART_MODE_RELAY        3
 
-#define EOS_CELL_MAX_USSD_STR           128
-#define EOS_CELL_MAX_DIAL_STR           16
-
 #define EOS_CELL_UART_SIZE_BUF          1024
 
 void eos_cell_init(void);
diff --git a/fw/esp32/components/eos/include/eos.h b/fw/esp32/components/eos/include/eos.h
index 6f420ea..bc9dc51 100644
--- a/fw/esp32/components/eos/include/eos.h
+++ b/fw/esp32/components/eos/include/eos.h
@@ -3,9 +3,13 @@
 #define EOS_ERR_TIMEOUT             -2
 #define EOS_ERR_BUSY                -3
 
-#define EOS_ERR_FULL                -10
-#define EOS_ERR_EMPTY               -11
-#define EOS_ERR_NOTFOUND            -12
+#define EOS_ERR_SIZE                -10
+#define EOS_ERR_FULL                -11
+#define EOS_ERR_EMPTY               -12
+#define EOS_ERR_NOTFOUND            -13
+#define EOS_ERR_NOTSUPPORTED        -14
+
+#define EOS_ERR_NOMEM               -100
 
 #define EOS_TASK_PRIORITY_NET_XCHG  1
 #define EOS_TASK_PRIORITY_APP_XCHG  1
diff --git a/fw/esp32/components/eos/include/gsm.h b/fw/esp32/components/eos/include/gsm.h
index 7864b09..eb893d6 100644
--- a/fw/esp32/components/eos/include/gsm.h
+++ b/fw/esp32/components/eos/include/gsm.h
@@ -1,12 +1,14 @@
+#include <sys/types.h>
+#include <stdint.h>
+
 #define GSM_OK                      0
 #define GSM_ERR                     -1
 #define GSM_ERR_SIZE                -10
-#define GSM_ERR_NOT_SUPPORTED       -11
+#define GSM_ERR_NOTSUPPORTED        -11
 
 #define GSM_TS_SIZE                 25
 #define GSM_UD_SIZE                 160
 #define GSM_UDH_SIZE                140
-#define GSM_MSG_SIZE                GSM_UD_SIZE
 #define GSM_ADDR_SIZE               20
 
 /* Message-Type-Indicator */
@@ -124,16 +126,21 @@
 #define GSM_FLAG_MWI_OTHER          0x3000
 #define GSM_FLAG_MWI_MASK           0xf000
 
-uint8_t pdu_getc(char *pdu);
-void pdu_putc(uint8_t ch, char *pdu);
-void pdu_gets(char *pdu, uint8_t *s, int s_len);
-void pdu_puts(uint8_t *s, int s_len, char *pdu);
-int gsm_ucs2_to_7bit(uint16_t ucs2, char *gsm7, int gsm7_size);
-int gsm_7bit_to_ucs2(char *gsm7, int gsm7_len, uint16_t *ucs2);
-
-int gsm_7bit_enc(char *text, int text_len, char *pdu, int padb);
-int gsm_7bit_dec(char *pdu, char *text, int text_len, int padb);
-int gsm_addr_enc(char *addr, int addr_len, uint8_t addr_type, char *pdu, int pdu_size);
-int gsm_addr_dec(char *pdu, int pdu_len, char *addr, int *addr_len, uint8_t *addr_type);
-int gsm_sms_enc(char *addr, int addr_len, uint8_t addr_type, uint8_t *udh, int udh_len, uint8_t *msg, int msg_len, uint8_t enc, uint16_t flags, char *pdu, int pdu_size);
-int gsm_sms_dec(char *pdu, int pdu_len, char *addr, int *addr_len, uint8_t *addr_type, uint8_t *udh, int *udh_len, uint8_t *msg, int *msg_len, char *ts, uint8_t *enc, uint16_t *flags);
+size_t pdu_putc(char *pdu, uint8_t ch);
+ssize_t pdu_getc(char *pdu, uint8_t *ch);
+size_t pdu_puts(char *pdu, uint8_t *s, size_t s_len);
+ssize_t pdu_gets(char *pdu, uint8_t *s, size_t s_len);
+size_t pdu_7bit_enc(char *pdu, char *text, size_t text_len, int padb);
+ssize_t pdu_7bit_dec(char *pdu, char *text, size_t text_len, int padb);
+
+void gsm_dcs_enc(uint8_t enc, uint16_t flags, uint8_t *dcs);
+void gsm_dcs_dec(uint8_t dcs, uint8_t *enc, uint16_t *flags);
+ssize_t gsm_ts_enc(char *pdu, size_t pdu_size, char *ts);
+ssize_t gsm_ts_dec(char *pdu, size_t pdu_len, char *ts);
+int gsm_addr_enc(char *pdu, size_t pdu_size, char *addr, size_t addr_len, uint8_t addr_type);
+int gsm_addr_dec(char *pdu, size_t pdu_len, char *addr, size_t *addr_len, uint8_t *addr_type);
+int gsm_sms_enc(char *pdu, size_t pdu_size, char *addr, size_t addr_len, uint8_t addr_type, uint8_t *udh, size_t udh_len, uint8_t *txt, size_t txt_len, uint8_t enc, uint16_t flags);
+int gsm_sms_dec(char *pdu, size_t pdu_len, char *addr, size_t *addr_len, uint8_t *addr_type, uint8_t *udh, size_t *udh_len, uint8_t *txt, size_t *txt_len, uint8_t *enc, char *ts, uint16_t *flags);
+
+int gsm_ucs2_to_7bit(char *gsm7, size_t gsm7_size, uint16_t ucs2);
+int gsm_7bit_to_ucs2(char *gsm7, size_t gsm7_len, uint16_t *ucs2);
-- 
cgit v1.2.3