Services
Service declarations must occur inside of the context of a TW_MAKE_THING, TW_DECLARE_SHAPE, or TW_DECLARE_TEMPLATE. A Services require the declaration of a variable char* _tw_thing_name, which these commands create.
The TW_DECLARE_SERVICE(serviceName,description,inputShape,outputType,outputShape,serviceHandler) command defines a service, where
serviceName is a char* that defines the name of this service as it will appear on the platform.
description is an optional description. You can use TW_NO_DESCRIPTION here if no description is to be provided.
inputShape is a Data Shape. The process for declaring a Data Shape is described in Macros to Create Data Shapes and Single Columns. This Data Shape describes the input parameters of this function that are provided by the platform when this service is called.
outputType is a twBaseType, as described in Macros to Create Data Shapes and Single Columns. If a function intends to return a string, for example, this value would be TW_STRING. If outputType is TW_INFOTABLE, then outputShape must be a Data Shape that defines the InfoTable that this function returns. If outputType is not TW_INFOTABLE, then this parameter must be TW_NO_RETURN_DATASHAPE.
serviceHandler is a pointer to a function that will be called when this service is executed from the platform. It must have a specific function signature in C to act as a service handler function.
An example of a service handler function is shown below. The example is a function that adds two numbers and returns the result. This code would be in your main() function:
{
TW_MAKE_THING(thingName,TW_THING_TEMPLATE_GENERIC);
TW_DECLARE_SERVICE( "AddNumbers",
"Add two numbers together",
TW_MAKE_DATASHAPE(NO_SHAPE_NAME,
TW_DS_ENTRY("a", TW_NO_DESCRIPTION ,TW_NUMBER),
TW_DS_ENTRY("b", TW_NO_DESCRIPTION ,TW_NUMBER)
),
TW_NUMBER,
TW_NO_RETURN_DATASHAPE,
addNumbersService
);
}
The function below is the service handler for the addNumbersService. It is a C function that declares the pointer to the service addNumbersService:
enum msgCodeEnum addNumbersService(const char * entityName,
const char * serviceName,
twInfoTable * params, twInfoTable ** content, void * userdata) {
double a, b, res;

TW_LOG(TW_TRACE,"addNumbersService - Function called");
if (!params || !content) {
TW_LOG(TW_ERROR,"addNumbersService - NULL params or content pointer");
return TWX_BAD_REQUEST;
}
// Get the parameters
twInfoTable_GetNumber(params, "a", 0, &a);
twInfoTable_GetNumber(params, "b", 0, &b);

// perform the calculation
res = a + b;

// Return Results
*content = twInfoTable_CreateFromNumber("result", res);
if (*content) return TWX_SUCCESS;
else return TWX_INTERNAL_SERVER_ERROR;
}
Service handlers are aware of the name of the Thing on which they are operating, entityName. This name can be used to access their property values with TW_GET_PROPERTY(). The handlers are passed an InfoTable that represents their arguments and are expected to return a pointer to an InfoTable that contains the response from the function. User data is not used by any function in EdgeThingShapes and can be assumed to be NULL.
The macro TW_DECLARE_SERVICE() calls the existing C SDK function:
int twExt_Api_RegisterService(enum entityTypeEnum entityType,
char * entityName, char * serviceName, char * serviceDescription,
twDataShape * inputs, enum BaseType outputType,
twDataShape * outputDataShape, service_cb cb, void * userdata);
The use of the macro instead of this function increases readability since this declaration involves the creation of multiple, potentially complex InfoTables.
Was this helpful?