/** apci3120.c
 *
 *  Author: N. Gissler
 *  Creation: 12.12.2018
 *  $LastChangedDate: 2015-02-04 16:34:40 +0100 (Wed, 04 Feb 2015) $
 *  $LastChangedRevision: 1394 $
 *
 *  Copyright (C) 2014 ADDI-DATA GmbH
 *
 *  ADDI-DATA GmbH
 *  Airpark Business Center
 *  Airport Boulevard B210
 *  77836 Rheinmünster
 *  Germany
 *  Tel: +49(0)7229/1847-0    |  Fax: +49(0)7229/1847-200
 *  http://www.addi-data-com  |  info@addi-data.com
 **/

/***********************************************/

#include <dirent.h>
#include <unistd.h>
#include "common.h"

#include <apci3120-events.h>
#include "apci3120Lib.h"
/***********************************************/

int _boards[16];

/***********************************************/

int i_APCI3120_GetNumberOfBoards(uint8_t *boardCount)
{
  DIR *dp;
  struct dirent *ep;
  *boardCount = 0;
  dp = opendir ("/dev");
  if (dp == NULL)
    return -1;

  while ((ep = readdir(dp)) != NULL)
    if (strstr(ep->d_name, "apci3120_") != NULL)
      ++(*boardCount);

  closedir(dp);
  return 0;
}

int i_APCI3120_GetBoardFileDescriptor(uint8_t boardId)
{
  if (boardId > sizeof(_boards) / sizeof(*_boards))
    return -1;
  else if (_boards[boardId] > 0)
    return _boards[boardId];
  else
  {
    const char devPrefix[] = "/dev/apci3120_%u";
    char devPath[sizeof(devPrefix)];
    sprintf(devPath, devPrefix, boardId);
    _boards[boardId] = open(devPath, O_RDWR);
    return _boards[boardId];
  }
}

int i_APCI3120_CloseBoard(uint8_t boardId)
{
  int fd = _boards[boardId];
  _boards[boardId] = -1;
  return close(fd);
}

/***********************************************/

int i_APCI3120_Read4DigitalInputs(uint8_t boardId, unsigned char *values)
{
  int ret;
  unsigned char arg;

  ret = ioctl(i_APCI3120_GetBoardFileDescriptor(boardId), CMD_APCI3120_Read4DigitalInput, &arg);
  if (ret != 0)
  { 
    if (ret == 1)
      fprintf (stderr, "The open file descriptor parameter is wrong.\n"); 
    else
      fprintf(stderr, "ioctl error %d for CMD_APCI3120_Read4DigitalInput\n", ret); 
    *values = 0; 
    goto end;  
  }
     
  *values = arg;

end:
  return ret;
}

int i_APCI3120_SetDigitalOutputMemoryOn(uint8_t boardId)
{
  return ioctl(i_APCI3120_GetBoardFileDescriptor(boardId), CMD_APCI3120_SetOutputMemoryOn, NULL);
}

int i_APCI3120_SetDigitalOutputMemoryOff(uint8_t boardId)
{
  return ioctl(i_APCI3120_GetBoardFileDescriptor(boardId), CMD_APCI3120_SetOutputMemoryOn, NULL);
}

int i_APCI3120_Set4DigitalOutputsOn(uint8_t boardId, unsigned long mask)
{
  int ret;  
  ret = ioctl(i_APCI3120_GetBoardFileDescriptor(boardId), CMD_APCI3120_Set4DigitalOutputOn, mask);
  if (ret != 0)
  { 
    if (ret == 1)
      fprintf (stderr, "The open file descriptor parameter is wrong.\n"); 
    else
      fprintf(stderr, "ioctl error %d for CMD_APCI3120_Set4DigitalOutputOn\n", ret); 
    goto end;  
  }
end:
  return ret; 
}

int i_APCI3120_Set4DigitalOutputsOff(uint8_t boardId, unsigned long mask)
{
  int ret;  
  ret = ioctl(i_APCI3120_GetBoardFileDescriptor(boardId), CMD_APCI3120_Set4DigitalOutputOff, mask);
  if (ret != 0)
  { 
    if (ret == 1)
      fprintf (stderr, "The open file descriptor parameter is wrong.\n"); 
    else
      fprintf(stderr, "ioctl error %d for CMD_APCI3120_Set4DigitalOutputOn\n", ret); 
    goto end;  
  }
end:
  return ret; 
}

/***********************************************/
float computeVoltage(unsigned int value, unsigned int full_scale)
{
  // 16 bit ADC
  return (((float)(value & 0xFFFF) * full_scale) / 0x7FFF) - full_scale;
}

int i_APCI3120_Read1AnalogInput(uint8_t boardId, unsigned int *arg)
{
  int ret;  
    
  ret = ioctl(i_APCI3120_GetBoardFileDescriptor(boardId), CMD_APCI3120_Read1AnalogInput, arg);
  if (ret != 0)
  { 
    if (ret == 1)
      fprintf (stderr, "The open file descriptor parameter is wrong.\n"); 
    else
      fprintf(stderr, "ioctl error %d for CMD_APCI3120_Read1AnalogInput\n", ret); 
    goto end;  
  }
end:
  return ret; 
}

int i_APCI3120_ReadMoreAnalogInputs(uint8_t boardId, unsigned int *arg)
{
  int ret;  
    
  ret = ioctl(i_APCI3120_GetBoardFileDescriptor(boardId), CMD_APCI3120_ReadMoreAnalogInputs, arg);
  if (ret != 0)
  { 
    if (ret == 1)
      fprintf (stderr, "The open file descriptor parameter is wrong (error %d).\n", ret); 
    else if (ret == 2)
      fprintf(stderr, "Max selected channel should be <= 16 for arg[0] (error %d)\n", ret); 
    else if (ret == 3)
      fprintf(stderr, "Wrong parameter for channelArray  : arg[] for channel shoulb be < 16 (error %d)\n", ret); 
    else if (ret == 4)
      fprintf(stderr, "Wrong parameter found in table the gain array (error %d)\n", ret); 
    else if (ret == 5)
      fprintf(stderr, "Wrong parameter found in table the polarity array (error %d)\n", ret); 
    else if (ret == 6)
      fprintf(stderr, "The selected conversion time is wrong (error %d)\n", ret); 
    else 
      fprintf(stderr, "ioctl error %d for CMD_APCI3120_ReadMoreAnalogInputs\n", ret); 
    goto end;  
  }
end:
  return ret; 
}

/***********************************************/

int i_APCI3120_InitAnalogInputSequenceAcquisition(uint8_t boardId, struct apci3120_sequence_acquisition_data *sequence_data)
{
  int ret;  
  ret = ioctl(i_APCI3120_GetBoardFileDescriptor(boardId), CMD_APCI3120_InitAnalogInputSequenceAcquisition, sequence_data);
  if (ret != 0)
  { 
    if (ret == 1)
      fprintf (stderr, "The open file descriptor parameter is wrong (error %d).\n", ret); 
    else if (ret == 2)
      fprintf(stderr, "The user interrupt routine is not installed. (error %d)\n", ret); 
    else if (ret == 3)
      fprintf(stderr, "The size of the sequence table is wrong (error %d)\n", ret); 
    else if (ret == 4)
      fprintf(stderr, "Wrong parameter found in table the channel array (error %d)\n", ret); 
    else if (ret == 5)
      fprintf(stderr, "Wrong parameter found in table the gain array (error %d)\n", ret); 
    else if (ret == 6)
      fprintf(stderr, "Wrong parameter found in table the polarity array (error %d)\n", ret); 
    else if (ret == 7)
      fprintf(stderr, "The waiting time between two conversion cycles is too high  (error %d)\n", ret); 
    else 
      fprintf(stderr, "ioctl error %d for CMD_APCI3120_InitAnalogInputSequenceAcquisition\n", ret); 
    goto end;  
  }
end:
  return ret; 
}


int i_APCI3120_StartAnalogInputSequenceAcquisition(uint8_t boardId, struct apci3120_sequence_acquisition_data *sequence_data)
{
  int ret;  
    
  ret = ioctl(i_APCI3120_GetBoardFileDescriptor(boardId), CMD_APCI3120_StartAnalogInputSequenceAcquisition, sequence_data);
  if (ret != 0)
  { 
    if (ret == 1)
      fprintf (stderr, "The open file descriptor parameter is wrong (error %d).\n", ret); 
    else if (ret == 2)
      fprintf(stderr, "The cyclic conversion has not been initialized. (error %d)\n", ret); 
    else if (ret == 3)
      fprintf(stderr, "Interrupt routine has not been installed (error %d)\n", ret); 
    else if (ret == 4)
      fprintf(stderr, "There was still a running acquisition (error %d)\n", ret); 
    else 
      fprintf(stderr, "ioctl error %d for CMD_APCI3120_ReadMoreAnalogInputs\n", ret); 
    goto end;  
  }
end:
  return ret; 
}

int i_APCI3120_StopAnalogInputSequenceAcquisition(uint8_t boardId)
{
  int ret;  
    
  ret = ioctl(i_APCI3120_GetBoardFileDescriptor(boardId), CMD_APCI3120_StopSequenceAcquisition);
  if (ret != 0)
  { 
    if (ret == 1)
      fprintf (stderr, "The open file descriptor parameter is wrong (error %d).\n", ret); 
    else if (ret == 2)
      fprintf(stderr, "The cyclic conversion has not been started. (error %d)\n", ret); 
    else 
      fprintf(stderr, "ioctl error %d for CMD_APCI3120_ReadMoreAnalogInputs\n", ret); 
    goto end;  
  }
end:
  return ret; 
}

/***********************************************/
int i_APCI3120_EventEmpty(uint8_t boardId)
{
  int ret = 0;  
    
  ret = ioctl(i_APCI3120_GetBoardFileDescriptor(boardId), CMD_apci3120_EventEmpty,NULL);
  if (ret != 0)
  { 
    fprintf(stderr, "ioctl error %d for  CMD_apci3120_EventEmpty\n", ret); 
    goto end;  
  }
end:
  return ret; 

}

int i_APCI3120_EventWait(uint8_t boardId, apci3120_event_t *evt)
{
  int ret = 0;  
    
  ret = ioctl(i_APCI3120_GetBoardFileDescriptor(boardId), CMD_apci3120_EventWait, evt);
  if (ret != 0)
  { 
    fprintf(stderr, "ioctl error %d for CMD_apci3120_EventWait\n", ret); 
    goto end;  
  }
end:
  return ret; 

}

/***********************************************/

int i_APCI3120_SetBoardInterruptRoutine(uint8_t boardId)
{
  int ret;  
    
  ret = ioctl(i_APCI3120_GetBoardFileDescriptor(boardId), CMD_APCI3120_SetBoardInterruptRoutine, NULL);
  if (ret != 0)
  { 
    if (ret == 1)
      fprintf (stderr, "The open file descriptor parameter is wrong (error %d).\n", ret); 
    if (ret == 2)
      fprintf (stderr, "Interrupt routine is already installed (error %d) \n", ret); 
    if (ret == 3)
      fprintf (stderr, "Failed to install the interrupt routine (error %d) \n", ret); 
    else
      fprintf(stderr, "ioctl error %d for CMD_APCI3120_Read1AnalogInput\n", ret); 
    goto end;  
  }
end:
  return ret; 
}

int i_APCI3120_ResetBoardInterruptRoutine(uint8_t boardId)
{
  int ret;  
    
  ret = ioctl(i_APCI3120_GetBoardFileDescriptor(boardId), CMD_APCI3120_ResetBoardInterruptRoutine, NULL);
  if (ret != 0)
  { 
    if (ret == 1)
      fprintf (stderr, "The open file descriptor parameter is wrong (error %d).\n", ret); 
    if (ret == 2)
      fprintf (stderr, "There is not interrupt routine installed (error %d) \n", ret); 
    else
      fprintf(stderr, "ioctl error %d for CMD_APCI3120_Read1AnalogInput\n", ret); 
    goto end;  
  }
end:
  return ret; 
}

/***********************************************/

int i_APCI3120_Write1AnalogOutput(uint8_t boardId, unsigned int *arg)
{
  int ret;  
    
  ret = ioctl(i_APCI3120_GetBoardFileDescriptor(boardId), CMD_APCI3120_Write1AnalogOutput, arg);
  if (ret != 0)
  { 
    if (ret == 1)
      fprintf (stderr, "The open file descriptor parameter is wrong (error %d).\n", ret); 
    else if (ret == 2)
      fprintf(stderr, "Channel number range is 0-3 (error %d)\n", ret); 
    else if (ret == 3)
      fprintf(stderr, "Polarity error (error %d)\n", ret); 
    else if (ret == 4)
      fprintf(stderr, "Wrong output value for the output channel (error %d)\n", ret); 
    else 
      fprintf(stderr, "ioctl error %d for CMD_APCI3120_Read1AnalogOutput\n", ret); 
    goto end;  
  }
end:
  return ret; 
}
/***********************************************/
