From a65ba2429833eda44fbd286806a14cc5350d0391 Mon Sep 17 00:00:00 2001
From: Moises Silva <moy@sangoma.com>
Date: Sun, 20 Jul 2014 21:45:24 -0400
Subject: [PATCH] mod_freetdm: Added 'ftdm cas' command to read/write raw CAS
 bits

---
 libs/freetdm/mod_freetdm/mod_freetdm.c | 93 ++++++++++++++++++++++++++
 1 file changed, 93 insertions(+)

diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c
index 227d5a698f..57e11718bb 100755
--- a/libs/freetdm/mod_freetdm/mod_freetdm.c
+++ b/libs/freetdm/mod_freetdm/mod_freetdm.c
@@ -5243,6 +5243,98 @@ end:
 	return SWITCH_STATUS_SUCCESS;
 }
 
+#define CASINTS(cas) ((cas) & (1 << 3)) ? 1 : 0, \
+                     ((cas) & (1 << 2)) ? 1 : 0, \
+                     ((cas) & (1 << 1)) ? 1 : 0, \
+                     ((cas) & (1 << 0)) ? 1 : 0
+FTDM_CLI_DECLARE(ftdm_cmd_cas)
+{
+	uint32_t chan_id = 0;
+	switch_bool_t do_read = SWITCH_FALSE;
+	ftdm_channel_t *chan;
+	ftdm_iterator_t *iter = NULL;
+	ftdm_iterator_t *curr = NULL;
+	ftdm_span_t *span = NULL;
+	const char *write_bits_str = "";
+	int32_t abcd_bits = 0;
+
+	if (argc < 3) {
+		print_usage(stream, cli);
+		goto end;
+	}
+
+	if (!strcasecmp(argv[1], "read")) {
+		do_read = SWITCH_TRUE;
+		chan_id = argc > 3 ? atoi(argv[3]) : 0;
+	} else if (!strcasecmp(argv[1], "write") && argc >= 4) {
+		const char *str = NULL;
+		int mask = 0x08;
+		do_read = SWITCH_FALSE;
+		if (argc == 4) {
+			chan_id = 0;
+			write_bits_str = argv[3];
+		} else {
+			chan_id = atoi(argv[3]);
+			write_bits_str = argv[4];
+		}
+		if (strlen(write_bits_str) != 4) {
+			stream->write_function(stream, "-ERR Invalid CAS bits '%s'. CAS ABCD string must be composed of only four 1's and 0's (e.g. 1101)\n", write_bits_str);
+			goto end;
+		}
+		str = write_bits_str;
+		while (*str) {
+			if (*str == '1') {
+				abcd_bits |= mask;
+			} else if (*str != '0') {
+				stream->write_function(stream, "-ERR Invalid CAS bits '%s'. CAS ABCD string must be composed of only four 1's and 0's (e.g. 1101)\n", write_bits_str);
+				goto end;
+			}
+			str++;
+			mask = (mask >> 1);
+		}
+	} else {
+		print_usage(stream, cli);
+		goto end;
+	}
+
+	ftdm_span_find_by_name(argv[2], &span);
+	if (!span) {
+		stream->write_function(stream, "-ERR failed to find span %s\n", argv[2]);
+		goto end;
+	}
+
+	if (chan_id) {
+		if (chan_id > ftdm_span_get_chan_count(span)) {
+			stream->write_function(stream, "-ERR invalid channel\n");
+			goto end;
+		}
+		chan = ftdm_span_get_channel(span, chan_id);
+		if (do_read) {
+			ftdm_channel_command(chan, FTDM_COMMAND_GET_CAS_BITS, &abcd_bits);
+			stream->write_function(stream, "Read CAS bits from channel %d: %d%d%d%d (0x0%X)\n", chan_id, CASINTS(abcd_bits), abcd_bits);
+		} else {
+			stream->write_function(stream, "Writing 0x0%X to channel %d\n", abcd_bits, chan_id);
+		}
+	} else {
+		iter = ftdm_span_get_chan_iterator(span, NULL);
+		for (curr  = iter; curr; curr = ftdm_iterator_next(curr)) {
+			chan = ftdm_iterator_current(curr);
+			//ftdm_channel_command();
+			chan_id = ftdm_channel_get_id(chan);
+			if (do_read) {
+				ftdm_channel_command(chan, FTDM_COMMAND_GET_CAS_BITS, &abcd_bits);
+				stream->write_function(stream, "Read CAS bits from channel %d: %d%d%d%d (0x0%X)\n", chan_id, CASINTS(abcd_bits), abcd_bits);
+			} else {
+				stream->write_function(stream, "Writing 0x0%X to channel %d\n", abcd_bits, chan_id);
+			}
+		}
+		ftdm_iterator_free(iter);
+	}
+	stream->write_function(stream, "+OK\n");
+end:
+	return SWITCH_STATUS_SUCCESS;
+}
+
 SWITCH_STANDARD_API(ftdm_api_exec_usage)
 {
 	char *mycmd = NULL, *argv[10] = { 0 };
@@ -5323,6 +5415,7 @@ static ftdm_cli_entry_t ftdm_cli_options[] =
 	{ "queuesize", "<rxsize> <txsize> <span_id|span_name> [<chan_id>]", "", NULL, ftdm_cmd_queuesize, NULL },
 	{ "iostats", "enable|disable|flush|print <span_id|span_name> <chan_id>", "::[enable:disable:flush:print", NULL, ftdm_cmd_iostats, NULL },
 	{ "ioread", "<span_id|span_name> <chan_id> [num_times] [interval]", "", NULL, ftdm_cmd_ioread, NULL },
+	{ "cas", "read|write <span_id|span_name> [<chan_id>] [<write_bits>]", "::[read:write", NULL, ftdm_cmd_cas, NULL },
 
 	/* Stand-alone commands (not part of the generic ftdm API */
 	{ "ftdm_usage", "<span_id|span_name> <chan_id>", "", "Return channel call count", NULL, ftdm_api_exec_usage },