/*
 * SWRITFIL  A Simulink triggered write to a workspace variable.
 *
 *  Syntax:  [sys, x0] = swritwks(t,x,u,flag, varname, format, pulnum, threshold)
 *  This function has two inputs and no outputs. The first input is
 *  the signal to be stored. The second signal is the clock pulse.
 *
 *  varname is a string for the variable name.
 *  format   is the format to be written into the variable. The choices are:
 *            "data", "ascii"
 *  pulnum   number of pulses between saved data. If pulnum is a two 
 *           dimentional vector, the second element is the number of
 *           'offset' pulse before the first data is saved.
 *
 * Wes Wang  Feb. 7, 1995
 * Copyright 1996-2000 The MathWorks, Inc.
 * $Revision: 1.20 $  $Date: 2000/08/30 21:44:53 $
 */
#define S_FUNCTION_NAME swritwks

#include <string.h>    /* needed for string operation */

#ifdef MATLAB_MEX_FILE
#include "mex.h"      /* needed for declaration of mexErrMsgTxt */
#endif

/*
 * need to include simstruc.h for the definition of the SimStruct and
 * its associated macro definitions.
 */

#include "simstruc.h"
#include "tmwtypes.h"

/* For RTW */
#if defined(RT) || defined(NRT)  
#undef  mexPrintf
#define mexPrintf printf
#endif

/*
 * Defines for easy access of the input parameters
 */

#define NUM_ARGS      6
/* file name for the data to be saved */
#define VARNAME       ssGetArg(S, 0)
/* data type, which is a string of ASCII, Integer, float, or binary */
#define DATA_TYPE     ssGetArg(S, 1)
/* number of pulse count to trigger one saving record */
#define NUM_IN_BT     ssGetArg(S, 2)
/* maximum size of the data storage */
#define MAX_SIZE      ssGetArg(S, 3)
/* keep which part of the data 0--begin 1--end */
#define CUT_FLAG      ssGetArg(S, 4)
/* threshold in detecting the rising edge. */
#define THRESHOLD     ssGetArg(S, 5)

/*
 * mdlInitializeSizes - called to initialize the sizes array stored in
 *                      the SimStruct.  The sizes array defines the
 *                      characteristics (number of inputs, outputs,
 *                      states, etc.) of the S-Function.
 */

static void mdlInitializeSizes(SimStruct *S)
{
  /*
   * Set-up size information.
   */ 
    
  if (ssGetNumArgs(S) == NUM_ARGS) {
    int_T i;
    if ((mxGetN(VARNAME) > 1) && (mxGetM(VARNAME) > 1)) {
#ifdef MATLAB_MEX_FILE
      char_T err_msg[256];
      sprintf(err_msg, "Variable name should be a string vector.");
      mexErrMsgTxt(err_msg);
#endif  
    }

    if ((mxGetN(DATA_TYPE) > 1) && (mxGetM(DATA_TYPE) > 1)) {
#ifdef MATLAB_MEX_FILE
      char_T err_msg[256];
      sprintf(err_msg, "Data Type should be a string vector.");
      mexErrMsgTxt(err_msg);
#endif  
    }

    if (mxGetN(MAX_SIZE) * mxGetM(MAX_SIZE) > 1) {
#ifdef MATLAB_MEX_FILE
      char_T err_msg[256];
      sprintf(err_msg, "Data maximum storage size must be scalar.");
      mexErrMsgTxt(err_msg);
#endif  
    }

    if (mxGetN(CUT_FLAG) * mxGetM(CUT_FLAG) > 1) {
#ifdef MATLAB_MEX_FILE
      char_T err_msg[256];
      sprintf(err_msg, "Storage keeping flag must be a scalar.");
      mexErrMsgTxt(err_msg);
#endif  
    }

    if ((mxGetN(NUM_IN_BT) * mxGetM(NUM_IN_BT) > 2) 
      || (mxGetN(NUM_IN_BT) * mxGetM(NUM_IN_BT) < 1) ) {
#ifdef MATLAB_MEX_FILE
      char_T err_msg[256];
      sprintf(err_msg, "Dimension for trigger pulse number is incorrect.");
      mexErrMsgTxt(err_msg);
#endif  
    }
       
    ssSetNumContStates(    S, 0);
    ssSetNumDiscStates(    S, 0);
    ssSetNumInputs(        S, -1);
    ssSetNumOutputs(       S, 1);
    ssSetDirectFeedThrough(S, 0);
    ssSetNumInputArgs(     S, NUM_ARGS);
    ssSetNumSampleTimes(   S, 1);
    ssSetNumRWork(         S, 0);
    ssSetNumIWork(         S, 4);
    /* 1st: 0--start, not passed offset; 1--regular calculation
     * 2nd: accumulate accounting for the how many pulse passed
     * 3rd: 0: last trigger signal was below threshold 1: last
     *         trigger signal was above threshold
     * 4th: index of the saving point
     */
    ssSetNumPWork(         S, 0);
  } else {
#ifdef MATLAB_MEX_FILE
    char_T err_msg[256];
    sprintf(err_msg,
      "Wrong number of input arguments passed to S-function MEX-file.\n"
      "%d input arguments were passed in when expecting %d input arguments.\n",
    ssGetNumArgs(S) + 4, NUM_ARGS + 4);
    mexErrMsgTxt(err_msg);
#endif
  }
}

/*
 * mdlInitializeSampleTimes - initializes the array of sample times stored in
 *                            the SimStruct associated with this S-Function.
 */

static void mdlInitializeSampleTimes(SimStruct *S)
{
  /*
   * Note, blocks that are continuous in nature should have a single
   * sample time of 0.0.
   */

    ssSetSampleTimeEvent(S, 0, INHERITED_SAMPLE_TIME);
    ssSetOffsetTimeEvent(S, 0, FIXED_IN_MINOR_STEP_OFFSET);
}

/*
 * mdlInitializeConditions - initializes the states for the S-Function
 */

static void mdlInitializeConditions(real_T *x0, SimStruct *S)
{
  int_T    *CountFlag      = ssGetIWork(S);
  int_T    *CountNum       = ssGetIWork(S) + 1;
  int_T    *LastTrig       = ssGetIWork(S) + 2;
  int_T    *RowIndex       = ssGetIWork(S) + 3;
  int_T     numInput       = ssGetNumInputs(S);
  char_T eval_string[1024];
  char_T   varname[32];
  char_T   dataType[10];

#ifdef MATLAB_MEX_FILE
  mxArray *aryPoint;
#endif

  *CountFlag = 0;
  *CountNum  = 0;
  *LastTrig  = 0;

  /* printf("Initial Condition: before MATLAB_MEX_FILE.\n"); */
#ifdef MATLAB_MEX_FILE
  /* printf("Initial Condition: inside MATLAB_MEX_FILE.\n"); */
  if (mxGetString(DATA_TYPE, dataType, sizeof(dataType)) != 0) {
    mexErrMsgTxt("Error in Data Type specification.");
  }
  mxGetString(VARNAME, varname, sizeof(varname));
  if ((strcmp(dataType, "ascii") == 0) 
    || (strcmp(dataType, "ASCII") == 0)) {
    sprintf(eval_string, "%s = zeros(1, 0);", varname);
  } else {
    sprintf(eval_string, "%s = zeros(0, %i);", varname, numInput-1);
  }
  mexEvalString(eval_string);

  aryPoint = mexGetArray(varname, "caller");
  mexPutArray(aryPoint, "base");

  /* printf("%s\n", eval_string); */
#endif
}

/*
 * mdlOutputs - computes the outputs of the S-Function
 */

static void mdlOutputs(real_T *y, const real_T *x, const real_T *u, SimStruct *S, int_T tid)
{
  int_T    *CountFlag      = ssGetIWork(S);
  int_T    *CountNum       = ssGetIWork(S) + 1;
  int_T    *LastTrig       = ssGetIWork(S) + 2;
  int_T    *RowIndex       = ssGetIWork(S) + 3;

  real_T  trigThreshold   = mxGetPr(THRESHOLD)[0];
  int_T     cutFlag         = (int_T)mxGetPr(CUT_FLAG)[0];

  int_T     numInput       = ssGetNumInputs(S);
  int_T     i;

  char_T   varname[32];
  char_T   dataType[10];

#ifdef MATLAB_MEX_FILE
  mxArray *aryPoint;
#endif

  if ((*RowIndex >= mxGetPr(MAX_SIZE)[0]) && (mxGetPr(CUT_FLAG)[0] <= 0)) {
    /* need no process */
    return;
  }

  /*
   * acquire the buffer data
   */
  if ((u[numInput-1] >= trigThreshold) & (*LastTrig == 0)) {
#ifdef MATLAB_MEX_FILE
    if (mxGetString(DATA_TYPE, dataType, sizeof(dataType)) != 0) {
      mexErrMsgTxt("Error in Data Type specification.");
    }
#endif
    *CountNum += 1;
    if (*CountFlag) {
      /* action when count number is larger or equal to number count */
      int_T NumberInBetween = (int_T)mxGetPr(NUM_IN_BT)[0];

      if (*CountNum > NumberInBetween) {
        char_T eval_string[10240];
        char_T temp_string[10240];

        /* reset Count */
        *CountNum = 0;
        *RowIndex += 1;

#ifdef MATLAB_MEX_FILE
        sprintf(temp_string, "[");
        for (i = 0; i < numInput-1; i++) {
          sprintf(eval_string, "  %f", u[i]);
          strcat(temp_string, eval_string);
        }
        sprintf(eval_string, "]");
        strcat(temp_string, eval_string);

        mxGetString(VARNAME, varname, sizeof(varname));
		    
        /* assign the u value in varnae_temp to varname */
        if (*RowIndex <= mxGetPr(MAX_SIZE)[0]) {
          if ((strcmp(dataType, "ascii") == 0) 
            || (strcmp(dataType, "ASCII") == 0)) {
            sprintf(eval_string, "%s = [%s, setstr( %s )];",
              varname, varname, temp_string);
          } else {
            sprintf(eval_string, "%s = [%s; %s];", 
              varname, varname, temp_string);
          }
        } else {

          int_T max_m = (int_T)mxGetPr(MAX_SIZE)[0];
          if ((strcmp(dataType, "ascii") == 0) 
            || (strcmp(dataType, "ASCII") == 0)) {
            sprintf(eval_string, "%s = [%s(%i : %i), setstr( %s )];", 
              varname, varname, numInput, max_m * (numInput-1), temp_string);
          } else {
            sprintf(eval_string, "%s = [%s(2 : %i, :); %s];", 
              varname, varname, max_m, temp_string);
          }
        }

        if (strlen(eval_string) >= 10240) {
          mexErrMsgTxt("Input vector length is too big to handle in triggered to workspace block.");
        }
        mexEvalString(eval_string);
        /* printf("%s\n", eval_string); */
        aryPoint = mexGetArray(varname, "caller");
        mexPutArray(aryPoint, "base");

#endif
      }
    } else {
      i = 0;
      if ((mxGetN(NUM_IN_BT) * mxGetM(NUM_IN_BT)) < 2) {
        i = 1;
      } else {
        if (*CountNum > mxGetPr(NUM_IN_BT)[1])
          i = 1;
      }
      if (i) {
        /* this part will be run once only. p*/
        char_T eval_string[10240];
        char_T temp_string[10240];
#ifdef MATLAB_MEX_FILE
        sprintf(temp_string, "[");
        for (i = 0; i < numInput - 1; i++) {
          sprintf(eval_string, "  %f", u[i]);
          strcat(temp_string, eval_string);
        }
        sprintf(eval_string, "]");
        strcat(temp_string, eval_string);

        mxGetString(VARNAME, varname, sizeof(varname));

        /* assign the u value in varname_temp to varname */
        if ((strcmp(dataType, "ascii") == 0) || (strcmp(dataType, "ASCII") == 0)) {
          sprintf(eval_string, "%s = setstr( %s );", varname, temp_string);
        } else {
          sprintf(eval_string, "%s = %s;", varname, temp_string);
        }

        if (strlen(eval_string) >= 10240) {
          mexErrMsgTxt("Input vector length is too big to handle in triggered to workspace block.");
        }
        mexEvalString(eval_string);
        /* printf("%s\n", eval_string); */
        aryPoint = mexGetArray(varname, "caller");
        mexPutArray(aryPoint, "base");
#endif
        /* set flag, the Count flag setting avoid duplication of open file */
        *CountFlag = 1;
        *CountNum  = 0;
        *RowIndex  = 1;
      }
    }
  }
  if (u[numInput-1] >= trigThreshold) {
    *LastTrig = 1;
  } else {
    *LastTrig = 0;
  }
}

/*
 * mdlUpdate - computes the discrete states of the S-Function
 */

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

/*
 * mdlDerivatives - computes the derivatives of the S-Function
 */

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

/*
 * mdlTerminate - called at termination of model execution.
 */

static void mdlTerminate(SimStruct *S)
{
  char_T varname[40], eval_string[256];

  mxGetString(VARNAME, varname, sizeof(varname));
  strcat(varname, "_temp_sww");

#ifdef MATLAB_MEX_FILE
  /* make temperary space */
  sprintf(eval_string, "clear %s;", varname);
  mexEvalString(eval_string);
  /* printf("%s\n", eval_string); */
#endif
}

#ifdef  MATLAB_MEX_FILE    /* Is this file being compiled as a MEX-file? */
#include "simulink.c"      /* MEX-File interface mechanism */
#else
#include "cg_sfun.h"       /* Code generation registration function */
#endif



