Приведу ещё пример: асинхронная запись в файл, которую настоятельно рекомендует ОВЕН (по понятным причинам).
Пример от ОВЕН выглядит так:
Код:
CASE state_res OF
0:
res:=OwenFileOpenAsync('usb:test.dat','a',ADR(handle));
IF res=ASYNC_WORKING THEN
state:=1;
END_IF
1:
res:=OwenFileOpenAsync('test.dat','a',ADR(handle));
IF res=ASYNC_DONE THEN
IF handle<>0 THEN
state:=2;
ELSE
state:=0;
END_IF
ELSIF res<0 THEN
state:=0;
END_IF
2:
res:=OwenFileWriteAsync(handle,ADR(bufout),14,ADR(result));
IF res=ASYNC_WORKING THEN
state:=3;
ELSE
state:=6;
END_IF
3:
res:=OwenFileWriteAsync(handle,ADR(bufout),14,ADR(result));
IF res=ASYNC_DONE THEN
IF result=14 THEN
state:=4;
ELSE
state:=6;
END_IF
ELSIF res<0 THEN
state:=6;
END_IF
4:
res:=OwenFileReadAsync(handle,ADR(bufin),14,ADR(result));
IF res=ASYNC_WORKING THEN
state:=5;
ELSE
state:=6;
END_IF
5:
res:=OwenFileReadAsync(handle,ADR(bufin),14,ADR(result));
IF res=ASYNC_DONE THEN
IF result>=0 THEN
state:=6;
counter:=counter+1;
ELSE
state:=6;
END_IF
ELSIF res<0 THEN
state:=6;
END_IF
6:
res:=OwenFileCloseAsync(handle,ADR(result));
IF res=ASYNC_WORKING THEN
state:=7;
ELSE
state:=0;
END_IF
7:
res:=OwenFileCloseAsync(handle,ADR(result));
IF res=ASYNC_DONE THEN
IF result=0 THEN
state:=0;
ELSE
state:=0;
END_IF
ELSIF res<0 THEN
state:=0;
END_IF
ELSE
state:=0;
END_CASE
Что? Всё понятно? Прямо прочитали и сразу поняли?
Контрольный вопрос: чем отличается state=0 от state=1? Если честно, то я не особо понял.
На паузах это будет так (40 строк вместо 100):
Код:
WHILE TRUE
REPEAT
res:=OwenFileOpenAsync('usb:test.dat','a',ADR(handle));
IF res = ASYNC_WORKING THEN
ПАУЗА;
END_IF;
UNTIL res<>ASYNC_DONE
END_REPEAT;
IF res<0 OR handle=0 THEN
CONTINUE; (* ошибка, поехали сначала *)
END_IF
REPEAT
res:=OwenFileWriteAsync(handle,ADR(bufout),14,ADR(result));
IF res = ASYNC_WORKING THEN
ПАУЗА;
END_IF;
UNTIL res<>ASYNC_DONE
END_REPEAT;
(* читаем файл *)
IF result=14 THEN
REPEAT
res := OwenFileReadAsync(handle,ADR(bufin),14,ADR(result));
IF res = ASYNC_WORKING THEN
ПАУЗА;
END_IF;
UNTIL res<>ASYNC_DONE
END_REPEAT;
END_IF;
(* Закрытие файла *)
REPEAT
res := OwenFileCloseAsync(handle,ADR(result));
IF res = ASYNC_WORKING THEN
ПАУЗА;
END_IF;
UNTIL res<>ASYNC_DONE
END_REPEAT;
END_WHILE;
По-моему, вариант с паузами гораздо понятнее. Операции "открыть файл", "записать", "прочитать", "закрыть" стали встречаться в коде только 1 раз. В исходном варианте они встречались по 2 раза. Да и разнообразные "IF ... state:=5;" никак не прибавляют читабельности и понятности коду.
Можно ли было изначально написать на CASE более внятно? Вполне возможно.
Но, и вариант "на паузах" можно написать гораздо компактнее. А именно: видно, что каждая операция с файлом обёрнута в repeat-until.
Если в самой библиотеке объявить вспомогательные функции типа таких
Код:
ASYNC FUNCTION OwenFileOpenAsync2 : ASYNC_RET_VALUE
VAR_INPUT
stFileName: STRING(255);
stMode : STRING[3];
returnvalue:POINTER TO DWORD;
END_VAR
res: ASYNC_RET_VALUE;
VAR
END_VAR
REPEAT
res:=OwenFileOpenAsync(stFileName, stMode, returnvalue);
OwenFileOpenAsync2 := res;
IF res = ASYNC_WORKING THEN
ПАУЗА;
END_IF;
UNTIL res<>ASYNC_DONE
END_REPEAT;
END_FUNCTION
То "код примера работы с асинхронной библиотекой файлов станет таким.
16 понятных строк, там где было 100 строк на CASE state=2/state=6.
При этом стоит понимать, что код по-прежнему выполняется асинхронно, т.е. "не занимает" цикл ПЛК.
Код:
WHILE TRUE
res := OwenFileOpenAsync2('usb:test.dat','a',ADR(handle));
IF res<0 OR handle=0 THEN
CONTINUE; (* ошибка, поехали сначала *)
END_IF
res := OwenFileWriteAsync2(handle,ADR(bufout),14,ADR(result));
IF result=14 THEN
res := OwenFileReadAsync2(handle,ADR(bufin),14,ADR(result));
END_IF;
res := OwenFileCloseAsync2(handle,ADR(result));
END_WHILE;