clesio - 10 hours ago

Hello everyone,

I am trying to create a routine in CODESYS to export a report to a CSV file using the CAA.File library. The file is created successfully, but I am getting some unexpected/unknown characters in the generated CSV.

The problem seems to be related to the SIZEOF() function. I am using it for the szSize parameter of File.Write, as recommended in the CODESYS documentation. However, when I use SIZEOF(), the CSV contains extra characters and parts of previous strings.

I also tried using LEN(), but in my application the file is created empty, even though the string and the calculated length appear to be correct.

Here is the relevant part of my code:

PROGRAM Relatorio
VAR
    // Bool
    b_Executa_fb_Cria_Arquivo                           : BOOL;
    b_Executa_fb_Fecha_Arquivo                          : BOOL;

    b_Escreve_dados                                     : BOOL;
    b_Erro_fb_Escreve                                   : BOOL;


    //STR
    s_Nome_Arquivo                                      : STRING;
    s_Palavra                                           : STRING;
    s_Palavra_Anterior                                  : STRING;

    s_Data_Atualizada_Formatada                         : STRING;
    s_Dia                                               : STRING;
    s_Mes                                               : STRING;
    s_Ano                                               : STRING;

    s_Hora_Atualizada_Formatada                         : STRING;
    s_Hora                                              : STRING;
    s_Minu                                              : STRING;
    s_Segu                                              : STRING;

    //INT
    i_modo_fb_Cria_Arquivo                              : INT;
    i_ErroID_fb_Escreve                                 : INT;

    //UINT
    i_Tamanho_Palavra                                   : UINT;

    // Blocos de Funcao
    fb_Cria_Arquivo                                     : FILE.Open;
    fb_Fecha_Arquivo                                    : FILE.Close;
    fb_Escreve                                          : FILE.Write;   

    // DATA E HORA
    sc_DataTime                                         : SysTimeRtc.RTS_SYSTIMEDATE; // STRUCT = sc

    uidResultRtcGet                                     : UDINT;
    //stGetDate                                         : SysTimeRtc.RTS_SYSTIMEDATE;
    uidResultConvertToDate                              : UDINT;
    uidResult                                           : RTS_IEC_RESULT;
END_VAR
VAR_INPUT
    //BOOL
    b_SET_Executa_fb_Cria_Arquivo                       : BOOL;
    b_RES_Executa_fb_Cria_Arquivo                       : BOOL; 
    b_Executa_fb_Escrita                                : BOOL;

    // INT
    i_Linhas_Cabecalho                                  : INT;
    i_Linhas_Cabecalho_Anterior                         : INT;
END_VAR

// Para Testes
s_Nome_Arquivo                  := 'relatorio/Teste1M.CSV';
i_modo_fb_Cria_Arquivo          := 0;

// TRATAMENTO DE DATOS DATA e HORA

uidResultRtcGet := SysTimeRtcGet(uidResult);

uidResultConvertToDate := SysTimeRtcConvertUtcToDate(dwTimestampUtc := uidResultRtcGet, pDate := sc_DataTime);

// FORMATA DATA EM UMA STRING
s_Dia := UINT_TO_STRING(sc_DataTime.wDay);
s_Mes := UINT_TO_STRING(sc_DataTime.wMonth);
s_Ano := UINT_TO_STRING(sc_DataTime.wYear);
s_Data_Atualizada_Formatada := CONCAT(s_Dia, CONCAT('/', CONCAT(s_Mes, CONCAT('/', s_Ano))));

// FORMATA HORA EM UMA STRING
s_Hora := UINT_TO_STRING(sc_DataTime.wHour);
s_Minu := UINT_TO_STRING(sc_DataTime.wMinute);
s_Segu := UINT_TO_STRING(sc_DataTime.wSecond);
s_Hora_Atualizada_Formatada := CONCAT(s_Hora, CONCAT(':', CONCAT(s_Minu, CONCAT(':', s_Segu))));



// ABRE e CRIA ARQUIVO

IF  (b_SET_Executa_fb_Cria_Arquivo OR b_Executa_fb_Cria_Arquivo) AND NOT(b_RES_Executa_fb_Cria_Arquivo) THEN
    b_Executa_fb_Cria_Arquivo := TRUE;      
ELSE
    b_Executa_fb_Cria_Arquivo := FALSE;
END_IF

fb_Cria_Arquivo(
    xExecute        := b_Executa_fb_Cria_Arquivo,
    sFileName       := s_Nome_Arquivo,
    eFileMode       := i_modo_fb_Cria_Arquivo,
    xExclusive      := FALSE,
    );

//i_Tamanho_Palavra     := SizeOf(s_Palavra);

// ESCREVE NO ARQUIVO
fb_Escreve(
    xExecute        := b_Executa_fb_Escrita,
    hFile           := fb_Cria_arquivo.hFile,
    szSize          := SIZEOF(s_Palavra), 
    pBuffer         := ADR(s_palavra)
    );


// FECHA ARQUIVO
fb_Fecha_Arquivo(
    xExecute        := b_Executa_fb_Fecha_Arquivo,
    hFile           := fb_Cria_arquivo.hFile
    );


IF Criacao_Edicao_Arquivos.b_Escreve_Cabecalho THEN
    CASE i_Linhas_Cabecalho OF
        1 : 
            s_palavra := 'ESTERILIZADOR';
        2:
            s_palavra := 'MAQ4; $R$L';
        3: 
            s_palavra := CONCAT(CONCAT('CLIENTE: ',GVL.sReceitaAtual), '$R$L');
        4:
            s_palavra := CONCAT(CONCAT('NUMERO LOTE: ',DINT_TO_STRING(GVL.Lote)), '$R$L');
        5: 
            s_palavra := CONCAT(CONCAT('OPERADOR: ', DINT_TO_STRING(GVL.Operador)), '$R$L');
        6: 
            s_palavra := CONCAT(CONCAT('DATA: ', s_Data_Atualizada_Formatada), '$R$L');
        7:
            s_palavra := CONCAT(CONCAT('HORA: ', s_Hora_Atualizada_Formatada), '$R$L');
        8: 
            s_palavra := '$R$L';
        9:
            s_palavra := 'PARAMETROS AJUSTADOS $R$L';
        10:
            s_palavra := CONCAT('TEMPO PRE COND.: ', CONCAT(INT_TO_STRING(GVL.rc_T_PreCondicionamento), ' min $R$L'));
        11:
            s_palavra := CONCAT('PULSOS INERTIZACAO 1: ', CONCAT(INT_TO_STRING(GVL.rc_PulsosInertizacao_1), ' PULSOS $R$L'));
        12:
            s_palavra := CONCAT('PULSOS INERTIZACAO 2: ', CONCAT(INT_TO_STRING(GVL.rc_PulsosInertizacao_2), ' PULSOS $R$L'));
        13:
            s_palavra := CONCAT('PULSOS AERACAO: ', CONCAT(INT_TO_STRING(GVL.rc_PulsosAeracao_2), ' PULSOS $R$L'));
        14: 
            s_palavra := CONCAT('PRESSAO DE VACUO 1: ', CONCAT(REAL_TO_STRING(GVL.rc_PV1_max), ' bar $R$L'));   
        15: 
            s_palavra := CONCAT('PRESSAO DE VACUO 2: ', CONCAT(REAL_TO_STRING(GVL.rc_PV2), ' bar $R$L'));   
        16: 
            s_palavra := CONCAT('PRESSAO INERTIZACAO 1: ', CONCAT(REAL_TO_STRING(GVL.rc_PN1), ' bar $R$L'));
        17: 
            s_palavra := CONCAT('PRESSAO INERTIZACAO 2: ', CONCAT(REAL_TO_STRING(GVL.rc_PN2), ' bar $R$L'));            
        18: 
            s_palavra := CONCAT('PRESSAO AERACAO: ', CONCAT(REAL_TO_STRING(GVL.rc_PAR), ' bar $R$L'));
        19: 
            s_palavra := CONCAT('PRESSAO ETO: ', CONCAT(REAL_TO_STRING(GVL.rc_PressaoETO), ' bar $R$L'));
        20: 
            s_palavra := CONCAT('PRESSAO Compl.: ', CONCAT(REAL_TO_STRING(GVL.rc_PressaoETO_2), ' bar $R$L'));
        21: 
            s_palavra := CONCAT('MASSA ETO: ', CONCAT(REAL_TO_STRING(GVL.rc_QuantidadeETO), ' Kg $R$L'));
        22: 
            s_palavra := CONCAT('TEMPO PRE COND. Vacuo/Vapor: ', CONCAT(INT_TO_STRING(GVL.rc_T_Vapor_1), ' min $R$L'));         
        23: 
            s_palavra := CONCAT('SET-POINT: ', CONCAT(REAL_TO_STRING(GVL.ihm_SPTemperatura), ' Β°C $R$L'));      
        24: 
            s_palavra := CONCAT('TEMPO ESTERILIZACAO: ', CONCAT(INT_TO_STRING(GVL.rc_TempoEsterilizacao), ' min $R$L'));
        25: 
            s_palavra := CONCAT('TEMPO PARADA: ', CONCAT(INT_TO_STRING(GVL.rc_T_PressaoParada), ' min $R$L'));          
        26: 
            s_palavra := CONCAT('UMIDADE: ', CONCAT(REAL_TO_STRING(GVL.rc_UmidadeRelativa), ' % $R$L'));
        27:
            s_palavra := '$R$L';            
    END_CASE    
END_IF

Note: The code I am attaching does not include the execution/sequence management of the function blocks. I have omitted this part to keep the example focused on the CSV writing routine. The function blocks are triggered and managed by a separate state machine.

I am not sure what the correct approach is in this case, especially since the official documentation recommends using SIZEOF() for szSize.

I will attach my code and a screenshot of the generated CSV showing the issue.

Has anyone experienced something similar or could suggest the correct way to write a changing STRING to a CSV file using CAA.File.Write?