Jump to content

    
Sign in to follow this  
Alex_Golubev

Как лучше сделать реализацию на языки си протокола?

Recommended Posts

Вопрос к Гуру. 

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

пошаговое объяснение работы протокола змодем. Понял не все, надеюсь пойму.
  Прием файла --->
 * 1.  ---> Получаю команду RZ+CR в числовом виде в .hex формате 72 7A 0D
 * 2.  ---> Получаю запрос "Так называемый ZRQINIT" в .hex формате 2A 2A 18 42 30 30 30 30 30 30 30 30 30 30 30 30 30 30 8D 8A 11 раскладывается по HEX HEADER "* * ZDLE B TYPE F3/P0 F2/P1 F1/P2 F0/P3 CRC-1 CRC-2 CR LF XON" причем 8D 8A в xor операции
 * 3.  <--- Я должен ответить на запрос "ZRQINIT" отвечаю в HEX формате (взял за основу HEX формат) "2A 2A 18 42 30 31 30 30 30 30 30 30 32 33 62 65 30 0D 8A" причем самое интересное может прийти запрос а может и не прийти запрос нужно обрабатывать два события
 * 4.  ---> Получаю запрос "ZFILE" с заголовком названия файла сначала получаю "2A 18 41 04 00 00 00 01 99 27" После сразу приходит "68 65 6C 6C 6F 77 6F 72 6C 64 2E 74 78 74 00 31 37 20 31 33 37 33 36 37 33 36 32 35 34 20 31 30 30 36 34 34 00 18 6B 18 51 4A"
 * 5.  <--- После сразу отвечаю ZPAD отправляю посылку "2A 2A 18 42 30 39 30 30 30 30 30 30 30 30 61 38 37 63 0D 8A"
 * 6.  ---> Получаю данные файл в .bin формате "68 65 6C 6C 6F 20 77 6F 72 6C 64 21 21 21 21 21 21 18 68 B3 94" в конце контрольная сумма Crc16
 * 7.  ---> В силу короткого файла получаю конец файла "ZEOF" "2A 2A 18 42 30 62 31 31 30 30 30 30 30 30 38 31 65 63 8D 8A 11"
 * 8.  <--- Отвечаю в .bin формате "2A 2A 18 42 30 31 30 30 30 30 30 30 32 33 62 65 30 0D 8A"
 * 9.  ---> Принимаю пакет ZFIN "2A 2A 18 42 30 38 30 30 30 30 30 30 32 33 62 65 30 0D 8A"
 * 10. <--- Отвечаю ZFIN "2A 2A 18 42 30 38 30 30 30 30 30 30 32 33 62 65 30 0D 8A"
 * 11. ---> Получаю два символа "OO"
 *
 * Проблемы:
 * 1. Использую виртуальный ком порт на stm32. По виртуальному ком порту может прийти от 1 байта до 64 байт. Пример может сразу прийти RZ+CR или сначала R потом Z  потом CR
 * 2. Обрабатываю входную информацию в векторе прерывания USB
 * 3. Высылаю данные ответа через USB
 * Есть идеи как лучше это реализовать на си ? 

Share this post


Link to post
Share on other sites
14 minutes ago, Alex_Golubev said:

Есть идеи как лучше это реализовать на си ?

Наверняка есть. Я не "гуру" в С, но меня всегда огорчают подобные вопросы.

Покажите сначала свою идею. Начните с чего-то. Попробуйте вообще реализовать это на С. А тогда Вам уже подскажут, "как лучше", укажут на ошибки.

Вы же на рассчитываете здесь получить готовое решение, просто озвучив проблемы?

А то звучит как: "я-то знаю, как реализовать. Но желаю совершенства. Может, у кого есть идеи получше"?

Share this post


Link to post
Share on other sites

Я написал тестовую программу когда изучал протокол. Но мне она очень не нравится ищу варианты более правильного кода.

вот тест:

Скрытый текст

    if(UserRxBufferFS[0] == 'r' && UserRxBufferFS[1] == 'z' && UserRxBufferFS[2] == CRZmodem){ // если пришла команда c zmodem "rz" + cr
    comandeZmodem = 1; // устанавливаем флаг что пришла команда, дабы на следующем вызове прерывания произошел вход в обработчик входного пакета данных
    HEADERFile = 0; // сброс всех основных флагов
    DataFile = 0;
    counteFile = 0; // счетчик принимаемого файла
    OO = 0; // сброс флага конца приема данных
    }


    if(HEADERFile){ // если устанавился флаг приема заголовочных данных

    	uint16_t i = 0;
    	uint16_t conterChar = 0;

    	for(i = 0; i < *Len; i++){
    		if(UserRxBufferFS[i] != ZDLE){
    		bufUsb[conterChar++] = UserRxBufferFS[i];
    		}
    		else{
    			if(UserRxBufferFS[i] == ZDLE){

            	 if((UserRxBufferFS[i + 1] & 0x60) == 0x40){
            		 UserRxBufferFS[i + 1] &= 0xbf;
        		     bufUsb[conterChar++] = UserRxBufferFS[i + 1];
        		     i = i + 1;
            	 }
            	 }
    		}
    	}// наложена маска на первый байт crc 16 в случаи приема в hex формате

    if(!rZModem_crcUpdate(bufUsb,conterChar))
    {
    	asm("nop"); // тест
    }
    rZModem_sendHexHeader(ZRPOS); // ответ на загаловок
    HEADERFile = 0; // сброс флага о готовности взятия загаловка
    }



    if(DataFile){ // прием файла максимальная длина файла по протоколу zmodem 1024 байта
    if(counteFile < 1024){
     for(uint16_t i = counteFile; i < counteFile + *Len; i++){
    	 bufUsb[i] = UserRxBufferFS[i];
     }
    }
    else{
    	DataFile = 0;
    }
    counteFile += *Len;

    }


    if(comandeZmodem){ // если пришла команда rz+cr

    	if(UserRxBufferFS[0] == 'o' && UserRxBufferFS[1] == 'o' && OO){
    	comandeZmodem = 0;
    	OO = 0;
    	}

    	if(UserRxBufferFS[0] == ZPAD && UserRxBufferFS[1] == ZPAD && UserRxBufferFS[2] == ZDLE && UserRxBufferFS[3] == ZHEX){ // hex формат "ZPAD , ZPAD, ZDLE, ZHEX"

    		if(UserRxBufferFS[18] == (CRZmodem^0x80) && UserRxBufferFS[19] == (LF^0x80) && UserRxBufferFS[20]== XON) // пришли последнее команды говорящие о конце покета
    		{
    			uint8_t bufcomand[7];
    			memset(bufcomand,0,sizeof(bufcomand)); // убираю какахи из буфера
             for(uint8_t i = 0; i < 7; i++){
            	 bufcomand[i] = rZModem_getNextHexCh(UserRxBufferFS[4 + i*2], UserRxBufferFS[4 + i*2 + 1]); // 4 5   6 7   8 9    10 11    12 13  14 15    16 17
             }
             if(!rZModem_crcUpdate(bufcomand,7)){
            	 if(bufcomand[0] == ZRQINIT){
            	 rZModem_sendHexHeader(ZRINIT); // ответ на ZRINIT
            	 }

            	 if(bufcomand[0] == ZEOF){ // по суте как понял присылается в конце после передачи файла
            	 rZModem_sendHexHeader(ZRINIT); // ответ на ZEOF
            	 }

            	 if(bufcomand[0] == ZFIN){
            	 rZModem_sendHexHeader(ZFIN); // ответ на ZFIN
            	 OO = 1;
            	 }
             }
             else{
             comandeZmodem = 0; // не сошлось crc начинаем сначала
             }

    		}
    	}
    	else if(UserRxBufferFS[0] == ZPAD && UserRxBufferFS[1] == ZDLE && UserRxBufferFS[2] == ZBIN){ // bin формат

    		uint8_t bufcomand[7];
    		uint8_t counterComand = 0;
    		uint8_t j = 7;
    		memset(bufcomand,0,sizeof(bufcomand)); // убираю какахи из буфера

             for(uint8_t i = 0; i < j; i++){ // на случай если получил иинвернтированый дюбильный zdle, нах он нужен?
            	 if(UserRxBufferFS[i + 3] != ZDLE){
            	  bufcomand[counterComand++] = UserRxBufferFS[i + 3];
            	 }
            	 else{
            		 if(UserRxBufferFS[i + 3] == ZDLE){
                    	 if((UserRxBufferFS[i + 1 + 3] & 0x60) == 0x40){
                    		 UserRxBufferFS[i + 1 + 3] &= 0xbf;
                    		 bufcomand[counterComand++] = UserRxBufferFS[i + 1 + 3];
                		     i = i + 1;
                		     j = j + 1; // пока не придумал более лучшей вариант но охота счетчик j убрать иногда приходит zdle зачем не ясно
                    	 }
            		 }
            	 }
             }

             if(!rZModem_crcUpdate(bufcomand,7)){
            	 if(bufcomand[0] == ZFILE){
            		 HEADERFile = 1;
            	 }

            	 if(bufcomand[0] == ZDATA){
            		 DataFile = 1;
            		 counteFile = 0; // обнуляем счетчик длины приемного буфера файла
            	 }
             }
             else{
             comandeZmodem = 0; // не сошлась crc начинаем сначала
             }

    	}
    }

 

 

Share this post


Link to post
Share on other sites

Подобные вещи решаются с помощью Конечных Автоматов. У Вас есть несколько состояний (ожидание RZ+CR, ожидание ZRQINIT, ожидание ZFIN и т.п.) и условий, по которым автомат переходит из одного состояние в другое (определённая последовательность байт или т.п.).

1) Почитайте про конечные автоматы, на листочке постройте граф переходов для разбора вашего протокола

2) Посмотрите как конечные автоматы на реализуются на СИ (на swich/case или на таблице переходов)

3) Реализуйте построенный граф на Си

Например, можете посмотреть на WAKE - там в функциях Port_Read и Port_Write на конечных автоматах (на основе swich/case) разбор протокола сделан.

Share this post


Link to post
Share on other sites

Я почитал теорию и подумываю использовать автомат с магазином памяти. Как понял он полностью покрывает приём передачу файла, и приём передачу команд для работы с терминалом. Может у кого есть боевая реализация на си?  Или может подсказать где взять можно. 

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this