Считать пакет символов в массив и затем проанализировать - PullRequest
0 голосов
/ 31 августа 2018

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

Я работаю с парой разработчиков, пытаясь заставить их говорить друг с другом. Одна доска, с которой мне нужно поговорить, дала пример кода, с которым я пытался работать. Функция TX работает нормально, я просто недостаточно знаком с C, чтобы полностью понять, что я делаю.

Функция RX, которую они предоставляют:

int recv_packet(char *p, int len){
    char c;
    int received = 0;
    /* sit in a loop reading bytes until we put together
    * a whole packet.
    * Make sure not to copy them into the packet if we
    * run out of room.
    */
    while(1) {
        /* get a character to process
        */
        c = UART_GetChar();
        /* handle bytestuffing if necessary
        */
        switch(c) {
            /* if it's an END character then we're done with
            * the packet
            */
            case END:
                /* a minor optimization: if there is no
                * data in the packet, ignore it. This is
                * meant to avoid bothering IP with all
                * the empty packets generated by the
                * duplicate END characters which are in
                * turn sent to try to detect line noise.
                */
                if(received)
                    return received;
                else
                    break;
            /* if it's the same code as an ESC character, wait
            * and get another character and then figure out
            * what to store in the packet based on that.
            */
            case ESC:
                c = UART_GetChar();
                /* if "c" is not one of these two, then we
                * have a protocol violation. The best bet
                * seems to be to leave the byte alone and
                * just stuff it into the packet
                */
                switch(c) {
                    case ESC_END:
                        c = END;
                        break;
                    case ESC_ESC:
                        c = ESC;
                        break;
                }
            /* here we fall into the default handler and let
            * it store the character for us
            */
            default:
                if(received < len)
                p[received++] = c;
        }
    }
}

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

int main() {
    char arr[10] = {0};
    recv_packet(arr, 10);
    /*then parse it somehow-- 
    * I'll figure this out on my own, 
    * but for now I just want to read it all 
    * into an array.
    */
    parse_function(arr);
}

Так что, если вы прошли через все это .... мой большой вопрос, как мне предотвратить заполнение массива, если я уменьшу длину сообщения, которое мне нужно получить? устройство, с которым я использую C для общения, отправит обратно последовательность шестнадцатеричных символов, начинающихся и заканчивающихся 0xC0 (иначе определяемых в другом коде как «END»), но середина - это целый беспорядок в гексе, который является ответом от устройство в зависимости от того, что я отправляю в send_packet. Я думаю, я мог бы сделать arr очень большим на всякий случай, но я хочу знать, какое правильное кодирование будет диктовать в этом сценарии.

Ответы [ 2 ]

0 голосов
/ 31 августа 2018

Я говорю, что вам нужно больше анализа - 2 шага. Шаг первый: определите (или соблюдайте) протокол, который вы собираетесь использовать. Протокол должен определять максимальную длину пакета, и более крупный пакет не будет допустимым. Размещенная вами подпрограмма уже защищена от слишком большого количества пакетов, но проверка ее подлинности не выполняется. Протокол может определять фиксированную длину для пакета или разные длины для разных типов пакетов, или что угодно, и вы должны проверить их.

Шаг второй: получать по одному пакету за раз, управлять им, а затем начинать заново.

Есть две техники, которые могут помочь в простой ситуации выше. Если вам нужно передать большие объемы данных, используйте более одного пакета для (большого) блока логических данных; например, если вы принимаете данные и сохраняете их где-то еще, например, на флэш-памяти, нехорошо получать все данных и затем сохранять все данных. Делайте это по частям, возможно, вместе с проверкой согласованности.

Второе предложение: если вы беспокоитесь, что можете потерять пакет при управлении другим, вы должны использовать прерывания (возможно, вы уже это делаете). Таким образом, вы можете получать , а манипулировать данными. Иногда двойной буфер может помочь; получить пакет, поместить его во вторичный (двойной) буфер, начать снова получать, пока вы анализируете вторичный буфер. Это можно даже сделать непосредственно в подпрограмме прерывания (переключение буферов вместо копирования между ними), но это, вероятно, не в тему.

- ОБНОВЛЕНИЕ ПОСЛЕ КОММЕНТАРИИ НИЖЕ -

На самом деле, когда речь идет о передаче данных, обработка входящих данных при их получении является наиболее эффективным (и, вероятно, безопасным) способом. В любом случае вы должны получать и анализировать (две вещи), поэтому код не становится больше. Вы не тратите время на ожидание данных и не тратите ненужный баран. По крайней мере, некоторая низкоуровневая часть протокола должна быть выполнена во время приема (подпрограмма, которую вы опубликовали, делает что-то с побегами). Как вы упомянули, при получении иногда вы можете знать, сколько данных придет после.

0 голосов
/ 31 августа 2018

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

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

Так что вместо char arr[10] = {0}; вы могли бы сделать

char arr[10000];

и просто используйте его снова и не беспокойтесь о том, что не хватит места.

...