Я пытаюсь проанализировать длину полученного сообщения. Длина указана в BCD. Когда я использую ReadSmallInt()
, я получаю показание, интерпретируемое как шестнадцатеричное значение, а не как двоично-десятичное.
Итак, если у меня есть такое сообщение:
00 84 60 00 00 00 19 02 10 70 38 00 00 0E C0 00
00 16 45 93 56 00 01 79 16 62 00 00 00 00 00 00
08 00 00 00 00 02 10 43 02 04 02 35 31 35 31 35
31 35 31 35 31 35 31 53 41 4C 45 35 31 30 30 31
32 33 34 35 36 37 38 31 32 33 34 35 36 37 38 39
30 31 32 33
Я ожидаю, что ReadSmallInt()
вернет 84, но вместо этого он возвращает 132, что правильно, если вы читаете шестнадцатеричное значение вместо двоично-десятичного.
Согласно этому ответу, ReadSmallInt()
читается как BCD, так как в примерах он получает 11 и 13 (BCD) в качестве длины вместо 17 и 19 (шестнадцатеричный).
Я зафиксировал это клейкой лентой, но есть ли более элегантный способ?
int calculated_length;
// getting the length in Hexa
calculated_length = AContext->Connection->IOHandler->ReadSmallInt();
// converting from hex binary to hex string
UnicodeString bcdLength = UnicodeString().sprintf(L"%04x", calculated_length);
// converting from hex string to int
calculated_length = bcdLength.ToInt();
ucBuffer.Length = calculated_length -2;
AContext->Connection->IOHandler->ReadBytes(ucBuffer, calculated_length - 2);
Согласно этому ответу,
ReadSmallInt
читается как BCD
Это неправильно. Вы неправильно истолковали то, что говорит этот ответ. НИЧТО в этом ответе не указывает на то, что ReadSmallInt()
читается в двоично-десятичном коде, потому что это не так, поскольку Indy вообще НЕ поддерживает чтение/запись BCD. ReadSmallInt()
просто считывает 2 байта и возвращает их как есть в виде 16-битного десятичного целого числа (при необходимости меняя порядок байтов). Итак, если вам нужно вместо этого прочитать BCD, вам придется читать байты, а затем анализировать их самостоятельно. Или найдите библиотеку BCD, которая сделает это за вас.
Если вы еще раз внимательно перечитаете этот другой вопрос, в двух примерах он дает:
24 24 00 11 12 34 56 FF FF FF FF 50 00 8B 9B 0D 0A
24 24 00 13 12 34 56 FF FF FF FF 90 02 00 0A 8F D4 0D 0A
3-й и 4-й байты представляют длину сообщения (x00 x11
и x00 x13
соответственно). Как 16-битные значения в сетевом порядке байтов, они представляют собой десятичные целые числа 17 и 19 соответственно. И если вы подсчитаете присутствующие байты, вы увидите, что эти значения являются правильными длинами байтов этих сообщений. Таким образом, здесь нет никаких BCD.
Это отличается от вашего примера. Байты x00 x84
в сетевом порядке байтов представляют собой десятичное целое число 132. Но ваше сообщение имеет размер 84 байта, а не 132 байта. Таким образом, очевидно, что байты x00 x84
НЕ представляют 16-битное десятичное значение, поэтому ReadSmallInt()
— это неправильный метод для использования в первую очередь.
В вашем коде «клейкой ленты» вы берете десятичное значение, которое возвращает ReadSmallInt()
(132
), преобразуете его в шестнадцатеричную строку ('0084'
), а затем анализируете его в десятичное значение (84
). В Indy нет метода, который сделает за вас такое преобразование.
Это «работает» в вашем случае, но является ли это правильным преобразованием для выполнения, я не могу сказать наверняка, поскольку вы не предоставили никаких подробностей о протоколе, с которым имеете дело. Но если вы думаете, что байты представляют собой BCD, вам следует интерпретировать байты с точки зрения фактического BCD.
В упакованном BCD байт может представлять собой двузначное число. В данном случае байт x84
(10000100b
) содержит два полубайта 1000b
(8
) и 0100b
(4
), поэтому вместе они образуют десятичное число 84, которое вычисляется следующим образом:
BYTE b = 0x84;
int len = (int((b >> 4) & 0x0F) * 10) + int(b & 0x0F);
Теперь, как это распространяется на несколько байтов в BCD, я не уверен, так как мой опыт работы с BCD очень ограничен. Но вам придется выяснить это, если вам нужно обрабатывать сообщения длиной более 99 байтов, что является наибольшим десятичным числом, которое может представлять один байт BCD.
Мне не понравилось мое решение, но, похоже, оно должно быть таким. Поскольку ReadSmallInt() читает два байта, максимальная длина, которую я могу обработать таким образом, будет 9999, что более чем достаточно для того, что я делаю. Спасибо за объяснение.