Вход

Просмотр полной версии : Работа с архивом через библиотеку CAA File



KuristinaK
12.04.2021, 02:06
Здравствуйте.
У меня есть проект, в котором данные записываются в файл на sd. Работала по руководству "архивация codesys v3.5".
Не могу найти ошибку - файл не создается на спк (размер памяти sd в drives показывается). Может быть, глаз замылился. Посмотрите, пожалуйста.
----
Скинула простейший проект функционала (собственно, упростила пример из руководства, ничего нового не добавляя).

Евгений Кислов
12.04.2021, 07:06
Добрый день.

1. Ваш проект в принципе не компилируется:

54480

Должно быть так:

54481

2. У вас как минимум три алгоритмические ошибки, допущенные во время "упрощения" примера:
- в шаге CLOSE должен быть реализован переход на шаг OPEN (с учетом того, что остальные шаги вам не нужны)
- строка 38 ( xWBusy := TRUE; ) выполняется каждый цикл ПЛК. Посмотрите, как в примере этот код вынесен в условие срабатывания триггера команды записи.
Для отладки можно просто закомментировать эту строку и присваивать значение этой переменной вручную в редакторе при онлайн-подключении.
- неправильная логика на шаге CREATE. Правильная логика: ловим xDone ---> значит, файл открылся ---> переходим на следующий шаг; ловим xError ---> какие-то ошибки ----> переходим на шаг CLOSE.
У вас же вы сразу при попадании в шаг уходите в ветку ELSE (так как ошибок нет - блок еще ведь даже не закончил работу), а хэндл в этот момент еще не получен.

54482

После исправления этих ошибок ваш проект у меня работает корректно:

54483

Dimarf1
14.04.2021, 16:16
Добрый день, работать с овеном только начинаю, сейчас пишу архиватор под ПЛК200. С примером разобрался, однако при попытке вызова фб Open с аргументом File.MODE.MREADPLUS на выходе имеем ошибку WRONG_PARAMETER. В чем может быть дело, фб вызываю как в примере, только с другим MODE?
п.с. Возможно ли вообще сделать так, чтобы при достижении архива например в 1000 строк, старые записи удалялись, а новые записывались в конец?

Евгений Кислов
14.04.2021, 16:35
Добрый день, работать с овеном только начинаю, сейчас пишу архиватор под ПЛК200. С примером разобрался, однако при попытке вызова фб Open с аргументом File.MODE.MREADPLUS на выходе имеем ошибку WRONG_PARAMETER. В чем может быть дело, фб вызываю как в примере, только с другим MODE?
п.с. Возможно ли вообще сделать так, чтобы при достижении архива например в 1000 строк, старые записи удалялись, а новые записывались в конец?

Добрый день.
А файл, который вы пытаетесь открыть, уже создан?


Возможно ли вообще сделать так, чтобы при достижении архива например в 1000 строк, старые записи удалялись, а новые записывались в конец?

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

Dimarf1
15.04.2021, 10:48
Добрый день.
А файл, который вы пытаетесь открыть, уже создан?
Да, пробовал и с созданным и без файла. Не понятно, что делать после этой ошибки, т.к. файл вроде как не открыт, т.е. закрывать его не нужно, но повторное открытие с другим моде уже не работает.



Если нужно добавлять записи именно в конец (а не переписывать с первой строки) - то, на мой взгляд, простых и эффективных способов нет.
Жаль, конечно. А есть способ просто начать перезапись с первой строки ? С режимом MREADPLUS возникли вышеуказанные проблемы.

Евгений Кислов
15.04.2021, 14:24
Да, пробовал и с созданным и без файла. Не понятно, что делать после этой ошибки, т.к. файл вроде как не открыт, т.е. закрывать его не нужно, но повторное открытие с другим моде уже не работает.


Жаль, конечно. А есть способ просто начать перезапись с первой строки ? С режимом MREADPLUS возникли вышеуказанные проблемы.

Выложите простейший проект (только работа с файлом), в котором воспроизводится ваша проблема.

Dimarf1
15.04.2021, 15:06
Выложите простейший проект (только работа с файлом), в котором воспроизводится ваша проблема.


BLINK1sek(ENABLE:=xEnb , TIMELOW:=T#2000MS , TIMEHIGH:=T#2000MS );

// детектируем сигнал записи в файл
fbWriteTrig(CLK:=BLINK1sek.OUT);
wSek:=USINT_TO_REAL(usiSek)/100 + usiSek;

// если получен сигнал записи, то подготавливаем строку архива и взводим соответствующий флаг
IF fbWriteTrig.Q THEN

// собираем строку архива - метку времени и значения
sArchEntry := CONCAT(sCurrentDate, c_sDelimiter);
sArchEntry := CONCAT(sArchEntry, sCurrentTime);
sArchEntry := CONCAT(sArchEntry, c_sDelimiter);
sArchEntry := CONCAT(sArchEntry, '#0=');
//sArchEntry := CONCAT(sArchEntry, WORD_TO_STRING(stExportData.wValue) );
//sArchEntry := CONCAT(sArchEntry, c_sDelimiter);
sArchEntry := CONCAT(sArchEntry, REAL_TO_FSTRING(wSek, 2) );
sArchEntry := CONCAT(sArchEntry, '$N');
sArchEntry := CONCAT(sArchEntry, '$R');


// получаем путь к выбранному устройству
sDevicePath := DEVICE_PATH(iDevicePath);

// склеиваем его с именем выбранного файла
sFileName := CONCAT(sDevicePath, sVisuFileName);

xWBusy := TRUE;
END_IF

CASE eState OF

FileWork.OPEN: // шаг открытия файла

IF xWBusy THEN
fbFileOpen(xExecute:=TRUE, sFileName:=sFileName, eFileMode:=File.MODE.MREADPLUS);
END_IF
// если файл, в который производится запись, не существует, то создадим его и запишем в него заголовок архива
IF fbFileOpen.eError=FILE.ERROR.NOT_EXIST THEN
fbFileOpen(xExecute:=FALSE);
eState := FileWork.CREATE;
xTitle := TRUE;
END_IF
IF fbFileOpen.eError=FILE.ERROR.WRONG_PARAMETER THEN
fbFileOpen(xExecute:=FALSE);
eState := FileWork.CLOSE;
iK:=iK+1;

END_IF
// если файл существует и был успешно открыт, то переходим к шагу записи в файл
IF fbFileOpen.xDone THEN
hFile := fbFileOpen.hFile;
fbFileOpen(xExecute:=FALSE);
eState := FileWork.GET_POS;

END_IF



FileWork.CREATE: // шаг создания файла

// в созданном файле еще нет записей
uiArchEntry:=0;

fbFileOpen(xExecute:=TRUE, sFileName:=sFileName, eFileMode:=FILE.MODE.MWRITE);

IF fbFileOpen.xDone THEN
hFile := fbFileOpen.hFile;
fbFileOpen(xExecute:=FALSE);

// после создания файла можно перейти к шагу записи данных
eState := FileWork.WRITE;
END_IF

IF fbFileOpen.xError THEN
// обработка ошибок
END_IF


FileWork.GET_POS:

fbFileGetPos( xExecute:=TRUE, hFile:=hFile );

IF fbFileGetPos.xDone THEN
udiCurPos:=fbFileGetPos.udiPos;
fbFileGetPos(xExecute:=FALSE);

// вернемся на шаг открытия файла для ожидания следующего управляющего сигнала
eState := FileWork.SET_READ_POS;
END_IF
IF (udiCurPos = udiArchSize) AND (uiArchEntry >= 30) THEN
udiCurPos:=0;
eState := FileWork.SET_READ_POS;
END_IF

IF fbFileGetPos.xError THEN
fbFileGetPos(xExecute:=FALSE);

END_IF

FileWork.SET_READ_POS:

fbFileSetPos( xExecute:=TRUE, hFile:=hFile, udiPos:=udiCurPos );

IF fbFileSetPos.xDone THEN
fbFileSetPos(xExecute:=FALSE);
// вернемся на шаг открытия файла для ожидания следующего управляющего сигнала
eState := FileWork.WRITE;
END_IF

IF fbFileSetPos.xError THEN
fbFileSetPos(xExecute:=FALSE);
//eState := FileWork.OPEN;
END_IF

FileWork.WRITE: // шаг записи в буфер

// если это первая запись в файле - то перед ней запишем заголовок
//IF xTitle THEN
// sArchEntry := CONCAT(c_sTitle, sArchEntry);

// после первой записи заголовок записывать уже не нужно
// xTitle := FALSE;
//END_IF

// запись строки архива в файл
fbFileWrite(xExecute:=TRUE, hFile:=hFile, pBuffer:=ADR(sArchEntry), szSize:=INT_TO_UDINT(LEN(sArchEntry)));

IF fbFileWrite.xDone THEN
fbFileWrite(xExecute:=FALSE);

// после записи число строк в архиве увеличилось на одну
uiArchEntry:=uiArchEntry+1;

// теперь можно перейти к шагу сброса буфера в файл
eState := FileWork.FLUSH;
END_IF

IF fbFileWrite.xError THEN
// обработка ошибок
END_IF


FileWork.FLUSH: // шаг сброса буфера в файл

fbFileFlush(xExecute:=TRUE, hFile:=hFile);

IF fbFileFlush.xDone THEN
fbFileFlush(xExecute:=FALSE);

// теперь можно перейти к шагу закрытия файла
eState:=FileWork.CLOSE;
END_IF

IF fbFileFlush.xError THEN
// обработка ошибок
END_IF


FileWork.CLOSE: // шаг закрытия файла

fbFileClose(xExecute:=TRUE, hFile:=hFile);

IF fbFileClose.xDone THEN
fbFileClose(xExecute:=FALSE);
xWBusy := FALSE;

// теперь можно перейти к шагу определения размера файла
eState := FileWork.GET_SIZE;
ELSE
xWBusy := FALSE;
eState := FileWork.GET_SIZE;
END_IF


FileWork.GET_SIZE: // шаг определения размера файла

fbFileGetSize(xExecute:=TRUE, sFileName:=sFileName);

// определяем размер файла
IF fbFileGetSize.xDone THEN
udiArchSize:=fbFileGetSize.szSize;
fbFileGetSize(xExecute:=FALSE);

// вернемся на шаг открытия файла для ожидания следующего управляющего сигнала
eState := FileWork.OPEN;
END_IF

// размер несуществующего файла...
IF fbFileGetSize.eError=FILE.ERROR.NOT_EXIST THEN

// очевидно, можно интерпретировать как ноль
udiArchSize := 0;
fbFileGetSize(xExecute:=FALSE);

// вернемся на шаг открытия файла для ожидания следующего управляющего сигнала
eState := FileWork.OPEN;
ELSIF fbFileGetSize.xError THEN
fbFileGetSize(xExecute:=FALSE);
eState := FileWork.OPEN;
END_IF

END_CASE

Если вместо MREADPLUS указать MAPPD код работает, но без кольцевой перезаписи, в таком виде только растет счетчик ошибки WRONG_PARAMETER в переменной iK.

Евгений Кислов
15.04.2021, 16:25
Выложите именно проект, пожалуйста, а не код.

Dimarf1
15.04.2021, 17:15
Выложите именно проект, пожалуйста, а не код.

Прошу прощения, проект во вложении

Евгений Кислов
16.04.2021, 08:34
Я проверил ваш проект у себя - он работает корректно с File.MODE.MREADPLUS.
Файл test.csv я предварительно создал в /root/CODESYS/PlcLogic и назначил ему нужные права.

54615

Если есть возможность организовать доступ по TeamViewer - давайте посмотрим, что происходит на вашем устройстве.