/*
 *****************************************************************************
 *                                                                           *
 *                 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: antenna.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 antenna configuration for each of the
           enabled antennas
 *     - Close the radio
 *     - Shut down the library
 *****************************************************************************
 */

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

// change antenna path in RM300 + antenna-switch-board RF output port
const int RFID_ANTENNA_PORT_LOGIC_TO_PHYSICAL[][16] = {
	{0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0,  0,  0,  0,  0,  0},	// power-on default, all logic ports map to physical #0
// MAC with 'ideal' switch board
	{0, 1, 2, 3, 4, 5, 6, 7,  8,  9, 10, 11, 12, 13, 14, 15},	// one-to-one mapping, no translation
// MAC v2.6.5.4 with v2 switch board
//	{0, 1, 2, 3, 4, 5, 6, 7,  8,  9, 10, 11, 12, 13, 14, 15};	// no mapping
//	{4, 5, 2, 3, 6, 7, 0, 1, 12, 13, 10, 11, 14, 15,  8,  9};	// LED light# when no mapping (start from 0)
	{6, 7, 2, 3, 0, 1, 4, 5, 14, 15, 10, 11,  8,  9, 12, 13},	// ==> the physical port for logical #
// MAC v2.6.5.4 with v3 switch board
//	{0, 1, 2, 3, 4, 5, 6, 7,  8,  9, 10, 11, 12, 13, 14, 15};	// no mapping
//	{7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10,  9,  8};	// LED light# when no mapping (start from 0)
	{7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10,  9,  8}	// ==> the physical port for logical #
};

/* Get the state of each antenna.  For enabled antennas, get the          */
/* configuration for that antenna.                                        */
RFID_STATUS display_antenna_status(	RFID_RADIO_HANDLE handle,
									int antenna,
									RFID_ANTENNA_PORT_STATUS *pAntennaStatus)
{
    RFID_STATUS                 status = RFID_STATUS_OK;
	RFID_ANTENNA_PORT_CONFIG    antennaConfig;

	printf("Antenna #%d: %s\n", antenna,	// );
//	printf("\tState: %s\n",
			(pAntennaStatus->state == RFID_ANTENNA_PORT_STATE_DISABLED ?
			 "disabled" : "enabled"));
#if 0
	if (RFID_ANTENNA_PORT_STATE_DISABLED == pAntennaStatus->state)
	{
		return(status);
	}
#endif
	printf("\tLast Antenna Sense Value: %u ohms\n",
		pAntennaStatus->antennaSenseValue);

	antennaConfig.length = sizeof(RFID_ANTENNA_PORT_CONFIG);
	status = RFID_AntennaPortGetConfiguration(handle, antenna, &antennaConfig);
	if (RFID_STATUS_OK != status)
	{
		fprintf(stderr,
			"ERROR: RFID_AntennaPortGetConfiguration returned %d\n",
			status);
		return(status);
	}

	printf("\tPower Level: %.1f dBm\n", (double) antennaConfig.powerLevel / 10);
	printf("\tDwell Time: %u ms\n", antennaConfig.dwellTime);
	printf("\tNumber Inventory Cycles: %u\n",
			antennaConfig.numberInventoryCycles);
	printf("\tPhysical RX: %u\n", antennaConfig.physicalRxPort);
	printf("\tPhysical TX: %u\n", antennaConfig.physicalTxPort);
	printf("\tAntenna Sense Threshold (global): %u ohms\n\n",
			antennaConfig.antennaSenseThreshold);

	return(status);
}


int main(
    int     argc,
    char**  argv
    )
{
    RFID_STATUS                 status;
    RFID_RADIO_ENUM*            pEnum;
    RFID_RADIO_HANDLE           handle;
    INT32U                      antenna;
    RFID_ANTENNA_PORT_STATUS    antennaStatus;
    RFID_ANTENNA_PORT_CONFIG    antennaConfig_new;
    int change_antenna_config = 0;
    int physical_port = -1;		// -1: use pre-defined mapping table, 0..15: use specified physical port for logical port 'antenna_new'
    int set_all_ports = -1;		// -1: display all ports info. only, 0: set specific port(s), 1: set all ports
    int antenna_map_idx = -1;	// index of mapping table: -1: don't use, 0: original design, 1: for v2 switch board, 2: for v3 switch board.
    int powerLevel = -1;
    int dwellTime = -1;
    int numberInventoryCycles = -1;
    int antennaSenseThreshold = -1;
    char antenna_list[16];		// when value is 1, apply setting to indexed (logic) antenna

    memset(antenna_list, 0x0, sizeof(antenna_list));
    if(argc > 1) {
    	int arg_idx = 1;

    	// build the list of selected antennas
    	while(argc > arg_idx) {
    		if(argv[arg_idx][0] == '-')
    			break;
   			antenna = atoi(argv[arg_idx++]);
   			if(antenna >= 0 && antenna < 16)
   				antenna_list[antenna] = 1;
			set_all_ports = 0;
    	}

    	while(argc > arg_idx) {
    		char *pValue;
    		if(argv[arg_idx][0] == '-') {
    			switch(argv[arg_idx][1]) {
    			case 'c':	// set numberInventoryCycles
					if(set_all_ports < 0)
						set_all_ports = 1;
    				pValue = argv[arg_idx] + 2;
    				if(*pValue == 0)
    					pValue = argv[++arg_idx];
    				if(arg_idx >= argc) {
    					printf("parameter not given\n");
    					return(-1);
    				}
    				numberInventoryCycles = atoi(pValue);
    		    //	printf("numberInventoryCycles=%d\n", numberInventoryCycles);
    				change_antenna_config = 1;
    				break;

    			case 'p':	// use specified physical port
					if(set_all_ports < 0)
						set_all_ports = 1;
    				pValue = argv[arg_idx] + 2;
    				if(*pValue == 0)
    					pValue = argv[++arg_idx];
    				if(arg_idx >= argc) {
    					printf("parameter not given\n");
    					return(-1);
    				}
    				physical_port = atoi(pValue);
    				physical_port &= 0x0F;
    		    //	printf("physical_port=%d\n", physical_port);
    				change_antenna_config = 1;
    				break;

    			case 's':	// set antennaSenseThreshold
					if(set_all_ports < 0)
						set_all_ports = 1;
    				pValue = argv[arg_idx] + 2;
    				if(*pValue == 0)
    					pValue = argv[++arg_idx];
    				if(arg_idx >= argc) {
    					printf("parameter not given\n");
    					return(-1);
    				}
    				antennaSenseThreshold = atoi(pValue);
    		    //	printf("antennaSenseThreshold=%d\n", antennaSenseThreshold);
    				change_antenna_config = 1;
    				break;

    			case 't':	// set dwellTime
					if(set_all_ports < 0)
						set_all_ports = 1;
    				pValue = argv[arg_idx] + 2;
    				if(*pValue == 0)
    					pValue = argv[++arg_idx];
    				if(arg_idx >= argc) {
    					printf("parameter not given\n");
    					return(-1);
    				}
    				dwellTime = atoi(pValue);
    		    //	printf("dwellTime=%d\n", dwellTime);
    				change_antenna_config = 1;
    				break;

    			case 'v':	// specified switch board version
					if(set_all_ports < 0)
						set_all_ports = 1;
    				pValue = argv[arg_idx] + 2;
    				if(*pValue == 0)
    					pValue = argv[++arg_idx];
    				if(arg_idx >= argc) {
    					printf("parameter not given\n");
    					return(-1);
    				}
    				antenna_map_idx = atoi(pValue);
    		    //	printf("antenna_map_idx=%d\n", antenna_map_idx);
    				change_antenna_config = 1;
    				break;

    			case 'w':	// set powerLevel
					if(set_all_ports < 0)
						set_all_ports = 1;
    				pValue = argv[arg_idx] + 2;
    				if(*pValue == 0)
    					pValue = argv[++arg_idx];
    				if(arg_idx >= argc) {
    					printf("parameter not given\n");
    					return(-1);
    				}
    				powerLevel = atoi(pValue);
    		    //	printf("powerLevel=%d\n", powerLevel);
    				change_antenna_config = 1;
    				break;

    			default:
    		    	printf("Usage: %s [0] [1] ... [15] [-c] [-p] [-s] [-t] [-v] [-w]\n"
    		    			"\tN: 0~15, specify logic port(s) to use; if none given, display or set parameters to all ports\n"
    		    			"\t-c numberInventoryCycles\n"
    		    			"\t-p physical_port\n"
    		    			"\t-s antennaSenseThreshold\n"
    		    			"\t-t dwellTime\n"
    		    			"\t-v switch_board_version\n"
    		    			"\t-w power_level_in_0.1_(i.e.,_1/10th)_dBm\n"
    		    			"\t-? | -h: help, the usage.\n\n", argv[0]);
    		    	return(0);
    			}
    		}
    		arg_idx++;
    	}
    	if(physical_port >= 0) {
    		antenna_map_idx = -1;
    	}
    //	printf("logic-port: %d\nphysical-port: %d\nswitch-board-version: %d\n\n", antenna_new, physical_port, antenna_map_idx);
    }

    /* 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;
    }

    if(set_all_ports < 0)
    	printf("Current antenna configuration:\n");

	for (antenna = 0; RFID_STATUS_OK == status; ++antenna)
	{
		/* Get the state of each antenna.  For enabled antennas, get the          */
		/* configuration for that antenna.                                        */
		antennaStatus.length = sizeof(RFID_ANTENNA_PORT_STATUS);
		status = RFID_AntennaPortGetStatus(handle, antenna, &antennaStatus);
		if (RFID_STATUS_OK != status)
		{
			break;
		}

		if(set_all_ports < 0) {
			status = display_antenna_status(handle, antenna, &antennaStatus);
			continue;
		}

		if(set_all_ports == 0 && !antenna_list[antenna]) {
			if(RFID_ANTENNA_PORT_STATE_ENABLED == antennaStatus.state) {
				printf("Disable antenna #%d\n", antenna);
				status = RFID_AntennaPortSetState(handle, antenna, RFID_ANTENNA_PORT_STATE_DISABLED);
				if (RFID_STATUS_OK != status)
				{
					fprintf(
						stderr,
						"ERROR: RFID_AntennaPortSetState returned %d\n",
						status);
					goto CLOSE_RADIO;
				}
			}
			continue;
		}

		if(set_all_ports > 0 || antenna_list[antenna]) {
			if(change_antenna_config) {
				antennaConfig_new.length = sizeof(RFID_ANTENNA_PORT_CONFIG);
				status = RFID_AntennaPortGetConfiguration(handle, antenna, &antennaConfig_new);
				if (RFID_STATUS_OK != status)
				{
					fprintf(stderr,
						"ERROR: RFID_AntennaPortGetConfiguration returned %d\n",
						status);
					goto CLOSE_RADIO;
				}

				if(antenna_map_idx >= 0 || physical_port >= 0) {
					antennaConfig_new.physicalTxPort = antennaConfig_new.physicalRxPort =
							(physical_port >= 0) ? physical_port : RFID_ANTENNA_PORT_LOGIC_TO_PHYSICAL[antenna_map_idx][antenna];
				}
				if(powerLevel >= 0) {
					antennaConfig_new.powerLevel = powerLevel;
				}
				if(dwellTime >= 0) {
					antennaConfig_new.dwellTime = dwellTime;
				}
				if(numberInventoryCycles >= 0) {
					antennaConfig_new.numberInventoryCycles = numberInventoryCycles;
				}
				if(antennaSenseThreshold >= 0) {
					antennaConfig_new.antennaSenseThreshold = antennaSenseThreshold;
				}
				status = RFID_AntennaPortSetConfiguration(handle, antenna, &antennaConfig_new);
			//	printf("main(): RFID_AntennaPortSetConfiguration(): antenna #%d\n", antenna);

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

			if(antenna_list[antenna]) {
				printf("Enable antenna #%d\n", antenna);
				status = RFID_AntennaPortSetState(handle, antenna, RFID_ANTENNA_PORT_STATE_ENABLED);
				if (RFID_STATUS_OK != status)
				{
					fprintf(
						stderr,
						"ERROR: RFID_AntennaPortSetState returned %d\n",
						status);
					goto CLOSE_RADIO;
				}
			}

			antennaStatus.length = sizeof(RFID_ANTENNA_PORT_STATUS);
			status = RFID_AntennaPortGetStatus(handle, antenna, &antennaStatus);
			if (RFID_STATUS_OK != status)
			{
				fprintf(
					stderr,
					"ERROR: RFID_AntennaPortGetState returned %d\n",
					status);
				goto CLOSE_RADIO;
			}
			status = display_antenna_status(handle, antenna, &antennaStatus);
		}
	}

    /* If we are here, we broke out of loop after RFID_AntennaPortGetStatus call. */
    /* We exepect an invalid parameter error when we request an invalid antenna   */
    /* port, which will happen when the loop exhausts the set of valid antennas   */
    /* Any other error is unexpected and is reported.                             */
    if (status && (RFID_ERROR_INVALID_PARAMETER != status))
    {
        fprintf(stderr,
                "ERROR: RFID_AntennaPortGetStatus returned %d for antenna %d\n",
                status,
                antenna);
	//	goto CLOSE_RADIO;
    }

CLOSE_RADIO:
    RFID_RadioClose(handle);

CLEANUP_ENUM:
    free(pEnum);

SHUTDOWN_LIBRARY:
    RFID_Shutdown();

EXIT:
    return 0;
} /* main */
