PDA

Просмотр полной версии : [Вопрос] Контрольная сумма


anselm
11.11.2013, 10:30
И снова здравствуйте!
У меня вопрос по контрольной сумме в ответе.
Есть связка GSM-модем Maestro-100, К-105 и ТЭКОН-19. Делаю успешные запросы с командой 11 и получаю ответы, но очень часто (где-то с частотой 50/50) они приходят с неправильной контрольной суммой, несмотря на правильную сигнатуру всего ответа. Например, такой ответ:
68 06 06 68 01 01 47 44 20 40 6D 16
Всё здесь правильно, включая пришедшее число float = 2.504167 - а вот контрольная сумма неправильная 6D, тогда как должна быть ED.
Тут же делаю такой же запрос и получаю уже абсолютно правильный ответ с правильной контрольной суммой:
68 06 06 68 01 01 7B 32 2C 40 1B 16
Контрольную сумму для данного ответа считаю по такому алгоритму:
unsigned char CS(const char* a)
{
unsigned char b = 0;
for(int i=4; i<10; i++) {
b = (b + a) % 256;
}
return b;
}
Подскажите пожалуйста, где тут кроется ошибка?

[I]Добавлено через 13 минут

Дополнение.
Сейчас заметил ещё одну закономерность: ВСЕ ошибочные контрольные суммы отличаются ровно на 80h от правильной контрольной суммы!
К чему бы это?

Добавлено через 19 минут

Дополнение.
Получается, что контрольную сумму надо брать по модулю 128, а не 256?

anselm
11.11.2013, 12:23
Везде заменил char на unsigned char - не помогло.

gae
11.11.2013, 13:02
Как известно, передача всех чисел проходит младшими битами вперед, и у Вас проблемы возникают на самом последнем бите байта, если он отличен от нуля.
А если в других байтах ответа (например, в мантиссе) есть байты больше 0х80, они нормально проходят?
Проверьте настройки всей связки, одинаковую скорость, одинаковость числа стоп-бит (один!). Попробуйте заменить модем.
Проверьте свое ПО, вовремя ли оно читает последние два байта ответа.

anselm
12.11.2013, 11:56
Решено.
Спасибо, gae, ваши замечания помогли. Действительно, модем присылал байты, которые ВСЕ были меньше 0x80! Видимо, я неправильно настроил COM-порт. И, видимо, COM-порт надо было перевести в неканонический режим. Это можно сделать одной командой cfmakeraw (http://www.opennet.ru/man.shtml?topic=tcgetattr):
termios attr = {0};
cfmakeraw(&attr);
cfsetispeed(&attr, B9600);
cfsetospeed(&attr, B9600);
Теперь ответ выглядит красиво и контрольная сумма не врёт:
<< 10 41 01 11 04 01 04 5C 16
>> 68 06 06 68 01 01 74 79 9C 40 CB 16
Чему я очень рад! :)