/*
 * SPOW  S-Function to compute u^k or k^u.
 * DSP Blockset S-Function to compute u^k or k^u.
 * This SIMULINK S-function takes the input vector to a power, or
 * raises a number to the power of the input vector; it is called by 
 * the u.^k block in the DSP Blockset.
 *
 *  Copyright 1995-2000 The MathWorks, Inc.
 *  $Revision: 1.9 $  $Date: 2000/05/05 20:16:15 $
 */

#define S_FUNCTION_NAME spow

#include <math.h>
#include <string.h>   /* strcmp() */

#include "dsp_sim.h"

#define NUMINPUTARGS    2
#define POW_FORM        ssGetArg(S, 0)
#define POW_ARG         ssGetArg(S, 1)

typedef enum {
    uPowk,
    kPowu
} PowForm;


static void mdlInitializeSizes(SimStruct *S)
{
    char powForm[16];
    
    ssSetNumContStates(    S, 0);                 /* number of continuous states */
    ssSetNumDiscStates(    S, 0);                 /* number of discrete states */
    ssSetNumInputs(        S, DYNAMICALLY_SIZED); /* number of inputs */
    ssSetNumOutputs(       S, DYNAMICALLY_SIZED); /* number of outputs */
    ssSetDirectFeedThrough(S, 1);                 /* direct feedthrough flag */
    ssSetNumSampleTimes(   S, 1);                 /* number of sample times */
    ssSetNumInputArgs(     S, NUMINPUTARGS);      /* number of input arguments */
    ssSetNumRWork(         S, 0);                 /* number of real work vector elements */
    ssSetNumIWork(         S, 1);                 /* number of integer work vector elements */
    ssSetNumPWork(         S, 0);                 /* number of pointer work vector elements */

    /*
     * Two forms of pow are supported by this S-Function, determine
     * which one it is...
     */
#ifdef MATLAB_MEX_FILE
    if (mxGetString(POW_FORM, powForm, sizeof(powForm)) != 0) {
	mexErrMsgTxt("Error in pow specification.");
    }
#else    
    /*
     * In case of code generation, don't bother with error checking:
     * (works around bug in mxGetString as defined in cg_matrx.h)
     */
    mxGetString(POW_FORM, powForm, sizeof(powForm));
#endif

    if ((strcmp(powForm, "pow(u,k)") == 0) ||
	(strcmp(powForm, "pow(k,u)") == 0)) {
	int width;

	/*
	 * If the pow arg, k, is a vector, set the input/output
	 * widths to the length of the vector.  No dynamic sizing
	 * in that case.
	 */
	width = mxGetNumberOfElements(POW_ARG);
	if (width != 1) {
	    ssSetNumInputs(S, width);
	    ssSetNumOutputs(S, width);
	}
    } else {
#ifdef MATLAB_MEX_FILE
        mexErrMsgTxt("Invalid pow specificier.");
#endif
    }
}


static void mdlInitializeSampleTimes(SimStruct *S)
{
    ssSetSampleTimeEvent(S, 0, INHERITED_SAMPLE_TIME);
    ssSetOffsetTimeEvent(S, 0, 0.0);
}


static void mdlInitializeConditions(real_T *x0, SimStruct *S)
{
    char powForm[16];

    /*
     * Two forms of pow are supported by this S-Function, determine
     * which one it is...
     */
#ifdef MATLAB_MEX_FILE
    if (mxGetString(POW_FORM, powForm, sizeof(powForm)) != 0) {
	mexErrMsgTxt("Error in pow specification.");
    }
#else    
    /* in case of code generation, don't bother with error checking: */
    /* (works around bug in mxGetString as defined in cg_matrx.h)    */
    mxGetString(POW_FORM, powForm, sizeof(powForm));
#endif

    if (strcmp(powForm, "pow(u,k)") == 0) {
	ssSetIWorkValue(S, 0, uPowk);
    } else if (strcmp(powForm, "pow(k,u)") == 0) {
	ssSetIWorkValue(S, 0, kPowu);
    } else {
#ifdef MATLAB_MEX_FILE
        mexErrMsgTxt("Invalid pow specificier.");
#endif
    }
}


static void mdlOutputs(real_T *y, const real_T *x, const real_T *u, 
                       SimStruct *S, int_T tid)
{
#ifdef __linux__
    real_T arg1, arg2;
#endif
    int i, width;
    real_T *k = mxGetPr(POW_ARG);
    int kIncr = mxGetNumberOfElements(POW_ARG) == 1 ? 0 : 1;

    width = ssGetNumInputs(S);
    switch (ssGetIWorkValue(S, 0)) {
	
      case uPowk: {
	real_T *k = mxGetPr(POW_ARG);
	int kIncr = (mxGetNumberOfElements(POW_ARG) == 1) ? 0 : 1;

#ifndef __linux__
	for (i = 0; i < width; i++, k += kIncr)
	    *y++ = pow(*u++, *k);
#else
        /* -O without this will cause an internal compiler error */
	for (i = 0; i < width; i++, k += kIncr) {
	    arg1=*u++;
            arg2=*k;
	    *y++ = pow(arg1, arg2);
	}
#endif
	
	break;
      }
	
      case kPowu: {
#ifndef __linux__
	for (i = 0; i < width; i++, k += kIncr)
	    *y++ = pow(*k, *u++);
#else
		/* -O without this will cause an internal compiler error */
	for (i = 0; i < width; i++, k += kIncr) {
	    arg1=*k;
            arg2=*u++;
	    *y++ = pow(arg1, arg2);
	}
#endif
	
	break;
      }
    }
}


static void mdlUpdate(real_T *x, const real_T *u, SimStruct *S, int_T tid)
{
}

static void mdlDerivatives(real_T *dx, const real_T *x, const real_T *u, 
                           SimStruct *S, int_T tid)
{
}

static void mdlTerminate(SimStruct *S)
{
}

#include "dsp_trailer.c"

/* [EOF]: spow.c */
