Some hints on how to use the SOAP functions in a C/C++ program. More...
In this documentation, functions are described as follows.
int MXCommon__GetModuleType(void * _, struct MXCommon__ByteArrayResponse * Response);
Two main differences can be remarked in the function prototypes:
The prefix:
soap_call_
The first three parameters of the SOAP stub:
struct soap *soap const char *soap_endpoint const char *soap_action
The C function prototype has the following syntax:
int soap_call_MXCommon__GetModuleType(struct soap *soap, const char *soap_endpoint, const char *soap_action, void *_, struct MXCommon__ByteArrayResponse *Response);
Functions to call in C/C++ are called stubs and can be found in the MSXEXXXXStub.h file.
When programming with gSOAP in C/C++ language, some rules have to be followed to avoid memory leaks, slow socket disconnections and multi-threading compliancy.
Note: Software code pieces in this chapter comes from SOAP calls sample
Opening and initializing an SOAP connection (using the gSOAP functions)
struct soap *soapContext; // IP address of the MSX-E and after the ':' is the MSX-E SOAP server port number char soap_endpoint[] = IP_ADDRESS":5555"; // Allocates and initialize a new runtime context if ((soapContext = soap_new ()) == NULL) return EXIT_FAILURE; // Initializes the SOAP context with options soap_init2 (soapContext, SOAP_IO_KEEPALIVE, SOAP_IO_KEEPALIVE); // Sets timeouts in seconds soapContext->send_timeout = 1; soapContext->recv_timeout = 1; soapContext->accept_timeout = 1;
Remark: A new runtime context is required in each new thread!
Calling the MSX-E SOAP functions
Important
See C/C++ language SOAP function prototypes to call the MSX-E SOAP functions.
for ( ; ; ) { soap_error = soap_call_MXCommon__GetModuleTemperatureValueAndStatus (soapContext, soap_endpoint, NULL, option, &tempResponse); ... // As gSOAP doesn't released automatically the memory that it allocates to // deserialize SOAP data we have to released it explicitly. // There is no need to call the function in each loop cycle, // it depends on the application, and desired performance and // available memory. soap_destroy (soapContext); soap_end (soapContext); ... }
Error management
There are 3 types of errors that can be generated by the MSX-E SOAP functions:
SOAP errors: It is the SOAP function return value. More details about the error can be obtained by using the soap_faultstring function.
soap_error = soap_call_MXCommon__GetModuleTemperatureValueAndStatus (soapContext, soap_endpoint, NULL, option, &tempResponse); if (soap_error) printf ("message: %s\n", *soap_faultstring (soapContext));
Remark: soap_faultstring has to be called just after the SOAP function call that generates the SOAP error and before the call of soap_destroy and soap_end.
The MSX-E error (iReturnValue): Returns errors that are not linux specific. The iReturnValue variable is located in the response structure. These errors are described in this documentation.
soap_error = soap_call_MXCommon__GetModuleTemperatureValueAndStatus (soapContext, soap_endpoint, NULL, option, &tempResponse); // Check for errors, if there are, stop the loop if (checkErrors (soapContext, soap_endpoint, NULL, soap_error, tempResponse.sResponse.iReturnValue, tempResponse.sResponse.syserrno)) break;
The MSX-E system error (syserrno): Returns linux specific errors. This variable has to be checked only if iReturnValue = -1 or iReturnValue <= -100. It returns the linux errno error. More details about the error can be obtained by using the soap_call_MXCommon__Strerror function.
struct MXCommon__ByteArrayResponse byteArrayResponse; memset (&byteArrayResponse, 0, sizeof (struct MXCommon__ByteArrayResponse)); soap_error = soap_call_MXCommon__GetModuleTemperatureValueAndStatus (soapContext, soap_endpoint, NULL, option, &tempResponse); if ((tempResponse.sResponse.iReturnValue == -1) || ((tempResponse.sResponse.iReturnValue <= -100) && tempResponse.sResponse.syserrno)) { soap_call_MXCommon__Strerror (soapContext, soap_endpoint, soap_action, tempResponse.sResponse.syserrno, &byteArrayResponse); // Display the system error printf ("\nSystem error: %s\n", byteArrayResponse.sArray.__ptr); }
Close the SOAP connection
Before to quit the application or when no MSX-E SOAP function calls are necessary, the SOAP connection has to be closed and the context has to be released. Call following functions in this order: soap_destroy, soap_end, soap_free.
// Release SOAP soap_destroy (soapContext); soap_end (soapContext); // Close the socket an release the SOAP context soap_free (soapContext);
Here a sample code, and it's makefile, to read the MSX-E internal temperature.
To compile it, use make IP_ADDRESS=YOUR_MSX-E_IP_ADDRESS don't forget to set the INTERFACE_COMMON_LIBRARY_DIR to point on the MSX-E Common Interface_Library directory.
Remark: Don't use blank spaces in the directories and file names.
temperature.c file
#include <unistd.h> #include <stdio.h> #include <stdbool.h> #include <string.h> #include <errno.h> #include <MXCommon.nsmap> // this file must be included only once in the project #include <assert.h> #include <sys/stat.h> #include <termios.h> //----------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------- /** kbhit for linux. @retval 0: No key pressed. @retval <>0: Key pressed. */ int kbhit (void) { struct termios oldt, newt; struct timeval tv; fd_set read_fd; int status; tcgetattr (STDIN_FILENO, &oldt); memcpy (&newt, &oldt, sizeof (newt)); newt.c_lflag &= ~(ICANON | ECHO); tcsetattr (STDIN_FILENO, TCSANOW, &newt); tv.tv_sec = 0; tv.tv_usec = 0; FD_ZERO (&read_fd); FD_SET (0, &read_fd); status = select (1, &read_fd, NULL, NULL, &tv); tcsetattr (STDIN_FILENO, TCSANOW, &oldt); if (status < 0) return 0; else return (status); } //----------------------------------------------------------------------------------------- /** getch for linux. @retval key: Key number. */ int getch (void) { struct termios oldt, newt; int ch; tcgetattr (STDIN_FILENO, &oldt); memcpy (&newt, &oldt, sizeof (newt)); newt.c_lflag &= ~(ICANON | ECHO); tcsetattr (STDIN_FILENO, TCSANOW, &newt); ch = getchar(); tcsetattr (STDIN_FILENO, TCSANOW, &oldt); return (ch); } //----------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------- /** Check if the SOAP call returns an error, display it. @param[in] soapContext : SOAP context structure. @param[in] soap_endpoint : IP and port number of the system to access. @param[in] soap_action : SOAP action required by the Web service. @param[in] soap_error: The SOAP function return value. @param[in] msxe_error: The MSX-E system return value contained in the response structure (iReturnValue). @param[in] msxe_syserrno: The MSX-E system errno value contained in the response structure (syserrno). @retval 0: No error. @retval 1: Error. */ int checkErrors (struct soap *soapContext, const char *soap_endpoint, const char *soap_action, int soap_error, int msxe_error, int msxe_syserrno) { if ((soap_error != 0) || (msxe_error != 0)) { printf ("MSX-E function response error: %d\n", msxe_error); printf ("soap error: %d ", soap_error); // In case of an SOAP error, display it if (soap_error) printf ("message: %s\n", *soap_faultstring (soapContext)); else { // It's not an SOAP error but a system error if ((msxe_error == -1) || ((msxe_error <= -100) && msxe_syserrno)) { struct MXCommon__ByteArrayResponse byteArrayResponse; memset (&byteArrayResponse, 0, sizeof (struct MXCommon__ByteArrayResponse)); // Get the system error if (soap_call_MXCommon__Strerror (soapContext, soap_endpoint, soap_action, msxe_syserrno, &byteArrayResponse)) printf ("\nsoap_call_MXCommon__Strerror error: %s\n", *soap_faultstring (soapContext)); else // Display the system error printf ("\nSystem error: %s\n", byteArrayResponse.sArray.__ptr); } } return 1; } return 0; } //----------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------- int main (void) { struct soap *soapContext; unsigned long option = 0; struct MXCommon__GetModuleTemperatureValueAndStatusResponse tempResponse; int soap_error = 0; char *tempStatus[] = {"NOT AVAILABLE", "TOO LOW", "LOW", "NOMINAL", "HIGH", "TOO HIGH"}; // IP address of the MSX-E and after the ':' is the MSX-E SOAP server port number char soap_endpoint[] = IP_ADDRESS":5555"; memset (&tempResponse, 0, sizeof (struct MXCommon__GetModuleTemperatureValueAndStatusResponse)); // Allocates and initialize a new runtime context if ((soapContext = soap_new ()) == NULL) return EXIT_FAILURE; // Initializes the SOAP context with options soap_init2 (soapContext, SOAP_IO_KEEPALIVE, SOAP_IO_KEEPALIVE); // Sets timeouts in seconds soapContext->send_timeout = 1; soapContext->recv_timeout = 1; soapContext->accept_timeout = 1; for ( ; ; ) { soap_error = soap_call_MXCommon__GetModuleTemperatureValueAndStatus (soapContext, soap_endpoint, NULL, option, &tempResponse); // Check for errors, if there are, stop the loop if (checkErrors (soapContext, soap_endpoint, NULL, soap_error, tempResponse.sResponse.iReturnValue, tempResponse.sResponse.syserrno)) break; // There is no error printf ("MSX-E Temperature: %.2lf °C status: ", tempResponse.dTemperatureValue); if (tempResponse.ulTemperatureStatus < 6) printf ("%s ", tempStatus[tempResponse.ulTemperatureStatus]); else printf ("unknown "); printf ("(ESC to quit)\n"); // As gSOAP doesn't released automatically the memory that it allocates to // deserialize SOAP data we have to released it explicitly. // There is no need to call the function in each loop cycle, // it depends on the application, and desired performance and // available memory. soap_destroy (soapContext); soap_end (soapContext); // Listen on keyboard actions if (kbhit ()) if (getch () == 27) // Check if ESC key has been used break; } // Release SOAP soap_destroy (soapContext); soap_end (soapContext); // Close the socket an release the SOAP context soap_free (soapContext); return EXIT_SUCCESS; }
Makefile
TOPDIR :=$(shell pwd) CC :=$(CROSS)$(CC) LD :=$(CROSS)ld STRIP :=$(CROSS)strip ifneq ($(INTERFACE_COMMON_LIBRARY_DIR),"") INTERFACE_COMMON_LIBRARY_DIR =$(TOPDIR)/../../Interface_Library endif # The MSX-E IP address ifneq ($(IP_ADDRESS),"") IP_ADDRESS =192.168.99.99 endif # File implementing SOAP client SOAPSOURCES := $(INTERFACE_COMMON_LIBRARY_DIR)/MSXEClient.o $(INTERFACE_COMMON_LIBRARY_DIR)/MSXEC.o $(INTERFACE_COMMON_LIBRARY_DIR)/stdsoap2.o CFLAGS += -pipe -Wall -O0 -Winline -I$(INTERFACE_COMMON_LIBRARY_DIR) -DIP_ADDRESS=\"$(IP_ADDRESS)\" TEMPERATURE_SRC := temperature.o BINS := temperature all: $(BINS) temperature: $(SOAPSOURCES) $(TEMPERATURE_SRC) $(CC) $(CFLAGS) -o $@ $^ $(STRIP) $@ clean: -rm -f $(BINS) -rm -f $(INTERFACE_COMMON_LIBRARY_DIR)/*.o -rm -f *.o