Codesys#CSV Fileを作成しよう

今回はCodesysのCAA.Fileを使ってCSVを書き込む関数やプログラム例を書きます。確かにCodesysにはIOT LibraryにCSVの関数がありますが、有料らしいので、とりあえずFile.Openなど一番シンプルの方法で実装したいと思います。

ライブラリ追加

Application>Library Managerをクリックします。

Add Libraryします。

Advancedをクリックします。

Fileを絵r倍、File Access を追加します。

Function Block

CAA.Fileはたくさんの関数があり、今回はサンプルプログラムで使用したFile.Open・File.Write・File.Closeのみに説明します。

FILE.Open

このFunction Blockは既存にあるFileを開くや新規File作成できます。戻り値はhFileというObjectで、このObjectを使ってFile.Read・File.Write・File.CloseにあるhFileのInputパラメタにとして使います。

VAR_INPUT

xExecuteBOOL立ち上げ=Startたち下げ=Stop
sFileNameCAA.FILENAMEFile名やFileのPath
eFileModeFile modeFileを開くのModeになります。Write・Read・Appendなど
xExclusiveBOOL使用不可、Always Falseしてください

VAR_OUTPUT

xDoneBOOL1=正常実行した
xBusyBOOL1=実行中
xErrorBOOL1=エラーあり
eErrorERRORBlockのエラーID
hFileCAA.HANDLEFile ID、Write・Readなどで使われてる

File.Write

このFunction BlockはFile.OpenからきたFile Object hFile経由でFileに文字列を書き込むことができます。メモリPointerのpBufferは文字列を書き込む中はPointer値を変えるのは禁止で、そして実際何Byte書き込まれたのかFBからCheckしません。あと、書き込む中Online Changeはできるだけ避けてください。

VAR_INPUT

xExecuteBOOL立ち上げ=Startたち下げ=Stop
xAbortBOOL1=FB実行停止し、Outputは初期状態に戻る
udiTimeOutUDINT単位はµsでFBの実行TimeOut時間設定
xExclusiveBOOL使用不可、Always Falseしてください
hFileCAA.HANDLEFile.OpenからのFile Handle
pBufferCAA.PVOID書き込むの文字列のメモリアドレス(ADRからもらえる)
szSizeCAA.SIZE書き込むの文字列Byte数(SizeOFからもらえる)

VAR_OUTPUT

xDoneBOOL1=正常実行した
xBusyBOOL1=実行中
xErrorBOOL1=エラーあり
eErrorERRORBlockのエラーID

File.Close

This function block terminates the file access, i.e. closes the file.

VAR_INPUT

xExecuteBOOL立ち上げ=Startたち下げ=Stop
xAbortBOOL1=FB実行停止し、Outputは初期状態に戻る
udiTimeOutUDINT単位はµsでFBの実行TimeOut時間設定
xExclusiveBOOL使用不可、Always Falseしてください
hFileCAA.HANDLEFile.OpenからのFile Handle

VAR_OUTPUT

xDoneBOOL1=正常実行した
xBusyBOOL1=実行中
xErrorBOOL1=エラーあり
eErrorERRORBlockのエラーID

流れ

まず関数を初期化し、書き込むのコマンドを待ちます。

書き込むのコマンド来たらFileが存在してるかどうかをCheckします。あればそのままデータを書き込みますし、なければFileを作成しCSVのHeaderを書いてからデータを書きます。

最後はFileをCloseします。

もちろんFile.Openなどを呼び出すときあればError Stepに飛び、Resetくるまで待ちます。

実装

VAR

VAR
//File Objects
fopen:FILE.Open;
fclose:FILE.Close;
fwrite:FILE.Write;
hFile: CAA.HANDLE;

//Path,Header,Text that you want to Write
//$R$N is break-line in Windows OS
sFileName:STRING:=’C:\data\file.txt’;
sFileHeader:STRING(80):=’Date,data1,data2,data3,data4,data5$R$N’;
sFileText:STRING(80):=’20210102,1,2,3,String,1.24$R$N’;

//Operation Flag
bWrite:BOOL;
bReopen:BOOL;
bError:BOOL;
bReset:BOOL;
iState:INT:=0;
iError:FILE.ERROR;
iLastStep:INT;
END_VAR

VAR CONSTANT

VAR CONSTANT
ciStepInit :INT:=0;
ciStepWaitCmd :INT:=5;
ciStepCheckPathAndOpen :INT:=10;
ciStepCreateNew :INT:=30;
ciStepAppend :INT:=35;
ciStepWriteHeader :INT:=40;
ciStepWriteLine :INT:=45;
ciStepClose :INT:=60;
ciStepError :INT:=990;
END_VAR

Code

CASE iState OF

ciStepInit:
//Reset all the Instance
fopen(
xExecute:=FALSE
);
fclose(
xExecute:=FALSE
);
fwrite(
xExecute:=FALSE
);
bReset:=FALSE;
bReopen:=FALSE;
IF NOT fopen.xBusy
AND NOT fclose.xBusy
AND NOT fwrite.xBusy
THEN
iState:=ciStepWaitCmd;
END_IF

//
ciStepWaitCmd:

IF bWrite THEN
IF NOT fopen.xBusy
AND NOT fclose.xBusy
AND NOT fwrite.xBusy
THEN
iState:=ciStepCheckPathAndOpen;
END_IF
bWrite:=FALSE;
END_IF;

//
ciStepCheckPathAndOpen:
//FILE.MODE.MREADPLUS=OPEN Files and Return Error if following path is not Exist
fopen(
sFileName:=sFileName
,eFileMode:=FILE.MODE.MREADPLUS
,xExecute:=TRUE
);
IF fopen.xDone
AND NOT fopen.xError
THEN
hFile:=fopen.hFile;
fopen(
xExecute:=FALSE
);
//If path is OK, close the file 1 times and re-open in append mode.
bReopen:=TRUE;
iState:=ciStepClose;
ELSIF fopen.xError THEN
//if Current path is not exist
//FILE.ERROR.NOT_EXIST
IF fopen.eError  =FILE.ERROR.NOT_EXIST THEN
iState:=ciStepCreateNew;
fopen(
xExecute:=FALSE
);
ELSE
iError:=fopen.eError;
iLastStep:=iState;
iState:=ciStepError;
END_IF
END_IF

//open the file in append mode
ciStepAppend:
bReopen:=False;
fopen(
sFileName:=sFileName
,eFileMode:=FILE.MODE.MAPPD
,xExecute:=TRUE
);
IF fopen.xDone
AND NOT fopen.xError
THEN
hFile:=fopen.hFile;
fopen(
xExecute:=FALSE
);
iState:=ciStepWriteLine;
ELSIF fopen.xError THEN
iLastStep:=iState;
iState:=ciStepError;
iError:=fopen.eError;
END_IF;

//Case using if check path is fail.
ciStepCreateNew :
//FILE.MODE.MREADPLUS=OPEN Files and Create new one if following path is not Exist
fopen(
sFileName:=sFileName
,eFileMode:=FILE.MODE.MAPPENDPLUS
,xExecute:=TRUE
);
IF fopen.xDone
AND NOT fopen.xError
THEN
hFile:=fopen.hFile;
fopen(
xExecute:=FALSE
);
iState:=ciStepWriteHeader;
ELSIF fopen.xError THEN
iLastStep:=iState;
iState:=ciStepError;
iError:=fopen.eError;
END_IF;

//CSV FIles – Need the a,c,v,c,a,d.. Header
ciStepWriteHeader:
fwrite(
xExecute:=TRUE
,hFile:=hFile
,pBuffer:=ADR(sFileHeader)
,szSize:=LEN(sFileHeader)
);
IF fwrite.xDone
AND NOT fwrite.xError
THEN
fwrite(
xExecute:=FALSE
);
iState:=ciStepAppend;
ELSIF fwrite.xError THEN
iLastStep:=iState;
iState:=ciStepError;
iError:=fwrite.eError;

END_IF;
//
ciStepWriteLine:
fwrite(
xExecute:=TRUE
,hFile:=hFile
,pBuffer:=ADR(sFileText)
,szSize:=LEN(sFileText)
);
IF fwrite.xDone
AND NOT fwrite.xError
THEN
fwrite(
xExecute:=FALSE
);
iState:=ciStepClose;
ELSIF fwrite.xError THEN
iLastStep:=iState;
iState:=ciStepError;
iError:=fwrite.eError;

END_IF;

ciStepClose:
fclose(
xExecute:=TRUE
,hFile:=hFile
);
IF fclose.xDone THEN
fclose(
xExecute:=FALSE
);
IF bReopen THEN
//Logic if File path is exist,need to re-open in append mode
iState:=ciStepAppend;
ELSE
iState:=ciStepWaitCmd;
END_IF
ELSIF fwrite.xError THEN
iLastStep:=iState;
iState:=ciStepError;
iError:=fclose.eError;
END_IF

ciStepError:
IF bReset THEN
iState:=ciStepInit;
END_IF;

END_CASE

結果

このようなFileができます。

CSViewerから見ますとちゃんとCSV Formatになっていますね。

最後

Sample Codeは以下のLinkでダウンロードしてください。

https://github.com/soup01Threes/Codesys/blob/main/codesys_writecsv.projectarchive

はーい、お疲れ様です。

もしなにか質問あれば、メール・コメント・Twitterなどでもどうぞ!

Twitterのご相談:@3threes2

メールのご相談:soup01threes*gmail.com (*を@に)

Footer_Basic

Please Support some devices for my blog

Amazon Gift List

Find ME

Twitter:@3threes2
Email:soup01threes*gmail.com (* to @)
YoutubeChannel:https://www.youtube.com/channel/UCQ3CHGAIXZAbeOC_9mjQiWQ

シェアする

  • このエントリーをはてなブックマークに追加

フォローする

コメント

  1. Yusei Aoi より:

    こんにちは
    CODESYS初心者です。
    アップされているコードをそのままコピペして動かしてみました。
    正しいパスを指定して実行すると、iStateはシーケンス通り0-5-10-60-35-45-60と進んでいるんですが、ファイルが出力されません。
    存在しないファイル名で実行してもiStateが30に入らず上記の順番で処理されてしまいました。
    なにか原因わかりますでしょうか。

    • gomamenotes より:

      確認しまので少々おまちください。
      返事はそのままでいいですか?メールでよろしいですか??

  2. Yusei Aoi より:

    ありがとうございます。お願いします。
    返事はそのままでもメールでも大丈夫です。

    • gomamenotes より:

      Yusei Aoiさま

      ご返事ありがとうございます。先ほど記事の最後にあるGitHubのプロジェクトをダンロードし、確認しました。
      Fileは無事に作成され、中ににも書き込まれました。
      おそらくですが、
      1-Pathの設定、sFileNameはVARの初期値だけで与えられましたので、
      sFileName:STRING:=’C:\data\file.txt’;
      その値をVAR宣言エリアを変えても反映はしないと思います。
      一回Resetする必要がありますね。

      2-私のプログラムにPathをCheckするStepは不足のところがあるかもしれません。
      ciStepCheckPathAndOpenのStepはPathをCheckし>ciStepCreateNewに戻るような流れです。
      その中に作成するのはFileだけです。Folderまで作成しないので、多分そこも原因の一つではないかなと思います。

      自分もできるだけSampleコードをUploadする前に確認・エラー処理をするつもりですが、抜けが出てきて申し訳ございません。

      Blogみていただきありがとうございます。
      あなたのコメントは私が続くの力になります。

      よろしくおねがいします。

  3. Yousei Aoi より:

    かなり月日が経ってしましましたが当時無事解決できました。
    ご親切にありがとうございました。