/*
 *****************************************************************************
 *                                                                           *
 *                 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: randomcw.c 66460 2010-12-28 01:44: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 each one in turn and
 *       - Retrieve the MAC version
 *       - Turn on random CW on the radio, for the specified duration
 *       - Close the radio
 *     - Shut down the library
 *
 * Parameters:
 *   A single argument specifies how long (in milliseconds) the random CW
 *   should be generated.
 *
 *****************************************************************************
 */

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

#include "rfid_library.h"
#include "rfid_packets.h"
#include "print_packet.h"
#include "byte_swap.h"
#include "sample_utility.h"
#include "hostifregs.h"

INT32S RFID_CALLBACK PacketCallbackFunction(
    RFID_RADIO_HANDLE   handle,
    INT32U              bufferLength,
    const INT8U*        pBuffer,
    void *              context
    );

int main(int argc, char** argv)
{
    RFID_STATUS                 status;
    RFID_VERSION                libraryVersion;
    RFID_RADIO_ENUM*            pEnum;
    INT32U                      index;
    RFID_RADIO_HANDLE           handle;
    int                         indent_level = 0;
    int                         duration = 0;
    RFID_RANDOM_CW_PARMS        randomCwParms;
    INT32U                      origHstCmnDiags;
    INT32U                      hstCmnDiags;


    if (argc != 2)
    {
        printf("Invalid arguement list.  Must specify duration.\n");
        printf("   Usage:  randomcw <duration in milliseconds>\n");
        goto EXIT;
    }
    else
    {
        duration = atoi(argv[1]);
    }

    /* First open the library */
    status = RFID_Startup(&libraryVersion, 0);
    if (RFID_STATUS_OK != status)
    {
        printf("RFID_Startup() failed.  RC = %d\n", status);
        goto EXIT;
    }

    /* Allocate a buffer for radio enumeration */
    pEnum = (RFID_RADIO_ENUM *) malloc(sizeof(RFID_RADIO_ENUM));
    if (NULL == pEnum)
    {
        printf("Failed to allocate memory\n");
        goto CLEANUP_1;
    }

    /* Initialize the enumeration buffer */
    pEnum->length      = sizeof(RFID_RADIO_ENUM);
    pEnum->totalLength = sizeof(RFID_RADIO_ENUM);

    /* Keep attempting to enumerate while the library says that the buffer is */
    /* too small.  This accounts for a situation where a radio may be plugged */
    /* in between the call to enumerate and the return with the previously    */
    /* needed buffer size.                                                    */
    while (RFID_ERROR_BUFFER_TOO_SMALL ==
        (status = RFID_RetrieveAttachedRadiosList(pEnum, 0)))
    {
        /* Allocate a new, larger buffer */
        RFID_RADIO_ENUM* pNewEnum =
            (RFID_RADIO_ENUM *) realloc(pEnum, pEnum->totalLength);
        if (NULL == pNewEnum)
        {
            printf("Failed to reallocate memory\n");
            goto CLEANUP_2;
        }
        pEnum = pNewEnum;
    }

    /* Verify that the enumeration was successful */
    if (RFID_STATUS_OK != status)
    {
        printf("RFID_RetrieveAttachedRadiosList failed:  RC = %d\n", status);
        goto CLEANUP_2;
    }

    printf("RFID_RADIO_ENUM.length      = %u\n", pEnum->length);
    printf("RFID_RADIO_ENUM.totalLength = %u\n", pEnum->totalLength);
    printf("RFID_RADIO_ENUM.countRadios = %u\n", pEnum->countRadios);


    /* For each radio in the list, open it, try to get its MAC version,    */
    /* try to perform an inventory, then close it                          */
    for (index = 0; index < pEnum->countRadios; ++index)
    {
        RFID_VERSION macVersion;

        printf("Radio %u:\n", index + 1);
        printf("\tStructure length: %u\n", pEnum->ppRadioInfo[index]->length);
        printf("\tCookie: 0x%.8x\n", pEnum->ppRadioInfo[index]->cookie);
        printf("\tDriver Version:\n");
        printf("\t\tMajor: %u\n",
            pEnum->ppRadioInfo[index]->driverVersion.major);
        printf("\t\tMinor: %u\n",
            pEnum->ppRadioInfo[index]->driverVersion.minor);
        printf("\t\tMaintenance: %u\n",
            pEnum->ppRadioInfo[index]->driverVersion.maintenance);
        printf("\t\tRelease: %u\n",
            pEnum->ppRadioInfo[index]->driverVersion.release);
        printf("\tUnique ID Length: %u\n", pEnum->ppRadioInfo[index]->idLength);
        PrintRadioUniqueId("Unique ID: ",
            pEnum->ppRadioInfo[index]->idLength,
            pEnum->ppRadioInfo[index]->pUniqueId);

        /* Open the radio */
        if (RFID_STATUS_OK !=
            (status =
            RFID_RadioOpen(pEnum->ppRadioInfo[index]->cookie, &handle, 0)))
        {
            printf("RFID_RadioOpen failed:  RC = %d\n", status);
            continue;
        }

        /* Attempt to get the MAC version for the radio */
        if (RFID_STATUS_OK !=
            (status = RFID_MacGetVersion(handle, &macVersion)))
        {
            printf("RFID_MacGetVersion failed: RC = %d\n", status);
        }
        else
        {
            printf("\tMAC Version:\n");
            printf("\t\tMajor: %u\n", macVersion.major);
            printf("\t\tMinor: %u\n", macVersion.minor);
            printf("\t\tMaintenance: %u\n", macVersion.maintenance);
            printf("\t\tRelease: %u\n", macVersion.release);
        }


        /* Enable tx random status packet.  This is a custom packet enable, so
           need to go direct to the HST_CMNDIAGS register.
        */

        if (RFID_STATUS_OK !=
            (status = RFID_MacReadRegister(handle, HST_CMNDIAGS, &origHstCmnDiags)))
        {
            printf("RFID_MacReadRegister failed: RC = %d\n", status);
        }
        hstCmnDiags = origHstCmnDiags;
        hstCmnDiags |= 0x81;
        if (RFID_STATUS_OK !=
            (status = RFID_MacWriteRegister(handle, HST_CMNDIAGS, hstCmnDiags)))
        {
            printf("RFID_MacWriteRegister failed: RC = %d\n", status);
        }

        randomCwParms.length        = sizeof(RFID_RANDOM_CW_PARMS);
        randomCwParms.duration      = duration;
        randomCwParms.context       = &indent_level;
        randomCwParms.pCallback     = PacketCallbackFunction;
        randomCwParms.pCallbackCode = NULL;

        /* Attempt to perform random CW on the radio */
        if (RFID_STATUS_OK !=
            (status = RFID_RadioTurnCarrierWaveOnRandom(handle, &randomCwParms)))
        {
            printf("RFID_RadioTurnCarrierWaveOnRandom: RC = %d\n", status);
        }

        RFID_MacClearError(handle);

        /* restore packet control register (HST_CMNDIAGS) */

        if (RFID_STATUS_OK !=
            (status = RFID_MacWriteRegister(handle, HST_CMNDIAGS, origHstCmnDiags)))
        {
            printf("RFID_MacWriteRegister failed: RC = %d\n", status);
        }

        /* Close the radio */
        RFID_RadioClose(handle);
    }

CLEANUP_2:
    /* Free the dynamically alloated memory */
    free(pEnum);

CLEANUP_1:
    /* Shut down the library */
    RFID_Shutdown();

EXIT:
    return 0;
}

INT32S PacketCallbackFunction(
    RFID_RADIO_HANDLE   handle,
    INT32U              bufferLength,
    const INT8U*        pBuffer,
    void *              context
    )
{
    int *indent = (int *)context;
    RFID_UNREFERENCED_LOCAL(handle);

    PacketTrace(bufferLength, pBuffer, indent, NULL);

    return 0;
}
