PDA

Просмотр полной версии : Часть массива перевести в строку



=Алекс=
04.03.2016, 21:51
Я новичок, кто может помогите. :rolleyes:
Получаю массив 10 ff 90 00 00 07 00 72 16 04 35 36 35 36 88 19, в котором часть 35 36 35 36 нужно преобразовать в строку. Должно получится 5656.

Для преобразования прочитал, что удобнее использовать библиотеку oscat.lib


input:ARRAY [0..18] OF BYTE:= 16#10, 16#FF, 16#90, 16#00, 16#00, 16#07, 16#00, 16#72, 16#16, 16#04, 16#35, 16#36, 16#35, 16#36, 16#88, 16#19;
out: STRING:= CHR_TO_STRING(input[11])+CHR_TO_STRING(input[12])+CHR_TO_STRING(input[13])+CHR_TO_STRING(input[14]);

Такой вариант кода не дает компилировать.
Подскажите пожалуйста как это делается правильно...

_Pavel_
04.03.2016, 23:14
Обьявите строку. И скопируйте нужное количество байтов в нее из входного массива с помощью функции SysMemCpy()

Валенок
05.03.2016, 00:36
И нолик в конец не забываем

capzap
05.03.2016, 07:22
Где описан тип CHR?
а вместо многобукв и добавления доп.библиотеки можно так


foo : STRING;
bar : POINTER TO STRING(4);

#######
bar := ADR(input[11]);
foo:=bar^;

_Pavel_
05.03.2016, 10:19
capzap, а если adr будет нечетный не получим ли мы зависание при обращении к указателю?
А если в буфере будет строка другой длины?

=Алекс=
05.03.2016, 10:30
Где описан тип CHR?
а вместо многобукв и добавления доп.библиотеки можно так


foo : STRING;
bar : POINTER TO STRING(4);

#######
bar := ADR(input[11]);
foo:=bar^;


Попробовал! Отлично работает! Спасибо за примерчик ;)
только немного подправил, т.к. немного результат был сдвинут...
bar : POINTER TO STRING(3);
bar := ADR(input[10]);

capzap
05.03.2016, 11:10
capzap, а если adr будет нечетный не получим ли мы зависание при обращении к указателю?
А если в буфере будет строка другой длины?

а может Вы изучите работу указателей и не будет у Вас этих если

Валенок
05.03.2016, 11:44
а если adr будет нечетный не получим ли мы зависание при обращении к указателю?
тут соглашусь с capzap. Если в основе - байтовый тип (byte,bool,sint,usint,string,массивы из этого), то адрес не имеет значения. Даже внутри структуры или фб. Даже структуры* или фб* где внутри - тока эти типы или массивы их них.
*То что при статическом размещении их адреса будут выровнены под 4 байта а размер неявно увеличен до кратного 4-ем, ничуть не меняет ранее сказанное

А если в буфере будет строка другой длины?
.. заранее неизвестная. Вот тут интересней. Поэтому я и напомнил про нолик с Вашего позволения

_Pavel_
05.03.2016, 11:59
Согласен по поводу первого обычный String он байтовый и все хорошо. Просто я подумал что ТС парсит сетевой пакет т.е. сейчас например ему нужно 5656 а потом придет 565656. Хотелость предложить более общее решение и надежное. Вдруг он захочет воспользоваться такой же технологией(указателем) и для других типов в будущем что приведет к известным последствиям.

capzap
05.03.2016, 12:06
Согласен по поводу первого обычный String он байтовый и все хорошо. Просто я подумал что ТС парсит сетевой пакет т.е. сейчас например ему нужно 5656 а потом придет 565656. Хотелость предложить более общее решение и надежное. Вдруг он захочет воспользоваться такой же технологией(указателем) и для других типов в будущем что приведет к известным последствиям.
советую пролистать библиотеку oscat, там массивы обрабатываются с помощью указателя на один байт, дополнительным входом используется количество единиц для обработки, в такой функции можете и спереди и сзади наставить кучу проверок, чтоб соответствовала Вашему представлению валидности

=Алекс=
05.03.2016, 12:07
Еще вопрос, по той же теме...
Есть другой массив 10 ff 90 00 00 07 00 72 43 04 cc ef c8 41 47 5e, в котором часть cc ef c8 41 нужно преобразовать в REAL. Должно получится 25.12.
Из первого ответа такая обработка не работает, получаю абракадабру...
Подскажите что тут можно придумать?

Валенок
05.03.2016, 12:13
Согласен по поводу первого обычный String он байтовый и все хорошо. Просто я подумал что ТС парсит сетевой пакет т.е. сейчас например ему нужно 5656 а потом придет 565656. Хотелость предложить более общее решение и надежное. Вдруг он захочет воспользоваться такой же технологией(указателем) и для других типов в будущем что приведет к известным последствиям.

например

кол-во заранее известно


var_input
index,size : word;
var_output
str : string(...);
overflow : bool;
------
overflow := size >= (sizeof(str) - 1);
size := min(size,sizeof(str) - 1);
sysmemcpy(adr(str),adr(buffer[index]),size);
sysmemset(adr(str) + size,0,1);



неизвестно


var_input
index : word;
var_output
str : string(...);
overflow : bool;
var
i : word; //без языков
p : pointer to array[0..65535] of byte;
-----
p := adr(str);
for i := 0 to sizeof(str) - 1 do
p^[i] := buffer[index + i];
overflow := false;
if p^[i] = 0 then exit; end_if
overflow := true;
end_for

Писал на слух. Возможны мелкие очепятки

capzap
05.03.2016, 12:21
Еще вопрос, по той же теме...
Есть другой массив 10 ff 90 00 00 07 00 72 43 04 cc ef c8 41 47 5e, в котором часть cc ef c8 41 нужно преобразовать в REAL. Должно получится 25.12.
Из первого ответа такая обработка не работает, получаю абракадабру...
Подскажите что тут можно придумать?
переверните байты ззеркально, если не получится то сделайте такую последовательность 3,4,1,2

Валенок
05.03.2016, 12:31
Предполагаю что тс не понимает о чем речь.
Строки тут вообще не при делах

function get : real
var_input
index : word;
----
sysmemcpy(adr(get),adr(buffer[index]),sizeof(get));

Вот тут и возможно

переверните байты ззеркально, если не получится то сделайте такую последовательность 3,4,1,2

ps
дальнейшее форматирование - это вообще другая история

=Алекс=
05.03.2016, 13:06
Написал вот так:

buffer:ARRAY [0..18] OF BYTE:= 16#10, 16#ff, 16#90, 16#00, 16#00, 16#07, 16#00, 16#72, 16#43, 16#04, 16#cc, 16#ef, 16#c8, 16#41, 16#47, 16#5e;
sysmemcpy(adr(get),adr(buffer[10]),sizeof(get));
Этот буфер каждый раз читается из com порта, в com порт приходит один и тот же ответ.
Но при тесте я вижу на первом цикле правильный REAL ответ. А дальше ерунда, и ПЛК перезагружается...
Надо что-то еще чистить каждый раз?

Валенок
05.03.2016, 13:13
Обратите внимание на строчку

function get : real
ну и на то, что входной index не может быть больше 15-ти, если

buffer:ARRAY [0..18] OF BYTE

=Алекс=
05.03.2016, 13:37
Исправил.

buffer:ARRAY [0..15] OF BYTE:= 16#10, 16#ff, 16#90, 16#00, 16#00, 16#07, 16#00, 16#72, 16#43, 16#04, 16#cc, 16#ef, 16#c8, 16#41, 16#47, 16#5e;
get:REAL;
------------------
sysmemcpy(adr(get),adr(buffer[10]),sizeof(get));
Первый цикл считает верное значение, далее все не то, а после 8 цикла ребут ПЛК.

То что писали про function get : real - это именно нужно создать новую функцию и к ней обращаться, или можно так как я тут написал?

P.S. Попробовал сделал отдельную функцию, как предлагал Валенок. Работает одинакого, т.е. первый ответ есть, а на восьмой запрос ребут.
Как-то можно увидеть причину ребута? У меня работает код с использованием оператора Case. Пробовал ставить точки останова, но так и не увидел ошибки...

Валенок
05.03.2016, 15:05
...Первый цикл....
Ввиду очень широкого трактования слова "цикл" и факта - "вы здесь недавно", рекомендую Вам выложить весь код

PS
buffer:ARRAY [0..15]
Я имел ввиду не размер буфера, а входной индекс отвечающий за выход за его приделы при p[index + 3]^

=Алекс=
05.03.2016, 16:18
Прикрепил свой проект.
Там 4 запроса, на первый запрос ответа нет (он и не нужен). Второй запрос, ответ от прибора одинаковый, говорит что на связи. Третий запрос получаем адрес прибора, четвертый чтение параметра.
Ответы: на 1 = нет
на 2 = 10 ff 3f 37 2a 01 4f 16
на 3 = 10 ff 90 00 00 07 00 72 16 04 31 32 33 34 17 cc (это 1234)
на 4 = 10 ff 90 00 00 07 00 72 43 04 cc ef c8 41 37 5e (это 25,12).

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

capzap
05.03.2016, 16:30
как я и писал последовательность 3,4,2,1 получается число 25.1170883178711

Валенок
05.03.2016, 17:23
Как вариант - нет контроля возможного переполнения вторичного буфера otvet.
Просто проанализируйте что будет если для comand_type = 0 придет 6,6 и еще раз 6. Без раздумий о том, откуда они возьмутся.

=Алекс=
05.03.2016, 20:57
Как вариант - нет контроля возможного переполнения вторичного буфера otvet.
Просто проанализируйте что будет если для comand_type = 0 придет 6,6 и еще раз 6. Без раздумий о том, откуда они возьмутся.
Буфер otvet чистится каждый раз перед новым запросом...

FOR i:=0 TO 15 DO
otvet[i]:=0;
END_FOR

Подскажите, а как можно контролировать переполнение? или можно просто увеличить буфер otvet до 30 например?

Про comand_type = 0 в rejim = 0 ответа нет (стоит заглушка). Когда rejim = 2, то проверяю наличие ответа с длиной принятого ответа = 7. Если да, присваиваю string = good.
Про повторные ответы прибора не понял, прибор же вроде отвечает один раз на запрос. ПЛК прочитав ответ длиной 7, дальше не слушает порт, по идее все остальное улетает мимо... Или я ошибаюсь?

Валенок
06.03.2016, 01:17
Код-то чего убрали ? Ваши сикреты вряд ли тут кому нужны.

Когда rejim = 2, то проверяю наличие ответа с длиной принятого ответа = 7.
Да пофигу на Ваш rejim. У Вас жесткие условия выхода 7 или 15. Как Вам 18 ? Па буковам - просто проанализируйте что будет еcли придет 6,6 и еще раз 6. В разных циклах. За 600мс много чего может навалится в порт. На другой стороне случайно начихают в порт, ваша прога - в перезагруз.

Это

Буфер otvet чистится каждый раз перед новым запросом...
можно вообще выкинуть. Пустая трата времени

=Алекс=
06.03.2016, 12:08
Методом тыка, заметил, что при уменьшении времени ожидания ответа до 100мс. ПЛК перестал перезагружаться...
Но и правильных ответов на запрос нету...
Подскажите а как можно фильтровать полученный ответ, зная что начало ответа прибора 16#10, 16#FF, 16#90 далее отсчитать длину и остальное просто не сохранять в буфер?
Я не пойму как это сделать... Вернее как правильно это записать...
Структуру чтения ответа брал из примера с сайта Овен.


buf_otvet: ARRAY [0..7] OF BYTE ;
otvet: ARRAY [0..15] OF BYTE ;
byte_read:DWORD;
l:DWORD:=0;
-----
byte_read:=SysComRead(port_number, ADR(buf_otvet), 8, 0);
IF byte_read>0 THEN
FOR i:=0 TO byte_read-1 DO
otvet[l+i]:=buf_otvet[i];
END_FOR
l:=l+byte_read;

l откуда считается (длина запроса), т.е. по коду присвоения нет, только в конце в виде очищения приравнивается к нулю? И не пойму, зачем массив otvet заполняется с индексом l+i а не просто i ?

Валенок
06.03.2016, 12:42
при уменьшении времени ожидания ответа до 100мс. ПЛК перестал перезагружаться...
Вы вообще ответы читаете ? За 600мс много чего может навалится в порт


брал из примера с сайта Овен
Косяки могут быть где угодно у кого угодно. Главное - их увидеть. В том коде - есть потенциальная мина.


l откуда ... ? И не пойму .. i ?
К авторам. В данном фрагменте вообще много лишнего


а как можно фильтровать полученный ответ, зная что начало ответа прибора 16#10, 16#FF, 16#90 далее отсчитать длину и остальное просто не сохранять в буфер?
Сначала надо определится, что является разделением пакетов - символы и/или время ? (таймаут - отдельная песня).
Раз Вы копались с получением real'а непосредственно в бинарнике, смело предположу что константы гонять по сети Вы не будете и осторожно напомню, что при разделении "только символ" легко можете получить случайный разрез при некоторых значениях в данных.

далее отсчитать длину и остальное просто не сохранять в буфер?
И если разделение "только символ", то почему "остальное" не может следующим пакетом ?
Вновь выложенный проект если и смогу посмотреть, то позднее (календарь-с)

=Алекс=
09.03.2016, 11:05
Вы вообще ответы читаете ? За 600мс много чего может навалится в порт
Конечно читаю :) Я просто не придумал как оградить буфер от переполнения, поэтому и методом тыка, увидел, что при меньшем времени буфер не успевает завалить данными, и ПЛК не ребутится...


Сначала надо определится, что является разделением пакетов - символы и/или время ? (таймаут - отдельная песня).
Пошагово отлаживал программу, заметил, что наполнение массива otvet после каждого запроса выполняется правильно, так же как я вижу через снифер. Совпадает с описанием протокола обмена.
Но когда запускаю без точек останова, то вижу что данные сначала идут верные, а потом идет абракадабра и ребут ПЛК.

byte_read:=SysComRead(port_number, ADR(buf_otvet), 7, 0);
FOR i:=0 TO byte_read-1 DO
otvet[l+i]:=buf_otvet[i];
END_FOR

Еще для эксперимента, поменял скорость обмена на 9600, и Время ожидания ответа = 300ms; Задержка между запросами=T#1000ms;
В итоге данные получаю стабильным id прибора (string), а t1 (real) через раз или два верное значение каждого опроса...
Подскажите как можно правильно контролировать начало массива otvet? По протоколу, ответ каждого запроса одинаковы первые 3 байта: 16#10, 16#FF, 16#90