Автор Тема: Запаковка, распаковка пакетов по протоколу Advanced  (Прочитано 888 раз)

pitbullko

  • Пользователь
  • *****
  • Сообщений: 4
Доброго времени, пытаюсь разобраться в инструкции к протоколу advanced. И никак не могу понять как упаковываются/распаковываются пакеты, почему-то очень скудное объяснение в мануале.
Запаковать пакет у меня получилось(делал как в демо базе), а вот прочитать никак не получается. Может ли кто привести примеры распаковки получаемого пакета или хотябы написать алгоритм распаковки?
Может есть более расширенный мануал чем этот? https://www.ironlogic.ru/il_new.nsf/file/ru_protocol_description_advanced_v2.pdf

gsa

  • Пользователь
  • *****
  • Сообщений: 269
Добрый день. Вот моя функция распаковки ответа от конвертера на C++:
UINT_PTR DecodePack(vector<BYTE> &oDst, LPCBYTE pPack, UINT_PTR nCount)
{
LPCBYTE pIn = pPack;
LPCBYTE pEof = (pPack + nCount);
BYTE nCS = 0;
INT i;
BYTE a[4];
BYTE b;

oDst.clear();
pIn++;
while (pIn < pEof)
{
for (i = 0; i < 4; i++)
{
b = *pIn;
if (b > 0x7F)
b ^= 0xCA;
a[i] = b;
pIn++;
}
b = (*pIn++) ^ 0xCA;
for (i = 0; i < 4; i++)
if ((b & (1 << i)) > 0)
a[i] |= 0x80;
AppendByteArray(oDst, a, _countof(a));
}
if (oDst[1] > oDst.size()) // если реальный размер пакета > размера декодированного
{
return 0; // некорректный пакет
}
pIn = oDst.data();
pEof = oDst.data() + oDst[1];
while (pIn < pEof)
nCS += *pIn++;
if (nCS != 255)
{
return 0; // ошибка CRC
}
oDst.resize(oDst[1]);
return oDst.size();
}

pitbullko

  • Пользователь
  • *****
  • Сообщений: 4
Наверное я чего-то недопонимаю. Отправляю запрос на чтение лицензии. Приходит ответ:
Data: 1e 4f  c6 c2 cb cb  cb ea 7f 7f c6 7f 7f 7f 7f c5 0d
После преобразования получаю, что длина пакета = 22, хотя должна быть 12.
Пробовал уже по-всякому, и никак. И тестовой базой в аксессе, и по примеру выше и по мануалу, все равно не то.

« Последнее редактирование: 23 Августа 2024, 14:41 от pitbullko »

gsa

  • Пользователь
  • *****
  • Сообщений: 269
В функции входящие 5 байт преобразуются в 4 байта (кроме кода канала 0x1E и завершающего символа 0d), поэтому размер данных результата должен быть меньше входящих данных.

gsa

  • Пользователь
  • *****
  • Сообщений: 269
Вот функция декодирования пакета на Delphi:
function TAdvancedProto.DecodeCvtPack(AData: PByte; ACount: Integer;
    var VPacketId, VLicenseN, VCmd: Byte; var VParams: Cardinal;
    var VBody: TByteBuffer): HResult;
  procedure _DecodeCvt5to4(AIn5: PByte; VOut4: PByte);
  var
    pOut: PByte;
    I: Integer;
    b: Byte;
  begin
    pOut := VOut4;
    for I := 0 to 3 do
    begin
      pOut^ := AIn5^;
      Inc(AIn5);
      if pOut^ > $7F then
        pOut^ := pOut^ xor $CA;
      Inc(pOut);
    end;

    pOut := VOut4;
    b := AIn5^ xor $CA;
    for I := 0 to 3 do
    begin
      if (b and (1 shl I)) <> 0 then
        pOut^ := pOut^ or $80;
      Inc(pOut);
    end;
  end;
var
  nChannel, nCS, nHdrSize: Byte;
  I, nPkSize, nBlockCnt: Integer;
  pOut, pIn, pInEnd: PByte;
begin
  if ACount < 9 then
    Exit(GC_E_BAD_CVT_RESPONSE); // Размер пакета слишком мал

  nChannel := AData^;
  Inc(AData);
  Dec(ACount);
  if (AData + ACount - 1)^ = $0d then
  begin
    Dec(ACount);
    if ACount < 8 then
      Exit(GC_E_BAD_CVT_RESPONSE); // Размер пакета слишком мал
  end;

  // Преобразуем 5 -> 4
  nBlockCnt := (ACount div 5);
  m_rTempBuf.Size := (nBlockCnt * 4);
  pIn := AData;
  pOut := m_rTempBuf.Memory;
  for I := 1 to nBlockCnt do
  begin
    _DecodeCvt5to4(pIn, pOut);
    Inc(pIn, 5);
    Inc(pOut, 4);
  end;

  // Читаем заголовок 4-8 байт
  if TChannel(nChannel) = cnUpdateFw then
    nHdrSize := 6
  else
    nHdrSize := 8;

  nPkSize := m_rTempBuf[1];
  // Если указанный размер пакета > размера декодированного,
  if nPkSize > m_rTempBuf.Size then
    Exit(GC_E_BAD_CVT_RESPONSE); // Некорректный пакет

  VLicenseN := m_rTempBuf[2];
  VPacketId := m_rTempBuf[3];

  VCmd := m_rTempBuf[4];
  VParams := 0;
  Move(m_rTempBuf.Memory[5], VParams, 3);

  // Считаем контрольную сумму
  nCS := 0;
  pIn := m_rTempBuf.Memory;
  pInEnd := pIn + nPkSize;
// Выключаем Overflow checking
{$IFOPT Q+}
{$DEFINE CKOVERFLOW}
{$Q-}
{$ENDIF}
  while pIn <> pInEnd do
  begin
    Inc(nCS, pIn^);
    Inc(pIn);
  end;
{$IFDEF CKOVERFLOW}
{$UNDEF CKOVERFLOW}
{$Q+}
{$ENDIF}
  if nCS <> $ff then
    Exit(GC_E_BAD_CVT_RESPONSE); // ошибка CRC

  VBody.SetData(@m_rTempBuf.Memory[nHdrSize], nPkSize - nHdrSize);

  Result := S_OK;
end;

pitbullko

  • Пользователь
  • *****
  • Сообщений: 4
Да это-то понятно, что первый 1E и последний 0D байт не нужно преобразовывать, проблема же в том, что после преобразования получается какая-то ерунда.
Вот я беру пять байт: 4f c6 c2 cb cb. Потом преобразовываю их, и получаю: CF 96 12 9B

Вот код из 1С, который это делает    
Для i = 0 По 3 Цикл                
Результат.Вставить(i, ПобитовоеИли(Вход[i],ПобитовыйСдвигВлево(ПобитовоеИ(ПобитовыйСдвигВправо(Вход[4],i),1),7)));
КонецЦикла;
Это копия того кода что в мануале.
По вашему коду результат другой и тоже не правильный - CF 16 12 1B.
Для i = 0 По 3 Цикл

b = Вход[i];
if b > 127 Then
b = cmBin2Dec(cmXOR(HexToBin("0xCA"), Dec2Bin(b)));
endif;
a.Вставить(i, b);
КонецЦикла;

b = cmBin2Dec(cmXOR(HexToBin("0xCA"), Dec2Bin(Вход[4]))); //xоr-им пятый байт, хотя нигде не сказано об этом,
                                                                                                                        //Если этого не делать, то результат CF 96 12 9B как и у меня.

Для i = 0 По 3 Цикл

Если ПобитовоеИ(b,(ПобитовыйСдвигВлево(1, i))) > 0 Тогда
a[i] = ПобитовоеИли(a[i],ЧислоИзШестнадцатеричнойСтроки("0x80"));   
КонецЕсли;
КонецЦикла;
Вот поэтому и проблема, распаковав пакет - он не соответтсвует тому что описано в мануале.

gsa

  • Пользователь
  • *****
  • Сообщений: 269
Не знаю почему не получается, вроде всё правильно.

pitbullko

  • Пользователь
  • *****
  • Сообщений: 4
Спасибо за помощь! Код рабочий, просто оказывается 1C парила мозги с приемом пакетов и неправильно преобразовывала входную информацию, если конкретнее, то вместо С6 получала 416, а вместо EA получала 43А, не знаю с чем это связано, написал конвертер и все сработало.