diff options
Diffstat (limited to 'fw/esp32/components/eos/cell_sms.c')
-rw-r--r-- | fw/esp32/components/eos/cell_sms.c | 268 |
1 files changed, 263 insertions, 5 deletions
diff --git a/fw/esp32/components/eos/cell_sms.c b/fw/esp32/components/eos/cell_sms.c index ef8a8c9..2648dc0 100644 --- a/fw/esp32/components/eos/cell_sms.c +++ b/fw/esp32/components/eos/cell_sms.c @@ -1,24 +1,282 @@ #include <stdlib.h> +#include <string.h> #include <stdio.h> #include <esp_log.h> #include "eos.h" +#include "net.h" +#include "unicode.h" +#include "gsm.h" +#include "at_cmd.h" #include "cell.h" +#define CTRL_Z 0x1a + +static const char *TAG = "EOS SMS"; + +static char cmd[256]; + +static char pdu[4096]; +static int pdu_len; + +static uint8_t udh[GSM_UDH_SIZE]; +static int udh_len; + +static uint8_t msg[GSM_MSG_SIZE]; +static int msg_len; +static uint8_t msg_enc; + +static char orig_addr[GSM_ADDR_SIZE]; +static int orig_addr_len; +static uint8_t orig_addr_type; + +static char smsc_addr[GSM_ADDR_SIZE]; +static int smsc_addr_len; +static uint8_t smsc_addr_type; + +static char smsc_timestamp[GSM_TS_SIZE]; + +uint16_t flags; + +static int sms_decode(unsigned char *buf, uint16_t *_len) { + int i, j, rv; + uint16_t len = 0; + uint8_t pid; + uint8_t smsc_info, smsc_info_len; + + if (pdu_len < 2) return GSM_ERR_SIZE; + smsc_info = pdu_getc(pdu); + smsc_info_len = 2 * (smsc_info + 1); + if (pdu_len < smsc_info_len) return GSM_ERR_SIZE; + + if (smsc_info > 1) { + pdu_putc((smsc_info - 1) * 2, pdu); + 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, &pid, orig_addr, &orig_addr_len, &orig_addr_type, udh, &udh_len, msg, &msg_len, smsc_timestamp, &msg_enc, &flags); + if (rv < 0) return rv; + if (msg_enc == GSM_ENC_8BIT) return EOS_ERR; + + buf[0] = flags; + len += 1; + + memcpy(buf + len, smsc_timestamp, GSM_TS_SIZE); + 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; + + i = 0; + j = 0; + while (i < orig_addr_len) { + uint16_t ch; + + 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; + } + buf[len - 1] = j; + 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; + } + + i = 0; + j = 0; + while (i < msg_len) { + utf32_t ch; + + if (msg_enc == GSM_ENC_7BIT) { + uint16_t _ch; + + rv = gsm_7bit_to_ucs2((char *)msg + i, msg_len - i, &_ch); + ch = _ch; + } else { + if (((msg_len - i) < 4) && (utf16_len(msg + i) > 2)) { + rv = EOS_ERR; + } else { + rv = utf16_dec(msg + 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; + } + buf[len + j] = '\0'; + + buf = buf + len; + printf("BODY: %s\n", buf); + /* + while (*buf) { + printf("%02x ", *buf); + buf++; + } + printf("\n"); + */ + + len += j + 1; + *_len = len; + + return EOS_OK; +} + +static int sms_encode(unsigned char *buffer, uint16_t size) { + utf32_t ch; + int i, rv; + char *addr; + uint8_t addr_type; + int addr_len; + + if (size == 0) return EOS_ERR; + + flags = buffer[0]; + buffer += 1; + size -= 1; + + if (size < 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 (size < 2 + addr_len) return EOS_ERR; + buffer += 2 + addr_len; + size -= 2 + addr_len; + + i = 0; + msg_len = 0; + while (i < size) { + rv = utf8_dec(buffer + i, &ch); + if (rv < 0) return EOS_ERR; + if (ch >= 0xffff) return EOS_ERR; + i += rv; + + rv = gsm_ucs2_to_7bit(ch, (char *)msg + msg_len, sizeof(msg) - msg_len); + if (rv < 0) return EOS_ERR; + msg_len += rv; + } + + pdu_putc(0, pdu); + rv = gsm_sms_enc(0, 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; +} void eos_cell_sms_handler(unsigned char mtype, unsigned char *buffer, uint16_t size) { int rv; - rv = eos_modem_take(1000); - if (rv) return; - buffer += 1; size -= 1; switch (mtype) { + case EOS_CELL_MTYPE_SMS_LIST: + if (size == 0) return; + snprintf(cmd, sizeof(cmd), "AT+CMGL=%d\r", buffer[0]); + + rv = eos_modem_take(1000); + if (rv) return; + at_cmd(cmd); + do { + unsigned char *buf; + uint16_t len; + + rv = at_expect("^\\+CMGL: [0-9]+,[0-9],.*,[0-9]+$", "^OK", 1000); + if (rv != 1) break; + + rv = eos_modem_readln(pdu, sizeof(pdu), 1000); + if (rv) break; + pdu_len = strlen(pdu); + + buf = eos_net_alloc(); + buf[0] = EOS_CELL_MTYPE_SMS | EOS_CELL_MTYPE_SMS_MSG_ITEM; + rv = sms_decode(buf + 1, &len); + if (rv) { + eos_net_free(buf); + } else { + len++; + eos_net_free(buf); + // eos_net_send(EOS_NET_MTYPE_CELL, buf, len); + } + } while (1); + eos_modem_give(); + + break; + + case EOS_CELL_MTYPE_SMS_SEND: + rv = sms_encode(buffer, size); + if (rv) return; + + snprintf(cmd, sizeof(cmd), "AT+CMGS=%d\r", pdu_len / 2); + + rv = eos_modem_take(1000); + if (rv) return; + at_cmd(cmd); + at_cmd(pdu); + rv = at_expect("^OK", "^ERROR", 1000); + eos_modem_give(); + + break; } +} - eos_modem_give(); +static void sms_received_handler(char *urc, regmatch_t m[]) { + int ref, rv; + + sscanf(urc + m[1].rm_so, "%6d", &ref); + + snprintf(cmd, sizeof(cmd), "AT+CMGR=%d\r", ref); + at_cmd(cmd); + + rv = at_expect("^\\+CMGR: [0-9],.*,[0-9]+$", "^ERROR", 1000); + if (rv == 1) { + unsigned char *buf; + uint16_t len; + + rv = eos_modem_readln(pdu, sizeof(pdu), 1000); + if (rv) return; + pdu_len = strlen(pdu); + + rv = at_expect("^OK", NULL, 1000); + + buf = eos_net_alloc(); + buf[0] = EOS_CELL_MTYPE_SMS | EOS_CELL_MTYPE_SMS_MSG_NEW; + rv = sms_decode(buf + 1, &len); + if (rv) { + eos_net_free(buf); + } else { + len++; + eos_net_send(EOS_NET_MTYPE_CELL, buf, len); + } + } } -void eos_cell_sms_init(void) {} +void eos_cell_sms_init(void) { + at_urc_insert("^\\+CMTI: .*,([0-9]+)$", sms_received_handler, REG_EXTENDED); +} |