IronLogic СКУД
Адаптеры & Конвертеры => Z-397 WEB => Тема начата: pitbullko от 23 Августа 2024, 12:05
-
Доброго времени, пытаюсь разобраться в инструкции к протоколу advanced. И никак не могу понять как упаковываются/распаковываются пакеты, почему-то очень скудное объяснение в мануале.
Запаковать пакет у меня получилось(делал как в демо базе), а вот прочитать никак не получается. Может ли кто привести примеры распаковки получаемого пакета или хотябы написать алгоритм распаковки?
Может есть более расширенный мануал чем этот? https://www.ironlogic.ru/il_new.nsf/file/ru_protocol_description_advanced_v2.pdf
-
Добрый день. Вот моя функция распаковки ответа от конвертера на 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();
}
-
Наверное я чего-то недопонимаю. Отправляю запрос на чтение лицензии. Приходит ответ:
Data: 1e 4f c6 c2 cb cb cb ea 7f 7f c6 7f 7f 7f 7f c5 0d
После преобразования получаю, что длина пакета = 22, хотя должна быть 12.
Пробовал уже по-всякому, и никак. И тестовой базой в аксессе, и по примеру выше и по мануалу, все равно не то.
-
В функции входящие 5 байт преобразуются в 4 байта (кроме кода канала 0x1E и завершающего символа 0d), поэтому размер данных результата должен быть меньше входящих данных.
-
Вот функция декодирования пакета на 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;
-
Да это-то понятно, что первый 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"));
КонецЕсли;
КонецЦикла;
Вот поэтому и проблема, распаковав пакет - он не соответтсвует тому что описано в мануале.
-
Не знаю почему не получается, вроде всё правильно.
-
Спасибо за помощь! Код рабочий, просто оказывается 1C парила мозги с приемом пакетов и неправильно преобразовывала входную информацию, если конкретнее, то вместо С6 получала 416, а вместо EA получала 43А, не знаю с чем это связано, написал конвертер и все сработало.