changeset 49:40f781efdbe1

ater: beginning of D144 mode
author Mychaela Falconia <falcon@freecalypso.org>
date Tue, 24 Sep 2024 05:59:28 +0000
parents 3cc26391d24d
children 6ba4de500532
files ater/activate.c ater/dbits.c ater/submux.h ater/tx_func.c
diffstat 4 files changed, 135 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/ater/activate.c	Fri Sep 13 01:03:43 2024 +0000
+++ b/ater/activate.c	Tue Sep 24 05:59:28 2024 +0000
@@ -66,6 +66,7 @@
 	/* good to proceed now */
 	at->is_active = true;
 	at->is_data = false;
+	at->is_data_144 = false;
 	at->is_efr = is_efr;
 	init_trau_ul_frame(nr);
 	at->ul_frame.c_bits[16] = dtxd;
@@ -76,21 +77,26 @@
 void cmd_activate_csd(int argc, char **argv)
 {
 	int nr;
-	bool ir_16k, is_hr;
+	bool ir_16k, is_144, is_hr;
 	struct ater_subslot *at;
 
 	if (argc < 3 || argc > 4) {
-usage:		fprintf(stderr, "usage: %s 0|1|2|3 8|16 [hr]\n", argv[0]);
+usage:		fprintf(stderr, "usage: %s 0|1|2|3 8|16|14.4 [hr]\n", argv[0]);
 		return;
 	}
 	if (argv[1][0] < '0' || argv[1][0] > '3' || argv[1][1])
 		goto usage;
 	nr = argv[1][0] - '0';
-	if (!strcmp(argv[2], "8"))
+	if (!strcmp(argv[2], "8")) {
+		is_144 = false;
 		ir_16k = false;
-	else if (!strcmp(argv[2], "16"))
+	} else if (!strcmp(argv[2], "16")) {
+		is_144 = false;
 		ir_16k = true;
-	else
+	} else if (!strcmp(argv[2], "14.4")) {
+		is_144 = true;
+		ir_16k = true;
+	} else
 		goto usage;
 	if (argv[3]) {
 		if (strcmp(argv[3], "hr"))
@@ -98,6 +104,10 @@
 		is_hr = true;
 	} else
 		is_hr = false;
+	if (is_hr && (is_144 || ir_16k)) {
+		fprintf(stderr, "error: HR above 8 kbit/s is impossible\n");
+		return;
+	}
 
 	at = &subslots[nr];
 	if (at->is_active) {
@@ -108,7 +118,9 @@
 	/* good to proceed now */
 	at->is_active = true;
 	at->is_data = true;
+	at->is_data_144 = is_144;
 	at->is_hr_data = is_hr;
+	at->d144_edata = false;
 	init_trau_ul_frame_csd(nr, ir_16k);
 }
 
--- a/ater/dbits.c	Fri Sep 13 01:03:43 2024 +0000
+++ b/ater/dbits.c	Tue Sep 24 05:59:28 2024 +0000
@@ -41,6 +41,10 @@
 		fprintf(stderr, "error: subslot %d is not in data mode\n", nr);
 		return;
 	}
+	if (at->is_data_144) {
+		fprintf(stderr, "error: subslot %d is in D144 mode\n", nr);
+		return;
+	}
 	fr = &at->ul_frame;
 	d_offset = atoi(argv[2]);
 	if (d_offset >= 252) {
--- a/ater/submux.h	Fri Sep 13 01:03:43 2024 +0000
+++ b/ater/submux.h	Tue Sep 24 05:59:28 2024 +0000
@@ -22,6 +22,8 @@
 	bool is_data;
 	bool is_hr_data;
 	bool is_efr;
+	bool is_data_144;
+	bool d144_edata;
 	struct osmo_trau_frame ul_frame;
 	unsigned mfrm_count;
 	uint8_t *play_buffer;
--- a/ater/tx_func.c	Fri Sep 13 01:03:43 2024 +0000
+++ b/ater/tx_func.c	Tue Sep 24 05:59:28 2024 +0000
@@ -18,6 +18,100 @@
 #include "submux.h"
 #include "out_frame.h"
 
+/*
+ * The following hard-coded frame is based on TS 48.060 section 5.3.1.
+ * 0-based octet numbers in the comments are as in the spec.
+ */
+static const ubit_t d144_sync_frame[320] = {
+	0, 0, 0, 0, 0, 0, 0, 0,		/* octet 0 */
+	0, 0, 0, 0, 0, 0, 0, 0,		/* octet 1 */
+	1, 1, 0, 1, 0, 0, 1, 1,		/* octet 2 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 3 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 4 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 5 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 6 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 7 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 8 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 9 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 10 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 11 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 12 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 13 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 14 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 15 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 16 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 17 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 18 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 19 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 20 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 21 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 22 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 23 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 24 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 25 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 26 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 27 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 28 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 29 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 30 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 31 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 32 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 33 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 34 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 35 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 36 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 37 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 38 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 39 */
+};
+
+/*
+ * The following hard-coded frame is based on TS 48.060 section 5.3.2.
+ * 0-based octet numbers in the comments are as in the spec.
+ */
+static const ubit_t d144_idle_edata[320] = {
+	0, 0, 0, 0, 0, 0, 0, 0,		/* octet 0 */
+	0, 0, 0, 0, 0, 0, 0, 0,		/* octet 1 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 2 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 3 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 4 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 5 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 6 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 7 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 8 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 9 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 10 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 11 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 12 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 13 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 14 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 15 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 16 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 17 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 18 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 19 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 20 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 21 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 22 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 23 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 24 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 25 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 26 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 27 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 28 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 29 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 30 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 31 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 32 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 33 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 34 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 35 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 36 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 37 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 38 */
+	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 39 */
+};
+
 void init_trau_ul_frame(int nr)
 {
 	struct ater_subslot *at = &subslots[nr];
@@ -42,6 +136,20 @@
 	memset(fr->d_bits, 1, 63 * 4);
 }
 
+static void handle_d144(int nr)
+{
+	struct ater_subslot *at = &subslots[nr];
+	struct msgb *msg;
+
+	msg = msgb_alloc_c(g_ctx, 320, "TRAU-UL-frame");
+	if (!msg)
+		return;
+	memcpy(msg->tail, at->d144_edata ? d144_idle_edata : d144_sync_frame,
+		320);
+	msgb_put(msg, 320);
+	osmo_i460_mux_enqueue(at->schan, msg);
+}
+
 static void handle_play(struct ater_subslot *at)
 {
 	if (at->play_wait_align) {
@@ -68,6 +176,10 @@
 
 	if (!at->is_active)
 		return;
+	if (at->is_data_144) {
+		handle_d144(nr);
+		return;
+	}
 	if (at->play_buffer)
 		handle_play(at);
 	if (!at->is_data) {