#ifndef __RTL__

#include <string.h>
#include <sys/types.h>
#include <errno.h>
#ifndef _MSC_VER
#include <sys/stat.h>
#include <sys/time.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#endif /*_MSC_VER*/

#else /*__RTL__*/

#include <rtl.h>
#include <string.h>
#include <signal.h>
#include <posix/unistd.h>

#define strerror(x) "?RTL?"

#endif /*__RTL__*/

#include "can_vca.h"


/*******************************************************************/
/* Logging support */

/**
 * vca_h2log - converts VCA handle to printable number
 * @vcah: VCA handle
 *
 * Header: can_vca.h
 * Return Value: unique printable VCA handle number
 */

long vca_h2log(vca_handle_t vcah)
{
  return vcah;
}

void vca_canmsg2log(canmsg_t *msg, int format)
{
  int i;
  vca_log(VCA_LDOMAIN,0|VCA_LOGL_CONT," {f:0x%x,cob:%d,id:%ld/0x%lx,len:%d,[",
  	msg->flags,msg->cob,msg->id,msg->id,msg->length);
  for(i=0;i<msg->length;i++){
    if(i) vca_log(VCA_LDOMAIN,0|VCA_LOGL_CONT,",");
    vca_log(VCA_LDOMAIN,0|VCA_LOGL_CONT,"0x%x",msg->data[i]);
  }
  vca_log(VCA_LDOMAIN,0|VCA_LOGL_CONT,"]}\n");
}

/*******************************************************************/
/* Basic functions */

/**
 * vca_open_handle - opens new VCA handle from CAN driver
 * @vcah_p: points to location filled by new VCA handle
 * @dev_name: name of requested CAN device, if NULL, default VCA_DEV_NAME is used
 * @options: options argument, can be NULL
 * @flags: flags modifying style of open (VCA_O_NOBLOCK)
 *
 * Header: can_vca.h
 * Return Value: VCA_OK in case of success
 */

int vca_open_handle(vca_handle_t *vcah_p, const char *dev_name, const char *options, int flags)
{
  int fd, err;
  int o_flags=0;
  if(dev_name==NULL)
    dev_name=VCA_DEV_NAME;
  if(options==NULL)
    options="";
  if(flags&VCA_O_NONBLOCK)
    o_flags=O_NONBLOCK;
  fd=open(dev_name,O_RDWR|o_flags);
  *vcah_p=fd;

  if(fd<0){
    err=errno;
    if(vca_debug_flg&(VCA_DEB_HANDLE|VCA_DEB_ERROR))
      vca_log(VCA_LDOMAIN,0,"Error: vca_open_handle(\"%s\",\"%s\") returned %s\n",
      		dev_name,options,strerror(err));
    return -1;
  }
  if(vca_debug_flg&(VCA_DEB_HANDLE))
    vca_log(VCA_LDOMAIN,0,"vca_open_handle(\"%s\",\"%s\") -> handle %ld\n",
      	     dev_name,options,vca_h2log(*vcah_p));
  return VCA_OK;
}

/**
 * vca_close_handle - closes previously acquired VCA handle
 * @vcah: VCA handle
 * Header: can_vca.h
 * Return Value: Same as libc close() returns.
 */

int vca_close_handle(vca_handle_t vcah)
{
  int fd;

  if(vca_debug_flg&(VCA_DEB_HANDLE))
    vca_log(VCA_LDOMAIN,0,"vca_close_handle(h:%ld)\n",vca_h2log(vcah));

  fd=vca_h2fd(vcah);
  return close(fd);
}

/**
 * vca_send_msg_seq - sends sequentially block of CAN messages 
 * @vcah: VCA handle
 * @messages: points to continuous array of CAN messages to send
 * @count: count of messages in array
 *
 * Header: can_vca.h
 * Return Value: Number of sucessfully sent messages or error < 0
 */

int vca_send_msg_seq(vca_handle_t vcah, canmsg_t *messages, int count)
{
  int fd, ret, sent;
  fd=vca_h2fd(vcah);
  ret=write(fd,messages,count*sizeof(canmsg_t));
  if(ret==-EAGAIN) ret=0;
  if (ret<0){
    if(vca_debug_flg&(VCA_DEB_RAWMSG|VCA_DEB_ERROR))
      vca_log(VCA_LDOMAIN,0,"Error: vca_send_msg_seq(%ld,...) returned %s\n",
      		vca_h2log(vcah),strerror(errno));
    return -1;
  }
  sent=ret/sizeof(canmsg_t);
  if(vca_debug_flg&(VCA_DEB_RAWMSG)){
    vca_log(VCA_LDOMAIN,0,"vca_send_msg_seq(%ld,...,%d): sent %d\n",
   	vca_h2log(vcah),count,sent);
    if(vca_debug_flg&(VCA_DEB_MSGDATA)){
      int i;
      for(i=0;i<sent;i++)
        vca_canmsg2log(messages+i,0);
    }
  }
  return sent;
}

/**
 * vca_rec_msg_seq - receive sequential block of CAN messages 
 * @vcah: VCA handle
 * @messages: points to array for received CAN messages
 * @count: number of message slots in array
 *
 * Header: can_vca.h
 * Return Value: number of received messages or error < 0
 */

int vca_rec_msg_seq(vca_handle_t vcah, canmsg_t *messages, int count)
{
  int fd, ret, received, i;
  fd=vca_h2fd(vcah);
  
  messages->flags=0; /* Ensure standard receive, else RTR coud be set */
  
  ret=read(fd,messages,count*sizeof(canmsg_t));
  if(ret==-EAGAIN) ret=0;
  if (ret<0){
    if(vca_debug_flg&(VCA_DEB_RAWMSG|VCA_DEB_ERROR))
      vca_log(VCA_LDOMAIN,0,"Error: vca_rec_msg_seq(%ld,...) returned %s\n",
      		vca_h2log(vcah),strerror(errno));
    return -1;
  }
  received=ret/sizeof(canmsg_t);
  if(vca_debug_flg&(VCA_DEB_RAWMSG)){
    vca_log(VCA_LDOMAIN,0,"vca_rec_msg_seq(%ld,...,%d): received %d\n",
   	vca_h2log(vcah),count,received);
    if(vca_debug_flg&(VCA_DEB_MSGDATA)){
      for(i=0;i<received;i++)
        vca_canmsg2log(messages+i,0);
    }
  }
  return received;
}

/**
 * vca_wait - blocking wait for the new message(s)
 * @vcah: VCA handle
 * @wait_msec: number of miliseconds to wait, 0 => forever
 * @what: 0,1 => wait for Rx message, 2 => wait for Tx - free
 *        3 => wait for both
 *
 * Header: can_vca.h
 * Return Value: Positive value if wait condition is satisfied
 */

int vca_wait(vca_handle_t vcah, int wait_msec, int what)
{
  int ret, fd;
  struct timeval timeout;
  fd_set set;
  
  fd=vca_h2fd(vcah);
  if(!what) what=1;
  
  FD_ZERO (&set);
  FD_SET (fd, &set);
  timeout.tv_sec = wait_msec/1000;
  timeout.tv_usec = (wait_msec%1000)*1000;
  while ((ret=select(FD_SETSIZE,(what&1)?&set:NULL, (what&2)?&set:NULL,
  		NULL,&timeout))==-1 && errno==-EINTR);
  if(ret<0){
    if(vca_debug_flg&(VCA_DEB_ERROR))
      vca_log(VCA_LDOMAIN,0,"Error: vca_wait(%ld,...) returned %s\n",
      		vca_h2log(vcah),strerror(errno));
  }
  return ret;
}


