* add function to change c-bits in TRAU frame from uplink to downlink
* add function to re-encode an exploded TRAU frame into a bit-per-byte stream

diff --git a/src/trau_frame.c b/src/trau_frame.c
index 8eb2b45..9d7e517 100644
--- a/src/trau_frame.c
+++ b/src/trau_frame.c
@@ -27,7 +27,7 @@
 
 #include <openbsc/trau_frame.h>
 
-static u_int32_t get_bits(u_int8_t *bitbuf, int offset, int num)
+static u_int32_t get_bits(const u_int8_t *bitbuf, int offset, int num)
 {
 	int i;
 	u_int32_t ret = 0;
@@ -41,7 +41,7 @@
 }
 
 /* Decode according to 3.1.1 */
-static void decode_fr(struct decoded_trau_frame *fr, u_int8_t *trau_bits)
+static void decode_fr(struct decoded_trau_frame *fr, const u_int8_t *trau_bits)
 {
 	int i;
 	int d_idx = 0;
@@ -62,7 +62,7 @@
 }
 
 /* Decode according to 3.1.2 */
-static void decode_amr(struct decoded_trau_frame *fr, u_int8_t *trau_bits)
+static void decode_amr(struct decoded_trau_frame *fr, const u_int8_t *trau_bits)
 {
 	int i;
 	int d_idx = 0;
@@ -84,7 +84,7 @@
 	memcpy(fr->d_bits + d_idx, trau_bits + 305, 11);
 }
 
-int decode_trau_frame(struct decoded_trau_frame *fr, u_int8_t *trau_bits)
+int decode_trau_frame(struct decoded_trau_frame *fr, const u_int8_t *trau_bits)
 {
 	u_int8_t cbits5 = get_bits(trau_bits, 17, 5);
 
@@ -116,3 +116,117 @@
 
 	return 0;
 }
+
+const u_int8_t ft_fr_down_bits[] = { 1, 1, 1, 0, 0 };
+const u_int8_t ft_idle_down_bits[] = { 0, 1, 1, 1, 0 };
+
+/* modify an uplink TRAU frame so we can send it downlink */
+int trau_frame_up2down(struct decoded_trau_frame *fr)
+{
+	u_int8_t cbits5 = get_bits(fr->c_bits, 0, 5);
+
+	switch (cbits5) {
+	case TRAU_FT_FR_UP:
+		memcpy(fr->c_bits, ft_fr_down_bits, 5);
+		/* clear time alignment */
+		memset(fr->c_bits+5, 0, 6);
+		/* FIXME: SP / BFI in case of DTx */
+		/* C12 .. C21 are spare and coded as '1' */
+		memset(fr->c_bits+11, 0, 10);
+		break;
+	case TRAU_FT_EFR:
+		/* clear time alignment */
+		memset(fr->c_bits+5, 0, 6);
+		/* FIXME: set UFE appropriately */
+		/* FIXME: SP / BFI in case of DTx */
+		break;
+	case TRAU_FT_IDLE_UP:
+		memcpy(fr->c_bits, ft_idle_down_bits, 5);
+		/* clear time alignment */
+		memset(fr->c_bits+5, 0, 6);
+		/* FIXME: SP / BFI in case of DTx */
+		/* C12 .. C21 are spare and coded as '1' */
+		memset(fr->c_bits+11, 0, 10);
+		break;
+	case TRAU_FT_FR_DOWN:
+	case TRAU_FT_IDLE_DOWN:
+	case TRAU_FT_OM_DOWN:
+	case TRAU_FT_DATA_DOWN:
+		/* we cannot convert a downlink to a downlink frame */
+		return -EINVAL;
+		break;
+	case TRAU_FT_AMR:
+	case TRAU_FT_OM_UP:
+	case TRAU_FT_DATA_UP:
+	case TRAU_FT_D145_SYNC:
+	case TRAU_FT_EDATA:
+		fprintf(stderr, "unimplemented TRAU Frame Type 0x%02x\n", cbits5);
+		return -1;
+		break;
+	default:
+		fprintf(stderr, "unknown TRAU Frame Type 0x%02x\n", cbits5);
+		return -1;
+		break;
+	}
+
+	return 0;
+
+}
+
+static void encode_fr(u_int8_t *trau_bits, const struct decoded_trau_frame *fr)
+{
+	int i;
+	int d_idx = 0;
+
+	trau_bits[16] = 1;
+	/* C1 .. C15 */
+	memcpy(trau_bits+17, fr->c_bits+0, 15);
+	/* D1 .. D255 */
+	for (i = 32; i < 304; i+= 16) {
+		trau_bits[i] = 1;
+		memcpy(trau_bits+i+1, fr->d_bits + d_idx, 15);
+		d_idx += 15;
+	}
+	/* D256 .. D260 */
+	trau_bits[304] = 1;
+	memcpy(trau_bits + 305, fr->d_bits + d_idx, 5);
+	/* C16 .. C21 */
+	memcpy(trau_bits+310, fr->c_bits+15, 6);
+	/* T1 .. T4 */
+	memcpy(trau_bits+316, fr->t_bits+0, 4);
+}
+
+
+int encode_trau_frame(u_int8_t *trau_bits, const struct decoded_trau_frame *fr)
+{
+	u_int8_t cbits5 = get_bits(fr->c_bits, 0, 5);
+	
+	/* 16 bits of sync header */
+	memset(trau_bits, 0, 16);
+
+	switch (cbits5) {
+	case TRAU_FT_FR_UP:
+	case TRAU_FT_FR_DOWN:
+	case TRAU_FT_IDLE_UP:
+	case TRAU_FT_IDLE_DOWN:
+	case TRAU_FT_EFR:
+		encode_fr(trau_bits, fr);
+		break;
+	case TRAU_FT_AMR:
+	case TRAU_FT_OM_UP:
+	case TRAU_FT_OM_DOWN:
+	case TRAU_FT_DATA_UP:
+	case TRAU_FT_DATA_DOWN:
+	case TRAU_FT_D145_SYNC:
+	case TRAU_FT_EDATA:
+		fprintf(stderr, "unimplemented TRAU Frame Type 0x%02x\n", cbits5);
+		return -1;
+		break;
+	default:
+		fprintf(stderr, "unknown TRAU Frame Type 0x%02x\n", cbits5);
+		return -1;
+		break;
+	}
+
+	return 0;
+}