Перейти к содержанию
    

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

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

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

пошаговое объяснение работы протокола змодем. Понял не все, надеюсь пойму.
  Прием файла --->
 * 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
 * Есть идеи как лучше это реализовать на си ? 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

14 minutes ago, Alex_Golubev said:

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

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

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

вот тест:

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

    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 начинаем сначала
             }

    	}
    }

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Есть программы (пакеты) для linux с поддержкой zmodem. Посмотрите исходники lrzsz или minicom.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...