From MdsWiki
[edit] Calling MDSplus from C ProgramsJustin Burruss burruss@fusion.gat.com [edit] IntroductionThis document explains the C API to MDSplus. This guide is intended for users that are comfortable with programming in the C programming language. [edit] Header Files & LibrariesC source code that calls the MDSplus API must include the MDSplus header file Here is an example of a typical compile on an HP-UX UNIX machine: triton 114: /usr/bin/c89 -o mdsplus_example mdsplus_example.c -I/usr/local/mdsplus/include -L/usr/local/mdsplus/lib -lMdsLib [edit] DescriptorsMDSplus uses descriptors to pass around data. A descriptor is basically just a struct with the raw data and a description of that raw data. Use the int descr (int *dtype, void *data, int *dim1, ...); The DTYPE_UCHAR DTYPE_USHORT DTYPE_ULONG DTYPE_ULONGLONG DTYPE_CHAR DTYPE_SHORT DTYPE_LONG DTYPE_LONGLONG DTYPE_FLOAT DTYPE_DOUBLE DTYPE_COMPLEX DTYPE_COMPLEX_DOUBLE DTYPE_CSTRING DTYPE_EVENT_NOTIFY DTYPE_EVENT Use dim1, etc. to specify the dimensions of the data. Omit the dim argument for scalar quantities. So for example, to build a descriptor for a scalar float: int null = 0; int dtype_flt = DTYPE_FLOAT; float data; int flt_descr = descr(dtype_flt, &data, &null); To build a descriptor for a 1-dimensional signal with 1000 elements: int null = 0; int dtype_flt = DTYPE_FLOAT; float data[1000]; int sig_descr = descr(dtype_flt, data, 1000, &null); One final note on descriptors: there can be no more than 256 descriptors at any one time. This is because the descriptor numbers (the return value from the [edit] Functions[edit] Function StatusThe MDSplus functions (except for the MdsConnect function) return a status int. The status is OK if the least significant bit (LSB) is set. So to check the status, do a bitwise AND on the LSB. You may want to include the following function in your code:
/* status_ok Description: Returns 1 if OK, 0 otherwise. Status is OK if the LSB is set. Dependencies: none. */ int status_ok( int status ) { return ( (status & 1) == 1 ); } Alternatively, you could define a macro: #define status_ok(status) (((status) & 1) == 1) Note that testing the least significant bit is the same as testing to see if a number is odd or even. If the LSB is set, then the status will be an odd number. If the LSB is not set, then the status will be an even number. [edit] Function SummaryHere's a summary of the MDSplus functions:
[edit] Using MDSplus FunctionsYou can first use Since you need to know the size of the signal before you build a descriptor for it, you should first use /* get_signal_length Description: Returns the length of the specified signal if successful, -1 if not successful. Assumes the the user is already connected to the MDSplus server, and that the tree is already open. Uses the tdi intrinsic function SIZE() to get the signal length. Dependencies: stdio.h (for fprintf, sprintf) mdslib.h (for MdsValue, descr) string.h (for memset) */ int get_signal_length(const char *signal) { /* local vars */ int dtype_long = DTYPE_LONG; char buf[1024]; int size; int null = 0; int idesc = descr(&dtype_long, &size, &null); int status; /* init buffer */ memset(buf,0,sizeof(buf)); /* put SIZE() TDI function around signal name */ snprintf(buf,sizeof(buf)-1,"SIZE(%s)",signal); /* use MdsValue to get the signal length */ status = MdsValue(buf, &idesc, &null, 0); if ( !( (status & 1) == 1 ) ) { fprintf(stderr,"Unable to get length of %s.\n",signal); return -1; } /* return signal length */ return size; } So for example, if we have a signal called PRESSURE in a tree called MYTREE on a server named atlas.gat.com, we could do something like this: #include <stdio.h> #include <string.h> #include <mdslib.h> #include "myheaderfile.h" /* include status_ok() and get_signal_length() */ int main(int argc, char *argv[]) { /* local vars */ int dtype_float = DTYPE_FLOAT; int null = 0; int status; int socket; float *data; /* array of floats used for signal */ float *timebase; /* array of floats used for timebase */ int sigdesc; /* signal descriptor */ int timedesc; /* descriptor for timebase */ int size; /* length of signal */ int i, len; int shot = 100; /* just an example shot number */ /* Connect to MDSplus */ socket = MdsConnect("atlas.gat.com"); if ( socket == -1 ) { fprintf(stderr,"Error connecting to Atlas.\n"); return -1; } /* Open tree */ status = MdsOpen("MYTREE", &shot); if ( !status_ok(status) ) { fprintf(stderr,"Error opening tree for shot %l.\n",shot); return -1; } /* use get_signal_length to get size of signal */ size = get_signal_length("PRESSURE"); if ( size < 1 ) { /* error */ fprintf(stderr,"Error retrieving length of signal\n"); return -1; } /* use malloc() to allocate memory for the signal */ data = (float *)malloc(size * sizeof(float)); if ( !data ) { fprintf(stderr,"Error allocating memory for data\n"); return -1; } /* create a descriptor for this signal */ sigdesc = descr(&dtype_float, data, &size, &null); /* retrieve signal */ status = MdsValue("PRESSURE", &sigdesc, &null, &len ); if ( !status_ok(status) ) { /* error */ fprintf(stderr,"Error retrieving signal\n"); return -1; } /* use malloc() to allocate memory for the timebase */ timebase = (float *)malloc(size * sizeof(float)); if ( !timebase ) { fprintf(stderr,"Error allocating memory for timebase\n"); free( (void *)data ); return -1; } /* create a descriptor for the timebase */ timedesc = descr(&dtype_float, timebase, &size, &null); /* retrieve timebase of signal */ status = MdsValue("DIM_OF(PRESSURE)", &timedesc, &null, 0); if ( !status_ok(status) ) { /* error */ fprintf(stderr,"Error retrieving timebase\n"); free( (void *)data ); free( (void *)timebase ); return -1; } /* do whatever with the data */ /* example: print ALL the data */ for ( i = 0 ; i < size ; i++ ) printf("%i X:%f Y:%f\n", i, timebase[i], data[i]); /* free the dynamically allocated memory when done */ free( (void *)data ); free( (void *)timebase ); /* done */ return 0; } [edit] Execute TCL Commands using MdsValue()You can send TCL commands to the MDSplus server via the TDI function TCL(). Normally, output from the TCL commands executed through the TCL() function goes to stdout. Since the commands are executed on the server, your client program will not see the command output (which will end up in the server logfile). However, it is possible to provide the TCL() function with an optional output argument in order to see any output from the TCL commands executed through the function. Like any TDI expression, evaluate the TDI function TCL() using MdsValue(). The following code demonstrates how to do this. #include <stdio.h> #include <mdslib.h> /* Define a macro to check status of MDSplus functions */ #define status_ok(status) (((status) & 1) == 1) int main() { int dtype_long = DTYPE_LONG; int dtype_cstring = DTYPE_CSTRING; int status, tstat, len, shot=100, null=0, socket; int bufsize = 1024; char buf[1024]; int idesc = descr(&dtype_long, &tstat, &null); int sdesc = descr(&dtype_cstring, buf, &null, &bufsize); /* Connect to MDSplus server */ puts("Connecting to MDSplus server."); socket = MdsConnect("atlas.gat.com"); if ( socket == -1 ) { fprintf(stderr,"Error connecting to MDSplus server.\n"); return -1; } /* Open tree */ puts("Opening tree."); status = MdsOpen("MYTREE", &shot); if ( !status_ok(status) ) { fprintf(stderr,"Error opening tree for shot %l.\n",shot); return -1; } /* Demonstrate use of the TDI function TCL() to send TCL commands to the MDSplus server. */ /* First, send the TCL command to the server. */ puts("Demonstrating use of TCL() function."); status = MdsValue("TCL(\"SHOW DEF\",_output)",&idesc,&null,&len); if ( !status_ok(status) ) { fprintf(stderr,"Error with SHOW DEF command.\n"); return -1; } printf("Status of TCL(\"SHOW DEF\") = %i\n",tstat); /* If the command was successful, print its output. */ if ( status_ok(tstat) ) { status = MdsValue("_output",&sdesc,&null,&len); if ( !status_ok(status) ) { fprintf(stderr,"Error getting _output from SHOW DEF command.\n"); return -1; } printf("Output of TCL(\"SHOW DEF\") = %s\n",buf); } return 0; } [edit] Sample Code for HP-UXHere's some sample code for HP-UX. This example works at DIII-D on Hydra (which is running HP-UX 11i). It connects to Atlas, opens the EFIT01 tree for shot 107000, and prints the first 10 data points in the AMINOR signal. To run this example, copy the Makefile and the source file into a directory. Use the command Note that the MDSplus header files and libraries used by this Makefile are not in the default area, so you will most likely need to modify the Makefile to point to the right directories. Makefile CC = /usr/bin/c89 FLAGS = -I/f/mdsplus/hp/mdsplus/include -L/f/mdsplus/hp/mdsplus/lib \ -lMdsLib example: example.c $(CC) $(FLAGS) example.c -o example debug_example: example.c $(CC) $(FLAGS) -g example.c -o example clean: rm -f *~ core example Remember that makefiles require tabs (not spaces) in front of the commands. If you cut and paste the above makefile, make sure that the file has tabs, not spaces. If you have trouble with the makefile and you're sure you're using tabs (not spaces), then use the command example.c #include <stdio.h> #include <string.h> #include <mdslib.h> #define EXIT_FAILURE -1 #define status_ok(status) (((status) & 1) == 1) int get_signal_length(const char *signal) { /* local vars */ int dtype_long = DTYPE_LONG; char buf[1024]; int size; int null = 0; int idesc = descr(&dtype_long, &size, &null); int status; /* init buffer */ memset(buf,0,sizeof(buf)); /* put SIZE() TDI function around signal name */ snprintf(buf,sizeof(buf)-1,"SIZE(%s)",signal); /* use MdsValue to get the signal length */ status = MdsValue(buf, &idesc, &null, 0); if ( !status_ok(status) ) { fprintf(stderr,"Unable to get length of %s.\n",signal); return EXIT_FAILURE; } /* return signal length */ return size; } int main(int argc, char *argv[]) { /* local vars */ int dtype_float = DTYPE_FLOAT; int null = 0; int shot = 107000; int status; int socket; float *data; /* array of floats used for signal */ float *timebase; /* array of floats used for timebase */ int sigdesc; /* signal descriptor */ int timedesc; /* descriptor for timebase */ int size; /* length of signal */ int i, len; /* Connect to MDSplus */ socket = MdsConnect("atlas.gat.com"); if ( socket == -1 ) { fprintf(stderr,"Error connecting to Atlas.\n"); return EXIT_FAILURE; } /* Open tree */ status = MdsOpen("EFIT01", &shot); if ( !status_ok(status) ) { fprintf(stderr,"Error opening EFIT01 tree for shot %l.\n",shot); return EXIT_FAILURE; } /* use get_signal_length to get size of signal */ size = get_signal_length("\\AMINOR"); if ( size < 1 ) { /* error */ fprintf(stderr,"Error retrieving length of signal\n"); return EXIT_FAILURE; } /* use malloc() to allocate memory for the signal */ data = (float *)malloc(size * sizeof(float)); if ( !data ) { fprintf(stderr,"Error allocating memory for data\n"); return EXIT_FAILURE; } /* create a descriptor for this signal */ sigdesc = descr(&dtype_float, data, &size, &null); /* retrieve signal */ status = MdsValue("\\AMINOR",&sigdesc, &null, &len ); if ( !status_ok(status) ) { /* error */ fprintf(stderr,"Error retrieving signal\n"); free( (void *)data ); return EXIT_FAILURE; } /* use malloc() to allocate memory for the timebase */ timebase = (float *)malloc(size * sizeof(float)); if ( !timebase ) { fprintf(stderr,"Error allocating memory for timebase"); free( (void *)data ); return EXIT_FAILURE; } /* create a descriptor for the timebase */ timedesc = descr(&dtype_float, timebase, &size, &null); /* retrieve timebase of signal */ status = MdsValue("DIM_OF(\\AMINOR)", &timedesc, &null, 0); if ( !status_ok(status) ) { /* error */ fprintf(stderr,"Error retrieving timebase\n"); free( (void *)data ); free( (void *)timebase ); return EXIT_FAILURE; } /* do whatever with the data */ /* example: print first 10 data points */ for ( i = 0 ; i < size && i < 10 ; i++ ) printf("%i X:%f Y:%f\n", i, timebase[i], data[i]); /* free the dynamically allocated memory when done */ free( (void *)data ); free( (void *)timebase ); /* done */ return 0; } Note that it is necessary to quote the backslash character with another backslash when building the string \AMINOR. If you run into bugs while writing your own MDSplus code, try compiling with the -g option and use a debugger. |