Приведу ещё пример: асинхронная запись в файл, которую настоятельно рекомендует ОВЕН (по понятным причинам).
Пример от ОВЕН выглядит так:
Что? Всё понятно? Прямо прочитали и сразу поняли?Код: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):
По-моему, вариант с паузами гораздо понятнее. Операции "открыть файл", "записать", "прочитать", "закрыть" стали встречаться в коде только 1 раз. В исходном варианте они встречались по 2 раза. Да и разнообразные "IF ... state:=5;" никак не прибавляют читабельности и понятности коду.Код: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;
Можно ли было изначально написать на 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;




Ответить с цитированием