CAA.File.Write – Unexpected characters when writing a CSV file

clesio
2026-09-08
2026-09-09
  • clesio - 2026-09-08

    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?

     
  • TimvH

    TimvH - 2026-09-09

    For sure you must use LEN(). SIZEOF() means you write a number of bytes based on the size of the variable type. For your STRING this will be 80 characters, but this will write unexpected characters in your file.

     

Log in to post a comment.