summaryrefslogtreecommitdiff
path: root/code
diff options
context:
space:
mode:
authorUros Majstorovic <majstor@majstor.org>2020-08-05 03:10:01 +0200
committerUros Majstorovic <majstor@majstor.org>2020-08-05 03:10:01 +0200
commit9fcfdb87e3de42232544cf61d82cedc3661364cf (patch)
tree53e6b04f62f625a80dbe72a56916234b1c20e2f0 /code
parentba38183139e19d5e07a4f30822eb285dde9bd7ca (diff)
sms pdu mode impl added
Diffstat (limited to 'code')
-rw-r--r--code/esp32/components/eos/gsm.c453
-rw-r--r--code/esp32/components/eos/gsm_cp.c109
-rw-r--r--code/esp32/components/eos/include/gsm.h117
3 files changed, 679 insertions, 0 deletions
diff --git a/code/esp32/components/eos/gsm.c b/code/esp32/components/eos/gsm.c
new file mode 100644
index 0000000..788722e
--- /dev/null
+++ b/code/esp32/components/eos/gsm.c
@@ -0,0 +1,453 @@
+#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) {
+ sprintf(pdu, "%.2X", ch);
+}
+
+void pdu_puts(uint8_t *s, int s_len, char *pdu) {
+ int i;
+
+ for (i=0; i<s_len; i++) {
+ sprintf(pdu + 2 * i, "%.2X", s[i]);
+ }
+}
+
+void pdu_gets(char *pdu, uint8_t *s, int s_len) {
+ int i, ch;
+
+ for (i=0; i<s_len; i++) {
+ sscanf(pdu + 2 * i, "%2X", &ch);
+ s[i] = ch;
+ }
+}
+
+void gsm_dcs_dec(uint8_t dcs, uint8_t *enc, uint16_t *flags) {
+ if ((dcs & GSM_DCS_GENERAL_IND) == 0) {
+ *enc = dcs & GSM_DCS_ENC;
+ if (dcs & GSM_DCS_CLASS_IND) {
+ *flags |= GSM_FLAG_CLASS;
+ *flags |= (uint16_t)(dcs & GSM_DCS_CLASS) << 8;
+ }
+ if (dcs & GSM_DCS_COMPRESS_IND) *flags |= GSM_FLAG_COMPRESS;
+ if (dcs & GSM_DCS_DELETE_IND) *flags |= GSM_FLAG_DELETE;
+ } else {
+ uint8_t group = dcs & GSM_DCS_GROUP;
+
+ switch (group) {
+ case GSM_DCS_MWI_DISCARD:
+ case GSM_DCS_MWI_STORE_GSM7:
+ case GSM_DCS_MWI_STORE_UCS2:
+ if (group == GSM_DCS_MWI_STORE_UCS2) {
+ *enc = GSM_ENC_UCS2;
+ } else {
+ *enc = GSM_ENC_7BIT;
+ }
+ if (GSM_DCS_MWI_DISCARD) *flags |= GSM_FLAG_DISCARD;
+ *flags |= GSM_FLAG_MWI;
+ *flags |= (uint16_t)(dcs & (GSM_DCS_MWI_SENSE | GSM_DCS_MWI_TYPE)) << 12;
+ break;
+
+ case GSM_DCS_ENCLASS:
+ *flags |= GSM_FLAG_CLASS;
+ *flags |= (uint16_t)(dcs & GSM_DCS_CLASS) << 8;
+ *enc = dcs & GSM_DCS_ENCLASS_ENC ? GSM_ENC_8BIT : GSM_ENC_7BIT;
+ break;
+ }
+ }
+}
+
+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) {
+ uint8_t tz;
+ int tz_hh, tz_mm;
+
+ if (pdu_size < 14) return GSM_ERR;
+
+ pdu[1] = ts[2]; // YY
+ pdu[0] = ts[3];
+
+ pdu[3] = ts[5]; // MM
+ pdu[2] = ts[6];
+
+ pdu[5] = ts[8]; // DD
+ pdu[4] = ts[9];
+
+ pdu[7] = ts[11]; // hh
+ pdu[6] = ts[12];
+
+ pdu[9] = ts[14]; // mm
+ pdu[8] = ts[15];
+
+ pdu[11] = ts[17]; // ss
+ pdu[10] = ts[18];
+
+ sscanf(ts + 20, "%2d:%2d", &tz_hh, &tz_mm);
+ tz = tz_hh * 4 + tz_mm / 15;
+ tz = (tz / 10) | ((tz % 10) << 4);
+ if (ts[19] == '-') tz |= 0x08;
+
+ pdu_putc(tz, pdu + 12);
+
+ return 14;
+}
+
+int gsm_ts_dec(char *pdu, int pdu_len, char *ts) {
+ uint8_t tz;
+
+ if (pdu_len < 14) return GSM_ERR;
+
+ ts[0] = '2';
+ ts[1] = '0';
+ ts[2] = pdu[1]; // YY
+ ts[3] = pdu[0];
+ ts[4] = '-';
+ ts[5] = pdu[3]; // MM
+ ts[6] = pdu[2];
+ ts[7] = '-';
+ ts[8] = pdu[5]; // DD
+ ts[9] = pdu[4];
+ ts[10] = 'T';
+ ts[11] = pdu[7]; // hh
+ ts[12] = pdu[6];
+ ts[13] = ':';
+ ts[14] = pdu[9]; // mm
+ ts[15] = pdu[8];
+ ts[16] = ':';
+ ts[17] = pdu[11]; // ss
+ ts[18] = pdu[10];
+
+ tz = pdu_getc(pdu + 12);
+ if (tz & 0x08) {
+ ts[19] = '-';
+ tz = tz & ~0x08;
+ } else {
+ ts[19] = '+';
+ }
+ tz = (tz & 0x0f) * 10 + (tz >> 4);
+ sprintf(ts + 20, "%.2d:%.2d", tz / 4, (tz % 4) * 15);
+
+ 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;
+
+ addr_type |= GSM_EXT;
+
+ if ((addr_type & GSM_TON) == GSM_TON_ALPHANUMERIC) {
+ int _addr_len = DIVC(addr_len * 7, 4);
+
+ _pdu_len = 4 + DIVC(_addr_len, 2) * 2;
+ if (pdu_size < _pdu_len) return GSM_ERR;
+
+ pdu_putc(_addr_len, pdu);
+ pdu_putc(addr_type, pdu + 2);
+ gsm_7bit_enc(addr, addr_len, pdu, 0);
+ } else {
+ int i;
+
+ if (addr_type & GSM_TON_INTERNATIONAL) {
+ if (addr[0] != '+') return GSM_ERR;
+ addr++;
+ addr_len--;
+ }
+ _pdu_len = 4 + DIVC(addr_len, 2) * 2;
+ if (pdu_size < _pdu_len) return GSM_ERR;
+
+ pdu_putc(addr_len, pdu);
+ pdu_putc(addr_type, pdu + 2);
+ for (i=0; i<addr_len / 2; i++) {
+ pdu[4 + 2 * i] = addr[2 * i + 1];
+ pdu[4 + 2 * i + 1] = addr[2 * i];
+ }
+ if (addr_len % 2 != 0) {
+ pdu[4 + 2 * i] = 'F';
+ pdu[4 + 2 * i + 1] = addr[2 * i];
+ }
+ }
+
+ return _pdu_len;
+}
+
+int gsm_addr_dec(char *pdu, int pdu_len, char *addr, int addr_size, int *addr_len, uint8_t *addr_type) {
+ int _pdu_len;
+
+ if (pdu_len < 4) return GSM_ERR;
+
+ *addr_len = pdu_getc(pdu);
+ *addr_type = pdu_getc(pdu + 2);
+
+ if (!(*addr_type & GSM_EXT)) return GSM_ERR;
+
+ _pdu_len = 4 + DIVC(*addr_len, 2) * 2;
+ if (pdu_len < _pdu_len) return GSM_ERR;
+
+ if ((*addr_type & GSM_TON) == GSM_TON_ALPHANUMERIC) {
+ *addr_len = (*addr_len * 4) / 7;
+ if (addr_size < *addr_len) return GSM_ERR;
+
+ gsm_7bit_dec(pdu + 4, addr, *addr_len, 0);
+ } else {
+ int i;
+ int _addr_len = *addr_len;
+
+ if (*addr_type & GSM_TON_INTERNATIONAL) {
+ addr[0] = '+';
+ addr++;
+ (*addr_len)++;
+ }
+ if (addr_size < *addr_len) return GSM_ERR;
+
+ for (i=0; i<_addr_len / 2; i++) {
+ addr[2 * i] = pdu[4 + 2 * i + 1];
+ addr[2 * i + 1] = pdu[4 + 2 * i];
+ }
+ if (_addr_len % 2 != 0) {
+ addr[2 * i] = pdu[4 + 2 * i + 1];
+ }
+ }
+
+ return _pdu_len;
+}
+
+int gsm_sms_enc(uint8_t pid, 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;
+ uint8_t mti = GSM_MTI_SUBMIT;
+ uint8_t dcs = 0;
+ uint8_t udl;
+
+ if (udh_len) mti |= GSM_UDHI;
+
+ if (pdu_size < 4) return GSM_ERR;
+ pdu_putc(mti, pdu);
+ pdu_putc(00, pdu + 2);
+ _pdu_len += 4;
+
+ rv = gsm_addr_enc(addr, addr_len, addr_type, pdu + _pdu_len, pdu_size - _pdu_len);
+ if (rv < 0) return rv;
+ _pdu_len += rv;
+
+ if (pdu_size < _pdu_len + 4) return GSM_ERR;
+ gsm_dcs_enc(enc, flags, &dcs);
+ pdu_putc(pid, pdu + _pdu_len);
+ pdu_putc(dcs, pdu + _pdu_len + 2);
+ _pdu_len += 4;
+
+ if (enc == GSM_ENC_7BIT) {
+ int udh_blen = 0;
+ int padb = 0;
+
+ if (udh_len) {
+ udh_blen = 8 * (udh_len + 1);
+ padb = DIVC(udh_blen, 7) * 7 - udh_blen;
+ }
+ udl = DIVC(udh_blen, 7) + msg_len;
+
+ if (pdu_size < _pdu_len + (DIVC(udl * 7, 8) + 1) * 2) return GSM_ERR;
+ pdu_putc(udl, pdu + _pdu_len);
+ _pdu_len += 2;
+
+ if (udh_len) {
+ pdu_putc(udh_len, pdu + _pdu_len);
+ pdu_puts(udh, udh_len, pdu + _pdu_len + 2);
+ _pdu_len += (udh_len + 1) * 2;
+ }
+
+ rv = gsm_7bit_enc((char *)msg, msg_len, pdu + _pdu_len, padb);
+ if (rv < 0) return rv;
+ _pdu_len += rv;
+ } else {
+ udl = msg_len + (udh_len ? udh_len + 1 : 0);
+
+ if (pdu_size < _pdu_len + (udl + 1) * 2) return GSM_ERR;
+ pdu_putc(udl, pdu + _pdu_len);
+ _pdu_len += 2;
+
+ if (udh_len) {
+ pdu_putc(udh_len, pdu + _pdu_len);
+ pdu_puts(udh, udh_len, pdu + _pdu_len + 2);
+ _pdu_len += (udh_len + 1) * 2;
+ }
+
+ pdu_puts(msg, msg_len, pdu + _pdu_len);
+ _pdu_len += msg_len * 2;
+ }
+
+ return _pdu_len;
+}
+
+int gsm_sms_dec(char *pdu, int pdu_len, uint8_t *pid, char *addr, int addr_size, int *addr_len, uint8_t *addr_type, uint8_t *udh, int udh_size, int *udh_len, uint8_t *msg, int msg_size, int *msg_len, char *ts, uint8_t *enc, uint16_t *flags) {
+ int rv, _pdu_len = 0;
+ uint8_t mti;
+ uint8_t dcs;
+ uint8_t udl;
+
+ if (pdu_len < 2) return GSM_ERR;
+ mti = pdu_getc(pdu);
+ _pdu_len += 2;
+ if ((mti & GSM_MTI) != GSM_MTI_DELIVER) return GSM_ERR;
+
+ rv = gsm_addr_dec(pdu + _pdu_len, pdu_len - _pdu_len, addr, addr_size, addr_len, addr_type);
+ if (rv < 0) return rv;
+ _pdu_len += rv;
+
+ if (pdu_len < _pdu_len + 4) return GSM_ERR;
+ *pid = pdu_getc(pdu + _pdu_len);
+ dcs = pdu_getc(pdu + _pdu_len + 2);
+ _pdu_len += 4;
+ gsm_dcs_dec(dcs, enc, flags);
+
+ rv = gsm_ts_dec(pdu + _pdu_len, pdu_len - _pdu_len, ts);
+ if (rv < 0) return rv;
+ _pdu_len += rv;
+
+ if (pdu_len < _pdu_len + 2) return GSM_ERR;
+ udl = pdu_getc(pdu + _pdu_len);
+ _pdu_len += 2;
+
+ if ((mti & GSM_UDHI) && (udl == 0)) return GSM_ERR;
+ *udh_len = 0;
+
+ if (*enc == GSM_ENC_7BIT) {
+ int udh_blen = 0;
+ int padb = 0;
+
+ if (pdu_len < _pdu_len + DIVC(udl * 7, 8) * 2) return GSM_ERR;
+
+ if (mti & GSM_UDHI) {
+ *udh_len = pdu_getc(pdu + _pdu_len);
+ udh_blen = 8 * (*udh_len + 1);
+ padb = DIVC(udh_blen, 7) * 7 - udh_blen;
+
+ if (udl * 7 < udh_blen) return GSM_ERR;
+ if (udh_size < *udh_len) return GSM_ERR;
+
+ pdu_gets(pdu + _pdu_len + 2, udh, *udh_len);
+ _pdu_len += (*udh_len + 1) * 2;
+ } else {
+ *udh_len = 0;
+ }
+
+ *msg_len = udl - DIVC(udh_blen, 7);
+ if (msg_size < *msg_len) return GSM_ERR;
+
+ rv = gsm_7bit_dec(pdu + _pdu_len, (char *)msg, *msg_len, padb);
+ if (rv < 0) return rv;
+ _pdu_len += rv;
+ } else {
+ if (pdu_len < _pdu_len + udl * 2) return GSM_ERR;
+
+ if (mti & GSM_UDHI) {
+ *udh_len = pdu_getc(pdu + _pdu_len);
+
+ if (udl < *udh_len + 1) return GSM_ERR;
+ if (udh_size < *udh_len) return GSM_ERR;
+
+ pdu_gets(pdu + _pdu_len + 2, udh, *udh_len);
+ _pdu_len += (*udh_len + 1) * 2;
+ } else {
+ *udh_len = 0;
+ }
+
+ *msg_len = udl - (*udh_len ? *udh_len + 1 : 0);
+ if (msg_size < *msg_len) return GSM_ERR;
+
+ pdu_gets(pdu + _pdu_len, msg, *msg_len);
+ _pdu_len += *msg_len * 2;
+ }
+
+ return _pdu_len;
+}
diff --git a/code/esp32/components/eos/gsm_cp.c b/code/esp32/components/eos/gsm_cp.c
new file mode 100644
index 0000000..3ab98c5
--- /dev/null
+++ b/code/esp32/components/eos/gsm_cp.c
@@ -0,0 +1,109 @@
+#include <stdint.h>
+
+#include "gsm.h"
+
+#define UCS2_SUPL_SIZE 11
+
+static const uint16_t gsm7_to_ucs2[128] = {
+ 0x0040, 0x00a3, 0x0024, 0x00a5, 0x00e8, 0x00e9, 0x00f9, 0x00ec, 0x00f2, 0x00c7, 0x000a, 0x00d8, 0x00f8, 0x000d, 0x00c5, 0x00e5,
+ 0x0394, 0x005f, 0x03a6, 0x0393, 0x039b, 0x03a9, 0x03a0, 0x03a8, 0x03a3, 0x0398, 0x039e, 0x001b, 0x00c6, 0x00e6, 0x00df, 0x00c9,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x00a4, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
+ 0x00a1, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x00c4, 0x00d6, 0x00d1, 0x00dc, 0x00a7,
+ 0x00bf, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x00e4, 0x00f6, 0x00f1, 0x00fc, 0x00e0
+};
+
+static const uint16_t gsm7e_to_ucs2[128] = {
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x000c, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+ 0xffff, 0xffff, 0xffff, 0xffff, 0x005e, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x007b, 0x007d, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x005c,
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x005b, 0x007e, 0x005d, 0xffff,
+ 0x007c, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x20ac, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff
+};
+
+static const uint16_t ucs2_to_gsm7[256] = {
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x000a, 0xffff, 0x1b0a, 0x000d, 0xffff, 0xffff,
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x001b, 0xffff, 0xffff, 0xffff, 0xffff,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0002, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
+ 0x0000, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x1b3c, 0x1b2f, 0x1b3e, 0x1b14, 0x0011,
+ 0xffff, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x1b28, 0x1b40, 0x1b29, 0x1b3d, 0xffff,
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+ 0xffff, 0x0040, 0xffff, 0x0001, 0x0024, 0x0003, 0xffff, 0x005f, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x0060,
+ 0xffff, 0xffff, 0xffff, 0xffff, 0x005b, 0x000e, 0x001c, 0x0009, 0xffff, 0x001f, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+ 0xffff, 0x005d, 0xffff, 0xffff, 0xffff, 0xffff, 0x005c, 0xffff, 0x000b, 0xffff, 0xffff, 0xffff, 0x005e, 0xffff, 0xffff, 0x001e,
+ 0x007f, 0xffff, 0xffff, 0xffff, 0x007b, 0x000f, 0x001d, 0xffff, 0x0004, 0x0005, 0xffff, 0xffff, 0x0007, 0xffff, 0xffff, 0xffff,
+ 0xffff, 0x007d, 0x0008, 0xffff, 0xffff, 0xffff, 0x007c, 0xffff, 0x000c, 0x0006, 0xffff, 0xffff, 0x007e, 0xffff, 0xffff, 0xffff
+};
+
+static const uint16_t ucs2_to_gsm7_supl[UCS2_SUPL_SIZE][2] = {
+ {0x0394, 0x10},
+ {0x03a6, 0x12},
+ {0x0393, 0x13},
+ {0x039b, 0x14},
+ {0x03a9, 0x15},
+ {0x03a0, 0x16},
+ {0x03a8, 0x17},
+ {0x03a3, 0x18},
+ {0x0398, 0x19},
+ {0x039e, 0x1a},
+ {0x20ac, 0x1b65}
+};
+
+int gsm_ucs2_to_7bit(uint16_t ucs2, char *gsm7, int gsm7_size) {
+ uint16_t ch = 0xffff;
+ int ret = 0;
+
+ if (gsm7_size < 1) return GSM_ERR;
+
+ if (ucs2 < 256) {
+ ch = ucs2_to_gsm7[ucs2];
+ } else {
+ int i;
+
+ for (i=0; i<UCS2_SUPL_SIZE; i++) {
+ if (ucs2_to_gsm7_supl[i][0] == ucs2) {
+ ch = ucs2_to_gsm7_supl[i][1];
+ break;
+ }
+ }
+ }
+ if (ch == 0xffff) return GSM_ERR;
+ if (ch & 0xff00) {
+ if (gsm7_size < 2) return GSM_ERR;
+ *gsm7 = 0x1b;
+ gsm7++;
+ ret++;
+ }
+ *gsm7 = ch & 0x7f;
+ ret++;
+
+ return ret;
+}
+
+int gsm_7bit_to_ucs2(char *gsm7, int gsm7_len, uint16_t *ucs2) {
+ int ret;
+
+ if (gsm7_len < 1) return GSM_ERR;
+ if (*gsm7 != 0x1b) {
+ *ucs2 = gsm7_to_ucs2[*gsm7 & 0x7f];
+ ret = 1;
+ } else {
+ if (gsm7_len < 2) return GSM_ERR;
+ gsm7++;
+ ret = 2;
+ *ucs2 = gsm7e_to_ucs2[*gsm7 & 0x7f];
+ }
+ if (*ucs2 == 0xffff) return GSM_ERR;
+
+ return ret;
+}
diff --git a/code/esp32/components/eos/include/gsm.h b/code/esp32/components/eos/include/gsm.h
new file mode 100644
index 0000000..2c4f7b4
--- /dev/null
+++ b/code/esp32/components/eos/include/gsm.h
@@ -0,0 +1,117 @@
+#define GSM_OK 0
+#define GSM_ERR -1
+
+/* Message-Type-Indicator */
+#define GSM_MTI 0x03
+#define GSM_MTI_DELIVER 0x00
+#define GSM_MTI_DELIVER_REPORT 0x00
+#define GSM_MTI_SUBMIT 0x01
+#define GSM_MTI_SUBMIT_REPORT 0x01
+#define GSM_MTI_COMMAND 0x02
+#define GSM_MTI_COMMAND_REPORT 0x02
+
+#define GSM_MMS 0x04 /* More-Messages-to-Send */
+#define GSM_RD 0x04 /* Reject-Duplicates */
+#define GSM_LP 0x08 /* Loop-Prevention */
+
+/* Validity-Period-Format */
+#define GSM_VPF 0x18
+#define GSM_VPF_NONE 0x00
+#define GSM_VPF_ENHANCED 0x08
+#define GSM_VPF_RELATIVE 0x10
+#define GSM_VPF_ABSOLUTE 0x18
+
+#define GSM_SRI 0x20 /* Status-Report-Indication */
+#define GSM_SRR 0x20 /* Status-Report-Request */
+#define GSM_SRQ 0x20 /* Status-Report-Qualifier */
+#define GSM_UDHI 0x40 /* User-Data-Header-Indicator */
+#define GSM_RP 0x80 /* Reply-Path */
+
+/* Type-of-Number */
+#define GSM_TON 0x70
+#define GSM_TON_UNKNOWN 0x00
+#define GSM_TON_INTERNATIONAL 0x10
+#define GSM_TON_NATIONAL 0x20
+#define GSM_TON_NETWORK 0x30
+#define GSM_TON_SUBSCRIBER 0x40
+#define GSM_TON_ALPHANUMERIC 0x50
+#define GSM_TON_ABBRREVIATED 0x60
+
+/* Numbering-Plan-Identification */
+#define GSM_NPI 0x0f
+#define GSM_NPI_UNKNOWN 0x00
+#define GSM_NPI_TELEPHONE 0x01
+#define GSM_NPI_DATA 0x03
+#define GSM_NPI_TELEX 0x04
+#define GSM_NPI_SCS1 0x05
+#define GSM_NPI_SCS2 0x06
+#define GSM_NPI_NATIONAL 0x08
+#define GSM_NPI_PRIVATE 0x09
+#define GSM_NPI_ERMES 0x0a
+
+#define GSM_EXT 0x80
+
+/* Protocol-Identifier */
+#define GSM_PID_DEFAULT 0
+#define GSM_PID_TYPE0 64
+
+/* Data-Coding-Scheme */
+#define GSM_DCS_CLASS 0x03
+#define GSM_DCS_ENC 0x0c
+
+#define GSM_DCS_CLASS_IND 0x10
+#define GSM_DCS_COMPRESS_IND 0x20
+#define GSM_DCS_DELETE_IND 0x40
+#define GSM_DCS_GENERAL_IND 0x80
+#define GSM_DCS_GROUP 0xf0
+
+#define GSM_DCS_MWI_DISCARD 0xc0
+#define GSM_DCS_MWI_STORE_GSM7 0xd0
+#define GSM_DCS_MWI_STORE_UCS2 0xe0
+#define GSM_DCS_MWI_SENSE 0x08
+#define GSM_DCS_MWI_TYPE 0x03
+
+#define GSM_DCS_ENCLASS 0xf0
+#define GSM_DCS_ENCLASS_ENC 0x04
+
+/* Parameter-Indicator */
+#define GSM_PI_PID 0x01
+#define GSM_PI_DCS 0x02
+#define GSM_PI_UD 0x04
+#define GSM_PI_EXT 0x08
+
+/* character set */
+#define GSM_ENC_7BIT 0x00
+#define GSM_ENC_8BIT 0x04
+#define GSM_ENC_UCS2 0x08
+
+/* message waiting indication */
+#define GSM_MWI_TYPE_VOICEMAIL 0x00
+#define GSM_MWI_TYPE_FAX 0x01
+#define GSM_MWI_TYPE_EMAIL 0x02
+#define GSM_MWI_TYPE_OTHER 0x03
+
+/* flags */
+#define GSM_FLAG_COMPRESS 0x0001
+#define GSM_FLAG_DELETE 0x0002
+#define GSM_FLAG_DISCARD 0x0004
+
+/* message class */
+#define GSM_FLAG_CLASS 0x0400
+#define GSM_FLAG_CLASS0 0x0000 /* Flash */
+#define GSM_FLAG_CLASS1 0x0100 /* ME-specific */
+#define GSM_FLAG_CLASS2 0x0200 /* (U)SIM-specific */
+#define GSM_FLAG_CLASS4 0x0300 /* TE-specific */
+#define GSM_FLAG_CLASS_MASK 0x0f00
+
+/* message waiting indication */
+#define GSM_FLAG_MWI 0x4000
+#define GSM_FLAG_MWI_SENSE 0x8000
+#define GSM_FLAG_MWI_VOICEMAIL 0x0000
+#define GSM_FLAG_MWI_FAX 0x1000
+#define GSM_FLAG_MWI_EMAIL 0x2000
+#define GSM_FLAG_MWI_OTHER 0x3000
+#define GSM_FLAG_MWI_MASK 0xf000
+
+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);