summaryrefslogtreecommitdiff
path: root/code/esp32/components/eos/gsm.c
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/esp32/components/eos/gsm.c
parentba38183139e19d5e07a4f30822eb285dde9bd7ca (diff)
sms pdu mode impl added
Diffstat (limited to 'code/esp32/components/eos/gsm.c')
-rw-r--r--code/esp32/components/eos/gsm.c453
1 files changed, 453 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;
+}