diff options
Diffstat (limited to 'src/gsm')
-rw-r--r-- | src/gsm/gsm_utils.c | 118 |
1 files changed, 89 insertions, 29 deletions
diff --git a/src/gsm/gsm_utils.c b/src/gsm/gsm_utils.c index 5da713c2..6b9cadc4 100644 --- a/src/gsm/gsm_utils.c +++ b/src/gsm/gsm_utils.c @@ -73,28 +73,44 @@ static int gsm_septet_lookup(uint8_t ch) return -1; } +/* Compute the number of octets from the number of septets, for instance: 47 septets needs 41,125 = 42 octets */ +uint8_t gsm_get_octet_len(const uint8_t sept_len){ + int octet_len = (sept_len * 7) / 8; + if ((sept_len * 7) % 8 != 0) + octet_len++; + + return octet_len; +} + /* GSM 03.38 6.2.1 Character unpacking */ -int gsm_7bit_decode(char *text, const uint8_t *user_data, uint8_t length) +int gsm_7bit_decode_hdr(char *text, const uint8_t *user_data, uint8_t septet_l, uint8_t ud_hdr_ind) { int i = 0; - int l = 0; - int septet_l = (length * 8) / 7; + int shift = 0; + uint8_t *rtext = calloc(septet_l, sizeof(uint8_t)); uint8_t tmp; - /* FIXME: We need to account for user data headers here */ - i += l; - for (; i < septet_l; i++){ + /* skip the user data header */ + if (ud_hdr_ind) { + /* get user data header length + 1 (for the 'user data header length'-field) */ + shift = ((user_data[0] + 1) * 8) / 7; + if ((((user_data[0] + 1) * 8) % 7) != 0) + shift++; + septet_l = septet_l - shift; + } + + for (i = 0; i < septet_l; i++) { rtext[i] = - ((user_data[(i * 7 + 7) >> 3] << - (7 - ((i * 7 + 7) & 7))) | - (user_data[(i * 7) >> 3] >> - ((i * 7) & 7))) & 0x7f; + ((user_data[((i + shift) * 7 + 7) >> 3] << + (7 - (((i + shift) * 7 + 7) & 7))) | + (user_data[((i + shift) * 7) >> 3] >> + (((i + shift) * 7) & 7))) & 0x7f; } for(i = 0; i < septet_l; i++){ /* this is an extension character */ - if(rtext[i] == 0x1b && i + 1 < length){ + if(rtext[i] == 0x1b && i + 1 < septet_l){ tmp = rtext[i+1]; *(text++) = gsm_7bit_alphabet[0x7f + tmp]; i++; @@ -104,14 +120,21 @@ int gsm_7bit_decode(char *text, const uint8_t *user_data, uint8_t length) *(text++) = gsm_septet_lookup(rtext[i]); } + if (ud_hdr_ind) + i += shift; *text = '\0'; free(rtext); return i; } +int gsm_7bit_decode(char *text, const uint8_t *user_data, uint8_t septet_l) +{ + return gsm_7bit_decode_hdr(text, user_data, septet_l, 0); +} + /* GSM 03.38 6.2.1 Prepare character packing */ -static int gsm_septet_encode(uint8_t *result, const char *data) +int gsm_septet_encode(uint8_t *result, const char *data) { int i, y = 0; uint8_t ch; @@ -139,38 +162,75 @@ static int gsm_septet_encode(uint8_t *result, const char *data) return y; } -/* GSM 03.38 6.2.1 Character packing */ -int gsm_7bit_encode(uint8_t *result, const char *data) -{ - int i,y,z = 0; - /* prepare for the worst case, every character expanding to two bytes */ - uint8_t *rdata = calloc(strlen(data) * 2, sizeof(uint8_t)); +/* 7bit to octet packing */ +int gsm_septets2octets(uint8_t *result, uint8_t *rdata, uint8_t septet_len, uint8_t padding){ + int i = 0, z = 0; uint8_t cb, nb; int shift = 0; + uint8_t *data = calloc(septet_len + 1, sizeof(uint8_t)); - y = gsm_septet_encode(rdata, data); - - for(i = 0; i < y; i++) { - if(shift == 7 && i + 1 < y){ - shift = 0; - continue; + if (padding) { + shift = 7 - padding; + /* the first zero is needed for padding */ + memcpy(data + 1, rdata, septet_len); + septet_len++; + } else + memcpy(data, rdata, septet_len); + + for(i = 0; i < septet_len; i++) { + if (shift == 7) { + /* + * special end case with the. This is necessary if the + * last septet fits into the previous octet. E.g. 48 + * non-extension characters: + * ....ag ( a = 1100001, g = 1100111) + * result[40] = 100001 XX, result[41] = 1100111 1 */ + if (i + 1 < septet_len) { + shift = 0; + continue; + } else if (i + 1 == septet_len) + break; } - cb = (rdata[i] & 0x7f) >> shift; - if(i + 1 < y){ - nb = (rdata[i + 1] & 0x7f) << (7 - shift); + cb = (data[i] & 0x7f) >> shift; + if (i + 1 < septet_len) { + nb = (data[i + 1] & 0x7f) << (7 - shift); cb = cb | nb; } result[z++] = cb; - shift++; } - free(rdata); + free(data); + return z; } +/* GSM 03.38 6.2.1 Character packing */ +int gsm_7bit_encode(uint8_t *result, const char *data) +{ + int y = 0, z = 0; + /* prepare for the worst case, every character expanding to two bytes */ + uint8_t *rdata = calloc(strlen(data) * 2, sizeof(uint8_t)); + y = gsm_septet_encode(rdata, data); + z = gsm_septets2octets(result, rdata, y, 0); + + free(rdata); + + /* + * We don't care about the number of octets (z), because they are not + * unique. E.g.: + * 1.) 46 non-extension characters + 1 extension character + * => (46 * 7 bit + (1 * (2 * 7 bit))) / 8 bit = 42 octets + * 2.) 47 non-extension characters + * => (47 * 7 bit) / 8 bit = 41,125 = 42 octets + * 3.) 48 non-extension characters + * => (48 * 7 bit) / 8 bit = 42 octects + */ + return y; +} + /* convert power class to dBm according to GSM TS 05.05 */ unsigned int ms_class_gmsk_dbm(enum gsm_band band, int class) { |