Last active
December 6, 2020 05:28
-
-
Save jbrzozoski/376b32bfe4eed2f4a49418600abc44ed to your computer and use it in GitHub Desktop.
GSM Time to Unix
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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