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

Как скопировать символы из обычного буфера в массив строк?

Зачем вообще что-то копировать и перемещать? Скролинг делается "скролингом" индекса. Я не знаю как у вас меняется индекс (кол-во) принятых строк str_buffer_write_position. Допустим изменятеся от 0 до 10000000000000000000000000000000000.

тогда

#define RX_BUFFER_SIZE 256

uint8_t rx_buffer[RX_BUFFER_SIZE];
char TERMINAL_TEXT[100][256];

for(uint8_t i=0;i<255;i++) TERMINAL_TEXT[str_buffer_write_position%100][i]=rx_buffer[i];

и ни чего, при появлении 101-ой строки ни куда не нужно перекопировать.

последняя строка всегда str_buffer_write_position%100

можно, для читаемости кода так

#define RX_BUFFER_SIZE 256 
  uint8_t rx_buffer[RX_BUFFER_SIZE]; 
char TERMINAL_TEXT[100][256]; 
static int index = 0;

index = str_buffer_write_position%100;
for(uint8_t i=0;i<255;i++) 
  TERMINAL_TEXT[index][i]=rx_buffer[i];

 

for(uint8_t i=0;i<255;i++) TERMINAL_TEXT[str_buffer_write_position][i]=rx_buffer[i];

У вас же не каконить ПК с говновиндой, у вас МК со всеми потрахами. Зачем какие-то memmove и т.п.? Используйте DMA.

 

ps

сделайте буфер размером степень 2, т.е. 128 или 64. Тогда
 

#define RX_BUFFER_SIZE 256
  uint8_t rx_buffer[RX_BUFFER_SIZE];
char TERMINAL_TEXT[128][256];
static int index = 0x7f;

//при получении новой строки инкремент индекса

++index &= 0x7f; //или (128-1), или (64-1)
//for(uint8_t i=0;i<255;i++)
//  TERMINAL_TEXT[index][i]=rx_buffer[i];
memcpy(&TERMINAL_TEXT[index][0], rx_buffer, 255);

 

у вас index всегда будет указывать на последнюю принятую строку. не нужно ни каких адски сдвигов массивов с текстом, не будет ни какой нагрузки на МК.

Изменено пользователем razrab83

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


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

char TERMINAL_TEXT[128][256];


++index &= 0x7f; //или (128-1), или (64-1)
uint32_t *pOut = (uint32_t *)&TERMINAL_TEXT[index][0];
uint32_t *pInt = (uint32_t *)rx_buffer;
for(uint8_t i=0;i<64;i++) //копируем 256 байт
  pOut[i] = pInt[i];

ps в 4 раза быстрее.... помните про выравнивание

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


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

1 hour ago, razrab83 said:

for(uint8_t i=0;i<255;i++) TERMINAL_TEXT[str_buffer_write_position%100][i]=rx_buffer[i];

 

Я понял в чем ваша идея. Я, по глупости,  переписывался содержимое всего массива. Нулевой элемент затирал первыпэм, первый затирал вторым... последний - новым. И так 100 раз. Вы же предлагаете затирать новым элементом  самый старый элемент. А чтобы не переписывать все остальные, просто сдвигать фокус чтения и нумероватт элементы от этого самого фокуса. То есть, скажем, получили мы 103 строку, она запишется в третий элемент массива. А  чтобы вывести список строк, нам нужно читать с четвёртого по сотый, а дельше нулевой, первый и второй. И так далее. Я правильно понял? 

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


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

12 минут назад, Salamander сказал:

 

Я понял в чем ваша идея. Я, по глупости,  переписывался содержимое всего массива. Нулевой элемент затирал первыпэм, первый затирал вторым... последний - новым. И так 100 раз. Вы же предлагаете затирать новым элементом  самый старый элемент. А чтобы не переписывать все остальные, просто сдвигать фокус чтения и нумероватт элементы от этого самого фокуса. То есть, скажем, получили мы 103 строку, она запишется в третий элемент массива. А  чтобы вывести список строк, нам нужно читать с четвёртого по сотый, а дельше нулевой, первый и второй. И так далее. Я правильно понял? 

Да! При этом, скорость "скролинга" не будет зависить от размера строкового буфера. Хоть буфер на 5 строк, хоть на 100 строк, хоть на 65000 строк.

 

 

Вывод начиная с самой старой строки
 

for(int i = 0; i<100; i++)

{

int j = i + str_buffer_write_position%100;

if( j > 99)

j -= 100;

printf(&TERMINAL_TEXT[j][0]);

}

как-то так (только "100" заменть на define)

Изменено пользователем razrab83

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


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

18 minutes ago, razrab83 said:

int j = i + str_buffer_write_position%100;

А зачем тут то остаток получать? Str_buffer_write_position  на данном этапе гарантированно будет обнуляться после ста, за счёт предшествующего кода. 

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


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

я ни где в коде не увидел (не писал)

str_buffer_write_position = ....

Переменная str_buffer_write_position измениться только после оператора "=".

for(uint8_t i=0;i<255;i++) TERMINAL_TEXT[str_buffer_write_position%100][i]=rx_buffer[i];

Тут str_buffer_write_position делится на 100, остаток от деления используется в качестве индекса массива, но сама переменная str_buffer_write_position  не меняется.

Если у вас где-то в коде str_buffer_write_position обнуляется, то тогда дополнительно в выводе %100 не нужно. 

Изменено пользователем razrab83

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


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

1 час назад, juvf сказал:

char TERMINAL_TEXT[128][256];


++index &= 0x7f; //или (128-1), или (64-1)
uint32_t *pOut = (uint32_t *)&TERMINAL_TEXT[index][0];
uint32_t *pInt = (uint32_t *)rx_buffer;
for(uint8_t i=0;i<64;i++) //копируем 256 байт
  pOut[i] = pInt[i];

ps в 4 раза быстрее.... помните про выравнивание

memcpy - заботится и о выравнивании и о скорости

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


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

On 4/9/2021 at 3:39 PM, razrab83 said:

Если у вас где-то в коде str_buffer_write_position обнуляется, то тогда дополнительно в выводе %100 не нужно. 

Действительно, обнуляется.

Ваш код (я уменьшил число строк до 15 для удобства)

for(int i = 0; i<100; i++)

{

int j = i + str_buffer_write_position;

if( j > 14)

j -= 15;

printf(&TERMINAL_TEXT[j][0]);

}

работает отлично.  Если понаблюдать отладчиком то имеем полноценный кольцевой буфер.

Но.... блин, вроде задача простая, а я что-то мозг весь сломал. Проблемы начинаются при чтении этого буфера.

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

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

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

Почему так получается? Смотрите, получена первая строка, str_buffer_write_position=1.   

Начинаем выводить, заполняем первую строку дисплея. i=0, тогда j = i + str_buffer_write_position дает нам "1".  И программа читает строку не из нулевого элемента массива, а из первого, а там пусто. И так дальше.

И лишь когда мы выводим последнюю строку, у нас срабатывает if( j > 14) j -= 15; и мы получаем "указатель" на нулевой элемент массива.

Логичная попытка сделать  j = i + str_buffer_write_position -1  (уменьшили на единицу) - это работает только на первой строке. Как только появляется следующая строка,  str_buffer_write_position увеличивается до 2 и тогда уже нужно отнимать 2.

По сути - до того как экран заполнится полностью, j = i + str_buffer_write_position нужно заменить на j=i. И тогда работает. Но  после заполнения экрана скроллинга нет по понятным причинам.

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

ЧТо думаете?

    
    

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


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

9 часов назад, Salamander сказал:

уже неактуально. решил.

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

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


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

35 minutes ago, Herz said:

Потрудились бы хоть в общих чертах сообщить, в чём же именно она состояла и как удалось решить.

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

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


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

Друзья еще вопрос.

Нашел готовую функцию разбиения строки на подстроки по разделителю

#include "stdio.h"   
#include "stdlib.h"   
#include "string.h"   
#include <assert.h>


char** str_split(char* a_str, const char a_delim)
{
    char** result    = 0;
    size_t count     = 0;
    char* tmp        = a_str;
    char* last_comma = 0;
    char delim[2];
    delim[0] = a_delim;
    delim[1] = 0;

    /* Count how many elements will be extracted. */
    while (*tmp)
    {
        if (a_delim == *tmp)
        {
            count++;
            last_comma = tmp;
        }
        tmp++;
    }

    /* Add space for trailing token. */
    count += last_comma < (a_str + strlen(a_str) - 1);

    /* Add space for terminating null string so caller
       knows where the list of returned strings ends. */
    count++;

    result = malloc(sizeof(char*) * count);

    if (result)
    {
        size_t idx  = 0;
        char* token = strtok(a_str, delim);

        while (token)
        {
            assert(idx < count);
            *(result + idx++) = strdup(token);
            token = strtok(0, delim);
        }
        assert(idx == count - 1);
        *(result + idx) = 0;
    }

    return result;
}

 

 

Проект с этой функцией компилируется, то есть никаких неизвестных функций в коде нет. Но вот при линковке получаю "Error: L6218E: Undefined symbol strdup (referred from main.o)."

Блин... почему так? Стандартные же библиотеки, include прописаны, чего еще не хватает? у меня KEIL, если что.

 

в string.h прототип strdup не описан. Я понимаю, что код писался под навороченные компиляторы и библиотеки к ним, а в KEIL они урезанные что ли.... но чем заменить эту функцию тогда? 

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


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

12 minutes ago, Aleksandr Baranov said:

А функция strtok Вам не пригодится?

Хм.. Вы указали на функцию, которая вызывается в той функции, что я привёл. Что скажете? 

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


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

Ах. прошу прощения.  Просмотрел по диагонали и не заметил. У меня в IAR есть strdup, но, в принципе, его можно заменить на strcpy, слегка изменив программу.

Изменено пользователем Aleksandr Baranov

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


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

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

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

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

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

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

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

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

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

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