// ExportEdits.txt See Citect Knowledge Base article Q4010 INT nFieldWidth[9]; // Widths of trend tag fields INT FUNCTION _TrnPeriodicExportCSV(STRING sFile, INT nTime, REAL nPeriod, INT nLength, INT nMode, INT nTags) STRING sListSep; // List separator STRING sHeader; // Header text STRING sData; // Field data buffer STRING sSeparator; // Selected list separator INT nError = 0; INT hFile; INT i, j, k; INT nDataValid; INT nBlock; // number of trend array blocks to be read INT nBlockSize; // block size INT nStartBlockOffsetMS = -1 * ((nLength - 1) * nPeriod); // offset to the starting time in block INT nEndBlockOffsetMS; // end time of the current block INT nRoundedMilliseconds; // Times get rounded to hundreds of milliseconds INT nTimeFieldWidth = 16; // # chars to pad out data for the time field INT nDateFieldWidth = 12; // # chars to pad out data for the date field INT MAXBLOCK = 256; // set to an eighth of the sTrnArray[] INT nCount = 0; INT nFactorMS = 1000; // We only use millisecond offsets if the span of the // data is sufficiently small. Otherwise we have to // use offsets in seconds IF MAXIMUM_EXPORT_SPAN / 1000 < ((nLength - 1) * nPeriod) THEN nFactorMS = 1; END nStartBlockOffsetMS = nStartBlockOffsetMS * nFactorMS; sListSep = WndGetProfile("Intl", "sList", ","); hFile = FileOpen(sFile,"w"); IF hFile <> -1 THEN IF nMode BITAND 0x0010 THEN ; // don't put field names in first row ELSE IF nMode BITAND 0x0002 THEN sHeader = _TrnExportAddField(hFile, sHeader, "TIME", nTimeFieldWidth, sListSep, nMode); ELSE sHeader = _TrnExportAddField(hFile, sHeader, "DATE", nDateFieldWidth, sListSep, nMode); sHeader = _TrnExportAddField(hFile, sHeader, "TIME", nTimeFieldWidth, sListSep, nMode); END FOR j = 0 TO nTags - 1 DO IF j < nTags - 1 THEN sSeparator = sListSep; ELSE sSeparator = ""; END nFieldWidth[j] = Max(StrLength(sTagArray[hTagArray[j]]) + 1, 16); sHeader = _TrnExportAddField(hFile, sHeader, sTagArray[hTagArray[j]], nFieldWidth[j], sSeparator, nMode); END FileWriteLn(hFile, sHeader); END nBlock = nLength / MAXBLOCK; FOR k = 0 TO nBlock DO IF k = nBlock THEN nBlockSize = nLength - nBlock * MAXBLOCK; ELSE nBlockSize = MAXBLOCK; END nEndBlockOffsetMS = nStartBlockOffsetMS + (((nBlockSize - 1) * nPeriod) * nFactorMS); FOR i = 0 TO nTags - 1 DO TrnGetTable(sTagArray[hTagArray[i]], _GetSecsFromOffsetMS(nTime, nEndBlockOffsetMS, nFactorMS), nPeriod, nBlockSize, aTrnArray[i*MAXBLOCK], nDisplayModeArray[hTagArray[i]], _GetMilliFromOffsetMS(nEndBlockOffsetMS, nFactorMS)); IsError(); END FOR i = 0 TO nBlockSize - 1 DO IF (nMode BITAND TABLE_MODE_IGNORE_INVALID) THEN nDataValid = 0; FOR j = 0 TO nTags - 1 DO IF (TrnIsValidValue(aTrnArray[i + j * MAXBLOCK]) = TREND_DATA_VALID) THEN nDataValid = 1; j = nTags - 1; END END ELSE nDataValid = 1; END IF (nDataValid = 1) THEN IF nMode BITAND 0x0002 THEN ; // don't show a date ELSE sData = _TrnExportAddField(hFile, sData, TimeToStr(_GetSecsFromOffsetMS(nTime, nStartBlockOffsetMS, nFactorMS), 9), nDateFieldWidth, sListSep, nMode); END IF (nPeriod < 1.0 OR (nMode BITAND 0x0008)) THEN nRoundedMilliseconds = _GetMilliSinceMidnightFromOffsetMS(nTime, nStartBlockOffsetMS, nFactorMS) / 100; nRoundedMilliseconds = nRoundedMilliseconds * 100; sData = _TrnExportAddField(hFile, sData, TimeToStr(nRoundedMilliseconds, 6), nTimeFieldWidth, sListSep, nMode); ELSE sData = _TrnExportAddField(hFile, sData, TimeToStr(_GetSecsFromOffsetMS(nTime, nStartBlockOffsetMS, nFactorMS), 1), nTimeFieldWidth, sListSep, nMode); END FOR j = 0 TO nTags - 1 DO IF j < nTags - 1 THEN sSeparator = sListSep; ELSE sSeparator = ""; END sData = _TrnExportAddField(hFile, sData, TrendValueToString(aTrnArray[i + j * MAXBLOCK], nDisplayModeArray[hTagArray[j]], nMode, 10, 5), nFieldWidth[j], sSeparator, nMode); END FileWriteLn(hFile, sData); sData = ""; END nStartBlockOffsetMS = nStartBlockOffsetMS + (nPeriod * nFactorMS); // Check task running signal IF TaskGetSignal(TaskHnd()) BITAND 0x0001 THEN i = nBlockSize; k = nBlock + 1; ELSE // Reduce CPU load IF nCount >= 300 THEN nCount = 0; SleepMS(100); ELSE nCount = nCount + 1; END END END END FileClose(hFile); ELSE nError = IsError(); END RETURN nError; END // Add a field on to the existing list of fields. If it's too long, log the existing data // and return the new field (padded out to the specified length with the separator added) // PRIVATE STRING FUNCTION _TrnExportAddField(INT hFile, STRING sData, STRING sField, INT iLength, STRING sListSep, INT nMode) IF (nMode BITAND 0x0020) THEN ; // No padding ELSE sField = StrPad(sField, " ", iLength); END IF StrLength(sData) + iLength + 1 > 255 THEN FileWrite(hFile, sData); RETURN sField + sListSep; ELSE RETURN sData + sField + sListSep; END END