Skip to content

Instantly share code, notes, and snippets.

@jbrzozoski
Last active December 6, 2020 05:28
Show Gist options
  • Save jbrzozoski/376b32bfe4eed2f4a49418600abc44ed to your computer and use it in GitHub Desktop.
Save jbrzozoski/376b32bfe4eed2f4a49418600abc44ed to your computer and use it in GitHub Desktop.
GSM Time to Unix
#include <stdint.h>
#include <stdio.h>
#include <time.h>
#ifndef TM_YEAR_BASE
#define TM_YEAR_BASE 1900
#endif
#ifndef GSM_YEAR_BASE
#define GSM_YEAR_BASE 2000
#endif
#define GSM_MINUTES_PER_TZ_OFFSET 15
#ifndef SECSPERMINUTE
#define SECSPERMINUTE 60
#endif
static uint8_t decode_ascii_hex_char(char x)
{
if (x >= 'a')
{
// Shift to uppercase (-0x20)
// Remove gap from '9' to 'A' (-7)
// Remove '0' offset (-0x30)
return (x - (0x20 + 0x07 + 0x30));
}
if (x >= 'A')
{
// Remove gap from '9' to 'A' (-7)
// Remove '0' offset (-0x30)
return (x - (0x07 + 0x30));
}
// Remove '0' offset (-0x30)
return (x - (0x30));
}
time_t scts_to_unix(struct tm *dest, const uint8_t *src)
{
// We've been given a time as a 14-character (7-byte) ASCII/binary-coded-decimal string, in this format:
// https://en.wikipedia.org/wiki/GSM_03.40#Time_Format
// NOTE: This function doesn't require the time string be null-terminated, and will only look at the 14-bytes
// We want to convert it to a POSIX struct tm
uint16_t gsm_year;
uint8_t gsm_month;
uint8_t gsm_day;
uint8_t gsm_hour;
uint8_t gsm_minute;
uint8_t gsm_second;
uint8_t temp_decode;
int8_t gsm_timezone;
struct tm tm_struct;
time_t timezone_offset;
if (dest == NULL)
{
return -1;
}
gsm_year = decode_ascii_hex_char(src[0]) + (decode_ascii_hex_char(src[1]) * 10) + GSM_YEAR_BASE;
gsm_month = decode_ascii_hex_char(src[2]) + (decode_ascii_hex_char(src[3]) * 10);
gsm_day = decode_ascii_hex_char(src[4]) + (decode_ascii_hex_char(src[5]) * 10);
gsm_hour = decode_ascii_hex_char(src[6]) + (decode_ascii_hex_char(src[7]) * 10);
gsm_minute = decode_ascii_hex_char(src[8]) + (decode_ascii_hex_char(src[9]) * 10);
gsm_second = decode_ascii_hex_char(src[10]) + (decode_ascii_hex_char(src[11]) * 10);
temp_decode = decode_ascii_hex_char(src[13]);
if (temp_decode >= 8) {
temp_decode -= 8;
gsm_timezone = decode_ascii_hex_char(src[12]) + (temp_decode * 10);
gsm_timezone = -gsm_timezone;
}
else {
gsm_timezone = decode_ascii_hex_char(src[12]) + (temp_decode * 10);
}
timezone_offset = gsm_timezone * GSM_MINUTES_PER_TZ_OFFSET * SECSPERMINUTE;
dest->tm_sec = gsm_second; // seconds after the minute 0-59
dest->tm_min = gsm_minute; // minutes after the hour 0-59
dest->tm_hour = gsm_hour; // hours since midnight 0-23
dest->tm_mday = gsm_day; // day of the month 1-31
dest->tm_mon = gsm_month - 1; // months since January 0-11
dest->tm_year = gsm_year - TM_YEAR_BASE; // years since 1900
dest->tm_wday = 0;
dest->tm_yday = 0;
dest->tm_isdst = -1;
return timezone_offset;
}
void demo_gsmtime(void)
{
char time_string_a[14] = "3130523210658A";
struct tm tm_struct;
time_t tz_offset;
printf("GSM/SCSTS: %s\n",time_string_a);
tz_offset = scts_to_unix(&tm_struct, time_string_a);
printf("asctime: %s",asctime(&tm_struct));
printf("tz_offset=%ld\n",tz_offset);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment