/** @file sample_apci1710.c
 
   This demonstrate how to use the incremental counter in user mode.
 
   @par CREATION  
   @author Lambert Sartory
   @date   11.01.2013
   
   @par VERSION
   @verbatim
   $LastChangedRevision:$
   $LastChangedDate:$
   @endverbatim   
   
   @par LICENCE
   @verbatim
    Copyright (C) 2013  ADDI-DATA GmbH for the source code of this module.
        
    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
        
   This program is free software; you can redistribute it and/or modify it under 
   the terms of the GNU General Public License as published by the Free Software 
   Foundation; either version 2 of the License, or (at your option) any later version.

   This program is distributed in the hope that it will be useful, 
   but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
   or FITNESS FOR A PARTICULAR PURPOSE. 
   See the GNU General Public License for more details.

   You should have received a copy of the GNU General Public License along with 
   this program; if not, write to the Free Software Foundation, 
   Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

   You shoud also find the complete GPL in the COPYING file 
   accompanying this source code.
   @endverbatim   
 */ 

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <stdarg.h>

#include <apci1710.h>

#include "sample_apci1710_common.h"

//--------------------------------------------------------------------------------
/**
 * @brief Read an integer value from stdin within a given range
 * @param minValue Minimum accepted value
 * @param maxValue Maximum accepted value
 * @param description Description to print to the user
 * @return The read integer value
 */
uint64_t readInteger(uint64_t minValue, uint64_t maxValue, char *description, ...)
{
    va_list args;
    uint64_t readValue;

    va_start(args, description);
    do
    {
        vfprintf(stdout, description, args);
        fprintf(stdout, " ");
        fflush(stdout);
        scanf("%lu", &readValue);
    }
    while (readValue < minValue || readValue > maxValue);
    return readValue;
}

//--------------------------------------------------------------------------------

/**
 * @brief Sample function to demonstrate the BISS master single cycle mode
 * @param fd File descriptor of the opened APCI-1710 device
 */
int sample(int fd)
{
    int ret = 0;
    uint8_t cpt = 0;
    uint8_t moduleIndex = 0;
    uint16_t sensorDataFreqDivisor = 0;
    double fSensor = 0.0;
    uint16_t registerDataFreqDivisor = 0;
    uint8_t channel0BISSSSIMode = 0;
    uint8_t channel0BISSMode = 0;
    uint8_t channel1BISSSSIMode = 0;
    uint8_t channel1BISSMode = 0;
    uint8_t nbrOfSlave = 0;
    uint8_t channel[6] = {0};
    uint8_t dataLength[6] = {0};
    uint8_t option[6] = {0};
    uint8_t CRCPolynom[6] = {0};
    uint8_t CRCInvert[6] = {0};
    uint32_t argArray[18];
    double angle;
    /* get the module index */
    moduleIndex = (uint8_t)readInteger(0, 3, "Enter the index of the module that you want to use (0->3)");

    /* get the sensor data frequency divisor */
    for (cpt = 0; cpt < 16; cpt++)
        printf("%hu : %.03lf kHz \n", cpt, (40000000 / (2.0 * (cpt + 1))) / 1000.0);
    for (cpt = 17; cpt < 32; cpt++)
        printf("%hu : %.03lf kHz \n", cpt, (40000000 / (20.0 * ((cpt & 0xF) + 1))) / 1000.0);
    sensorDataFreqDivisor = (uint16_t)readInteger(0, 31, "Enter the sensor data frequency divisor (0 to 15, 17 to 31)");

    /* internal computation to print correct informations */
    if (sensorDataFreqDivisor < 16)
        fSensor = (40000000 / (2.0 * (sensorDataFreqDivisor + 1)));
    else
        fSensor = (40000000 / (20.0 * ((sensorDataFreqDivisor & 0xF) + 1)));

    /* get the register data frequency divisor */
    for (cpt = 0; cpt < 8; cpt++)
        printf("%hu: %.03lf kHz\n", cpt, (fSensor / (1 << cpt)) / 1000.0);
    registerDataFreqDivisor = (uint16_t)readInteger(0, 7, "Enter the register data frequency divisor (0 to 7)");

    /* get the channel 0 mode */
    channel0BISSSSIMode = (uint8_t)readInteger(0, 1, "Does the channel 0 use Biss (0) or SSI (1)?");
    if (channel0BISSSSIMode == 0)
        channel0BISSMode = (uint8_t)readInteger(0, 1, "Does the channel 0 use mode B (0) or mode C (1)?");

    /* get the channel 1 mode */
    channel1BISSSSIMode = (uint8_t)readInteger(0, 1, "Does the channel 1 use Biss (0) or SSI (1)?");
    if (channel1BISSSSIMode == 0)
        channel1BISSMode = (uint8_t)readInteger(0, 1, "Does the channel 1 use mode B (0) or mode C (1)?");

    /* get the number of slaves (used sensors) */
    nbrOfSlave = (uint8_t)readInteger(1, 6, "How many slaves (sensors) do you want to use (1 to 6)?");

    /* get information concerning the slaves */
    for (cpt = 0; cpt < nbrOfSlave; cpt++)
    {
        printf("*************** Slave (sensor) %d ***************\n", cpt);
        channel[cpt]    = (uint8_t)readInteger(0, 1,   "Enter the channel used (0 to 1)");
        dataLength[cpt] = (uint8_t)readInteger(0, 64,  "Enter the data length (0 to 64)");
        CRCPolynom[cpt] = (uint8_t)readInteger(0, 255, "Enter the CRC polynom (0 to 255)");
        CRCInvert[cpt]  = (uint8_t)readInteger(0, 1,   "Is the CRC inverted (0: No, 1: Yes)?");
    }

    /* copy the parameters in the interface array */
    argArray[0] = moduleIndex;
    argArray[1] = sensorDataFreqDivisor;
    argArray[2] = registerDataFreqDivisor;
    argArray[3] = channel0BISSSSIMode;
    argArray[4] = channel0BISSMode;
    argArray[5] = channel1BISSSSIMode;
    argArray[6] = channel1BISSMode;
    argArray[7] = nbrOfSlave;
    for (cpt = 0; cpt < nbrOfSlave; cpt++)
    {
        ((uint8_t *)&argArray[8])[cpt] = channel[cpt];
        ((uint8_t *)&argArray[10])[cpt] = dataLength[cpt];
        ((uint8_t *)&argArray[12])[cpt] = option[cpt];
        ((uint8_t *)&argArray[14])[cpt] = CRCPolynom[cpt];
        ((uint8_t *)&argArray[16])[cpt] = CRCInvert[cpt];
    }
    
    /* initialize */
    ret = ioctl(fd, CMD_APCI1710_BissMasterInitSingleCycle, argArray);
    if (ret != 0)
    {
        printf("BissMasterInitSingleCycle, error : %d \n", ret);
        return 1;
    }
    printf("BissMasterInitSingleCycle: ok. \n");

    /* endless loop */
    for (;;)
    {
        for (cpt = 0; cpt < nbrOfSlave; cpt++)
        {
            memset(argArray, 0, sizeof(argArray));

            /* get the data */
            argArray[0] = moduleIndex;
            argArray[1] = cpt;
            ret = ioctl(fd, CMD_APCI1710_BissMasterSingleCycleDataRead, argArray);
            if (ret != 0)
            {
                printf("BissMasterSingleCycleDataRead, error : %d \n", ret);
                return 1;
            }
            angle = 360
                    *((double)((((uint64_t)(argArray[3])<<30)) + ((argArray[2] & 0xFFFFFFFC)>>2)))
                    /(((uint64_t)(1))<<(dataLength[cpt] - 2));
            printf("Slave %d, data high : 0x%08x data low : 0x%08x ( angle : %fdegrees : %s Warning : %s \t \n", cpt, 
									                                         argArray[3], 
									                                         argArray[2],
                                                                                                                 angle,
                                                                                                                 ((argArray[2]&0x2) ? "no":"yes"),
                                                                                                                 ((argArray[2]&0x1) ? "no":"yes"));
        }
        sleep(1);
    }

    /* release the single cycle */
    ret = ioctl(fd, CMD_APCI1710_BissMasterReleaseSingleCycle, &moduleIndex);
    if (ret != 0)
    {
        printf("BissMasterReleaseSingleCycle, error : %d \n", ret);
        return 1;
    }
    printf("BissMasterReleaseSingleCycle: ok. \n");

    return 0;
}

//--------------------------------------------------------------------------------


int main(int argc, char** argv)
{
    int * apci1710_card_fd;
    unsigned int apci1710_card_number = 0;

    apci1710_card_number = apci1710_find_cards(&apci1710_card_fd);
    printf("total: %d cards\n", apci1710_card_number);

    /* Use the first APCI-1710 */
    sample(apci1710_card_fd[0]);

    return 0;
}

//--------------------------------------------------------------------------------
