Это продолжение статьи про сетевые протоколы используемые с GPS-трекерах. Если в первой части мы обсуждали фрейм декодеры, то во второй части мы посмотрим на варианты кодирование различных типов полезных данных. Многие производители устройств для GPS-мониторинга разрабатывают собственные протоколы прикладного уровня для передачи данных от устройства на сервер, и иногда разработчики прибегают к различным изощренным и не всегда понятным решениям для кодирования данных.
Для тех, кто не читал или забыл первую часть, я напомню, что существуют две основных группы, на которые можно разделить все протоколы: текстовые и бинарные. В текстовых протоколах информация передается в виде ASCII кодов, а в бинарных, соответственно, все данные закодированы в big-endian или, реже, в little-endian бинарном виде.
Порядок байтов (endianness)
Порядок от старшего к младшему (big-endian) является стандартным для протоколов TCP и UDP, он используется в заголовках пакетов данных и во многих протоколах более высокого уровня. Поэтому порядок байтов от старшего к младшему часто называют сетевым порядком байтов (network byte order), и он является де-факто стандартом для кодирования бинарных данных в сетевых протоколах.
short i = 1; // 0x00 0x01 - big-endian (network byte order) // 0x01 0x00 - little-endian
Проблема в том, что центральные процессоры чаще всего используют порядок от младшего к старшему (little-endian), и поэтому многие производители GPS-трекеров решили кодировать данных в том же формате, что данные хранятся в памяти (т.е. little-endian). Список таких производителей достаточно большой, поэтому приведу только несколько примеров: Baltic Car Equipment (BCE, Литовская компания), Cellocator (крупная международная компания с главным офисом в Израиле) и ГалилеоСкай (известный российский производитель GPS-трекеров со штаб-квартирой в Перми).
Некоторые производители идут еще дальше и кодируют часть данных с одним порядком байт, а часть — с другим. Например, устройства китайской компании Topflytech и польского производителя Tytan GPS отсылают все данные в стандартном сетевом порядке байт, кроме чисел с плавающей запятой, которые отправляются в little-endian формате. Справедливости ради следует отметить, что Tytan GPS исправили проблему во второй версии своего протокола.
Географические координаты
Координаты (широта от -90° до +90°, долгота от -180° до +180°) могут быть представлены различными способами. GPS-приемники обычно возвращают значение в градусах и минутах с десятичной дробью, при этом положительные координаты представлены буквами «N» (северная широта) и «E» (восточная долгота), а отрицательные координаты — буквами «S» (южная широта) и «W» (западная долгота).
Наибольшее разнообразие вариантов кодирования координат можно встретить в текстовых протоколах. Знак координат может быть представлен либо буквой, либо знаком перед значением в градусах (в некоторых случаях явно указывается положительный знак). Значение может быть представлено либо в градусах с десятичными долями, либо в целочисленных градусах и минутах десятичной дробью. Точки в десятичной дроби могут быть опущены, и разделитель между широтой и долготой может также отсутствовать. Вот, например, несколько вариантов представления для координат Пентагона:
38.870989,-77.055961 // градусы десятичной дробью 3852.25934,N,07703.35766,W // градусы (2 знака для широты и 3 знака для долготы) и минуты десятичной дробью W77.055961,N38.870989 // полушарие и градусы десятичной дробью +38.870989,-77.055961 // явное указание северной широты знаком плюс 3852.2593N07703.3577E // отсутствие разделителя между координатами
В бинарных протоколах географические координаты обычно представлены либо целым числом которое нужно разделить на определенный коэффициент, чтобы получить координаты, либо числом с плавающей точкой (обычно 4 байта).
0x04 0x2b 0x9f 0xa4 -> 69967780 -> ( / 60 / 30000 ) -> 38.870989 // целое число 0xc2 0x9a 0x1c 0xa7 -> -77.055961 // число с плавающей точкой (float)
Знак координаты может храниться отдельно от значения координаты. Например, в протоколе от компании Tzone Digital Technology, биты знаков широты и долготы совмещены со значение направления в 2 байтах данных:
0x03 0x0E // 0 0 0 0 0 0 1 1 0 0 0 0 1 1 1 0 // | | | направление (9 бит) - 270 градусов // | | знак долготы - минус (западная долгота) // | знак широты - плюс (северная широта)
Еще один интересный вариант кодирования координат в бинарных — это двоично-десятичный код (binary-coded decimal или просто BCD). Суть кодирования заключается в том, что каждый десятичный разряд числа записывается в виде его четырёхбитного двоичного кода. Например, широта местоположения Пентагона в протоколах китайских компаний KHD или Gator будет выглядеть следующим образом:
0x03, 0x85, 0x22, 0x59, 0x34 -> 38 градусов 52.25934 минут
Обратите внимание, что запись в шестнадцатеричном виде в точности соответствует значению в десятичном виде. Получается, что данные, закодированные в BCD, относительно легко читаются человеком, но, к сожалению, этот вид кодирования усложняет чтение этих данных компьютером, а также увеличивает размер сообщения.
Дата и время
Подавляющее большинство или даже все протоколы при передаче координат на сервер содержат одну или несколько временных меток. Обычно это время определения координат GPS приемником, но иногда может быть дата и время внутренних часов GPS трекера на момент, когда посылка была сформирована. Некоторые трекеры отправляют две или даже больше временных меток.
В текстовых протоколах практически всегда время и дата разбиты на отдельные компоненты. Вот несколько примеров представления времени последнего перевода часов в России (26 октября 2014, 2 часа ночи):
2014/10/26,02:00:00 // дата и время с разделителями 020000.000,...261014 // время с точностью до миллисекунд 141026...020000 // дата и время без разделителей 20141026020000 14/10/26 2:00 // дата и время с точностью до минут
Важный момент, который стоит отметить — обычно время передается по гринвичу (UTC или GMT временные зоны). Важно это потому, что сервер и трекер могут находиться в разных временных зонах. Некоторые GPS-трекеры позволяют конфигурировать временную зону. При этом часть из них сообщает выбранную временную зону на сервер, а часть — нет. Для тех, которые не сообщают, требуется вручную задавать зону на сервере.
Один интересный пример проблемы с временными зонами — это безымянный протокол, используемый во множестве дешевых трекеров китайского производства. Трекер присылает локальные дату (год, месяц, день) и время (часы, минуты, секунды), а также время с точностью до миллисекунд по Гринвичу. Интересным в данном случае является то, что имея эти данные, можно посчитать дату по Гринвичу для временных зон от GMT-12 до GMT+12. Например, если на входе мы имеем 2016-01-01 01:00:00 (локальное время) и 59:00:00.000 (GMT), то результат на выходе будет 2015-12-31 59:00:00.000 (GMT). К сожалению, этот способ не работает для временных зон с отклонением от гринвича больше 12 часов.
Еще один примечательный вариант представления времени используется в стандартном протоколе TAIP. Время представлено в виде недель, дней и секунд с 6 января 1980 года. Значимость этой даты не совсем понятна, но это стандарт для многих GPS приемников.
Некоторые протоколы передают на сервер только текущее время суток. В данном случае единственное, что можно сделать, это подставить текущую дату по версии сервера. Соответственно это может привести к проблемам, если время сервера и устройства отличается или при любой задержке при передаче данных. Например, устройство может передать время 23:59:59, а при приеме этого сообщения на сервере уже будет начало следующего дня. Один вариант обхода этой проблемы — это сравнение полученной временной метки с текущим временем сервера, и если разница получается больше часа или нескольких часов, то нужно прибавить или отнять один день от полученной даты.
В бинарных протоколах дата и время либо разбиты на отдельные компоненты так же, как и в текстовых, либо хранятся в виде временной метки UNIX (количество секунд или миллисекунд с полуночи (00:00:00 GMT) 1 января 1970 года).
Заключение
Вся информация, представленная в данной статье, была накоплена по ходу работы над сервером GPS-мониторинга. Проект полностью Open Source, и если кому-нибудь интересно, то исходный код с реализацией всех приведенных протоколов можно найти на GitHub.
Также кого-то может заинтересовать документация на протоколы для GPS-трекеров. К сожалению, все имеющиеся документы не могу опубликовать в открытом доступе, так как некоторые из них конфиденциальные.
Автор: tananaev