Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
zhangtu
openairinterface5G
Commits
f9d740ee
Commit
f9d740ee
authored
Apr 10, 2016
by
Cedric Roux
Browse files
first commit of the T - review this commit, many things should
probably not be here.
parent
9185c693
Changes
21
Hide whitespace changes
Inline
Side-by-side
cmake_targets/CMakeLists.txt
View file @
f9d740ee
...
...
@@ -1484,6 +1484,13 @@ endif (${XFORMS})
set
(
CMAKE_MODULE_PATH
"
${
OPENAIR_DIR
}
/cmake_targets/tools/MODULES"
"
${
CMAKE_MODULE_PATH
}
"
)
#add the T tracer
add_boolean_option
(
T_TRACER True
"Activate the T tracer"
)
include_directories
(
"
${
OPENAIR_DIR
}
/common/utils/T"
)
add_boolean_option
(
T_USE_SHARED_MEMORY True
"Use shared memory to communicate with the T tracer"
)
set
(
T_SOURCE
${
OPENAIR_DIR
}
/common/utils/T/T.c
)
set
(
T_LIB
"-lrt"
)
# Hack on a test of asn1c version (already dirty)
add_definitions
(
-DASN1_MINIMUM_VERSION=924
)
...
...
@@ -1516,6 +1523,7 @@ add_executable(lte-softmodem
${
RTAI_SOURCE
}
${
XFORMS_SOURCE
}
${
XFORMS_SOURCE_SOFTMODEM
}
${
T_SOURCE
}
)
target_link_libraries
(
lte-softmodem
...
...
@@ -1529,6 +1537,8 @@ target_link_libraries (lte-softmodem pthread m ${CONFIG_LIBRARIES} rt crypt ${CR
target_link_libraries
(
lte-softmodem
${
LIBBOOST_LIBRARIES
}
)
target_link_libraries
(
lte-softmodem
${
LIB_LMS_LIBRARIES
}
)
target_link_libraries
(
lte-softmodem
${
T_LIB
}
)
# lte-softmodem-nos1 is both eNB and UE implementation
###################################################
add_executable
(
lte-softmodem-nos1
...
...
@@ -1552,6 +1562,7 @@ add_executable(lte-softmodem-nos1
${
RTAI_SOURCE
}
${
XFORMS_SOURCE
}
${
XFORMS_SOURCE_SOFTMODEM
}
${
T_SOURCE
}
)
target_link_libraries
(
lte-softmodem-nos1
-Wl,--start-group
...
...
@@ -1563,6 +1574,8 @@ target_link_libraries (lte-softmodem-nos1 pthread m ${CONFIG_LIBRARIES} rt crypt
target_link_libraries
(
lte-softmodem-nos1
${
LIBBOOST_LIBRARIES
}
)
target_link_libraries
(
lte-softmodem-nos1
${
LIB_LMS_LIBRARIES
}
)
target_link_libraries
(
lte-softmodem
${
T_LIB
}
)
# rrh
################################
#Note: only one RF type (USRP) is currently supported for RRH
...
...
@@ -1687,6 +1700,7 @@ add_executable(oaisim_nos1
${
HW_SOURCE
}
${
TRANSPORT_SOURCE
}
${
XFORMS_SOURCE
}
${
T_SOURCE
}
)
target_include_directories
(
oaisim_nos1 PUBLIC
${
OPENAIR_TARGETS
}
/SIMU/USER
)
target_link_libraries
(
oaisim_nos1
...
...
@@ -1700,6 +1714,7 @@ target_link_libraries (oaisim_nos1 pthread m ${CONFIG_LIBRARIES} rt crypt ${CRYP
#Force link with forms, regardless XFORMS option
target_link_libraries
(
oaisim_nos1 forms
)
target_link_libraries
(
lte-softmodem
${
T_LIB
}
)
# Unitary tests for each piece of L1: example, mbmssim is MBMS L1 simulator
#####################################
...
...
common/utils/T/T.c
0 → 100644
View file @
f9d740ee
#include "T.h"
#include <string.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <stdio.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
/* array used to activate/disactivate a log */
static
int
T_IDs
[
T_NUMBER_OF_IDS
];
int
*
T_active
=
T_IDs
;
static
int
T_socket
;
/* T_cache
* - the T macro picks up the head of freelist and marks it busy
* - the T sender thread periodically wakes up and sends what's to be sent
*/
volatile
int
_T_freelist_head
;
volatile
int
*
T_freelist_head
=
&
_T_freelist_head
;
int
T_busylist_head
;
T_cache_t
_T_cache
[
T_CACHE_SIZE
];
T_cache_t
*
T_cache
=
_T_cache
;
static
void
get_message
(
int
s
)
{
char
t
;
int
l
;
int
id
;
if
(
read
(
s
,
&
t
,
1
)
!=
1
)
abort
();
printf
(
"got mess %d
\n
"
,
t
);
switch
(
t
)
{
case
0
:
/* toggle all those IDs */
/* optimze? (too much syscalls) */
if
(
read
(
s
,
&
l
,
sizeof
(
int
))
!=
sizeof
(
int
))
abort
();
while
(
l
)
{
if
(
read
(
s
,
&
id
,
sizeof
(
int
))
!=
sizeof
(
int
))
abort
();
T_IDs
[
id
]
=
1
-
T_IDs
[
id
];
l
--
;
}
break
;
}
}
#ifndef T_USE_SHARED_MEMORY
static
void
*
T_send_thread
(
void
*
_
)
{
while
(
1
)
{
usleep
(
5000
);
__sync_synchronize
();
while
(
T_cache
[
T_busylist_head
].
busy
)
{
char
*
b
;
int
l
;
/* TODO: be sure about those memory barriers - in doubt one is
* put here too
*/
__sync_synchronize
();
b
=
T_cache
[
T_busylist_head
].
buffer
;
l
=
T_cache
[
T_busylist_head
].
length
;
while
(
l
)
{
int
done
=
write
(
T_socket
,
b
,
l
);
if
(
done
<=
0
)
{
printf
(
"%s:%d:%s: error sending to socket
\n
"
,
__FILE__
,
__LINE__
,
__FUNCTION__
);
abort
();
}
b
+=
done
;
l
-=
done
;
}
T_cache
[
T_busylist_head
].
busy
=
0
;
T_busylist_head
++
;
T_busylist_head
&=
T_CACHE_SIZE
-
1
;
}
}
return
NULL
;
}
#endif
/* T_USE_SHARED_MEMORY */
static
void
*
T_receive_thread
(
void
*
_
)
{
while
(
1
)
get_message
(
T_socket
);
return
NULL
;
}
static
void
new_thread
(
void
*
(
*
f
)(
void
*
),
void
*
data
)
{
pthread_t
t
;
pthread_attr_t
att
;
if
(
pthread_attr_init
(
&
att
))
{
fprintf
(
stderr
,
"pthread_attr_init err
\n
"
);
exit
(
1
);
}
if
(
pthread_attr_setdetachstate
(
&
att
,
PTHREAD_CREATE_DETACHED
))
{
fprintf
(
stderr
,
"pthread_attr_setdetachstate err
\n
"
);
exit
(
1
);
}
if
(
pthread_create
(
&
t
,
&
att
,
f
,
data
))
{
fprintf
(
stderr
,
"pthread_create err
\n
"
);
exit
(
1
);
}
if
(
pthread_attr_destroy
(
&
att
))
{
fprintf
(
stderr
,
"pthread_attr_destroy err
\n
"
);
exit
(
1
);
}
}
void
T_connect_to_tracer
(
char
*
addr
,
int
port
)
{
struct
sockaddr_in
a
;
int
s
;
#ifdef T_USE_SHARED_MEMORY
int
T_shm_fd
;
#endif
s
=
socket
(
AF_INET
,
SOCK_STREAM
,
0
);
if
(
s
==
-
1
)
{
perror
(
"socket"
);
exit
(
1
);
}
a
.
sin_family
=
AF_INET
;
a
.
sin_port
=
htons
(
port
);
a
.
sin_addr
.
s_addr
=
inet_addr
(
addr
);
if
(
connect
(
s
,
(
struct
sockaddr
*
)
&
a
,
sizeof
(
a
))
==
-
1
)
{
perror
(
"connect"
);
exit
(
1
);
}
/* wait for first message - initial list of active T events */
get_message
(
s
);
T_socket
=
s
;
#ifdef T_USE_SHARED_MEMORY
/* setup shared memory */
T_shm_fd
=
shm_open
(
T_SHM_FILENAME
,
O_RDWR
/*| O_SYNC*/
,
0666
);
shm_unlink
(
T_SHM_FILENAME
);
if
(
T_shm_fd
==
-
1
)
{
perror
(
T_SHM_FILENAME
);
abort
();
}
T_cache
=
mmap
(
NULL
,
T_CACHE_SIZE
*
sizeof
(
T_cache_t
),
PROT_READ
|
PROT_WRITE
,
MAP_SHARED
,
T_shm_fd
,
0
);
if
(
T_cache
==
NULL
)
{
perror
(
T_SHM_FILENAME
);
abort
();
}
close
(
T_shm_fd
);
#endif
#ifndef T_USE_SHARED_MEMORY
new_thread
(
T_send_thread
,
NULL
);
#endif
new_thread
(
T_receive_thread
,
NULL
);
}
common/utils/T/T.h
0 → 100644
View file @
f9d740ee
#ifndef _T_T_T_
#define _T_T_T_
#if T_TRACER
#include <stdint.h>
#include "T_defs.h"
/* T message IDs */
#include "T_IDs.h"
/* known type - this is where you add new types */
#define T_INT(x) int, (x)
#define T_FLOAT(x) float, (x)
#define T_BUFFER(x, len) buffer, ((T_buffer){addr:(x), length:(len)})
#define T_STRING(x) string, (x)
#define T_PRINTF(...) printf, (__VA_ARGS__)
/* for each known type a T_PUT_XX macro is defined */
#define T_PUT_int(argnum, val) \
do { \
int T_PUT_var = (val); \
T_CHECK_SIZE(sizeof(int), argnum); \
memcpy(T_LOCAL_buf + T_LOCAL_size, &T_PUT_var, sizeof(int)); \
T_LOCAL_size += sizeof(int); \
} while (0)
#define T_PUT_float(argnum, val) \
do { \
float T_PUT_var = (val); \
T_CHECK_SIZE(sizeof(float), argnum); \
memcpy(T_LOCAL_buf + T_LOCAL_size, &T_PUT_var, sizeof(float)); \
T_LOCAL_size += sizeof(float); \
} while (0)
#define T_PUT_buffer(argnum, val) \
do { \
T_buffer T_PUT_buffer_var = (val); \
T_PUT_int(argnum, T_PUT_buffer_var.length); \
T_CHECK_SIZE(T_PUT_buffer_var.length, argnum); \
memcpy(T_LOCAL_buf + T_LOCAL_size, T_PUT_buffer_var.addr, \
T_PUT_buffer_var.length); \
T_LOCAL_size += T_PUT_buffer_var.length; \
} while (0)
#define T_PUT_string(argnum, val) \
do { \
char *T_PUT_var = (val); \
int T_PUT_len = strlen(T_PUT_var) + 1; \
T_CHECK_SIZE(T_PUT_len, argnum); \
memcpy(T_LOCAL_buf + T_LOCAL_size, T_PUT_var, T_PUT_len); \
T_LOCAL_size += T_PUT_len; \
} while (0)
#define T_PUT_printf_deref(...) __VA_ARGS__
#define T_PUT_printf(argnum, x) \
do { \
int T_PUT_len = snprintf(T_LOCAL_buf + T_LOCAL_size, \
T_BUFFER_MAX - T_LOCAL_size, T_PUT_printf_deref x); \
if (T_PUT_len < 0) { \
printf("%s:%d:%s: you can't read this, or can you?", \
__FILE__, __LINE__, __FUNCTION__); \
abort(); \
} \
if (T_PUT_len >= T_BUFFER_MAX - T_LOCAL_size) { \
printf("%s:%d:%s: cannot put argument %d in T macro, not enough space" \
", consider increasing T_BUFFER_MAX (%d)\n", \
__FILE__, __LINE__, __FUNCTION__, argnum, T_BUFFER_MAX); \
abort(); \
} \
T_LOCAL_size += T_PUT_len + 1; \
} while (0)
/* structure type to detect that you pass a known type as first arg of T */
struct
T_header
;
/* to define message ID */
#define T_ID(x) ((struct T_header *)(uintptr_t)(x))
/* T macro tricks */
#define TN(...) TN_N(__VA_ARGS__,33,32,31,30,29,28,27,26,25,24,23,22,21,\
20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0)(__VA_ARGS__)
#define TN_N(n0,n1,n2,n3,n4,n5,n6,n7,n8,n9,n10,n11,n12,n13,n14,n15,n16,n17,\
n18,n19,n20,n21,n22,n23,n24,n25,n26,n27,n28,n29,n30,n31,n32,n,...) T##n
#define T(...) TN(__VA_ARGS__)
/* type used to send arbitrary buffer data */
typedef
struct
{
void
*
addr
;
int
length
;
}
T_buffer
;
extern
volatile
int
*
T_freelist_head
;
extern
T_cache_t
*
T_cache
;
/* used at header of Tn, allocates buffer */
#define T_LOCAL_DATA \
char *T_LOCAL_buf; \
int T_LOCAL_size = 0; \
int T_LOCAL_slot; \
T_LOCAL_slot = __sync_fetch_and_add(T_freelist_head, 1) \
& (T_CACHE_SIZE - 1); \
(void)__sync_fetch_and_and(T_freelist_head, T_CACHE_SIZE - 1); \
if (T_cache[T_LOCAL_slot].busy) { \
printf("%s:%d:%s: T cache is full - consider increasing its size\n", \
__FILE__, __LINE__, __FUNCTION__); \
abort(); \
} \
T_LOCAL_buf = T_cache[T_LOCAL_slot].buffer;
#define T_ACTIVE(x) T_active[(intptr_t)x]
#ifdef T_USE_SHARED_MEMORY
#define T_SEND() \
T_cache[T_LOCAL_slot].length = T_LOCAL_size; \
__sync_synchronize(); \
T_cache[T_LOCAL_slot].busy = 1; \
T_send(T_LOCAL_buf, T_LOCAL_size)
#else
/* T_USE_SHARED_MEMORY */
/* when not using shared memory, wait for send to finish */
#define T_SEND() \
T_cache[T_LOCAL_slot].length = T_LOCAL_size; \
__sync_synchronize(); \
T_cache[T_LOCAL_slot].busy = 1; \
T_send(T_LOCAL_buf, T_LOCAL_size); \
while (T_cache[T_LOCAL_slot].busy) usleep(1*1000)
#endif
/* T_USE_SHARED_MEMORY */
#define T_CHECK_SIZE(len, argnum) \
if (T_LOCAL_size + (len) > T_BUFFER_MAX) { \
printf("%s:%d:%s: cannot put argument %d in T macro, not enough space" \
", consider increasing T_BUFFER_MAX (%d)\n", \
__FILE__, __LINE__, __FUNCTION__, argnum, T_BUFFER_MAX); \
abort(); \
}
#if 0
#define T_PUT(type, var, argnum) \
do { \
if (T_LOCAL_size + sizeof(var) > T_BUFFER_MAX) { \
printf("%s:%d:%s: cannot put argument %d in T macro, not enough space" \
", consider increasing T_BUFFER_MAX (%d)\n", \
__FILE__, __LINE__, __FUNCTION__, argnum, T_BUFFER_MAX); \
abort(); \
} \
memcpy(T_LOCAL_buf + T_LOCAL_size, &var, sizeof(var)); \
T_LOCAL_size += sizeof(var); \
} while (0)
#endif
#if 0
#define T_PROCESS(x, argnum) \
do { \
T_PUT(typeof(x), x, argnum); \
} while (0)
#endif
#if 0
#define T_PROCESS(x, argnum) \
do { \
if (__builtin_types_compatible_p(typeof(x), int)) \
{ T_PUT(int, (intptr_t)(x), argnum); printf("int\n"); } \
else if (__builtin_types_compatible_p(typeof(x), short)) \
{ T_PUT(short, (intptr_t)(x), argnum); printf("short\n"); } \
else if (__builtin_types_compatible_p(typeof(x), float)) \
{ T_PUT(float, (x), argnum); printf("float\n"); } \
else if (__builtin_types_compatible_p(typeof(x), char *)) \
{ T_PUT(char *, (char *)(intptr_t)(x), argnum); printf("char *\n"); } \
else if (__builtin_types_compatible_p(typeof(x), float *)) \
{ T_PUT(float *, (float *)(intptr_t)(x), argnum); printf("float *\n"); } \
else if (__builtin_types_compatible_p(typeof(x), void *)) \
{ T_PUT(void *, (void *)(intptr_t)(x), argnum); printf("void *\n"); } \
else { \
printf("%s:%d:%s: unsupported type for argument %d in T macro\n", \
__FILE__, __LINE__, __FUNCTION__, argnum); \
abort(); \
} \
} while (0)
#endif
#define T_HEADER(x) \
do { \
if (!__builtin_types_compatible_p(typeof(x), struct T_header *)) { \
printf("%s:%d:%s: " \
"bad use of T, pass a message ID as first parameter\n", \
__FILE__, __LINE__, __FUNCTION__); \
abort(); \
} \
T_PUT_int(1, (int)(uintptr_t)(x)); \
} while (0)
#define T1(t) \
do { \
if (T_ACTIVE(t)) { \
T_LOCAL_DATA \
T_HEADER(t); \
T_SEND(); \
} \
} while (0)
#define T3(t,t0,x0) \
do { \
if (T_ACTIVE(t)) { \
T_LOCAL_DATA \
T_HEADER(t); \
T_PUT_##t0(2, x0); \
T_SEND(); \
} \
} while (0)
#define T5(t,t0,x0,t1,x1) \
do { \
if (T_ACTIVE(t)) { \
T_LOCAL_DATA \
T_HEADER(t); \
T_PUT_##t0(2, x0); \
T_PUT_##t1(3, x1); \
T_SEND(); \
} \
} while (0)
#define T7(t,t0,x0,t1,x1,t2,x2) \
do { \
if (T_ACTIVE(t)) { \
T_LOCAL_DATA \
T_HEADER(t); \
T_PUT_##t0(2, x0); \
T_PUT_##t1(3, x1); \
T_PUT_##t2(4, x2); \
T_SEND(); \
} \
} while (0)
#define T9(t,t0,x0,t1,x1,t2,x2,t3,x3) \
do { \
if (T_ACTIVE(t)) { \
T_LOCAL_DATA \
T_HEADER(t); \
T_PUT_##t0(2, x0); \
T_PUT_##t1(3, x1); \
T_PUT_##t2(4, x2); \
T_PUT_##t3(5, x3); \
T_SEND(); \
} \
} while (0)
#define T11(t,t0,x0,t1,x1,t2,x2,t3,x3,t4,x4) \
do { \
if (T_ACTIVE(t)) { \
T_LOCAL_DATA \
T_HEADER(t); \
T_PUT_##t0(2, x0); \
T_PUT_##t1(3, x1); \
T_PUT_##t2(4, x2); \
T_PUT_##t3(5, x3); \
T_PUT_##t4(6, x4); \
T_SEND(); \
} \
} while (0)
#define T13(t,t0,x0,t1,x1,t2,x2,t3,x3,t4,x4,t5,x5) \
do { \
if (T_ACTIVE(t)) { \
T_LOCAL_DATA \
T_HEADER(t); \
T_PUT_##t0(2, x0); \
T_PUT_##t1(3, x1); \
T_PUT_##t2(4, x2); \
T_PUT_##t3(5, x3); \
T_PUT_##t4(6, x4); \
T_PUT_##t5(7, x5); \
T_SEND(); \
} \
} while (0)
#define T15(t,t0,x0,t1,x1,t2,x2,t3,x3,t4,x4,t5,x5,t6,x6) \
do { \
if (T_ACTIVE(t)) { \
T_LOCAL_DATA \
T_HEADER(t); \
T_PUT_##t0(2, x0); \
T_PUT_##t1(3, x1); \
T_PUT_##t2(4, x2); \
T_PUT_##t3(5, x3); \
T_PUT_##t4(6, x4); \
T_PUT_##t5(7, x5); \
T_PUT_##t6(8, x6); \
T_SEND(); \
} \
} while (0)
#define T17(t,t0,x0,t1,x1,t2,x2,t3,x3,t4,x4,t5,x5,t6,x6,t7,x7) \
do { \
if (T_ACTIVE(t)) { \
T_LOCAL_DATA \
T_HEADER(t); \
T_PUT_##t0(2, x0); \
T_PUT_##t1(3, x1); \
T_PUT_##t2(4, x2); \
T_PUT_##t3(5, x3); \
T_PUT_##t4(6, x4); \
T_PUT_##t5(7, x5); \
T_PUT_##t6(8, x6); \
T_PUT_##t7(9, x7); \
T_SEND(); \
} \
} while (0)
#define T19(t,t0,x0,t1,x1,t2,x2,t3,x3,t4,x4,t5,x5,t6,x6,t7,x7,t8,x8) \
do { \
if (T_ACTIVE(t)) { \
T_LOCAL_DATA \
T_HEADER(t); \
T_PUT_##t0(2, x0); \
T_PUT_##t1(3, x1); \
T_PUT_##t2(4, x2); \
T_PUT_##t3(5, x3); \
T_PUT_##t4(6, x4); \
T_PUT_##t5(7, x5); \
T_PUT_##t6(8, x6); \
T_PUT_##t7(9, x7); \
T_PUT_##t8(10, x8); \
T_SEND(); \
} \
} while (0)
#define T21(t,t0,x0,t1,x1,t2,x2,t3,x3,t4,x4,t5,x5,t6,x6,t7,x7,t8,x8,t9,x9) \
do { \
if (T_ACTIVE(t)) { \
T_LOCAL_DATA \
T_HEADER(t); \
T_PUT_##t0(2, x0); \
T_PUT_##t1(3, x1); \
T_PUT_##t2(4, x2); \
T_PUT_##t3(5, x3); \
T_PUT_##t4(6, x4); \
T_PUT_##t5(7, x5); \
T_PUT_##t6(8, x6); \
T_PUT_##t7(9, x7); \
T_PUT_##t8(10, x8); \
T_PUT_##t9(11, x9); \
T_SEND(); \
} \
} while (0)
#define T23(t,t0,x0,t1,x1,t2,x2,t3,x3,t4,x4,t5,x5,t6,x6,t7,x7,t8,x8,t9,x9,t10,x10) \
do { \
if (T_ACTIVE(t)) { \
T_LOCAL_DATA \
T_HEADER(t); \
T_PUT_##t0(2, x0); \
T_PUT_##t1(3, x1); \
T_PUT_##t2(4, x2); \
T_PUT_##t3(5, x3); \
T_PUT_##t4(6, x4); \
T_PUT_##t5(7, x5); \
T_PUT_##t6(8, x6); \
T_PUT_##t7(9, x7); \
T_PUT_##t8(10, x8); \
T_PUT_##t9(11, x9); \
T_PUT_##t10(12, x10); \
T_SEND(); \
} \
} while (0)
#define T25(t,t0,x0,t1,x1,t2,x2,t3,x3,t4,x4,t5,x5,t6,x6,t7,x7,t8,x8,t9,x9,t10,x10,t11,x11) \
do { \
if (T_ACTIVE(t)) { \
T_LOCAL_DATA \
T_HEADER(t); \
T_PUT_##t0(2, x0); \
T_PUT_##t1(3, x1); \
T_PUT_##t2(4, x2); \
T_PUT_##t3(5, x3); \
T_PUT_##t4(6, x4); \
T_PUT_##t5(7, x5); \
T_PUT_##t6(8, x6); \
T_PUT_##t7(9, x7); \
T_PUT_##t8(10, x8); \
T_PUT_##t9(11, x9); \
T_PUT_##t10(12, x10); \
T_PUT_##t11(13, x11); \
T_SEND(); \
} \
} while (0)
#define T27(t,t0,x0,t1,x1,t2,x2,t3,x3,t4,x4,t5,x5,t6,x6,t7,x7,t8,x8,t9,x9,t10,x10,t11,x11,t12,x12) \
do { \
if (T_ACTIVE(t)) { \
T_LOCAL_DATA \
T_HEADER(t); \
T_PUT_##t0(2, x0); \
T_PUT_##t1(3, x1); \
T_PUT_##t2(4, x2); \
T_PUT_##t3(5, x3); \
T_PUT_##t4(6, x4); \
T_PUT_##t5(7, x5); \
T_PUT_##t6(8, x6); \
T_PUT_##t7(9, x7); \
T_PUT_##t8(10, x8); \
T_PUT_##t9(11, x9); \
T_PUT_##t10(12, x10); \
T_PUT_##t11(13, x11); \
T_PUT_##t12(14, x12); \
T_SEND(); \
} \
} while (0)
#define T29(t,t0,x0,t1,x1,t2,x2,t3,x3,t4,x4,t5,x5,t6,x6,t7,x7,t8,x8,t9,x9,t10,x10,t11,x11,t12,x12,t13,x13) \
do { \
if (T_ACTIVE(t)) { \
T_LOCAL_DATA \
T_HEADER(t); \
T_PUT_##t0(2, x0); \
T_PUT_##t1(3, x1); \
T_PUT_##t2(4, x2); \
T_PUT_##t3(5, x3); \
T_PUT_##t4(6, x4); \
T_PUT_##t5(7, x5); \
T_PUT_##t6(8, x6); \
T_PUT_##t7(9, x7); \
T_PUT_##t8(10, x8); \
T_PUT_##t9(11, x9); \
T_PUT_##t10(12, x10); \
T_PUT_##t11(13, x11); \
T_PUT_##t12(14, x12); \