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