/*
 *****************************************************************************
 *                                                                           *
 *                 IMPINJ CONFIDENTIAL AND PROPRIETARY                       *
 *                                                                           *
 * This source code is the sole property of Impinj, Inc.  Reproduction or    *
 * utilization of this source code in whole or in part is forbidden without  *
 * the prior written consent of Impinj, Inc.                                 *
 *                                                                           *
 * (c) Copyright Impinj, Inc. 2009. All rights reserved.                     *
 *                                                                           *
 *****************************************************************************
 */

/*
 *****************************************************************************
 *
 * $Id: algorithm.c 61503 2009-12-18 01:00:57Z dshaheen $
 * 
 * Description:
 *     This is a simple sample application for performing the following 
 *     functions:
 *     - Start up the RFID Reader Library 
 *     - Enumerate the attached radios
 *     - Open the first enumerated radio and
 *       - Retrieve the current singulation algorithm
 *       - Retrieve the current algorithm settings for each supported 
           inventory algorithm
 *     - Close the radio
 *     - Shut down the library
 *
 *****************************************************************************
 */

#include <stdio.h>
#include <stdlib.h>
#include "rfid_library.h"

/* Moved to static decl's to avoid warnings on inititializer for algorithmSettings */
static RFID_18K6C_SINGULATION_FIXEDQ_PARMS             fixedQParms;
static RFID_18K6C_SINGULATION_DYNAMICQ_PARMS           dynamicQParms;

int main(
    int     argc,
    char**  argv
    )
{
    RFID_STATUS                                     status;
    RFID_RADIO_ENUM*                                pEnum;
    RFID_RADIO_HANDLE                               handle;
    INT32U                                          index;
    RFID_18K6C_SINGULATION_ALGORITHM                algorithm;
    struct
    {
        RFID_18K6C_SINGULATION_ALGORITHM    algorithm;
        void*                               pParms;
    } algorithmSettings[] =
    {
        { 
            RFID_18K6C_SINGULATION_ALGORITHM_FIXEDQ, 
            &fixedQParms
        },
        {
            RFID_18K6C_SINGULATION_ALGORITHM_DYNAMICQ,
            &dynamicQParms
        }
    };

    RFID_UNREFERENCED_LOCAL(argc);
    RFID_UNREFERENCED_LOCAL(argv);

    /* Initialize the RFID library                                         */
    status = RFID_Startup(NULL, 0);
    if (RFID_STATUS_OK != status)
    {
        fprintf(stderr, "ERROR: RFID_Startup returned %d\n", status);
        goto EXIT;
    }

    /* Create an initial structure for enumerating the radios.  We'll adjust  */
    /* it once we know how big to make it.                                    */
    pEnum = (RFID_RADIO_ENUM *) malloc(sizeof(RFID_RADIO_ENUM));
    if (NULL == pEnum)
    {
        fprintf(stderr, "ERROR: Failed to allocate memory\n");
        goto SHUTDOWN_LIBRARY;
    }
    pEnum->length       = sizeof(RFID_RADIO_ENUM);
    pEnum->totalLength  = sizeof(RFID_RADIO_ENUM);

    /* Enumerate the radios                                                   */
    while (RFID_ERROR_BUFFER_TOO_SMALL == 
        (status = RFID_RetrieveAttachedRadiosList(pEnum, 0)))
    {
        RFID_RADIO_ENUM* pNewEnum = 
            (RFID_RADIO_ENUM *) realloc(pEnum, pEnum->totalLength);
        if (NULL == pNewEnum)
        {
            fprintf(stderr, "ERROR: Failed to allocate memory\n");
            goto CLEANUP_ENUM;
        }
        pEnum = pNewEnum;
    }

    if (RFID_STATUS_OK != status)
    {
        fprintf(
            stderr,
            "ERROR: RFID_RetrieveAttachedRadiosList returned %d\n",
            status);
        goto CLEANUP_ENUM;
    }

    /* Open up the first radio - if more than one radio is attached, so be it */
    if (!pEnum->countRadios)
    {
        fprintf(stderr, "ERROR: No radios attached to the system\n");
        goto CLEANUP_ENUM;
    }

    status = RFID_RadioOpen(pEnum->ppRadioInfo[0]->cookie, &handle, 0);
    if (RFID_STATUS_OK != status)
    {
        fprintf(stderr, "ERROR: RFID_RadioOpen returned %d\n", status);
        goto CLEANUP_ENUM;
    }

    /* Get the current singulation algorithm        */
    status = RFID_18K6CGetCurrentSingulationAlgorithm(
                 handle,
                 &algorithm);
    if (RFID_STATUS_OK != status)
    {
        fprintf(
            stderr,
            "ERROR: RFID_18K6CGetCurrentSingulationAlgorithm returned %d\n",
            status);
        goto CLOSE_RADIO;
    }
    printf("Current Singulation Algorithm: %s (%u)\n\n", 
            (RFID_18K6C_SINGULATION_ALGORITHM_DYNAMICQ == algorithm) ? 
             "Dynamic Q" : "Fixed Q", algorithm);

    /* For each singulation algorithm, get the configuration for the algorithm */
    fixedQParms.length    = sizeof(RFID_18K6C_SINGULATION_FIXEDQ_PARMS);
    dynamicQParms.length  = sizeof(RFID_18K6C_SINGULATION_DYNAMICQ_PARMS);
    for (index = 0;
        index < (sizeof(algorithmSettings)/sizeof(algorithmSettings[0]));
        ++index)
    {
        status = RFID_18K6CGetSingulationAlgorithmParameters(
                     handle,
                     algorithmSettings[index].algorithm,
                     algorithmSettings[index].pParms);
        if (RFID_STATUS_OK != status)
        {
            fprintf(
                stderr,
                "ERROR: RFID_18K6CGetSingulationAlgorithmParameters returned %d\n",
                status);
            goto CLOSE_RADIO;
        }

        /* Based upon the algorithm, print its configuration                   */
        switch (algorithmSettings[index].algorithm)
        {
            case RFID_18K6C_SINGULATION_ALGORITHM_FIXEDQ:
                {
                    RFID_18K6C_SINGULATION_FIXEDQ_PARMS* pParms =
                        (RFID_18K6C_SINGULATION_FIXEDQ_PARMS *) 
                    algorithmSettings[index].pParms;
                    printf("Algorithm: Fixed Q (%u)\n", 
                                algorithmSettings[index].algorithm);
                    printf("\tQ: %u\n", pParms->qValue);
                    printf("\tRetry Count: %u\n", pParms->retryCount);
                    printf("\tToggle Target: %s\n",
                                pParms->toggleTarget ? "true" : "false");
                    printf("\tRepeat Until No Tags: %s\n\n",
                                pParms->repeatUntilNoTags ? "true" : "false");
                    break;
                } /* RFID_18K6C_SINGULATION_ALGORITHM_FIXEDQ */
            case RFID_18K6C_SINGULATION_ALGORITHM_DYNAMICQ:
                {
                    RFID_18K6C_SINGULATION_DYNAMICQ_PARMS* pParms =
                        (RFID_18K6C_SINGULATION_DYNAMICQ_PARMS *) 
                    algorithmSettings[index].pParms;
                    printf("Algorithm: Dynamic Q (%u)\n",
                            algorithmSettings[index].algorithm);
                    printf("\tStart Q: %u\n", pParms->startQValue);
                    printf("\tMinimum Q: %u\n", pParms->minQValue);
                    printf("\tMaximum Q: %u\n", pParms->maxQValue);
                    printf("\tRetry Count: %u\n", pParms->retryCount);
                    printf("\tToggle Target: %s\n",
                            pParms->toggleTarget ? "true" : "false");
                    printf("\tThreshold Multiplier: %.2f\n\n",
                            (double) pParms->thresholdMultiplier / 4);
                    break;
                } /* RFID_18K6C_SINGULATION_ALGORITHM_DYNAMICQ */
        } /* switch (algorithm) */
    } /* for (...) */

CLOSE_RADIO:
    RFID_RadioClose(handle);

CLEANUP_ENUM:
    free(pEnum);

SHUTDOWN_LIBRARY:
    RFID_Shutdown();

EXIT:
    return 0;
} /* main */
