Страница 2 из 2 ПерваяПервая 12
Показано с 11 по 20 из 20

Тема: Контрольная сумма ТРМ201

  1. #11

    По умолчанию

    Цитата Сообщение от Дмитрий Егоренков Посмотреть сообщение
    не знаю. у меня получается bfc6.
    "ОПИСАНИЕ протокола обмена между ПЭВМ и приборами ОВЕН" не совсем корректное, особенно это касается "СТРУКТУРНОЙ СХЕМЫ ПРОТОКОЛА ОВЕН", вот и претензий много

    я, честно говоря, не первый раз такие спецификации читаю и работаю с ними, поэтому когда писал конфигуратор команд для протокола owen, делал ровно то, что написано в этих документах,

    а получилось это только после того, как увидел 2 "живые" команды на форуме

    вот чтобы такого не происходило, я бы порекомендовал сделать всего 3 дополнения:
    1. перерисуйте эту схему так, чтобы был виден четкий порядок бит, раз уж там они есть
    2. ваш CRC расчитывается с исключением из пакета кроме маркеров еще и самой контрольной суммы, т.е. не текущая, не нулевая, а вообще без этого члена
    3. в документации приведите 1-2 готовые команды, чтобы не ломать мозг

    получается, что заголовок имеет такую структуру:
    Код:
    typedef struct tagOwenHeader{
    	WORD	Low	: 8;
    	WORD	Size	: 4;
    	WORD	Query	: 1;
    	WORD	High	: 3;
    }OWEN_HEADER, *POWEN_HEADER;
    Low - младший байт адреса
    Size - размер поля данных - 2 (2 - это размер хеша имени)
    Query - признак запроса
    High - старшие 3 бита адреса

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

    на счет уровня приложения-представления - пока не проверял, будем смотреть дальше

    на счет переворачиваний, я пока без самого девайса не понял, но если разбить пакет на 3 сущности: заголовок, команда, CRC, то можно в принципе перевернуть все это дело перед кодированием тетрадами, но тогда не будет сходиться CRC и в данных будет бардак, либо можно тетрады выводить старшим полубайтом вперед, тогда можно не переворачивать, (все зависит от конечной реализации авторов; сам склюняюсь к тому, что все таки напутали порядок полубайтов), вобщем я сделал пока как есть

    в приложении мой конфигуратор команд, это консолька, которая позволяет просто собрать команду, в конечный вид, перед отправкой, так что сам девайс ей не нужен (если кто-то будет вводить имя команды, не забывайте про пробелы в конце этой команды, например "dev " или "ver ")

    (завтра проверю на девайсе, если успею, а сегодня просто выкладываю, т.к. команды уже сходятся по текущей теме и еще по этой: http://www.owen.ru/forum/showthread.php?t=7784)
    Вложения Вложения
    • Тип файла: zip owen.zip (44.6 Кб, Просмотров: 62)
    Последний раз редактировалось mega; 09.06.2010 в 15:18. Причина: подправил приложение: сдвиг старшей части адреса был на 4 бита, теперь как положено - на 8

  2. #12

    По умолчанию

    а вот и мой исходник этой консольки,
    кто желает встроить этот генератор себе в программу:
    Код:
    #include <windows.h>
    #include <tchar.h>
    #include <locale.h>
    #include <stdio.h>
    #include <conio.h>
    //
    BOOL ASCIIToCode( CHAR ch, CHAR*char_for_hash ){
    	ch	= toupper( ch ); 			//преобразуем все в верхний регистр
    	if( strchr( "0123456789", ch ) ){
    		*char_for_hash	= ch - '0';
    	}else if( (ch >= 'A') && (ch <= 'Z') ){
    		*char_for_hash	= ch - 'A' + 10;
    	}else{
    		switch( ch ){
    			case '-':
    				*char_for_hash	= 10 + 26;
    				break;
    			case '_':
    				*char_for_hash	= 10 + 26 + 1;
    				break;
    			case '/':
    				*char_for_hash	= 10 + 26 + 2;
    				break;
    			case ' ':
    				*char_for_hash	= 10 + 26 + 3;
    				break;
    			default:
    				return FALSE;
    		}
    	}
    	*char_for_hash	*= 2;
    	return TRUE;
    }
    //
    USHORT Hash( BYTE Byte, BYTE nbit, USHORT CRC ){
    	for( INT i = 0; i < nbit; i++, Byte <<= 1){
    		if(  ( Byte ^ ( CRC >> 8 ) ) & 0x80  ){
    			CRC	<<= 1;
    			CRC	^= 0x8F57;
    		}else{
    			CRC <<= 1;
    		}
    	}
    	return CRC;
    }
    //
    typedef union tagOwenHeader{
    	struct{
    		WORD	Low		: 8;
    		WORD	Size	: 4;
    		WORD	Query	: 1;
    		WORD	High	: 3;
    	};
    	BYTE		Bytes[2];
    }OWEN_HEADER, *POWEN_HEADER;
    //
    int _tmain( int argc, TCHAR *argv[] ) {
    	INT addr, size, Byte;
    	TCHAR query[2], cmd_fmt[2];
    	CHAR a_cmd[100];
    	BYTE Data[15];
    	BYTE Command[50];
    	OWEN_HEADER hdr;
    	INT l, i;
    	USHORT hash;
    	CHAR chfh;
    	//
    	_tsetlocale( LC_ALL, TEXT("Russian") );
    	//
    loop:
    	do{
    		fflush( stdin );
    		_tprintf_s( TEXT("Введите адрес устройства (0-2047): ") );
    	}while( _tscanf_s( TEXT("%i"), &addr ) != 1 );
    	//
    	do{
    		fflush( stdin );
    		_tprintf_s( TEXT("Это запрос? (y/n): ") );
    	}while( _tscanf_s( TEXT("%1[yn]"), &query, sizeof(query)/sizeof(TCHAR) ) != 1 );
    	//
    	do{
    		fflush( stdin );
    		_tprintf_s( TEXT("Введите размер блока данных (2-17): ") );
    	}while( (_tscanf_s( TEXT("%i"), &size ) != 1) || (size < 2) || (size > 17) );
    	//
    	do{
    		fflush( stdin );
    		_tprintf_s( TEXT("команда будет введена строкой? (y-строка/n-HASH): ") );
    	}while( _tscanf_s( TEXT("%1[yn]"), &cmd_fmt, sizeof(cmd_fmt)/sizeof(TCHAR) ) != 1 );
    	//
    	switch( cmd_fmt[0] ){
    		case TEXT('y'):
    cmd_loop:
    			do{
    				fflush( stdin );
    				_tprintf_s( TEXT("Введите имя команды (допустимый набор символов: [a-zA-Z0-9-_/ .]): ") );
    			}while( _tscanf_s( TEXT("%h[a-zA-Z0-9-_/ .]"), &a_cmd, sizeof(a_cmd)/sizeof(CHAR) ) != 1 );
    			//
    			_tprintf_s( TEXT("Имя команды: \"%hs\"\r\n"), a_cmd );
    			//
    			for( hash = 0, l = strlen( a_cmd ), i = 0 ; l-- ; ++i ){
    				if( a_cmd[i] != '.' ){
    					if( !ASCIIToCode( a_cmd[i], &chfh ) ){
    						goto cmd_loop;
    					}
    					if( a_cmd[i + 1] == '.' ){
    						++chfh;
    					}
    					hash	= Hash( chfh << 1, 7, hash );
    				}
    			}
    			break;
    		case TEXT('n'):
    			do{
    				fflush( stdin );
    				_tprintf_s( TEXT("Введите HASH команды: ") );
    			}while( _tscanf_s( TEXT("%hi"), &hash ) != 1 );
    			break;
    	}
    	_tprintf_s( TEXT("HASH команды: 0x%.4hx\r\n"), hash );
    	//
    	for( i = 0, l = size - 2 ; l-- ; ++i ){
    		do{
    			fflush( stdin );
    			_tprintf_s( TEXT("Введите %i-й байт команды (0-255): "), i + 3 );
    			if( _tscanf_s( TEXT("%i"), &Byte ) != 1 ){
    				continue;
    			}
    			if( Byte < 0 || Byte > 255 ){
    				continue;
    			}
    			Data[i] = Byte;
    			break;
    		}while( TRUE );
    	}
    	//
    	hdr.Low		= addr;
    	hdr.High	= addr >> 8;
    	hdr.Query	= ( query[0] == TEXT('y') ) ? 1 : 0;
    	hdr.Size	= (BYTE)(size - 2);
    	Command[0]	= hdr.Bytes[0];
    	Command[1]	= hdr.Bytes[1];
    	Command[2]	= (BYTE)(hash >> 8);
    	Command[3]	= (BYTE)hash;
    	for( i = 0, l = size - 2 ; l-- ; ++i ){
    		Command[4 + i]	= Data[i];
    	}
    	//
    	for( hash = 0, i = 0, l = 2 + size ; l-- ; ++i ){
    		hash	= Hash( Command[i], 8, hash );
    	}
    	Command[2 + size]	= (BYTE)(hash >> 8);
    	Command[3 + size]	= (BYTE)hash;
    	//
    	_tprintf_s( TEXT("--------\r\nКоманда:\r\n") );
    	for( i = 0, l = 4 + size ; l-- ; ++i ){
    		_tprintf_s( TEXT("%.2x"), Command[i] );
    	}
    	_tprintf_s( TEXT("\r\n#") );
    	for( i = 0, l = 4 + size ; l-- ; ++i ){
    		_tprintf_s( TEXT("%c"), 'G' + ( Command[i] >> 4 ) );
    		_tprintf_s( TEXT("%c"), 'G' + ( Command[i] & 0x0f ) );
    	}
    	_tprintf_s( TEXT("\\r\r\n--------\r\n") );
    	//
    	do{
    		fflush( stdin );
    		_tprintf_s( TEXT("Продолжить? (y/n): ") );
    	}while( _tscanf_s( TEXT("%1[yn]"), &query, sizeof(query)/sizeof(TCHAR) ) != 1 );
    	//
    	if( query[0] == TEXT('y') ){
    		goto loop;
    	}
    	return 0;
    }
    несколько похожий код я использовал у себя в трансляторе этого протокола в SCPI форму, пока все работает

    т.е. для съема-установки параметров использую формат обмена в удобочитаемой форме, типа такого:

    #devno:query:command\r

  3. #13

    По умолчанию

    то, что вы языком C плохо владеете, было ясно еще по первому сообщению. совершенно не обязательно выставлять это напоказ.

  4. #14

    По умолчанию

    Цитата Сообщение от дмитрий егоренков Посмотреть сообщение
    то, что вы языком C плохо владеете, было ясно еще по первому сообщению. совершенно не обязательно выставлять это напоказ.
    интересное умозаключение :)
    особенно интересно это слышать от человека, совершенно не понимающего битовую логику (я делаю такой вывод из посыла почитать тот самый документ, очевидные ошибки в котором я уже подчеркнул)

    если это техподдержка "овен", сочуствую вашей администрации, т.к. ликбез в культуре общения и программирования тут неизбежен :))

  5. #15

    По умолчанию

    это не умозаключение, а факт. ну ладно, я битовую логику не понимаю, вы-то вообще читать не умеете. посмотрите хотя бы раздел "3.3 структура кадра".

  6. #16

    По умолчанию

    ваши умозаключения неуместны - вот это факт,

    я читать умею, и как уже сказал, делал как раз по написанному, а
    если вы такой хорошоший специалист, давайте прямо здесь посчитаем пакет по пункту 3.3:

    адрес будет 513
    запрос будет стандартный - dev:

    1. делим адрес на 8 старших и 3 младших бита: 01000000 001b => 0x40 0x01
    2. извлекаем старшую часть адреса: 0x40
    3. извлекаем младшую часть адреса: 0x01
    4. ставим во второй байт бит запроса: 0x09
    5. ставим во второй байт размер 0: 0x09
    6. ставим хеш имени команды: 0xd681
    7. данных нет, контрольную сумму пока пропускаем
    8. формируем пакет: 40 09 d6 81

    а теперь покажите мне безграмотному, как из этого получить #GHLGTMOHTISS\r, т.е. 01 50 d6 81, грамотный вы наш,
    я вам даже предлагаю покрутить этот кубик рубик (попереварачивать байты местами)
    почему не получится, да потому что очевидно

    во первых берется 8 младших битов,

    во вторых - последовательность формирования кадра в описании нарушена, но это еще не все

    битовая схема да - иногда она рисуется октетами, тогда порядок бит будет обратный в каждом байте,
    только ведь это обязательно надо отмечать либо в тексте, либо направлением либо MSB-LSB прямо в схеме, загляните в любой rfc и посмотрите как там описаны протоколы,

    а раз вы не знаете слова "стандарт", то я уже показал вид заголовка на овеновские устройства на си,
    причем сделал это не для вас, а для тех, кому непосчасливится вновь читать этот документ

  7. #17

    По умолчанию

    давайте читать вместе, как сказку на ночь.

    --
    "2.11 Каждое сообщение и квитанция передается старшими байтами вперед."

    не полубайтами, не битами, а именно байтами. это относится как ко всему пакету (до кодирования в ASCII), так и к частям пакета -- локальному идентификатору параметра, полю данных и контрольной сумме.

    это положение имеет забавное следствие: строки в поле данных лежат старшим байтом вперед, то есть задом наперед.


    "структурная схема протокола овен"

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

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


    "3.1 Метод передачи байта "Тетрада-в-ASCII-символ"

    особо сказать нечего. один байт превращается в два. старший из них опять передается первым (сюрприз!). сказкам про избыточность не верьте -- эффективность такой проверки очень низкая.


    "3.3 Структура кадра"

    для 11-битных адресов в первом байте пакета находятся _старшие_ восемь бит адреса. младшие три бита находятся в _старших_ битах второго байта пакета.

    проще всего забыть про 11-битную адресацию, и считать, что весь адрес помещается в первом байте пакета.

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

    блок данных канального уровня -- это дань модели взаимодействия открытых систем, применение которой только запутывает описание протокола. проще думать об этом блоке как о двух сущностях -- локальном идентификаторе (hash-коде) параметра и поле данных.

    локальный идентификатор вы худо-бедно посчитали, так что перейдем к CRC.


    "4.5 Хеширование имен параметров и вычисление контрольной суммы сообщения"

    контрольная сумма пакета -- это классический CRC16 с самопальным полиномом. аккумулятор инициализируется 0. почему в описании дана рекурсивная функция я не знаю -- видимо так она использовалась в доисторических приборах. более вменяемый алгоритм в этой ветке есть.

    контрольная сумма помещается в пакет, (вы не поверите!) старшим байтом вперед.
    --


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


    n'est ce pas?

  8. #18

    По умолчанию

    > а теперь покажите мне безграмотному, как из этого получить #GHLGTMOHTISS\r, т.е. 01 50 d6 81, грамотный вы наш,

    короткий ответ: никак.

    во-первых, заголовок пакета должен выглядеть так:

    Код:
    typedef union tagOwenHeader
    {
    	struct
    	{
    		int	High : 8;
    		int	Size : 4;
    		int	Query : 1;
    		int	Low : 3;
    	};
    
    	unsigned char Bytes[2];
    }OWEN_HEADER, *POWEN_HEADER;
    во-вторых, так как адрес у вас 11-битный, засовывать его в заголовок надо так:

    Код:
    hdr.High = addr >> 3;
    hdr.Low = addr & 0x07;
    и в результате вы получите то, что и должны:

    40 30 D6 81 11 6D и #KGJKTMOHHHMT\В

    ну и для всех остальных.

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

    и вообще, все это стрельба из пушки по воробьям, потому что проще и понятней писать сразу в буфер (Command в нашем случае).

  9. #19

    По умолчанию Расчет контрольной суммы на Delphi

    //Расчет контрольной суммы по алгоритму овен
    Function TForm1.owenCRC16(str:string):string;
    const
    //AsChars: array[0..15] of Char = 'GHIJKLMNOPQRSTUV';
    HexChars: array[0..15] of Char = '0123456789ABCDEF';
    var
    b:byte;i,j:integer; crc:word;
    begin
    crc:= 0;
    for i:= 0 to (length(str)div 2)-1 do
    begin
    b:=strtoint('$'+copy(str,(2*i)+1,2));
    for j:=1 to 8 do
    begin
    if ((b xor(crc shr 8))and $80)>0 then
    begin
    crc:=crc shl 1;
    crc:=crc xor $8F57;
    end
    else
    crc:=crc shl 1;
    b:=b shl 1;
    end;
    end;
    result:=char(HexChars[crc div 4096])+
    char(HexChars[(crc mod 4096)div 256])+
    char(HexChars[((crc mod 4096)mod 256)div 16])+
    char(HexChars[((crc mod 4096)mod 256)mod 16]);
    end;
    Последний раз редактировалось denver; 17.01.2012 в 19:24.

  10. #20

    По умолчанию

    Mega, огромное вам спасибо за прогу!!!!!!!!!! Замучился получать эту CRC Для СИ 8. Когда же в России кончится самопал!? И появятся нормальные описания протоколов с примерами.

Страница 2 из 2 ПерваяПервая 12

Ваши права

  • Вы не можете создавать новые темы
  • Вы не можете отвечать в темах
  • Вы не можете прикреплять вложения
  • Вы не можете редактировать свои сообщения
  •