// Test program for the Vaunix LDA Driver Interface
// To use this program you must enter the IP addresses of your LDA devices
// in the laddevices[] string array
//
#include <stdbool.h>
#include <stdio.h>
#include <unistd.h>
#include <math.h>
#include <string.h>
#include "ldadrvr.h"

#define FALSE 0
#define TRUE !FALSE

#ifndef M_PI            // Apparently math.h isn't including it???
#define M_PI 3.14159
#endif

// Macros to enable configuration for set functionality with test app
#define RF_CONFIG                       0
#define RAMP_CONFIG                     0
#define SINEWAVE_PROFILE_CONFIG         0   
#define TRIANGLEWAVE_PROFILE_CONFIG     0
#define SQUAREWAVE_PROFILE_CONFIG       0
#define SAVE_CONFIG                     0

#define DEBUG_LEVEL 1

//char* ldadevices[] = {"192.168.1.94", "192.168.100.44"};
char* ldadevices[] = {"192.168.1.12"};

#define LDA_DEVICES  (sizeof(ldadevices)/sizeof(ldadevices[0]))

/* function prototypes */
void profileSine(int attenmax, int profile_length);
void profileTriangle(int attenmax, int profile_length);
void profileSquare(int attenmax, int profile_length);
void profileShow(int height, int profile_length);

/* globals */
unsigned int profile[1000]; // storage for an attenuation profile, 1000 is the maximum size
                            // Only devices with long profiles support 1000 elements in RAM only
                            // Legacy devices may support 50 or 100 element profiles
                            
int read_profile[1000]; // Read Profile data

/* code begins here */
int main (int argc, char *argv[]) {
    bool realhardware;
    unsigned int index, prfindex;
    float fdata;
    int ProfileLength;
    STATUS_REPORT_T status;
    LDADEVICE_DATA_T  ldadevicedata[LDA_DEVICES]; // MAX DEVICES list

    if (DEBUG_LEVEL > 0) printf("Calling fnLDA_Init()\r\n");
    fnLDA_Init();
    /* If you have actual hardware attached, set this to TRUE. Setting to FALSE will run in test mode */
    realhardware = TRUE;
    fnLDA_SetTestMode(!realhardware);

    printf("LDA Devices Length:%ld\n",LDA_DEVICES);

    /* Open all the lda devices Socket connection in the list */
    for (index=0; index <LDA_DEVICES; index++)
    {
        if(fnLDA_InitDevice(ldadevices[index]))
            printf("Device Socket Connection Error:%s\n",ldadevices[index]);
    }

    // Print all the get parameters status
    for (index=0; index <LDA_DEVICES; index++)
    {
        if(DEBUG_LEVEL > 0)
        {
            if(fnLDA_CheckDeviceReady(ldadevices[index])== STATUS_OK)
            {
                // Device IP
                 printf("Device IP:%s\n",ldadevices[index]);
                 printf("----------------------------------------------\n");

                // Device Name
                fnLDA_GetModelName(ldadevices[index], ldadevicedata[index].modelname);
                printf("Model Name:%s\n",ldadevicedata[index].modelname);

                // Serial#
                fnLDA_GetSerialNumber(ldadevices[index], &ldadevicedata[index].serialnumber);
                printf("Serial Number:%d\n",ldadevicedata[index].serialnumber);

                // Sw Version #
                fnLDA_GetSoftwareVersion(ldadevices[index], ldadevicedata[index].swversion);
                printf("SW Version:%s\n",ldadevicedata[index].swversion);

				fnLDA_GetFeatures(ldadevices[index], &ldadevicedata[index].ldafeature);
				printf("LDA Feature:%d\n",ldadevicedata[index].ldafeature);

				// Max Channels
				fnLDA_GetMaxChannels(ldadevices[index], &ldadevicedata[index].maxchannels);
				printf("Max Channels:%d\n",ldadevicedata[index].maxchannels);

                // IP Mode
                fnLDA_GetIPMode(ldadevices[index], &ldadevicedata[index].ipmode);
                printf("IP Mode:%d\n",ldadevicedata[index].ipmode);

                // IP Address
                fnLDA_GetIPAddress(ldadevices[index], ldadevicedata[index].ipaddress);
                printf("IP Address:%s\n",ldadevicedata[index].ipaddress);

                // Netmask
                fnLDA_GetNetmask(ldadevices[index], ldadevicedata[index].netmask);
                printf("Subnet Mask:%s\n",ldadevicedata[index].netmask);

                // Gateway
                fnLDA_GetGateway(ldadevices[index], ldadevicedata[index].gateway);
                printf("Gateway:%s\n",ldadevicedata[index].gateway);

                // Min Frequency
                fnLDA_GetMinWorkingFrequency(ldadevices[index], &ldadevicedata[index].minfrequency);
                printf("Min Frequency:%d\n",(ldadevicedata[index].minfrequency/10));
            
                // Max Frequency
                fnLDA_GetMaxWorkingFrequency(ldadevices[index], &ldadevicedata[index].maxfrequency);
                printf("Min Frequency:%d\n",(ldadevicedata[index].maxfrequency/10));

                // Min Attenuation
                fnLDA_GetMinAttenuation(ldadevices[index], &ldadevicedata[index].minattenuation);
                fdata = (ldadevicedata[index].minattenuation/20.0);
                printf("Min Attenuation:%f\n",fdata);

                // Max Attenuation
                fnLDA_GetMaxAttenuation(ldadevices[index], &ldadevicedata[index].maxattenuation);
                fdata = (ldadevicedata[index].maxattenuation/20.0);
                printf("Max Attenuation:%f\n",fdata);

                // Channel #
                fnLDA_GetChannel(ldadevices[index], &ldadevicedata[index].rf_channel);
                printf("Channel:%d\n",ldadevicedata[index].rf_channel);

                // Current Frequency
                fnLDA_GetWorkingFrequency(ldadevices[index], &ldadevicedata[index].rf_current_frequency);
                printf("Frequency:%d\n",(ldadevicedata[index].rf_current_frequency/10));

                // Current Attenuation
                fnLDA_GetAttenuation(ldadevices[index], &ldadevicedata[index].rf_attenuation);
                fdata = (ldadevicedata[index].rf_attenuation/20.0);
                printf("Attenuation:%f\n",fdata);

                // Ramp Start
                fnLDA_GetRampStart(ldadevices[index], &ldadevicedata[index].rampstart_attenuation);
                fdata = (ldadevicedata[index].rampstart_attenuation/20.0);
                printf("Ramp Start:%f\n",fdata);

                // Ramp End
                fnLDA_GetRampEnd(ldadevices[index], &ldadevicedata[index].rampstop_attenuation);
                fdata = (ldadevicedata[index].rampstop_attenuation/20.0);
                printf("Ramp Stop:%f\n",fdata);

                // Dwell Time
                fnLDA_GetDwellTime(ldadevices[index], &ldadevicedata[index].ramp_dwelltime);
                printf("Dwell Time:%d\n",(ldadevicedata[index].ramp_dwelltime));

                // Idle Time
                fnLDA_GetIdleTime(ldadevices[index], &ldadevicedata[index].ramp_idletime);
                printf("Idle Time:%d\n",(ldadevicedata[index].ramp_idletime));

                // Attenuation Step Size 
                fnLDA_GetAttenuationStep(ldadevices[index], &ldadevicedata[index].attenuationstep);
                printf("Attenuation Step Size:%d\n",(ldadevicedata[index].attenuationstep));

				if(ldadevicedata[index].ldafeature & HAS_BIDIR_RAMPS)
				{
	                // Dwell Time2
	                fnLDA_GetDwellTimeTwo(ldadevices[index], &ldadevicedata[index].ramp_bidirectional_dwelltime);
	                printf("Bi-directional Dwell Time:%d\n",(ldadevicedata[index].ramp_bidirectional_dwelltime));

	                // Hold Time
	                fnLDA_GetHoldTime(ldadevices[index], &ldadevicedata[index].ramp_bidirectional_holdtime);
	                printf("Bi-directional Hold Time:%d\n",(ldadevicedata[index].ramp_bidirectional_holdtime));

	                // Attenuation Step Size2 
	                fnLDA_GetAttenuationStepTwo(ldadevices[index], &ldadevicedata[index].attenuationstep);
	                printf("Attenuation Step Two:%d\n",(ldadevicedata[index].attenuationstep));
				}
				
                // Get Profile Count
                fnLDA_GetProfileCount(ldadevices[index], &ldadevicedata[index].profile_count);
                printf("Profile Count:%d\n",(ldadevicedata[index].profile_count));

                // Get Profile Max Length
                fnLDA_GetProfileMaxLength(ldadevices[index], &ldadevicedata[index].profile_maxlength);
                printf("Profile Maxlength:%d\n",(ldadevicedata[index].profile_maxlength));

                // Get Profile Dwell Time
                fnLDA_GetProfileDwellTime(ldadevices[index], &ldadevicedata[index].profile_dwelltime);
                printf("Profile Dwell Time:%d\n",(ldadevicedata[index].profile_dwelltime));

                // Get Profile Idle Time
                fnLDA_GetProfileIdleTime(ldadevices[index], &ldadevicedata[index].profile_idletime);
                printf("Profile Idle Time:%d\n",(ldadevicedata[index].profile_idletime));

  				// Get the profile data
				for (prfindex=0; prfindex < (unsigned int)ldadevicedata[index].profile_count; prfindex++) {
					status = fnLDA_GetProfileElement(ldadevices[index], prfindex, &read_profile[prfindex]);
					printf(" Get Profile Data status for element %d = %d\r\n", prfindex, read_profile[prfindex]);
					usleep(5000);
				}


            }
        }
    }   

    // Device 0 Set Command Test  -- Check Device 0 ready or not
    if(fnLDA_CheckDeviceReady(ldadevices[0])== STATUS_OK)
    {

#if RF_CONFIG
        // Set Channel
        if(fnLDA_SetChannel(ldadevices[0], 15))  // Setting the channel # 2
        {
            if(DEBUG_LEVEL > 0)
                printf("Channel Set Error\n");
        }

        // Set the Frequency too
        if(fnLDA_SetWorkingFrequency(ldadevices[0], 3200))  // 240MHz=240*10  in 100KHz Resolution 
        {
            if(DEBUG_LEVEL > 0)
                printf("Set Frequency Error\n");
        }

        // Set Attenuation
        if(fnLDA_SetAttenuation(ldadevices[0], 35*20)) // Setting Attenuation to 15dB - 10*20 in 0.05dB Resolution
        {
            if(DEBUG_LEVEL > 0)
                printf("Set Attenuation Error\n");
        }
#endif


#if RAMP_CONFIG

       // Set Ramp Start Configuration
        if(fnLDA_SetRampStart(ldadevices[0], 10*20))  // Setting the Ramp Start Attenuation 10dB = 10*20 in 0.05dB Resolution
        {
            if(DEBUG_LEVEL > 0)
                printf("Set Ramp Start Error\n");
        }

        // Set Ramp End Configuration
        if(fnLDA_SetRampEnd(ldadevices[0], 100*20))  // Setting the Ramp End Attenuation 100dB = 10*20 in 0.05dB Resolution
        {
            if(DEBUG_LEVEL > 0)
                printf("Set Ramp End Error\n");
        }

        // Set Dwell Time Configuration
        if(fnLDA_SetDwellTime(ldadevices[0], 90*10))  // Setting the Dwell time in milliseconds resolution 90msec = 90*10
        {
            if(DEBUG_LEVEL > 0)
                printf("Set Dwell Time Error\n");
        }

        // Set Idle Time Configuration
        if(fnLDA_SetIdleTime(ldadevices[0], 50*10))  // Setting the Idle time in milliseconds resolution 50msec = 50*10
        {
            if(DEBUG_LEVEL > 0)
                printf("Set Idle Time Error\n");
        }       

        // Set Bidirectional Dwell Time Configuration
        if(fnLDA_SetDwellTimeTwo(ldadevices[0], 30*10))  // Setting the Idle time in milliseconds resolution 30msec = 30*10
        {
            if(DEBUG_LEVEL > 0)
                printf("Set Idle Time Error\n");
        }   

        // Set Hold Time Configuration
        if(fnLDA_SetHoldTime(ldadevices[0], 20*10))  // Setting the Hold time in milliseconds resolution 20msec = 20*10
        {
            if(DEBUG_LEVEL > 0)
                printf("Set Idle Time Error\n");
        }   

       if(fnLDA_SetRampDirection(ldadevices[0], FALSE))  // Setting Ramp Direction True - Upwards, False - Downwards
        {
            if(DEBUG_LEVEL > 0)
                printf("Set Ramp Direction Error\n");
        }

        if(fnLDA_SetRampBidirectional(ldadevices[0], TRUE))  // Setting Ramp Bi-directional mode True - Bi-directional, False - Uni-directional
        {
            if(DEBUG_LEVEL > 0)
                printf("Set Ramp Direction Error\n");
        }

        if(fnLDA_SetRampMode(ldadevices[0], TRUE))  // Setting Ramp Control Mode True - COntinuous, False - Once
        {
            if(DEBUG_LEVEL > 0)
                printf("Set Ramp Direction Error\n");
        }   

#endif


#if SINEWAVE_PROFILE_CONFIG
        // Profile Test
        fnLDA_GetProfileMaxLength(ldadevices[0], &ProfileLength);

        // Create the profile data
        profileSine(ldadevicedata[0].maxattenuation, ProfileLength);

        // Set the profile data
        for (index=0; index < (unsigned int)ProfileLength; index++) {
            printf(" Setting Profile Element %d to %d\r\n", index, profile[index]);
            status = fnLDA_SetProfileElement(ldadevices[0], index, profile[index]);
            printf(" SetProfileElement status for element %d = %d\r\n", index, status);
            usleep(5000);
        }

        status = fnLDA_SetProfileCount(ldadevices[0], ProfileLength);
        printf(" SetProfileCount status for channel %d = %d\r\n", ldadevicedata[0].rf_channel, status);
        
        status = fnLDA_SetProfileIdleTime(ldadevices[0], (100 + ldadevicedata[0].rf_channel));       // Profile idle times of 101 ms, 102 ms, 103 ms, etc.
        printf(" SetProfileIdleTime status for channel %d = %d\r\n", ldadevicedata[0].rf_channel, status);
        
        status = fnLDA_SetProfileDwellTime(ldadevices[0], (20 + ldadevicedata[0].rf_channel));
        printf(" SetProfileDwellTime status for channel %d = %d\r\n", ldadevicedata[0].rf_channel, status);
        
        status = fnLDA_StartProfile(ldadevices[0], PROFILE_ONCE);
#endif


#if TRIANGLEWAVE_PROFILE_CONFIG
        // Profile Test
        fnLDA_GetProfileMaxLength(ldadevices[0], &ProfileLength);

        // Create the profile data
        profileTriangle(ldadevicedata[0].maxattenuation, ProfileLength);

        // Set the profile data
        for (index=0; index < (unsigned int)ProfileLength; index++) {
            printf(" Setting Profile Element %d to %d\r\n", index, profile[index]);
            status = fnLDA_SetProfileElement(ldadevices[0], index, profile[index]);
            printf(" SetProfileElement status for element %d = %d\r\n", index, status);
            usleep(5000);
        }

        status = fnLDA_SetProfileCount(ldadevices[0], ProfileLength);
        printf(" SetProfileCount status for channel %d = %d\r\n", ldadevicedata[0].rf_channel, status);
        
        status = fnLDA_SetProfileIdleTime(ldadevices[0], (100 + ldadevicedata[0].rf_channel));       // Profile idle times of 101 ms, 102 ms, 103 ms, etc.
        printf(" SetProfileIdleTime status for channel %d = %d\r\n", ldadevicedata[0].rf_channel, status);
        
        status = fnLDA_SetProfileDwellTime(ldadevices[0], (20 + ldadevicedata[0].rf_channel));
        printf(" SetProfileDwellTime status for channel %d = %d\r\n", ldadevicedata[0].rf_channel, status);
        
        status = fnLDA_StartProfile(ldadevices[0], PROFILE_ONCE);
#endif


#if SQUAREWAVE_PROFILE_CONFIG
        // Profile Test
        fnLDA_GetProfileMaxLength(ldadevices[0], &ProfileLength);

        // Create the profile data
        profileSquare(ldadevicedata[0].maxattenuation, ProfileLength);

        // Set the profile data
        for (index=0; index < (unsigned int)ProfileLength; index++) {
            printf(" Setting Profile Element %d to %d\r\n", index, profile[index]);
            status = fnLDA_SetProfileElement(ldadevices[0], index, profile[index]);
            printf(" SetProfileElement status for element %d = %d\r\n", index, status);
            usleep(5000);
        }

        status = fnLDA_SetProfileCount(ldadevices[0], ProfileLength);
        printf(" SetProfileCount status for channel %d = %d\r\n", ldadevicedata[0].rf_channel, status);
        
        status = fnLDA_SetProfileIdleTime(ldadevices[0], (100 + ldadevicedata[0].rf_channel));       // Profile idle times of 101 ms, 102 ms, 103 ms, etc.
        printf(" SetProfileIdleTime status for channel %d = %d\r\n", ldadevicedata[0].rf_channel, status);
        
        status = fnLDA_SetProfileDwellTime(ldadevices[0], (20 + ldadevicedata[0].rf_channel));
        printf(" SetProfileDwellTime status for channel %d = %d\r\n", ldadevicedata[0].rf_channel, status);
        
        status = fnLDA_StartProfile(ldadevices[0], PROFILE_ONCE);
#endif

    
#if SAVE_CONFIG  
    // Save Settings Configuration
    fnLDA_SaveSettings(ldadevices[0]);   // Save current configuration API

#endif
        
    }
    while(1);
}

/* support functions */
void profileSine(int attenmax, int profile_length) {
  /* calculate values for a sine wave attenuation profile. Use the size of
     the 'profile' array and divide a full wave into that many segments. */
  int i, nsegs;
  float fi, fstart, fend, fstep;
  float ftemp;
  //  #define M_PI 3.14159

  // catch a bad profile length argument to defend our profile array
  if (profile_length < 1 || profile_length > 1000) profile_length = 1000;

  nsegs = profile_length;
  printf("Making a sine wave in %d segments\r\n", nsegs);
  fstart = 0;
  fend = 2.0 * M_PI; /* 2 PI = 1 whole circle */
  fstep = (fend - fstart) / (float)nsegs;
  fi = fstart;
  for (i=0; i<nsegs; i++) {
    /* sin() results range from -1.0 to +1.0, and we want te rescale this
       to 0.0 to 1.0 */
    ftemp = (1.0 + sin(fi)) / 2.0;
    /* and now that we have a 0-1 value, multiply that by the maximum
       attenuation value */
    ftemp = ftemp * (float)attenmax;
    /* store that as the next step in the profile */
    profile[i] = (int)ftemp;
    /* we've set a value where the *attenuation* follows the curve. Now
       let's invert that so the *signal* follows. Comment this out if
       you want the attenuation to follow the instead. */
    profile[i] = attenmax - profile[i];
    /* get ready for the next one */
    fi = fi + fstep;
  }
}

void profileTriangle(int attenmax, int profile_length) {
  /* calculate values for a triangle attenuation profile. Use the size of
     the 'profile' array and divide a full wave into that many segments. */
  int i, nsegs;
  float fi, fstep;
  float ftemp;

  // catch a bad profile length argument to defend our profile array
  if (profile_length < 1 || profile_length > 1000) profile_length = 1000;

  nsegs = profile_length;
  printf("Making a triangle wave in %d segs\r\n", nsegs);
  /* the wave really has 4 parts - up to max, down to 0, down to min, up to 0
     so we'll divide into 4 pieces and then 'bounce' off of the extremes */
  fstep = 4.0 / (float)nsegs;
  fi = 0.0;
  for (i=0; i<nsegs; i++) {
    ftemp = (1.0 + fi) / 2.0;
    /* and now that we have a 0-1 value, multiply that by the maximum
       attenuation value */
    ftemp = ftemp * (float)attenmax;
    /* store that as the next step in the profile */
    profile[i] = (int)ftemp;
    /* we've set a value where the *attenuation* ramps. Now let's invert that
       so the *signal* ramps. Comment ths out if you want the attenuation
       to follow the ramp instead. */
    profile[i] = attenmax - profile[i];
    /* get ready for the next one */
    fi = fi + fstep;
    if (fi >= 1.0) {
      fi = 1.0;
      fstep = -fstep;
    }
    if (fi <= -1.0) {
      fi = -1.0;
      fstep = -fstep;
    }
  }
}

/* a little bonus profile generator - not as exciting as the other two */
void profileSquare(int attenmax, int profile_length) {
  /* calculate values for a square wave attenuation profile. Use the size of
     the 'profile' array and divide a full wave into that many segments. */
  int i, nsegs;

  // catch a bad profile length argument to defend our profile array
  if (profile_length < 1 || profile_length > 1000) profile_length = 1000;

  nsegs = profile_length;
  printf("Making two square waves in %d segs\r\n", nsegs);
  /* the wave really has 4 parts - max, min, max, min so we'll divide into
     4 pieces */
  for (i=0; i<nsegs; i++) {
    if ((i < (nsegs/4)) || ((i > nsegs/2) && (i < (3*nsegs)/4)))
      profile[i] = attenmax;
    else
      profile[i] = 0;
    /* we've set a value where the *attenuation* ramps. Now let's invert that
       so the *signal* ramps. Comment ths out if you want the attenuation
       to follow the ramp instead. */
    profile[i] = attenmax - profile[i];
  }
}

/* displays the profile data as a cheesy graph on the terminal output */
void profileShow(int height, int profile_length) {
  int i, j;
  unsigned int rl, rh, rs;

  // catch a bad profile length argument to defend our profile array
  if (profile_length < 1 || profile_length > 1000) profile_length = 1000;

  rs = 252 / height;
  rh = 252;
  rl = rh - rs + 1;
  for (i=height; i>0; i--) {
    for (j=0; j<profile_length; j++) {
      if ((profile[j] >= rl) && (profile[j] <= rh))
    printf("*");
      else
    printf(" ");
    }
    printf("\r\n");
    rh = rh - rs;
    rl = rl - rs;
    if (rl < rs) rl = 0;
  }
}

