/****************************************************************************
 *  License : All rights reserved for TES Electronic Solutions GmbH
 *            See included /docs/license.txt for details
 *  Project : D/AVE HD
 *  Purpose : Tlist dumping support functions 
 *  Platform: Altera NIOSII 
 ****************************************************************************
 * Version Control Information :
 *  $Revision: 5998 $
 *  $Date: 2015-09-18 14:23:26 +0200 (Fr, 18. Sep 2015) $
 *  $LastChangedBy: florian.zimmermann $
 ****************************************************************************
 * Change History (autogenerated):
 ****************************************************************************/    

#include "davehd_kernel_driver.h"
#include "davehd_kernel_client.h"
#include "davehd_kernel_tlist.h"

#ifdef DHD_KERNEL_TLIST_SUPPORT

#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>


/* memory buffer for tlist to speed up file I/O*/
typedef struct {
  dhd_char_t m_buf[10*1024];  /* buffer for 10k bytes of tlist*/
  dhd_char_t *m_buf_end,*m_buf_ptr;
  FILE *m_outfile;
} tlist_buffer_t;


static dhd_bool_t flush_tlist_buffer(tlist_buffer_t *buffer) {
  size_t size = buffer->m_buf_ptr-buffer->m_buf;

  if ((buffer == 0) || (buffer->m_outfile == 0)) {
    return DHD_FALSE;
  }
  
  if (size != 0) {
    if (fwrite(buffer->m_buf, size, 1, buffer->m_outfile) != 1) {
      return DHD_FALSE;
    }
    buffer->m_buf_ptr = buffer->m_buf;
  }
  
  return DHD_TRUE;
}



/*----------------------------------------------------------------------------------------------------------*/
/**/
dhd_enum_t dhd_gpu_tlist_start(dhd_tlist_t *a_tlist, const dhd_char_t *a_file) {  
  tlist_buffer_t *buffer;

  /* reject if already logging*/
  if (a_tlist->m_tlist_file != 0) {
    return E_DHD_ERROR_ALREADY_RUNNING;
  }

  /* create tlist buffer */
  buffer = malloc(sizeof(tlist_buffer_t));
  if (0 == buffer) {
    return E_DHD_ERROR_NO_MEMORY;
  }

  buffer->m_buf_ptr = buffer->m_buf;
  buffer->m_buf_end = buffer->m_buf_ptr + sizeof(buffer->m_buf)-1;
  
  /* open output file*/
  buffer->m_outfile = fopen(a_file, "wb");
  if (0 == buffer->m_outfile) {
    return E_DHD_ERROR_INVALID_ARGUMENT;
  }    

  /* init tlist data */
  a_tlist->m_tlist_data = buffer;
  a_tlist->m_tlist_file = a_file;

  return E_DHD_OK;
}

/*----------------------------------------------------------------------------------------------------------*/
/**/
dhd_enum_t dhd_gpu_tlist_stop(dhd_tlist_t *a_tlist) {

  /* noop if already closed*/
  if (a_tlist->m_tlist_file == 0) {
    return E_DHD_OK;
  }
  if (a_tlist->m_tlist_data == 0) {
    return E_DHD_ERROR_INTERNAL;
  }

  /* flush remaining content from buffer*/
  if (flush_tlist_buffer((tlist_buffer_t*)(a_tlist->m_tlist_data)) == DHD_FALSE) {
    return E_DHD_ERROR_INTERNAL;
  }  
  
  /* close file handle*/
  fclose( (FILE*) (((tlist_buffer_t*)(a_tlist->m_tlist_data))->m_outfile) );

  /* free buffer*/
  free(a_tlist->m_tlist_data);
  
  /* remove tlist data*/
  a_tlist->m_tlist_data = 0;
  a_tlist->m_tlist_file = 0;

  return E_DHD_OK;
}


/*----------------------------------------------------------------------------------------------------------*/
/**/
void dhd_gpu_tlist_printf(dhd_tlist_t *a_tlist, dhd_char_t *a_format, ...) {
  va_list args;
  
  tlist_buffer_t *buffer = (tlist_buffer_t*) a_tlist->m_tlist_data;
  
  if (a_tlist->m_tlist_data != 0) {
    dhd_bool_t success = DHD_FALSE;
    dhd_uint8_t try = 0;  /* try writing twice in case the buffer does not have enough room on first try*/

    while ((success == DHD_FALSE) && (try<2)) {
      size_t bytes_left = buffer->m_buf_end - buffer->m_buf_ptr + 1;
      dhd_int32_t bytes_written;

      va_start(args, a_format);
      bytes_written = vsnprintf(buffer->m_buf_ptr, bytes_left, a_format, args);
      va_end(args);
    
      if ((bytes_written > 0) && (bytes_written < bytes_left)) {
        /* success writing to the string (buffer did have enough room)*/
        buffer->m_buf_ptr += bytes_written;
        success = DHD_TRUE;        
      } else {
        flush_tlist_buffer(buffer);
      }      
      try++;
    }
  }
}


#endif

