Home | Developer's corner | Knowledge base | Working documents | Documentation | Tutorials | Training | How do I | Frequently asked questions | Technical support |
Workshop material, June 18-19, 2008
int main(...)
{
// tries to find openttcnd daemon on 127.0.0.1, port 5500:
int rv = otInitAdapter(0); // 127.0.0.1, 5500
if (rv) { /* report error */ }
}
include/isl/TTCN3.h: otInitAdapter()
Other way to initialize adapter:
// openttcnd is on 192.168.1.1:
otInitAdapter("192.168.1.1:5500");
// openttcnd is on 192.168.1.1, port 5600:
otInitAdapter("192.168.1.1:5600");
C:\Program Files\OpenTTCN\Tester3\etc\OpenTTCN.ini:
//change this line to change port name:
port = 5500
int otResolveInitialReferences(const char* id, const char** args);
(documentation for it is available in include\isl\TTCN3.h)
int otRegisterAdapter(const char* sessionName, const char* id);
(specified in include\tri\tri_ext.h)
otRegisterAdapter("MySessionName", "TRI");
// Adapter A:
otRegisterAdapter("MySessionName", "TRI");
// Adapter B:
otRegisterAdapter("MySessionName", "TRI:tsiP2");
otRegisterAdapter("MySessionName", "TCI_CD");
otRegisterAdapter("MySessionName", "TRI:tsiP1");
otRegisterAdapter("MySessionName", "TRI:tsiP2");
otRegisterAdapter("MySessionName", "TCI_CD");
otRegisterAdapter("MySessionName", "TRI_PA:ext_F1");
otRegisterAdapter("MySessionName", "TRI_PA:ext_F2");
Comments for:
int otRegisterAdapter(const char* sessionName, const char* id);
in C:\Program Files\OpenTTCN\SDK\include\tri\tri_ext.h
C:\Program Files\OpenTTCN\SDK\include\tri\tri.h:
TriStatus triSend (const TriComponentId* componentId, const TriPortId* tsiPortId, const TriAddress* sutAddress, const TriMessage* sendMessage);
typedef BinaryString TriAddress; typedef BinaryString TriMessage;
tri/tri.h
void triEnqueueMsg (const TriPortId* tsiPortId, const TriAddress* sutAddress, const TriComponentId* componentId, const TriMessage* receivedMessage);
void triEnqueueCall()
void triEnqueueReply()
void triEnqueueException()
(Rarely used currently.)
C:\Program Files\OpenTTCN\SDK\examples\timer
tri/tri_ext.h
otSetSAFlags(OT_SA_FLAG_VERBOSE);
tester run:
--log-encoded-as-text, -t log encoded messages in text format
--log-encoded-as-hex, -h log encoded messages in hex format
TCI-TM:
tci/tci_ext.h:
#define OT_TM_LOG_ENCODED_AS_HEX 0x00000020L #define OT_TM_LOG_ENQUEUED_EVENTS 0x00000040L ... int otSetTMFlags(unsigned long flags);
tester run:
--log-src-line-numbers, -l enable logging of source file line numbers --log-src-file-name, -f enable logging of source file name --print-stack-trace (added recently) --log-enqueued-events, -e log events that arrived to the port queue --log-mismatch-events, -m log mismatching communication statements --smart-mismatch, -M log mismatch that preceded non-pass verdict
More info: tester help more
Also in TCI-TM.
odb (debugger)
tci/tci_ext.h:
#define OT_CD_FLAG_VALIDATE_DECODED_VALUE 0x00000004L
Enabled by default.
To disable (for performance reasons): int otResetCDFlags(unsigned long flags);
In C:\Program Files\OpenTTCN\SDK\include\tci\tci_ext.h:
Set of options starting with OT_TM_LOG
(use otSetTMFlags(), otResetTMFlags() to set or reset these options)
Options need to be set before the commencement of the test campaign (i.e. before you run tciStartTestCase() or tciStartControl()).
TciTestCaseIdListType tciGetTestCases();
(specified in tci\tci.h)
(you need to call otSelectSession() beforehand to select active session)
ot start (command-line)
C:\Program Files\OpenTTCN\SDK\include\isl\TTCN3.h:
int otStartSystemServices(const char* installPath,
const char* port, int nowait,
otStatusIndicationListener listener);
cmd-line:
session create MySession
API:
C:\Program Files\OpenTTCN\SDK\include\isl\TTCN3.h:
int otCreateSession(const char* sessionName);
Callback (tci/tci.h):
void tciLog(String message);
session create dsrc importer2 load dsrc MySuite.mp
isl/TTCN3.h:
otCreateSession(); otDeleteSession(); otListSessions();
tri/tri_ext.h:
(persistent repository data is physically stored in Tester3\var directory)
persistent:
non-persistent data:
session stop
isl/TTCN3.h:
otStopAdapter()
ot stop
isl/TTCN3.h:
otStopSystemServices();
int otReportError(const char* errorReason);
(defined in isl\TTCN3.h - see comments in the header for more detail)
signature SimpleProc(
in integer p1,
out bitstring p2,
inout octetstring p3)
return integer
exception(
BS_0_1024,
RecordType,
EquivalentRecordType,
integer,
octetstring);
After the project is created:
/* for Sleep() call */
#include <windows.h>
#include <tri/tri.h>
#include <isl/TTCN3.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int status = otInitAdapter(0);
if (status)
{
printf("main(): otInitAdapter() failed.\n");
exit(status);
}
/* Register the adapter to OpenTTCN server */
status = otRegisterAdapter("simple", "TRI");
if (status)
{
printf("main(): otRegisterAdapter() failed.\n");
exit(status);
}
/* Enable printout of library diagnostic information */
otSetSAFlags(OT_SA_FLAG_VERBOSE);
printf("Init OK!\n");
/* Enter the infinite loop */
while (1) Sleep(100000);
/* Avoid compiler complaints */
return 0;
}
Build | Configuration Manager | Active solution configuration: Release
C:\Program Files\OpenTTCN\SDK
If you have another installation location, then project settings are different
Right-click on simple, then Properties, then:
Content of SA_impl.cxx:
#include <tri/tri.h>
/***************************************************************************
* Implementation of TRI interface (SA, user-provided part).
*/
TriStatus triSend
(const TriComponentId* componentId,
const TriPortId* tsiPortId,
const TriAddress* sutAddress,
const TriMessage* sendMessage)
{
return TRI_ERROR;
}
TriStatus triSAReset()
{
return TRI_OK;
}
TriStatus triExecuteTestCase
(const TriTestCaseId* testCaseId,
const TriPortIdList* tsiPortList)
{
return TRI_OK;
}
TriStatus triMap
(const TriPortId* compPortId,
const TriPortId* tsiPortId)
{
return TRI_OK;
}
TriStatus triUnmap
(const TriPortId* compPortId,
const TriPortId* tsiPortId)
{
return TRI_OK;
}
TriStatus triCall
(const TriComponentId* componentId,
const TriPortId* tsiPortId,
const TriAddress* sutAddress,
const TriSignatureId* signatureId,
const TriParameterList* parameterList)
{
return TRI_ERROR;
}
TriStatus triReply
(const TriComponentId* componentId,
const TriPortId* tsiPortId,
const TriAddress* sutAddress,
const TriSignatureId* signatureId,
const TriParameterList* parameterList,
const TriParameter* returnValue)
{
return TRI_ERROR;
}
TriStatus triRaise
(const TriComponentId* componentId,
const TriPortId* tsiPortId,
const TriAddress* sutAddress,
const TriSignatureId* signatureId,
const TriException* exception)
{
return TRI_ERROR;
}
TriStatus triSUTActionInformal
(const char* description)
{
return TRI_ERROR;
}
TriStatus triSUTActionTemplate
(const TriActionTemplate* templateValue)
{
return TRI_ERROR;
}
Content of PA_impl.cxx:
#include <tri/tri.h>
#include <isl/TTCN3.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/***************************************************************************
* Implementation of TRI interface (PA, user-provided part).
*/
TriStatus triPAReset()
{
return TRI_OK;
}
TriStatus triExternalFunction
(const TriFunctionId* functionId, /* in parameter */
TriParameterList* parameterList, /* inout parameter */
TriParameter* returnValue /* out parameter */)
{
// Example:
if (!strcmp(functionId->objectName, "MyFunct1"))
{
// implement MyFunct1
}
else if (!strcmp(functionId->objectName, "MyFunct2"))
{
// implement MyFunct2
}
// ...
else
{
otReportError("Unrecognized external function");
}
return TRI_ERROR;
}
TriStatus triStartTimer
(const TriTimerId* timerId,
TriTimerDuration timerDuration)
{
return TRI_ERROR;
}
TriStatus triStopTimer
(const TriTimerId* timerId)
{
return TRI_ERROR;
}
TriStatus triReadTimer
(const TriTimerId* timerId,
TriTimerDuration* elapsedTime)
{
return TRI_ERROR;
}
TriStatus triTimerRunning
(const TriTimerId* timerId,
unsigned char* running)
{
return TRI_ERROR;
}
Start openttcnd daemon:
ot start
Create a session named "simple":
session create simple
Add CD_impl.cxx to the project with the following content:
#include <tci/tci.h>
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <string.h>
/***************************************************************************
* Implementation of TCI interface (CD, user-provided encoding part).
*/
BinaryString tciEncode(TciValue value)
{
BinaryString result;
memset(&result, 0, sizeof(result));
return result;
}
/***************************************************************************
* Implementation of TCI interface (CD, user-provided decoding part).
*/
TciValue tciDecode(BinaryString message, TciType decHypothesis)
{
TciValue result = 0;
return result;
}
Add the following before adapter registration (main.cxx):
otSetEncoder(0, &tciEncode); otSetDecoder(0, &tciDecode);
Add the following include to main.cxx:
#include <tci/tci.h>
(Documentation for otSetEncoder() is here)
Added C:\courses\wsp6\simple\ttcn3\Main.ttcn file with the following content:
module Main
{
/*******************************************************************
* Message type definitions
*/
type integer uint8(0..255);
type integer uint16(0..65535);
type record Message
{
uint8 typeCode,
Payload payload optional
}
type record Payload
{
uint16 len,
charstring content
}
type octetstring Raw;
/*******************************************************************
* Other definitions
*/
// Address type used for UDP packets.
type record address
{
charstring host,
integer portField
}
modulepar
{
// IP address and UDP port number of the SUT.
charstring PX_SUT_IP_ADDR := "127.0.0.1";
integer PX_SUT_PORT := 7431;
}
type port PortType mixed
{
inout all;
}
type component ComponentType
{
port PortType p;
timer T_GUARD := 10.0;
var address sut_addr :=
{
host := PX_SUT_IP_ADDR,
portField := PX_SUT_PORT
};
}
type component SystemInterfaceType
{
port PortType tsiPort;
}
template Message GreetingRequest
(in template charstring phrase) :=
{
typeCode := 1,
payload :=
{
len := lengthof(phrase),
content := phrase
}
}
template Message GreetingResponse
(in template charstring phrase)
modifies GreetingRequest :=
{
typeCode := 2
}
/* the above is equivalent to the following:
{
typeCode := 2,
payload :=
{
len := lengthof(phrase),
content := phrase
}
}
*/
altstep DefaultAltstep() runs on ComponentType
{
[] any port.check
{
setverdict(fail);
stop;
}
[] T_GUARD.timeout
{
setverdict(fail);
stop;
}
}
testcase TC_R2D2_001()
runs on ComponentType
system SystemInterfaceType
{
activate(DefaultAltstep());
T_GUARD.start;
map(mtc:p, system:tsiPort);
p.send(GreetingRequest("Hello, world!")) to sut_addr;
p.receive(GreetingResponse("Hello, mankind!")) from sut_addr;
p.send(GreetingRequest("Hello, gentlemen!")) to sut_addr;
p.receive(GreetingResponse("Reformulate")) from sut_addr;
setverdict(pass);
}
}
importer3 load simple Main.ttcn
Add the following to CD_impl.cxx (in place of current tciEncode()):
/* for otReportError() */
#include <isl/TTCN3.h>
#define MAX_BUFFER_SIZE 4096
BinaryString tciEncode(TciValue value)
{
int len = 0;
BinaryString result;
TciType valType = tciGetType(value);
String typeName = tciGetName(valType);
TciTypeClassType typeClass = tciGetTypeClass(valType);
memset(&result, 0, sizeof(result));
if (typeClass == TCI_ADDRESS_TYPE)
{
len = sizeof(TciValue);
result.data = (unsigned char *) malloc(len);
memcpy(result.data, &value, len);
result.bits = len << 3;
}
else if (!strcmp(typeName, "Message"))
{
long typeCode = 0, length = 0;
unsigned char* buffer = 0;
TciValue payload = 0;
char* str = 0;
long str_len = 0;
buffer = (unsigned char *) malloc(MAX_BUFFER_SIZE);
memset(buffer, 0, MAX_BUFFER_SIZE);
len = 0;
typeCode = tciValueToLong(tciGetRecFieldValue(value, "typeCode"));
buffer[len++] = (unsigned char) typeCode;
payload = tciGetRecFieldValue(value, "payload");
/* 'payload' field is optional, so it may be omitted */
if (!tciNotPresent(payload))
{
long length = tciValueToLong(tciGetRecFieldValue(payload, "len"));
/* most significant byte first */
buffer[len++] = (unsigned char) (length >> 8);
buffer[len++] = (unsigned char) (length >> 0);
tciValueToCharstring(&str, &str_len,
tciGetRecFieldValue(payload, "content"));
memcpy(buffer + len, str, str_len);
len += str_len;
free(str);
}
result.data = buffer;
result.bits = len << 3;
}
else
{
otReportError("tciEncode(): Unrecognized value type.");
}
return result;
}
To use this code, you will need to #include "Utilities.h" to CD_impl.cxx and add files Utilities.h and Utilities.c to your Visual Studio project.
You will need to copy the code of Utilities.h and Utilities.c files referred to in the links of the previous paragraph into your Visual C++ project. Click on the links of the previous paragraph to see the content of both files. Note that these are not the same as in the examples\util directory shipped with the C SDK.
type record MyMessage
{
integer f1,
integer f2
}
with { encode "MyPropName1=MyPropValue1;MyPropName2=MyPropValue2",
variant "MyPropName4=MyPropValue4;MyPropName3=MyPropValue3" }
String tciGetTypeEncoding(TciType inst);
/* OpenTTCN Specific: MM4RV is as defined in [RM1]. */ String tciGetTypeEncodingVariant(TciType inst);
Search for "TciTypeClassType" in tci\tci.h
Replace triSend() implementation in SA_impl.cxx with the following fragment:
#include "Utilities.h"
TriStatus triSend
(const TriComponentId* componentId,
const TriPortId* tsiPortId,
const TriAddress* sutAddress,
const TriMessage* sendMessage)
{
TciValue addrValue = *((TciValue *) sutAddress->data);
unsigned long ipAddr = 0;
unsigned short portNumber = 0;
int result =
extractHostAndPortFromAddress(
&ipAddr, &portNumber, addrValue);
if (result) return TRI_ERROR;
result = sendDatagramPacket(
ipAddr,
portNumber,
(char*) sendMessage->data,
sendMessage->bits >> 3);
return (!result) ? TRI_OK : TRI_ERROR;
}
SUT implementation can be downloaded here.
Way to start SUT binary (in the zip package): start_sut.bat:
start Release\SystemUnderTest.exe 7431
Example of signature definition for procedure-based communication:
signature Signature(
in integer par1,
out bitstring par2,
MyRecordType par3,
inout OS_0_256 par4)
return integer
exception(
BS_0_1024,
RecordType);
signature ASP_Type1(
in integer par1,
in bitstring par2,
in MyRecordType par3,
in OS_0_256 par4);
template ASP_Type1 t1 :=
{
par1 := 1,
par2 := '1101'B,
par3 := { f1 := 1, f2 := 2 },
par4 := 'AF'O
}
...
p.call(t1);
TE - client, SUT - server:
call -> REQ (TE -> SUT) getreply -> RSP (TE <- SUT) catch -> ERR IND (TE <- SUT)
TE - server, SUT - client:
getcall -> REQ (TE <- SUT) reply -> RSP (TE -> SUT) raise -> ERR IND (TE -> SUT)
TriStatus triCall (const TriComponentId* componentId, const TriPortId* tsiPortId, const TriAddress* sutAddress, const TriSignatureId* signatureId, const TriParameterList* parameterList);
void triEnqueueReply (const TriPortId* tsiPortId, const TriAddress* sutAddress, const TriComponentId* componentId, const TriSignatureId* signatureId, const TriParameterList* parameterList, const TriParameter* returnValue);
void triEnqueueException (const TriPortId* tsiPortId, const TriAddress* sutAddress, const TriComponentId* componentId, const TriSignatureId* signatureId, const TriException* exception);
Message-based communication:
Procedure-based communication:
External functions:
SUT actions:
Message-based communication:
Procedure-based communication:
External functions:
It is accurately provided when decoding:
Decoding hypothesis may be accurately provided when decoding address.
Decoding hypothesis by default is not provided for the following cases:
int otSetCDFlags(unsigned long flags);
(found in tci/tci_ext.h)
otSetCDFlags(OT_CD_FLAG_MESSAGES_WITH_HYPOTHESIS |
OT_CD_FLAG_EXCEPTIONS_WITH_HYPOTHESIS);
TriParameterList pl; pl.parList = (TriParameter **) malloc(sizeof(TriParameter*) * 4); pl.length = 4; TriParameter** parList = pl.parList; parList[0] = (TriParameter*) malloc(sizeof(TriParameter)); memset(&(parList[0]->par), 0, sizeof(BinaryString)); parList[0]->mode = TRI_IN; parList[1] = (TriParameter*) malloc(sizeof(TriParameter)); memset(&(parList[1]->par), 0, sizeof(BinaryString)); /* Add code to set the value of parList[1]->par which is a BinaryString and which should contain encoding of the parameter in binary form */ parList[1]->mode = TRI_OUT; /* Do similar thing for the rest of IN parameters as we did for parList[0]. Do similar thing for the rest of INOUT, OUT parameters as we did for parList[1]. */
TriParameter rv; rv.par.data = (...) malloc(...); rv.mode = TRI_IN;
TriParameterList pl; pl.parList = (TriParameter **) malloc(sizeof(TriParameter*) * 4); pl.length = 4; TriParameter** parList = pl.parList; parList[0] = (TriParameter*) malloc(sizeof(TriParameter)); memset(&(parList[0]->par), 0, sizeof(BinaryString)); /* Add code to set the value of parList[0]->par which is a BinaryString and which should contain encoding of the parameter in binary form */ parList[0]->mode = TRI_IN; parList[1] = (TriParameter*) malloc(sizeof(TriParameter)); memset(&(parList[1]->par), 0, sizeof(BinaryString)); parList[1]->mode = TRI_OUT; /* Do similar thing for the rest of IN, INOUT parameters as we did for parList[0]. Do similar thing for the rest of OUT parameters as we did for parList[1]. */
Example C header file (My_C_Intf.h):
struct A
{
int f1;
char f2
};
int MyF(A p1, int p2);
Idea (similar to CORBA and IDL-to-C compiler):
This implies that C adapter is linked statically with the SUT C interface (same binary).
Example of generated 'stub' in TTCN-3 code:
type record A
{
c_int f1,
c_char f2
}
signature MyF(in A p1, in c_int p2) return c_int;
Signature parameters are then encoded into direct in-memory representation in the adapter (see relevant article in http://wiki.openttcn.com for more details on how to do that, 'C to TTCN-3 mapping').
Example of generated 'skeleton' on the adapter side (function parameters are already encoded into in-memory representation):
TriStatus triCall(...)
{
// Launch a new thread to make a C call:
...
}
// The following code is automatically generated by a translator
void MyNewThread(... /* same list of parameters as in triCall*/)
{
...
if (!strcmp(signatureId->objectName, "MyF"))
{
MyF(*((A *) parameterList->parList[0].data),
*((int *) parameterList->parList[1].data));
}
else if (!strcmp(signatureId->objectName, "MyF2"))
{
MyF2(...);
}
...
}
TriStatus triExternalFunction (const TriFunctionId* functionId, TriParameterList* parameterList, /* inout parameter */ TriParameter* returnValue); /* out parameter */
In TTCN-3:
external function F1(
in integer p1,
inout RecType p2,
out boolean p3)
return charstring;
function MyFunct()
{
...
var RecType v1;
var boolean v2;
var charstring v3 := F1(2 + 5, v1, v2);
// After call to F1(), v1 may and v2 should contain value assigned by the adapter.
}
BinaryString tciEncode(TciValue value)
{
TciType valType = tciGetType(value);
String typeName = tciGetName(valType);
BinaryString result;
memset(&result, 0, sizeof(BinaryString));
if (!strcmp(typeName, "T1"))
{
// Encoding of T1 value
}
else if (!strcmp(typeName, "T2"))
{
// Encoding of T2 value
}
...
else if (!strcmp(typeName, "T30"))
{
// Encoding of T30 value
}
else
{
otReportError("tciEncode(): Cannot recognize typeName");
}
return result;
}
otReportError() is defined in isl/TTCN3.h (see comments there for more details):
int otReportError(const char* errorReason);
BinaryString tciEncode(TciValue value)
{
TciType valType = tciGetType(value);
String typeVariantAttr = tciGetTypeEncodingVariant(valType);
BinaryString result;
memset(&result, 0, sizeof(BinaryString));
if (!strcmp(typeVariantAttr, "my variant attr val 1"))
{
// Encoding of value with type having 'val 1' variant attribute
}
else if (!strcmp(typeVariantAttr, "my variant attr val 2"))
{
...
}
...
else if (!strcmp(typeVariantAttr, "my variant attr val 3"))
{
...
}
else
{
otReportError("tciEncode(): Cannot recognize variant attribute");
}
return result;
}
BinaryString myTciEncode(TciValue value)
{
// Default (generic) encoder responsible for encoding of values of all types
// except T1 and MyModule.T2.
...
}
BinaryString myTciEncode2(TciValue value)
{
// This function is responsible solely for encoding of values of type T1
...
}
BinaryString myTciEncode3(TciValue value)
{
// This function is responsible solely for encoding of values of type MyModule.T2
...
}
int main()
{
...
otSetEncoder(0, &myTciEncode);
...
}
// Problem: tciGetTypeForName() calls
void F()
{
otSetEncoder(tciGetTypeForName("T1"), &myTciEncode2);
otSetEncoder(tciGetTypeForName("MyModule.T2"), &myTciEncode3);
}
// Creates MTC service TCI-CD query request as a side effect int otTMSelectSession(const char* sessionName);
In TTCN-3:
action("Please dial the number +1234567");
Callback in TRI:
TriStatus triSUTActionInformal (const char* description);
In TTCN-3:
action(myTmplRef);
Callback in TRI:
TriStatus triSUTActionTemplate (const TriActionTemplate* templateValue);
int lenInOctets = 5; BinaryString bs; memset(&bs, 0, sizeof(BinaryString)); bs.data = (unsigned char *) malloc(lenInOctets); bs.bits = lenInOctets << 3; // equivalent to lenInOctets * 8
Example of typedef with encode and variant attributes:
type RecType record
{
integer f1,
integer f2
}
with
{
encode "ENC:123",
variant "VAR:123
A:1,
B:2,
bits=3"
}
Retrieval of encode, variant attributes for typedefs:
In tci/tci.h:
/* OpenTTCN Specific: MM4RV is as defined in [RM1]. */ String tciGetTypeEncoding(TciType inst); /* OpenTTCN Specific: MM4RV is as defined in [RM1]. */ String tciGetTypeEncodingVariant(TciType inst);
Example of value with encode and variant attributes:
template RecType t1 := { f1 := 1, f2 := 2}
// with { encode "ABC", variant "DEF" }
...
p.send(t1);
-> tciEncode(t1); (invocation inside the SDK for C code)
Retrieval of encode, variant attributes for values:
In tci/tci.h:
String tciGetValueEncoding(TciValue inst); String tciGetValueEncodingVariant(TciValue inst);
Example of adapter code:
// String is defined as char*
String myEnc = tciGetTypeEncoding(tciGetTypeForName("MyTestSuiteType"));
if (!strcmp(myEnc, "MyEncodingValue"))
{
....
}
// When the function is exited, you do not need to
// deallocate memory occupied by myEnc.
TTCN-3 code:
type integer INT_16
with { variant "type=integer;length-in-bits=16;octet-order=msb-first" }
type integer INT_32
with { variant "type=integer;length-in-bits=32;octet-order=msb-first" }
type record Message
{
INT_16 f1,
INT_32 f2
}
with { variant "type=record-container" }
Conventional approach to tciEncode():
BinaryString tciEncode(TciValue value)
{
TciType valType = tciGetType(value);
String typeName = tciGetName(valType);
BinaryString result;
memset(&result, 0, sizeof(BinaryString));
if (!strcmp(typeName, "Message"))
{
// Encode field f1 using hard-coded knowledge that it is 16 bit
// Encode field f2 using hard-coded knowledge that it is 32 bit
}
else
{
otReportError("tciEncode(): Cannot recognize typeName");
}
return result;
}
Approach to tciEncode() using variant info (generic encoder):
BinaryString tciEncode(TciValue value)
{
TciType valType = tciGetType(value);
String variant = tciGetTypeEncodingVariant(TciType inst);
map<string, string> variantItems = parseVariant(variant);
BinaryString result;
memset(&result, 0, sizeof(BinaryString));
if (variantItems["type"] == "record-container")
{
// Call tciEncode() recursively for all fields of the record
// container and concatenate result of encoding into single
// result buffer.
...
}
else if (variantItems["type"] == "integer")
{
int lenInBits = stringToLong(variantItems["length-in-bits"]);
string octetOrder = variantItems["octet-order"];
if (octetOrder == "msb-first")
{
// Encode integer value into number of bits specified in lenInBits,
// most significant byte first
...
}
else if (octetOrder == "lsb-first")
{
// Encode integer value into number of bits specified in lenInBits,
// least significant byte first
...
}
}
else
{
otReportError("tciEncode(): Cannot recognize variant type");
}
return result;
}
... then you transfer ownership of the newly contained TciValue from yourself to the container
TciValue lenField = tciNewInstance(tciGetTypeForName("uint16"));
TciValue contentField = tciNewInstance(tciGetTypeForName("MyContent"));
TciValue payload = tciNewInstance(tciGetTypeForName("Payload"));
tciSetRecFieldValue(payload, "len", lenField);
tciSetRecFieldValue(payload, "content", contentField);
// The following will lead to segmentation fault:
tciSetRecFieldValue(payload, "alt_content", contentField);
More technical documentation is available at:
Full adapter example (adapter source code in C, TTCN-3 test case, example SUT) can be downloaded here.