Rambler's Top100
"Knowledge itself is power"
F.Bacon
Поиск | Карта сайта | Помощь | О проекте | ТТХ  
 Круглый стол
  
Правила КС
>> Настройки

Фильтр вопросов
>> Новые вопросы
отслеживать по
>> Новые ответы

Избранное

Страница вопросов
Поиск по КС


Специальные проекты:
>> К л ю к в а
>> Г о л о в о л о м к и

Вопрос №

Задать вопрос
Off-topic вопросы

Помощь

 
 К н и г и
 
Книжная полка
 
 
Библиотека
 
  
  
 


Поиск
 
Поиск по КС
Поиск в статьях
Яndex© + Google©
Поиск книг

 
  
Тематический каталог
Все манускрипты

 
  
Карта VCL
ОШИБКИ
Сообщения системы

 
Форумы
 
Круглый стол
Новые вопросы

 
  
Базарная площадь
Городская площадь

 
   
С Л С

 
Летопись
 
Королевские Хроники
Рыцарский Зал
Глас народа!

 
  
ТТХ
Конкурсы
Королевская клюква

 
Разделы
 
Hello, World!
Лицей

Квинтана

 
  
Сокровищница
Подземелье Магов
Подводные камни
Свитки

 
  
Школа ОБЕРОНА

 
  
Арсенальная башня
Фолианты
Полигон

 
  
Книга Песка
Дальние земли

 
  
АРХИВЫ

 
 

Сейчас на сайте присутствуют:
 
  
 
Во Флориде и в Королевстве сейчас  20:37[Войти] | [Зарегистрироваться]
Ответ на вопрос № 80598

01-02-2012 13:38
Добрый день, жители Королевства :)

Давно я сюда не заходил.

Но вот недавно встала действительно нужная и важная задача - сделать GPS сервер для проверки  разрабатываемого предприятием GPS-трекера.

Как работать с сокетными компонентами, уже разобрался (использую TServerSocket, Delphi 7).
А вот как вести обмен данными с самим трекером, не очень понятно.

Сервер должен работать вот с этим трекером: http://www.navis.ru/catalog_135_176.html

Описание протокола есть, но по нему не ясно, как передавать команды и получать ответы.

Собственно, вопрос - как можно обмениваться данными с GPS-трекерами? Было б неплохо с примерами.

[+] Добавить в избранные вопросы

Отслеживать ответы на этот вопрос по RSS

Ответы:


Уважаемые авторы вопросов! Большая просьба сообщить о результатах решения проблемы на этой странице.
Иначе, следящие за обсуждением, возможно имеющие аналогичные проблемы, не получают ясного представления об их решении. А авторы ответов не получают обратной связи. Что можно расценивать, как проявление неуважения к отвечающим от автора вопроса.

18-05-2012 10:45
но при блокирующем режиме хотя бы нет проблемы слипания пакетов и мусора лишнего при приеме данных. - уверяю Вас, что эта проблема НАДУМАННАЯ!!! Что пришло в сокет - то и будет...ничего лишнего. У Вас есть четкое описание посылки от треккера. Там (100 пудов) есть четкое начало и четкий конец. И пусть там хоть 100 пакетов "слипнутся" - разблюдовать их пара пустяков. А проблему придумывают те, которые не хотят писать алгоритмы с асинхронной обработкой! Все вспоминают добрым словом DOS. Нет я не против DOS, но те приемы для многопоточных Виндов...ну жуть!

18-05-2012 07:28 | Сообщение от автора вопроса
Сегодня вернулся все-таки к тому варианту, где сервер блокирующий.

Все не мог понять, как же ему правильно слать пакеты, трекер в упор не видел посылок от сервера. Вчера нашел на просторах сети, что лучше передавать записи (т.е. тип record) так - создать под пакет массив байтов, можно динамический, и наложить туда данные API-функцией CopyMemory.

Вот тогда-то наконец заработало. Разве что остается еще проблемка - трекер после того, как передаст некоторый набор данных, вдруг разрывает связь, а сервер от этого зависает. Но тут не знаю, разве сообщить об ошибке и разорвать связь со своей стороны, чтобы тупо не висеть.

Думаю, и в неблокирующем режиме тоже дело пойдет, но при блокирующем режиме хотя бы нет проблемы слипания пакетов и мусора лишнего при приеме данных. Поэтому и говорят, что его программировать проще.

16-05-2012 15:26
Так вот, ответ не отправляется, в WireShark не видно, что что-то отправилось, вместо этого опять возникает OnClientRead. ...мдя-я-я... Вы конечно извините...но кроме как ... такое повествование никак назвать нельзя!!! Ну возник OnClientRead - ТАК ВЫ ПРОЧИТАЙТЕ ЧЕГО ТАМ!!! И ДЕЛАЙТЕ ВЫВОДЫ, а не сможете, то перескажите чего там Вы прочитали. Потому как если
1 Так вот вычитал я сначала заголовок (16 байт), потом вторым вызовом ReceiveBuf саму информационную часть (IMEI устройства - 15 байт). Тогда по идее дальше ничего на этот момент нет от трекера.
2. Он начнет передавать телеметрию только если ответишь на переданный IMEI (это ж handshake).
Тогда вот это - ответ не отправляется - БРЕХНЯ, потому что опять OnClientRead срабатывает.- т.е. "железяка" начинает отвечать, а она - дура, и работает только так, как ее запрограммировали (см. выше свое же).
Пробовал и из OnClientWrite слать ответ - то же самое.- конечно то же самое, потому что хэлп ЧИТАТЬ нужно! Это событие возникает гарантированно тогда, когда на попытку чего-то отправить - Вы получаете эксепшн WSAEWOULDBLOCK. В этом случае Вы должны успокоиться и еще раз попытаться отправить только при получении этого эвента. Поскольку Ваши посылки размером с гулькин ... - Вы в эту ситуацию не попадете никогда.


16-05-2012 08:36 | Сообщение от автора вопроса
Попробовал я неблокирующий режим. Там дело еще хуже - принимаешь IMEI - ответ на него не отправляется.

Я там же, в OnClientRead после приема IMEI на него отвечаю.

Так вот, ответ не отправляется, в WireShark не видно, что что-то отправилось, вместо этого опять возникает OnClientRead.

Хочется понять, как это событие правильно использовать.

Как я понял, оно срабатывает, если в буфере есть данные.

Так вот вычитал я сначала заголовок (16 байт), потом вторым вызовом ReceiveBuf саму информационную часть (IMEI устройства - 15 байт). Тогда по идее дальше ничего на этот момент нет от трекера.

Он начнет передавать телеметрию только если ответишь на переданный IMEI (это ж handshake).

Так почему же ответ не отправляется, а опять OnClientRead срабатывает?

Пробовал и из OnClientWrite слать ответ - то же самое.

Уже задолбался с этим сервером.





05-05-2012 05:14
А у Вас планируются тысячи клиентов? Вы, простите, имеете лобби в каком-то министерстве? Типичный пример - циркуляры о комплектации чего-то исключительно чем-то. Мой Вам совет - отладтесь на TServerSocket в асинхронном режиме, особенно в части эвентов коннект/дисконнект/реад/еррор особенно с точки зрения потокобезопасности (никаких прямых вызовов экземпляров VCL и пр.). А потом, если у Вас действительно появятся такие тучи клиентов (а лучше до этого момента) спокойно напишете свой класс серверного сокета, в который и подсунете вот эти чуть подпедаленные обработчики. Примеры такого сокета есть у А.Григорьева на сайте, но лучше (я так сделал) купите его книгу. Я достаточно быстро написал свой класс клиента и сервера, но использую их только во вновь разрабатываемых приложениях. Старые как работали на TServer(Client)Socket-ах - так и работают... "Не трогай работающий код". ;-)

05-05-2012 03:14 | Сообщение от автора вопроса
Ну да, как раз о том я и читал, что если TServerSocket в режиме stNonBlocking, то очень много клиентов (где-то так 1000-2000) нет смысла подключать - асинхронный сервер на ServerSocket загнется от такого.

Видно таки или WinSock или какие-то другие компоненты использовать.

04-05-2012 13:15
Все Ваши рассуждения об синхроне/асинхроне - на мой взгляд не имеют под собой никакой основы. И опасения, извините, высосаны из пальца. Если у Вас есть ссылки откуда такая инфа - приведите. Я имею ввиду Асинхронные сокеты - это если у вас клиентов немного, тогда можно работать и через них, все клиенты обслуживает один и тот же поток. Если Вы имели ввиду Ваш компонент, то на нем действительно нормального сервера не написать - тут WinSock и статьи А.Григорьева Вам в помощь.

04-05-2012 10:37 | Сообщение от автора вопроса
За пример спасибо, надо будет попробовать.

Асинхронные сокеты - это если у вас клиентов немного, тогда можно работать и через них, все клиенты обслуживает один и тот же поток.

Я вот думаю - если серверу моему немного трекеров надо будет обрабатывать, может и на асинхронных сокетах остановиться, там хоть есть события все эти ClientRead/ClientWrite, ClientConnect/ClientDisconnect...

Просто если программе придется держать связь с большим числом клиентов, такой сервер захлебнется от вала информации.

Да и там же может быть склейка пакетов при асинхронном режиме.

Чисто для пробы, я ж пока только с одним единственным трекером работаю, можно и асинхронный сервер написать. Посмотреть хоть, как оно в таком случае работать будет.

04-05-2012 10:14
Никогда не "зарывался" столь глубоко, да и использовать блокирующие сокеты...нафиг нужно. Не сталкивался ни разу с такой необходимостью, да и у Вас она надуманная (мне так кажется).
Вот Вам код приема пакета с заголовком и, возможно, с "телом" разной длины. Написан был потомок, в котором перекрыт OnClientRead вот таким образом.

procedure TfmViewer.ssMainClientRead(Sender: TObject;
  Socket: TCustomWinSocket);
begin
  ReadSocket(Handle,MessRecivPacket,Socket);
end;




procedure ReadSocket(Handle: HWnd; Mess: Cardinal; Socket : TCustomWinSocket);
var
  CurrAddr: Pointer;
  Count: Integer;
//  Msg: TMessage;
begin
  if Socket.Data = nil
  then begin
  // т.е. ничего ранее принято не было, или предыдущий пакет был принят полностью
    GetMem(Pointer((@Socket.Data)^),sizeof(TPacket));
    ZeroMemory(Socket.Data,sizeof(TPacket));
    TPacket(Socket.Data^).Socket := Socket;
    TPacket(Socket.Data^).WaitByte := sizeof(TDataPacket);//это размер заголовка
    CurrAddr:=@TPacket(Socket.Data^).Packet;
  end
  else // т.е. идет "доприем" пакета
    with TPacket(Socket.Data^) do
          if Header //проверка на принятие полностью заголовка
          then CurrAddr := Pointer(Integer(@Packet)+sizeof(TDataPacket)+Packet.DataSize-WaitByte)
          else CurrAddr := Pointer(Integer(@Packet)+sizeof(TDataPacket)-WaitByte);

  while TPacket(Socket.Data^).WaitByte > 0 do begin
    Count := Socket.ReceiveBuf(CurrAddr^, TPacket(Socket.Data^).WaitByte); // попытка чтения "ожидаемого" кол-ва байт
    if Count > 0
    then begin // инкремент/декремент нужных полей на кол-во принятого
      dec(TPacket(Socket.Data^).WaitByte,Count);
      inc(Cardinal(CurrAddr),Count);
    end
    else Break;
  end;
  if (TPacket(Socket.Data^).WaitByte = 0) then begin
    // т.е. мы прочитали все, что ожидали
    if not TPacket(Socket.Data^).Header
    then begin
      // заголовок пакета прочитан
      if (TPacket(Socket.Data^).Packet.Marker = StartMarker) and
          (TPacket(Socket.Data^).Packet.PacketType in [ptConnect..ptWait])
        then begin
          //заголовок пакета корректен
          TPacket(Socket.Data^).Header := True;
          if TPacket(Socket.Data^).Packet.DataSize = 0
          then begin
            //больше читать в пакете нечего
            PostMessage(Handle,Mess,Integer(Socket.Data),0);
            Socket.Data := nil;
          end
          else begin
            //есть пристыкованные данные
            TPacket(Socket.Data^).WaitByte := TPacket(Socket.Data^).Packet.DataSize;
            ReallocMem(Pointer((@Socket.Data)^),sizeof(TPacket)+TPacket(Socket.Data^).WaitByte);
          end;
        end
        else begin
          // тут всякая фигня, которая никогда не работает, но в коде есть
          // т.е. заголовок некорректен и идет попытка найти в принятом "корректный" заголовок
          // "скольжением" по буферу
        end
    end
    else begin
      PostMessage(Handle,Mess,Integer(Socket.Data),0);
      Socket.Data := nil;
    end;
  end;
end;


04-05-2012 10:10 | Сообщение от автора вопроса
В WireShark, когда ответ *<A<size> отсылается, то видно, что опять передается сообщение *>A<size><x[0]-x[size-1]>, где <x[0]-x[size-1]> - массив записей телеметрии, а <size> - их количество.

Только не сразу это *>A появляется после ответа, а там может несколько раз пройти пинг-сообщение о текущем состоянии трекера, а потом уже опять *>A.

Так что вроде как все согласно протоколу.

Но в том то и дело, впечатление такое, что трекеру будто не доходит, что я ему таки ответил.

Ведь запись телеметрии все время одна и та же, а должны после ответа пойти новые.

Одни тольки пинги в виде текущего состояния каждые 30 сек и видно нормально.

04-05-2012 04:02 | Сообщение от автора вопроса
У него же есть эвент OnClientRead.

Да, но у меня же блокирующий режим. А там используются методы TWinSocketStream - Read(Buf, Count) - чтение и Write(Buf, Count) - запись в сокет.

Порывшись в сети, я увидел, что как-то можно использовать OnClientRead/OnClientWrite и в блокирующем режиме.

Но не вижу что-то понятного примера нигде как это использовать.

Видел только на форуме RSDN слова, что в таком случае не надо перекрывать метод Execute у TServerClientThread, а работать именно в OnClientRead/Write.

Вот интересно бы посмотреть бы подробнее код, как такое делается.
Справка, говорит, мол, получите ссылку на поток конкретного клиента через GetClientThread и дальше работайте с этим.

Это вроде так, если я правильно понимаю:


MyThread := TDeviceClient(ServerSocket1.Socket.GetThread(MyClientSocket));



TDeviceClient - это мой, значит, поток для клиента, наследник от TServerClientThread, что создан в OnGetThread.

А MyClientSocket - это созданный свой экземпляр сокета в OnGetSocket, ну или если свой не создавать, то запоминать тот, что создан автоматически?




03-05-2012 23:35
Даже разбираться в Вашем коде не хочется, потому что...
1. Давно не работал с TServerSocket-ом, но... У него же есть эвент OnClientRead. Откуда тогда вот этот ReadHeader в GetGPSData с
bytes_read := FCliSock.Read(hdr_Byte, 1);
mhead.Write(hdr_byte, bytes_read);
total_read := total_read + bytes_read;
????
Вы что поллингом (тупым чтением) пытаетесь что-то получать???? Когда захотел - тогда и начал пытаться доставать стек драйверов "отдай змей мне по одному байту"? Такой способ положен в основу "задр..ния серверов", эдакая разновидность DOS-атаки. Не так много способных обслуживать пару/тройку десятков клиентов, запросивших мегабайты, но читающих по одному байту, да и еще с задержками...остальные (сервера) просто валятся.
2.Сказано в протоколе, что на сообщение *>A нужно ответить количеством записей в массиве - *<A<количество записей>. Ну так и отвечаю. Однако запись все равно одна и та же. Ну не может такого быть, мне говорят. - а чем это подтверждается? Что показывает сниффер обмена (например wireshark)?

03-05-2012 10:42 | Сообщение от автора вопроса
Добрый день!

Что-то все же не получается заставить сервер нормально телеметрию принимать.


То ли TServerSocket такой тормозной, даже с отключением алгоритма Нейгла, то ли что, но вот не работает сервер как надо.

Попробовали мы отключить передачу вместо пинга текущего состояния.

В таком случае между посылками телеметрии пустые пакеты передаются (только 16-байтный заголовок без данных).

А тот массив телеметрических данных, который должен приниматься, он обозначается в начале сообщения преамбулой *>A, все время один и тот же.

И все время почему-то всего одна запись. И дата старая.

Сказано в протоколе, что на сообщение *>A нужно ответить количеством записей в массиве - *<A<количество записей>.

Ну так и отвечаю. Однако запись все равно одна и та же. Ну не может такого быть, мне говорят.
И я думаю, что не может. Но вот есть :)

Сейчас трекер настроен так, что данные скидываются в черный ящик с частотой 1 сек, и так же каждую секунду должна телеметрия передаваться.

Но судя по журналу, задержки немаленькие получаются - секунд так 30 между записями.

Говорят, трекер, если связи с сервером не было, должен начать передавать при возобновлении связи данные из черного ящика.

Вот как раз это и не работает.

Если это просто тормоза ServerSocket, то наверно,  остается попробовать WinSock API.

Вот так читаю данные GPS:




procedure TDeviceClient.GetGPSData(ADevice: TDevice; var TelRec: Cardinal; AsText: boolean);

var hdr: TPacketHeader;
    br, tr: longint;
    ws: integer;
    b: Byte;
    satcount: byte;
    hdop: real;
    mfile: TMemoryStream; { поток памяти, куда записываются принятые данные, чтоб потом разобрать пакет }
    mBlack: TMemoryStream;
    buf: array [0..64] of byte;
    msgtit: string;
    RecsCount: byte;
    k, j, m: integer;
    TMI_Info: array of TMI_Type_F5_2; { данные из черного ящика }
    TMI_Bytes: array of Byte;
    RecvBuf: array [1..90] of byte; { принимаем по 1 записи, но полностью }
    RecsSize: Word; { размер массива записей черного ящика, как раз для 40960 байт хватит }
    TMI_Rec: TMI_Type_F5_2;
    CurIndex: cardinal; { индекс записи текущего состояния устройства для ответа }
    Cur_TMI_Rec: TMI_Type_F5_2; { текущее состояние устройства }
    DataRec: ^TMI_Type_F5_2;
    sgGrid: TStringGrid;
    Log: TextFile;
    head: array [0..2] of char; { преамбула телеметричного повідомлення }
    ATab: TTabSheet;
    sgLog: TStringGrid;
    Item: TListItem;
    F5_2_Rec: pointer; { указатель на запись из черного ящика }
    PCur_TMI_Rec: pointer; { указатель на запись текущего состояния устройства }
    GPSRec: pointer;
    GPSRecs: ^byte;
    CurGPSRec: ^byte;
    HdrCRC, ADataCRC: Byte;
    kount: integer;
    tmp_head_sum, tmp_data_sum: Byte;
    data_byte: byte;
    TMI_File: TextFile;
    TMI_Hex: TextFile; { теперь .HEX - шестнадцатеричный }
    TMI_Text: TextFile; { GPS_INFO.TXT - текстовый }
    TMI_Black: TextFile;
    wr: integer;
    HexData: array of byte;
    FILL_BLOCK: array of byte;
    Data16: array [0..15] of Byte;
    HdrSiz: Byte;
    HdrByte: ^byte;
    DataByte: ^byte;
    ClientWait: boolean;
    BlackRec: TMI_Type_F5_2;
    BlackRec2: TMI_Type_F5_2;
    BlackRecPtr2: ^byte;
    BlackRecPtr: ^byte;

function ReadHeader(var Header: TPacketHeader): boolean;
var total_read, bytes_read: byte;
    mhead: TMemoryStream;
    hdr_Byte: byte;

begin
    Result := false;
    total_read := 0;
    bytes_read := 0;


      mhead := TMemoryStream.Create;

        while (total_read < 16) do
        begin
          {$IFDEF DEBUG}
            ServerLogAddSync('Чтение байтов заголовка...');
          {$ENDIF}
          try

            bytes_read := FCliSock.Read(hdr_Byte, 1);
            mhead.Write(hdr_byte, bytes_read);
            total_read := total_read + bytes_read;

          except
            on E: ESocketConnectionError do
              begin
                ServerLogAddSync('Заголовок не принят - разрываю соединение');
                ShowMessageFmt('Исключение %s в классе %s', [E.Message, E.ClassName]);

              end;
          end;

        end;

      mhead.Seek(0, soFromBeginning);
      mhead.Read(Header, 16);
      mhead.Free;

      if (total_read = 16) and (Header.Preamble[0] = ADevice.Preamble[1]) and (Header.Preamble[1] = ADevice.Preamble[2])
      and (Header.Preamble[2] = ADevice.Preamble[3]) and (Header.Preamble[3] = ADevice.Preamble[4]) then
      begin
      {$IFDEF DEBUG}
        ServerLogAddSync('ВСЕ 16 БАЙТ ЗАГОЛОВКА ПРИНЯТЫ НОРМАЛЬНО.');
      {$ENDIF}
      Result := true;
      end
      else
      begin
        ServerLogAddSync('Заголовок пакета не удалось принять');
        Result := false;
      end;
end;

function TMICRC(Data: TMI_Type_F5_2): byte;
var i: byte;
    b: ^byte;
    s: byte;
begin
b := @Data;

s := 0;

for i := 0 to SizeOf(TMI_Type_F5_2) do
  begin
    s := s xor b^;
    { sum := sum xor ord(cmd[i]); }
    Inc(b);
  end;
  Result := s;
end;

begin
  ServerLogAddSync('Подготовка к приему пакета телеметрии...');

  br := 0;

  ws := SizeOf(TPacketHeader);
  ServerLogAddSync('Ожидаемый размер заголовка: '+inttostr(ws));
  ServerLogAddSync('Ожидаю заголовок пакета данных...');



  if ReadHeader(Hdr) then
  begin

            ServerLogAddSync('Принят заголовок GPS-телеметрии...');
            ServerLogAddSync('Размер принятого заголовка: '+inttostr(SizeOf(hdr)));
            ServerLogAddSync('Преамбула: '+hdr.Preamble);
            ServerLogAddSync('ID отправителя: '+inttostr(hdr.SendID));
            ServerLogAddSync('ID получателя:  '+inttostr(hdr.RecvID));
            ServerLogAddSync('Размер информационной части телеметрии: '+inttostr(hdr.DataSize));
            ServerLogAddSync('Принимаю данные телеметрии...');

            ADataCRC := Hdr.ChkSum;
            HdrCRC := Hdr.HdrChkSum;

            HdrSiz := SizeOf(Hdr);

            tmp_head_sum := HeadCRC(hdr); { расчет контрольной суммы заголовка }

            ServerLogAddSync(Format('Принятая контрольная сумма заголовка %d: ', [HdrCRC]));
            ServerLogAddSync(Format('Вычисленная контрольная сумма заголовка %d: ', [tmp_head_sum]));
            ServerLogAddSync(Format('Принятая контрольная сумма данных %d: ', [ADataCRC]));

            tr := 0;



      if hdr.DataSize = 0 then
      begin
              RecsCount := 0;

                { Сюда попадаем - если пакет пустой, т.е. заголовок без данных }
                {$IFDEF DEBUG}
                AssignFile(TMI_Hex, 'GPS_INFO.HEX');
                if FileExists('GPS_INFO.HEX') then Append(TMI_Hex) else Rewrite(TMI_Hex);


                write(TMI_Hex, '['+TimeToStr(Now)+']'+#32); { регистрируем время заголовка }
                { запись заголовка пакета в HEX-дамп }
                HdrByte := @Hdr;
                for j := 0 to SizeOf(TPacketHeader)-1 do
                begin
                  write(TMI_Hex, IntToHex(HdrByte^, 2)+#32);
                  Inc(HdrByte);
                end;

                // сколько GPS-записей принято?
                write(TMI_Hex, IntToHex(RecsCount, 2)+#32);

                // филлер для разделения блоков данных -
                for j := 0 to 15 do write(TMI_Hex, 'FF'+#32);

                Writeln(TMI_Hex);
                Writeln(TMI_Hex);




              {$ENDIF}

              { Если заголовок пустой - отвечаем, что не приняли ничего }
              ServerLogAddSync('ПУСТОЙ ПАКЕТ - отвечаем об этом');
              ShowRecvPacketSync('#EMPTY');
              CloseFile(TMI_Hex);

                if (AsText = True) then
                begin
                AssignFile(TMI_Text, 'GPS_INFO.TXT');
                if FileExists('GPS_INFO.TXT') then Append(TMI_Text) else Rewrite(TMI_Text);

                LogHeaderAsText(TMI_Text, Hdr);

                CloseFile(TMI_Text);

                end;

      end
      else
      begin

          (* А эта ветка обрабатывается, если Hdr.DataSize>0, значит данные в пакете есть.

            Но почему-то нормальной выгрузки черного ящика добиться не удается *)


          { Эти файлы для журналирования приема данных в HEX и в читаемом виде }
          AssignFile(TMI_Hex, 'GPS_INFO.HEX');
          if FileExists('GPS_INFO.HEX') then Append(TMI_Hex) else Rewrite(TMI_Hex);

          if AsText = true then
          begin
            AssignFile(TMI_Text, 'GPS_INFO.TXT');
            if FileExists('GPS_INFO.TXT') then Append(TMI_Text) else Rewrite(TMI_Text);
          end;

            write(TMI_Hex, '['+TimeToStr(Now)+']'+#32); { регистрируем время заголовка }

            HdrByte := @Hdr;

            { скидываем заголовок в hex-файл }
            for j := 0 to SizeOf(TPacketHeader) do
            begin
            write(TMI_Hex, IntToHex(HdrByte^, 2)+#32);
            Inc(HdrByte);
            end;

            for j := 0 to 15 do write(tmi_hex, 'FF'+#32);

            writeln(TMI_Hex);
            writeln(TMI_Hex);

            { в другой файл - заголовок в читаемом человеком виде }
            if AsText then LogHeaderAsText(TMI_Text, Hdr);

        RecsCount := 0;

        FillChar(RecvBuf, SizeOf(recvbuf), 0);

        { Если заголовок не был пустым - принимаем блок данных }
        mfile := TMemoryStream.Create;

        tr := 0;

        while (tr < hdr.DataSize) do
        begin
          br := FCliSock.Read(RecvBuf, 1);
          mfile.Write(recvbuf, br);
          tr := tr + br;
        end;


           
            mfile.Seek(0, soFromBeginning);
            SetLength(TMI_Bytes, hdr.DataSize);
            mFile.Read(TMI_Bytes[0], hdr.DataSize);  { считываем весь пакет в массив }
            write(TMI_Hex, '['+TimeToStr(Now)+']'+#32); { записываем время приема пакета }

          mfile.Seek(0, soFromBeginning);
          mFile.Read(head, 3);

          { в этом if разбираемся, что за пакет пришел и
            шлем соответствующие ответы }

          if head = '*>A' then
            begin
                  ShowRecvPacketSync(head);
                  mfile.Seek(3, soFromBeginning);
                  mFile.Read(RecsCount, 1);

                  { Ответ на пакет *<A<количество записей> }
                  DebGPSDataReceived(ADevice, RecsCount);
                 
                  if RecsCount = 2 then
                    begin
                      { Тут если первый же пакет склеен с текущей телеметрией,
                        то я их разделяю, чтоб в журнале посмотреть }

                      mFile.Seek(4, soFromBeginning);
                      mfile.read(BlackRec, SizeOf(TMI_Type_F5_2));
                      mFile.Seek(5, soFromBeginning);
                      mFile.Read(Rec_No, 4);
                      mFile.Seek(11, soFromBeginning);
                      mfile.Read(ANextEvent, SizeOf(TEventTime));
                      mfile.Seek(90, soFromBeginning);
                      mFile.Read(BlackRec2, SizeOf(TMI_Type_F5_2));
                      mFile.Seek(97, soFromBeginning);
                      mFile.Read(DummyTime2, SizeOf(TEventTime));
                    end
                  else
                  begin
                    mFile.Seek(4, soFromBeginning);
                    mFile.Read(BlackRec, SizeOf(TMI_Type_F5_2));
                    mfile.Seek(5, soFromBeginning);
                    mFile.Read(Rec_No, 4);
                    mFile.Seek(11, soFromBeginning);
                    mfile.Read(ANextEvent, SizeOf(TEventTime));
                  end;

                  TelRec := NRec;

                  for j := 0 to High(TMI_Bytes) do write(TMI_Hex, inttohex(tmi_bytes[j], 2)+#32);

                  if AsText = true then
                  begin
                    if RecsCount = 2 then
                    begin
                      LogPacketAsText(TMI_Text, head, RecsCount, DummyTime, 0, BlackRec);
                      LogPacketAsText(TMI_Text, head, RecsCount, DummyTime2, 0, BlackRec2);
                    end
                    else begin
                      LogPacketAsText(TMI_Text, head, RecsCount, DummyTime, 0, BlackRec);
                    end;
                  end;
            end
          else if head = '*>T' then
          begin
                    ShowRecvPacketSync(head);
                    mFile.Seek(4, soFromBeginning);
                    // CurIndex - номер записи, почему-то он всегда 0 у сообщения *>T
                    mFile.Read(CurIndex, 4);
                    mFile.Seek(3, soFromBeginning);
                    mfile.Read(BlackRec, SizeOf(TMI_Type_F5_2));
                    ServerLogAddSync(Format('Посылка ответа на текущее сост. %d', [CurIndex]));
                    SendCurrentStatusAnswer(ADevice, CurIndex);
                   
                    for j := 0 to High(TMI_Bytes) do write(TMI_Hex, inttohex(tmi_bytes[j], 2)+#32);

                    if (AsText = true) then LogPacketAsText(TMI_Text, head, 1, DummyTime, 0, BlackRec);
          end
          else if head = '*#I' then
          begin
                                   
                  ShowRecvPacketSync(head);
                  if (head <> '*>T') and (head <> '*>A') then Sum_No := Sum_No + 1;
                  ServerLogAddSync('Принят пакет *#I');
                  SetLength(TMI_Bytes, hdr.DataSize);
                  mFile.Seek(3, soFromBeginning);
                  mfile.Read(BlackRec, SizeOf(TMI_Type_F5_2));
                  BlackRecPtr := @BlackRec;
                  ServerLogAddSync('Индекс принятой записи '+inttostr(FTelRec));
                  if (head <> '*>A') and (head <> '*>T') then FNewRec := FNewRec + 1;

                  if AsText = false then
                  begin
                      write(TMI_Hex, '('+inttostr(FNewRec)+')'+#32);
                      for j := 0 to (SizeOf(TMI_Type_F5_2)) do
                      begin
                        write(TMI_Hex, inttohex(BlackRecPtr^, 2)+#32);
                        Inc(BlackRecPtr);
                      end;
                  end
                  else LogPacketAsText(TMI_Hex, head, 1, DummyTime, 0, BlackRec);
          end
          else if head = '*#R' then
          begin
            { Попробуем таки принимать тут пакеты *#R - ближайшие записи
              ПОСЛЕ даты, указанной в параметре запроса }

            ShowRecvPacketSync(head);
            mfile.Seek(3, soFromBeginning);
            mfile.Read(NumRTime, SizeOf(TEventTime));
            mfile.Seek(9, soFromBeginning);
            mfile.Read(APage, 4);
            mfile.Seek(13, soFromBeginning);
            mFile.Read(BlackRec, SizeOf(TMI_Type_F5_2));
            mFile.Seek(20, soFromBeginning);
            mfile.Read(ANextEvent, SizeOf(TEventTime));
            if (AsText = true) then LogPacketAsText(TMI_Hex, head, 1, NumRTime, APage, BlackRec);
          end
          else if head = '*#A' then
          begin
            ShowRecvPacketSync(head);
            ServerLogAddSync('Принят ответ на запрос текущего состояния - *#A');
            mFile.Seek(3, soFromBeginning);
            mFile.Read(BlackRec, SizeOf(TMI_Type_F5_2));
            mfile.Seek(10, soFromBeginning);
            mFile.Read(NumRTime, SizeOf(TEventTime));
            if AsText then LogPacketAsText(TMI_Text, head, 1, NumRTime, 0, BlackRec);
          end;

            for j := 0 to 15 do write(TMI_Hex, 'FF'+#32);

            Writeln(TMI_Hex);
            Writeln(TMI_Hex);

            Finalize(TMI_Bytes);

            CloseFile(TMI_Hex);
            if (AsText = true) then CloseFile(TMI_Text);

          mfile.Free; { уничтожаем временный буфер }

    end;
  end
  else
  begin
    ServerLogAddSync('Заголовок пакета телеметрии не удалось принять');
  end;
end;




А ответ на телеметрическое сообщение *>A так делается:



procedure TDeviceClient.DebGPSDataReceived(ADevice: TDevice; recordCount: byte);
var Hdr: TPacketHeader;

    Data: array [0..3] of byte;
    b: ^Byte;
    k: byte;
    n: byte;
    s: string;
begin
{ Отсылаем ответ, что телеметрические записи получены }
{ заголовок }

for n := 1 to 4 do Hdr.Preamble[n-1] := ADevice.Preamble[n];

Hdr.RecvID := ADevice.SenderID;
Hdr.SendID := ADevice.ReceiverID;

Hdr.DataSize := 4; { 3 символа + 1 байт число записей }
{ данные }
Data[0] := ord('*');
Data[1] := ord('<');
Data[2] := ord('A');
Data[3] := recordCount;

{ контрольные суммы }
Hdr.ChkSum := DataCRC(@Data, Hdr.DataSize);
Hdr.HdrChkSum := HeadCRC(Hdr);

  { действие записывается в журнал }
  ServerLogAddSync('Отсылаю заголовок ответа на прием данных из "черного ящика":');
  ServerLogAddSync('Преамбула: '+Hdr.Preamble);
  ServerLogAddSync('ID приемника: '+inttostr(Hdr.RecvID));
  ServerLogAddSync('ID передатчика: '+inttostr(Hdr.SendID));
  ServerLogAddSync('Размер данных: '+inttostr(Hdr.DataSize));
  ServerLogAddSync('Контрольная сумма данных: '+inttostr(Hdr.ChkSum));
  ServerLogAddSync('Контрольная сумма заголовка: '+inttostr(Hdr.HdrChkSum));

  s := chr(Data[0])+chr(Data[1])+chr(Data[2]);

  ServerLogAddSync('Данные ответа: '+s+inttostr(Data[3]));
  ServerLogAddSync('Размер записи "Данные": '+inttostr(SizeOf(Data))); { должно быть 4 }

{ шлем ответ }
ServerLogAddSync('Отсылка ответа на передачу пакета GPS-данных из черного ящика');
ServerLogAddSync(Format('Принято записей ЧЯ: %d', [recordCount]));

FCliSock.Write(Hdr, SizeOf(TPacketHeader));
for k := 0 to 3 do FCliSock.Write(Data[k], 1);

ServerLogAddSync('Ответ на передачу пакета GPS-данных послан');
end;



Вот и непонятно - ответ посылается, но трекер будто в упор его не видит, раз телеметрическая запись одна и та же. Эх-х-х... :)

13-02-2012 23:54 | Комментарий к предыдущим ответам
Получается, зря только сюда постил - откуда такие выводы? Человек, когда родился, умеет только две вещи...остальному учится.
Запости, получил "пинка" (замечу в нужном направлении) и разобрался. А для каких целей тогда Королевство существует? Как только оно скатится до конечных решений и кодов - удалю у себя из ссылок. ;-)

03-02-2012 04:36 | Сообщение от автора вопроса
Да, я кажется понял. Оказалось, провтыкал насчет одного места в протоколе - там же кажый пакет данных, будь то команда, запрос или информация - сопровождаются небольшим заголовком.

Уже сделал чтоб сформировало и отослало заголовок пакета для команды перед самой командой.

Осталось только добиться получения ответов на эти команды, и тогда будет уже работать.

Получается, зря только сюда постил :)

03-02-2012 02:15
Так вот тебе с NTCB работать и нужно. Именно он обеспечивает интерфейс по TCP/IP а NMEA - для локального использования через UART модуля.
Какие функции заявляет NTCB? Что именно там непонятно?
Темболее, по вашим словам авторизация происходит - значит часть протокола Вы уже выполнили... остается дело за малым, выполнить остальную часть!

02-02-2012 07:41 | Сообщение от автора вопроса
Ну да, есть программа-конфигуратор.

Настроек E-Mail нет, а параметры SMS-ок - это только для пользователей устройства, чтобы с мобильника им управлять.
Настроек модема там нет тоже.

Есть только описание протоколов NTCB для обмена данных с сервером и NMEA. Вот как с ним, NTCB, толком работать, как раз не ясно.

02-02-2012 07:23
Блин, почитал описалово СИГНАЛ S-2117...посмеялся...
Надо же так заявлять о точности!!! Пусть поставят модуль на открытой местности и по-честному нарисуют на карте отсчеты от навигационного модуля в течение 2-3 часов. Если у них получится "розочка" с диаметром меньше 15 м - скажу, что они молодцы. Почти уверен, что меньше 50 м не получится!!!

02-02-2012 07:02
Нет, Вы подождите... Если у Вас есть некая железяка СИГНАЛ S-2117, то для того, чтобы что-нибудь сваять на ее базе НАДО иметь доку по протоколу общения с ней. Наверняка к ней имеется ПО, которое конфигурит ее, в плане:
1. Параметры соединения по GPRS (EDGE, и прочая).
2. Параметры и способы передачи сообщений, а именно м.б.
2.1. URL почтовика и параметры аккаунта и почтового ящика.
2.2. Параметры модема для передачи СМС-ок.
2.3. Хрен его знает, какой еще способ придумали разработчики СИГНАЛ S-2117.
3. Кол-во и тип "тревожных" датчиков на шлейфах.
4. Ну и прочая ерунда.
Отсюда вывод:
1. Не умеет передавать сообщения в виде "письма на мыло" - значит трындец, Ваше начальство обломалось с экономией на СМС-ках.
2. Навряд ли по ТСР есть возможность программировать п.2.
3. GPS-модули можно посредством NMEA программировать на набор и периодичность получения параметров (координаты, время, кол-во спутников и пр.), но... навряд-ли это возможно по ТСР соединению. Почему? Потому что о том, что у СИГНАЛ S-2117 есть Навстар/Глонасс-модуль Вы можете только догадываться. Говоря на языке ООП, он - в секции protected.
4. Опять же на ООП - в public у Вас только модуль, обеспечивающий ТСР-соединение. Есть в этой секции процедура трансляции команд в Навстар/Глонасс-модуль - читайте описание NMEA и пробуйте, но...это вряд ли. Очень сильно ВРЯД ЛИ!!!

02-02-2012 06:36 | Сообщение от автора вопроса
Не совсем понятно, что еще за "железка" и при чем она тут.

Почитав описание GPS-приемника, я вижу, что там, действительно, два UART интерфейса - один для данных NMEA, другой для BINR - собственного протокола приемника.

Только он же используется для настройки приемника. По BINR состояние датчиков трекера и координаты не получишь.







02-02-2012 02:06
Вообще-то, как правило GPS-чип оснащен UART-интерфейсом и после того как включился  инашел спутники с установленной периодичностью(примерно 1..10 раз в секунду) выдает текущие координаты в интерфейс. В вашем случае, между GPS и TCP/IP стеком находится железка-клиент, которая и управляет GPS-чипом. Вам нужно знать протокол работы именно с ЭТОЙ железкой и забыть про GPS-чип, вам он через сеть НЕДОСТУПЕН и "общатся" можно только с этой промежуточной железкой.

02-02-2012 01:06 | Сообщение от автора вопроса
Ну сам то IP трекера еще получаю, это да. Его же в OnAccept и получаем.

А вот как по GPRS трекером управлять, чтобы нужные данные получать - не очень понятно.

Вроде управление СМС-командами там, но у нас требуется, чтобы желательно без них, так как быстро ж деньги на счету так кончатся, если СМС-ками принимать каждые, скажем, 30 сек координаты.

Вот тут http://cybermonitor.ru работает же как-то через Интернет без всяких там СМС. Вот что-то подобное и нужно.

Конечно же, трекер - это клиент с точки зрения TCP/IP соединения.

После установки соединения он сам передает строку идентификации, так что авторизацию сделать получилось.

А вот дальше нужно каким-то образом передавать ему команды получения текущего состояния устройства и текущих координат, и т.д.

Вот насчет того, как программно им управлять, как раз информации нет. Есть только описание протоколов NTCB и NMEA.

Вообще, я читал, конечно, что например, на мобильные телефоны, можно смс-ки слать как электронную почту, используя как адрес телефона "номер@сайт оператора".



01-02-2012 20:24 | Вопрос к автору: запрос дополнительной информации
GPS-трекерами -да Вы хоть чертом лысым назовите эти устройства. Вы для себя уясните, что собой они представляют сервера или клиенты с точки зрения установки связи по ТСР. По идее подобные устройства являются клиентами. Получив по жэпээрэсу (или еще как) соединение, они коннектятся по (заложенному в их "мозгах") урлу или непосредственно IP. А под этим IP может быть и почтовик и приемник SMS-ок...как разработчик изхитрится.
Озвучьте эту инфу - будет конкретный ответ. А пока есть сомнения по поводу успеха предприятия из-за Описание протокола есть, но по нему не ясно, как передавать команды и получать ответы ... ;-)

Добавьте свое cообщение

Вашe имя:  [Войти]
Ваш адрес (e-mail):На Королевстве все адреса защищаются от спам-роботов
контрольный вопрос:
Жил-был у бабушки серенький КТО?
в качестве ответа на вопрос или загадку следует давать только одно слово в именительном падеже и именно в такой форме, как оно используется в оригинале.
Надоело отвечать на странные вопросы? Зарегистрируйтесь на сайте.
Тип сообщения:
Текст:
Жирный шрифт  Наклонный шрифт  Подчеркнутый шрифт  Выравнивание по центру  Список  Заголовок  Разделительная линия  Код  Маленький шрифт  Крупный шрифт  Цитирование блока текста  Строчное цитирование
  • вопрос Круглого стола № XXX

  • вопрос № YYY в тесте № XXX Рыцарской Квинтаны

  • сообщение № YYY в теме № XXX Базарной площади
  • обсуждение темы № YYY Базарной площади
  •  
     Правила оформления сообщений на Королевстве

    Страница избранных вопросов Круглого стола.
      
    Время на сайте: GMT минус 5 часов

    Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter.
    Функция может не работать в некоторых версиях броузеров.

    Web hosting for this web site provided by DotNetPark (ASP.NET, SharePoint, MS SQL hosting)  
    Software for IIS, Hyper-V, MS SQL. Tools for Windows server administrators. Server migration utilities  

     
    © При использовании любых материалов «Королевства Delphi» необходимо указывать источник информации. Перепечатка авторских статей возможна только при согласии всех авторов и администрации сайта.
    Все используемые на сайте торговые марки являются собственностью их производителей.

    Яндекс цитирования