3 * Copyright (C) 2012 BMW AG
5 * This file is part of GENIVI Project Dlt - Diagnostic Log and Trace console apps.
7 * Contributions are licensed to the GENIVI Alliance under one or more
8 * Contribution License Agreements.
11 * This Source Code Form is subject to the terms of the
12 * Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with
13 * this file, You can obtain one at http://mozilla.org/MPL/2.0/.
16 * \author Alexander Wenzel <alexander.aw.wenzel@bmw.de> BMW 2011-2012
18 * \file dlt_filetransfer.c
19 * For further information see http://www.genivi.org/.
24 /*******************************************************************************
26 ** SRC-MODULE: dlt-test-client.c **
32 ** AUTHOR : Alexander Wenzel Alexander.AW.Wenzel@bmw.de **
38 ** PLATFORM DEPENDANT [yes/no]: yes **
40 ** TO BE CHANGED BY USER [yes/no]: no **
42 *******************************************************************************/
44 /*******************************************************************************
46 ********************************************************************************
48 ** Initials Name Company **
49 ** -------- ------------------------- ---------------------------------- **
50 ** aw Alexander Wenzel BMW **
51 *******************************************************************************/
53 #include "dlt_filetransfer.h"
55 //!Defines the buffer size of a single file package which will be logged to dlt
56 #define BUFFER_SIZE 1024
58 //!Defines the minimum timeout between two dlt logs. This is important because dlt should not be flooded with too many logs in a short period of time.
59 #define MIN_TIMEOUT 20
62 #define DLT_FILETRANSFER_TRANSFER_ALL_PACKAGES LONG_MAX
65 //!Buffer for dlt file transfer. The size is defined by BUFFER_SIZE
66 unsigned char buffer[BUFFER_SIZE];
69 //!Get some information about the file size of a file
70 /**See stat(2) for more informations.
71 * @param file Absolute file path
72 * @return Returns the size of the file (if it is a regular file or a symbolic link) in bytes.
74 unsigned long getFilesize(const char* file){
77 return (unsigned long)st.st_size;
80 //!Get some information about the file serial number of a file
81 /** See stat(2) for more informations.
82 * @param file Absolute file path
83 * @return Returns a unique number associated with each filename
85 unsigned long getFileSerialNumber(const char* file){
90 ret = ret << (sizeof(ret)*8)/2;
95 //!Returns the creation date of a file
96 /** See stat(2) for more informations.
97 * @param file Absolute file path
98 * @return Returns the creation date of a file
100 time_t getFileCreationDate(const char* file){
106 //!Returns the creation date of a file
107 /** Format of the creation date is Day Mon dd hh:mm:ss yyyy
108 * @param file Absolute file path
109 * @return Returns the creation date of a file
111 char* getFileCreationDate2(const char* file){
115 struct tm *ts= localtime(&st.st_ctime);
119 //!Checks if the file exists
120 /**@param file Absolute file path
121 * @return Returns 1 if the file exists, 0 if the file does not exist
123 int isFile (const char* file)
126 return (stat (file, &st) == 0);
129 //!Waits a period of time
130 /**Waits a period of time. The minimal time to wait is MIN_TIMEOUT. This makes sure that the FIFO of dlt is not flooded.
131 * @param timeout Timeout to in ms but can not be smaller as MIN_TIMEOUT
133 void doTimeout(int timeout)
135 usleep(timeout * 1000);
138 //!Checks free space of the user buffer
140 * @param returns -1 if more than 50% space in the user buffer is free. Otherwise 1 will be returned.
142 int checkUserBufferForFreeSpace()
144 int total_size, used_size;
146 dlt_user_check_buffer(&total_size, &used_size);
148 if((total_size - used_size) < (total_size/2))
155 //!Deletes the given file
157 * @param filename Absolute file path
158 * @return If the file is successfully deleted, a zero value is returned.If the file can not be deleted a nonzero value is returned.
160 int doRemoveFile(const char*filename){
161 return remove( filename);
164 void dlt_user_log_file_errorMessage(DltContext *fileContext, const char *filename, int errorCode){
168 DLT_LOG(*fileContext,DLT_LOG_ERROR,
172 DLT_UINT(getFileSerialNumber(filename)),
173 DLT_STRING(filename),
174 DLT_UINT(getFilesize(filename)),
175 DLT_STRING(getFileCreationDate2(filename)),
176 DLT_UINT(dlt_user_log_file_packagesCount(fileContext,filename)),
177 DLT_UINT(BUFFER_SIZE),
181 DLT_LOG(*fileContext,DLT_LOG_ERROR,
185 DLT_STRING(filename),
193 //!Logs specific file inforamtions to dlt
194 /**The filename, file size, file serial number and the number of packages will be logged to dlt.
195 * @param fileContext Specific context
196 * @param filename Absolute file path
197 * @return Returns 0 if everything was okey.If there was a failure a value < 0 will be returned.
199 int dlt_user_log_file_infoAbout(DltContext *fileContext, const char *filename){
203 DLT_LOG(*fileContext,DLT_LOG_INFO,
205 DLT_STRING("file serialnumber"),DLT_UINT(getFileSerialNumber(filename)),
206 DLT_STRING("filename"),DLT_STRING(filename),
207 DLT_STRING("file size in bytes"),DLT_UINT(getFilesize(filename)),
208 DLT_STRING("file creation date"),DLT_STRING(getFileCreationDate2(filename)),
209 DLT_STRING("number of packages"),DLT_UINT(dlt_user_log_file_packagesCount(fileContext, filename)),
214 dlt_user_log_file_errorMessage(fileContext,filename,DLT_FILETRANSFER_ERROR_INFO_ABOUT);
215 return DLT_FILETRANSFER_ERROR_INFO_ABOUT;
219 //!Transfer the complete file as several dlt logs.
220 /**This method transfer the complete file as several dlt logs. At first it will be checked that the file exist.
221 * In the next step some generic informations about the file will be logged to dlt.
222 * Now the header will be logged to dlt. See the method dlt_user_log_file_header for more informations.
223 * Then the method dlt_user_log_data will be called with the parameter to log all packages in a loop with some timeout.
224 * At last dlt_user_log_end is called to signal that the complete file transfer was okey. This is important for the plugin of the dlt viewer.
225 * @param fileContext Specific context to log the file to dlt
226 * @param filename Absolute file path
227 * @param deleteFlag Flag if the file will be deleted after transfer. 1->delete, 0->notDelete
228 * @param timeout Timeout in ms to wait between some logs. Important that the FIFO of dlt will not be flooded with to many messages in a short period of time.
229 * @return Returns 0 if everything was okey. If there was a failure a value < 0 will be returned.
231 int dlt_user_log_file_complete(DltContext *fileContext, const char *filename, int deleteFlag, int timeout)
233 if(!isFile(filename))
235 dlt_user_log_file_errorMessage(fileContext,filename, DLT_FILETRANSFER_ERROR_FILE_COMPLETE);
236 return DLT_FILETRANSFER_ERROR_FILE_COMPLETE;
239 if(dlt_user_log_file_header(fileContext,filename) != 0)
241 return DLT_FILETRANSFER_ERROR_FILE_COMPLETE1;
244 if(dlt_user_log_file_data(fileContext, filename,DLT_FILETRANSFER_TRANSFER_ALL_PACKAGES,timeout) != 0)
246 return DLT_FILETRANSFER_ERROR_FILE_COMPLETE2;
249 if(dlt_user_log_file_end(fileContext,filename, deleteFlag) != 0)
251 return DLT_FILETRANSFER_ERROR_FILE_COMPLETE3;
257 //!This method gives information about the number of packages the file have
258 /**Every file will be divided into several packages. Every package will be logged as a single dlt log.
259 * The number of packages depends on the BUFFER_SIZE.
260 * At first it will be checked if the file exist. Then the file will be divided into
261 * several packages depending on the buffer size.
262 * @param fileContext Specific context to log the file to dlt
263 * @param filename Absolute file path
264 * @return Returns the number of packages if everything was okey. If there was a failure a value < 0 will be returned.
266 int dlt_user_log_file_packagesCount(DltContext *fileContext, const char *filename){
273 filesize = getFilesize(filename);
274 if(filesize < BUFFER_SIZE)
280 packages = filesize/BUFFER_SIZE;
282 if(filesize%BUFFER_SIZE == 0)
292 dlt_user_log_file_errorMessage(fileContext,filename,DLT_FILETRANSFER_ERROR_PACKAGE_COUNT);
297 //!Transfer the head of the file as a dlt logs.
298 /**The head of the file must be logged to dlt because the head contains inforamtion about the file serial number,
299 * the file name, the file size, package number the file have and the buffer size.
300 * All these informations are needed from the plugin of the dlt viewer.
301 * See the Mainpages.c for more informations.
302 * @param fileContext Specific context to log the file to dlt
303 * @param filename Absolute file path
304 * @return Returns 0 if everything was okey. If there was a failure a value < 0 will be returned.
306 int dlt_user_log_file_header(DltContext *fileContext,const char *filename){
310 DLT_LOG(*fileContext,DLT_LOG_INFO,
312 DLT_UINT(getFileSerialNumber(filename)),
313 DLT_STRING(filename),
314 DLT_UINT(getFilesize(filename)),
315 DLT_STRING(getFileCreationDate2(filename));
316 DLT_UINT(dlt_user_log_file_packagesCount(fileContext,filename)),
317 DLT_UINT(BUFFER_SIZE),
325 dlt_user_log_file_errorMessage(fileContext,filename, DLT_FILETRANSFER_ERROR_FILE_HEAD);
326 return DLT_FILETRANSFER_ERROR_FILE_HEAD;
330 //!Transfer the content data of a file.
331 /**See the Mainpages.c for more informations.
332 * @param fileContext Specific context to log the file to dlt
333 * @param filename Absolute file path
334 * @param packageToTransfer Package number to transfer. If this param is LONG_MAX, the whole file will be transferred with a specific timeout
335 * @param timeout Timeout to wait between dlt logs. Important because the dlt FIFO should not be flooded. Default is defined by MIN_TIMEOUT. The given timeout in ms can not be smaller than MIN_TIMEOUT.
336 * @return Returns 0 if everything was okey. If there was a failure a value < 0 will be returned.
338 int dlt_user_log_file_data(DltContext *fileContext,const char *filename, int packageToTransfer, int timeout){
346 file = fopen (filename,"rb");
349 dlt_user_log_file_errorMessage(fileContext,filename,DLT_FILETRANSFER_ERROR_FILE_DATA);
350 return DLT_FILETRANSFER_ERROR_FILE_DATA;
353 if( (packageToTransfer != DLT_FILETRANSFER_TRANSFER_ALL_PACKAGES && packageToTransfer > dlt_user_log_file_packagesCount(fileContext,filename)) || packageToTransfer <= 0)
355 DLT_LOG(*fileContext,DLT_LOG_ERROR,
356 DLT_STRING("Error at dlt_user_log_file_data: packageToTransfer out of scope"),
357 DLT_STRING("packageToTransfer:"),
358 DLT_UINT(packageToTransfer),
359 DLT_STRING("numberOfMaximalPackages:"),
360 DLT_UINT(dlt_user_log_file_packagesCount(fileContext,filename)),
361 DLT_STRING("for File:"),
364 return DLT_FILETRANSFER_ERROR_FILE_DATA;
369 if(packageToTransfer != DLT_FILETRANSFER_TRANSFER_ALL_PACKAGES)
371 // If a single package should be transferred. The user has to check that the free space in the user buffer > 50%
372 // if(checkUserBufferForFreeSpace()<0)
373 // return DLT_FILETRANSFER_ERROR_FILE_DATA_USER_BUFFER_FAILED;
375 fseek ( file , (packageToTransfer-1)*BUFFER_SIZE , SEEK_SET );
376 readBytes = fread(buffer, sizeof(char), BUFFER_SIZE, file);
378 DLT_LOG(*fileContext,DLT_LOG_INFO,
380 DLT_UINT(getFileSerialNumber(filename)),
381 DLT_UINT(packageToTransfer),
382 DLT_RAW(buffer,readBytes),
390 while( !feof( file ) )
392 // If the complete file should be transferred, the user buffer will be checked.
393 // If free space < 50% the package won't be transferred.
394 if(checkUserBufferForFreeSpace()>0)
397 readBytes = fread(buffer, sizeof(char), BUFFER_SIZE, file);
399 DLT_LOG(*fileContext,DLT_LOG_INFO,
401 DLT_UINT(getFileSerialNumber(filename)),
403 DLT_RAW(buffer,readBytes),
416 dlt_user_log_file_errorMessage(fileContext,filename,DLT_FILETRANSFER_ERROR_FILE_DATA);
417 return DLT_FILETRANSFER_ERROR_FILE_DATA;
421 //!Transfer the end of the file as a dlt logs.
422 /**The end of the file must be logged to dlt because the end contains inforamtion about the file serial number.
423 * This informations is needed from the plugin of the dlt viewer.
424 * See the Mainpages.c for more informations.
425 * @param fileContext Specific context to log the file to dlt
426 * @param filename Absolute file path
427 * @param deleteFlag Flag to delete the file after the whole file is transferred (logged to dlt).1->delete,0->NotDelete
428 * @return Returns 0 if everything was okey. If there was a failure a value < 0 will be returned.
430 int dlt_user_log_file_end(DltContext *fileContext,const char *filename,int deleteFlag){
435 DLT_LOG(*fileContext,DLT_LOG_INFO,
437 DLT_UINT(getFileSerialNumber(filename)),
442 if( doRemoveFile(filename) != 0 ){
443 dlt_user_log_file_errorMessage(fileContext,filename,DLT_FILETRANSFER_ERROR_FILE_END);
450 dlt_user_log_file_errorMessage(fileContext,filename,DLT_FILETRANSFER_ERROR_FILE_END);
451 return DLT_FILETRANSFER_ERROR_FILE_END;