From f29f3f46bcf0cba53792dc2b7beb81ee1bc144fd Mon Sep 17 00:00:00 2001
From: Reinhold Kainhofer <reinhold@kainhofer.com>
Date: Wed, 3 May 2017 23:36:57 +0200
Subject: [PATCH] Add bit-stuffing (or rather destuffing)

---
 .gitignore                 | Bin 199 -> 9383 bytes
 Vaillant_decode_bitstuff.c | 138 +++++++++++++++++++++++++++++++++++++
 2 files changed, 138 insertions(+)
 create mode 100644 Vaillant_decode_bitstuff.c

diff --git a/.gitignore b/.gitignore
index e65b455d37175fea3a23b738210eb01d59537980..2b887021851aeec6774761e894d1304d4dd90cb7 100644
GIT binary patch
literal 9383
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

delta 6
NcmZ4Pd7N>=aR3Tq0}ucJ

diff --git a/Vaillant_decode_bitstuff.c b/Vaillant_decode_bitstuff.c
new file mode 100644
index 0000000..321a89e
--- /dev/null
+++ b/Vaillant_decode_bitstuff.c
@@ -0,0 +1,138 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/time.h>
+#include <math.h>
+
+// Vaillant_decode_bitstuff.c Copyright 2017 Reinhold Kainhofer
+// License: GNU GPL 3.0
+// 
+//
+// Compile with:
+//     gcc Vaillant_decode_bitstuff.c -o Vaillant_decode_bitstuff
+// 
+// Reads a string of 0 and 1 from STDIN, tries to decode it as Vaillant-encoded
+// applies bit-unstaffing (i.e. if 5 consecutive one bits are followed by a 
+// zero bit, the zero bit is discarded and prints the converted result to 
+// STDOUT (prefixed with current date/time).
+// Decoding errors (i.e. no amplitude switch at the pulse mid-point) are
+// indicated by a ?
+//
+// This app is purely pipe-through, i.e. its usage is:
+//
+//     cat signalfile.txt | Vaillant_decode_bitstuff > decoded_signalfile.txt
+//
+// To process an output file while it is still written to, you can use tail. This 
+// will print the proper timestamps for the signals:
+//
+//     tail -n +1 -f signalfile.txt | ./Vaillant_decode_bitstuff
+
+typedef int bool;
+#define true 1
+#define false 0
+
+void main(int argc, char *argv[])
+{
+	setbuf(stdout, NULL);
+
+	bool insideZeroes = true;
+	int zeroes = 0;
+	
+	int ones = 0; // Count the number of consecutive ones in the output (for bit-unstuffing)
+	int pos = 0;  // Current output count in octet (to space bytes)
+	
+	int validPos = 0;
+	int comment = 0;
+
+	char ch, prev;
+	while(read(STDIN_FILENO, &ch, 1) > 0) {
+		// Everything starting with # is a comment until the end of line
+		if (ch == '#') {
+			comment = true;
+			if (!insideZeroes) printf("\n");
+			insideZeroes = 1;
+			continue;
+		}
+		// Ignore all line breaks and spaces (so output can be formatted before running through this app):
+		if (ch == '\n' || ch == '\r') {
+			comment = false;
+			continue;
+		}
+		// Ignore all spaces (so output can be formatted before running through this app) and comments:
+		if (comment || ch == ' ') {
+			continue;
+		}
+
+		// Keep track of how many zeroes we have (count at most up to 1000!)
+		if (ch == '0') {
+			if (zeroes++ > 1000) zeroes = 1000;
+		} else {
+			zeroes = 0;
+		}
+		// We have zeroes, so jump to the next char if we have another 0, reset otherwise
+		if (insideZeroes) {
+			if (ch == '0') {
+				prev = ch;
+				continue;
+			} else {
+				insideZeroes = false;
+				validPos = 0;
+				// A '1' after a long sequence of '0' means some kind of signal
+				// (valid or invalid), so print the current date/time to start
+				// a new line:
+				struct timeval  tv;
+				gettimeofday(&tv, NULL);
+				int millisec = tv.tv_usec/1000;
+
+				char fmt[64], s[64];
+				struct tm       *tm;
+				if((tm = localtime(&tv.tv_sec)) != NULL) {
+					strftime(fmt, sizeof fmt, "%F %T", tm);
+					snprintf(s, sizeof s, "%s.%03d", fmt, millisec);
+					printf("%s  ", s); 
+				}
+			}
+		}
+		if (ch != '0' && ch != '1') {
+			fwrite(&ch, 1, 1, stdout);
+		}
+		
+		// Inside the pulse => if state changed, it's a 1, if it stayed, it's a 0
+		if (validPos == 1) {
+			// bit-unstuffing: Ignore a 0 after exactly five consecutive 1 bits:
+			if (ch != prev) { // a transition indicates a one
+				ones++;
+				printf("1");
+				pos++;
+			} else { // no transition indicates a zero
+				if (ones!=5) {
+					printf("0");
+					pos++;
+				}
+				ones = 0;
+			}
+		} else { // validPos == 0
+			// If 0/1 does not change => INVALID, unless it stays 0, which indicates end of signal
+			if (ch == prev) {
+				if (ch == '0') {
+					insideZeroes = true;
+					zeroes = true;
+					printf("\n");
+					pos = 0;
+				} else {
+					printf("?");
+					pos++;
+				}
+			}
+		}
+		if (pos == 8) { // A full byte was printed, so add a space
+			pos = 0;
+			printf(" ");
+		}
+		// Switch validPos:
+		validPos = (validPos + 1) % 2;
+		prev = ch;
+	}
+	printf("\r\n");
+}
-- 
GitLab