From b7e15e0e2c1fef3a938c84d79022098f8482920a Mon Sep 17 00:00:00 2001
From: Bert Vermeulen <bert@biot.com>
Date: Fri, 13 Dec 2013 18:11:52 +0100
Subject: pdtest/runtc: Add support for Python output types.

---
 tests/runtc.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 71 insertions(+), 14 deletions(-)

(limited to 'tests/runtc.c')

diff --git a/tests/runtc.c b/tests/runtc.c
index e6266b0..902ca8e 100644
--- a/tests/runtc.c
+++ b/tests/runtc.c
@@ -123,7 +123,6 @@ void usage(char *msg)
 	if (msg)
 		fprintf(stderr, "%s\n", msg);
 
-	//while((c = getopt(argc, argv, "dP:p:o:i:O:f:S")) != -1) {
 	printf("Usage: runtc [-dPpoiOf]\n");
 	printf("  -d  Debug\n");
 	printf("  -P  <protocol decoder>\n");
@@ -136,16 +135,65 @@ void usage(char *msg)
 
 }
 
-static void srd_cb_bin(struct srd_proto_data *pdata, void *cb_data)
+/* This is a neutered version of libsigrokdecode's py_str_as_str(). It
+ * does no error checking, but then the only strings it processes are
+ * generated by Python's repr(), so are known good. */
+char *py_str_as_str(const PyObject *py_str)
+{
+	PyObject *py_encstr;
+	char *str, *outstr;
+
+	py_encstr = PyUnicode_AsEncodedString((PyObject *)py_str, "utf-8", NULL);
+	str = PyBytes_AS_STRING(py_encstr);
+	outstr = g_strdup(str);
+	Py_DecRef(py_encstr);
+
+	return outstr;
+}
+
+static void srd_cb_py(struct srd_proto_data *pdata, void *cb_data)
 {
-	struct srd_proto_data_binary *pdb;
 	struct output *op;
+	PyObject *pydata, *pyrepr;
+	GString *out;
+	char *s;
 
+	DBG("Python output from %s", pdata->pdo->di->inst_id);
 	op = cb_data;
-	if (op->type != SRD_OUTPUT_BINARY)
+	pydata = pdata->data;
+	DBG("ptr %p", pydata);
+
+	if (strcmp(pdata->pdo->di->inst_id, op->pd))
+		/* This is not the PD selected for output. */
+		return;
+
+	if (!(pyrepr = PyObject_Repr(pydata))) {
+		ERR("Invalid Python object.");
 		return;
+	}
+	s = py_str_as_str(pyrepr);
+	Py_DecRef(pyrepr);
+
+	/* Output format for testing is '<ss>-<es> <inst-id>: <repr>\n' */
+	out = g_string_sized_new(128);
+	g_string_printf(out, "%"PRIu64"-%"PRIu64" %s: %s\n",
+			pdata->start_sample, pdata->end_sample,
+			pdata->pdo->di->inst_id, s);
+	g_free(s);
+	if (write(op->outfd, out->str, out->len) == -1)
+		ERR("SRD_OUTPUT_PYTHON callback write failure!");
+	DBG("wrote '%s'", out->str);
+	g_string_free(out, TRUE);
+
+}
+
+static void srd_cb_bin(struct srd_proto_data *pdata, void *cb_data)
+{
+	struct srd_proto_data_binary *pdb;
+	struct output *op;
 
 	DBG("Binary output from %s", pdata->pdo->di->inst_id);
+	op = cb_data;
 	pdb = pdata->data;
 
 	if (strcmp(pdata->pdo->di->inst_id, op->pd))
@@ -160,7 +208,7 @@ static void srd_cb_bin(struct srd_proto_data *pdata, void *cb_data)
 		return;
 
 	if (write(op->outfd, pdb->data, pdb->size) == -1)
-		ERR("Oops!");
+		ERR("SRD_OUTPUT_BINARY callback write failure!");
 
 }
 
@@ -173,11 +221,8 @@ static void srd_cb_ann(struct srd_proto_data *pdata, void *cb_data)
 	int i;
 	char **dec_ann;
 
-	op = cb_data;
-	if (op->type != SRD_OUTPUT_ANN)
-		return;
-
 	DBG("Annotation output from %s", pdata->pdo->di->inst_id);
+	op = cb_data;
 	pda = pdata->data;
 	dec = pdata->pdo->di->decoder;
 	if (strcmp(pdata->pdo->di->inst_id, op->pd))
@@ -200,7 +245,7 @@ static void srd_cb_ann(struct srd_proto_data *pdata, void *cb_data)
 		g_string_append_printf(line, " \"%s\"", pda->ann_text[i]);
 	g_string_append(line, "\n");
 	if (write(op->outfd, line->str, line->len) == -1)
-		ERR("Oops!");
+		ERR("SRD_OUTPUT_ANN callback write failure!");
 	g_string_free(line, TRUE);
 
 }
@@ -290,6 +335,7 @@ static int run_testcase(char *infile, GSList *pdlist, struct output *op)
 	struct srd_session *sess;
 	struct srd_decoder *dec;
 	struct srd_decoder_inst *di, *prev_di;
+	srd_pd_output_callback_t cb;
 	struct pd *pd;
 	struct probe *probe;
 	struct option *option;
@@ -313,8 +359,20 @@ static int run_testcase(char *infile, GSList *pdlist, struct output *op)
 	if (srd_session_new(&sess) != SRD_OK)
 		return FALSE;
 	sr_session_datafeed_callback_add(sr_cb, sess);
-	srd_pd_output_callback_add(sess, SRD_OUTPUT_ANN, srd_cb_ann, op);
-	srd_pd_output_callback_add(sess, SRD_OUTPUT_BINARY, srd_cb_bin, op);
+	switch (op->type) {
+	case SRD_OUTPUT_ANN:
+		cb = srd_cb_ann;
+		break;
+	case SRD_OUTPUT_BINARY:
+		cb = srd_cb_bin;
+		break;
+	case SRD_OUTPUT_PYTHON:
+		cb = srd_cb_py;
+		break;
+	default:
+		return FALSE;
+	}
+	srd_pd_output_callback_add(sess, op->type, cb, op);
 
 	prev_di = NULL;
 	pd = NULL;
@@ -349,7 +407,6 @@ static int run_testcase(char *infile, GSList *pdlist, struct output *op)
 			g_hash_table_destroy(probes);
 		}
 
-
 		/* If this is not the first decoder in the list, stack it
 		 * on top of the previous one. */
 		if (prev_di) {
@@ -369,7 +426,7 @@ static int run_testcase(char *infile, GSList *pdlist, struct output *op)
 		else if (op->type == SRD_OUTPUT_BINARY)
 			l = dec->binary;
 		else
-			/* Only annotations and binary for now. */
+			/* Only annotations and binary can have a class. */
 			return FALSE;
 		idx = 0;
 		while(l) {
-- 
cgit v1.2.3-70-g09d2