Редизайн на основе текущей ветки мейнстрима + новые устройства.
[rtl-433.git] / src / pulse_demod.c
diff --git a/src/pulse_demod.c b/src/pulse_demod.c
new file mode 100755 (executable)
index 0000000..3935ce7
--- /dev/null
@@ -0,0 +1,403 @@
+/**
+ * Pulse demodulation functions
+ * 
+ * Binary demodulators (PWM/PPM/Manchester/...) using a pulse data structure as input
+ *
+ * Copyright (C) 2015 Tommy Vestermark
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include "pulse_demod.h"
+#include "bitbuffer.h"
+#include "util.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+
+int pulse_demod_pcm(const pulse_data_t *pulses, struct protocol_state *device)
+{
+       int events = 0;
+       bitbuffer_t bits = {0};
+       const int MAX_ZEROS = device->reset_limit / device->long_limit;
+       const int TOLERANCE = device->long_limit / 4;           // Tolerance is ±25% of a bit period
+
+       for(unsigned n = 0; n < pulses->num_pulses; ++n) {
+               // Determine number of high bit periods for NRZ coding, where bits may not be separated
+               int highs = (pulses->pulse[n] + device->short_limit/2) / device->short_limit;
+               // Determine number of bit periods in current pulse/gap length (rounded)
+               int periods = (pulses->pulse[n] + pulses->gap[n] + device->long_limit/2) / device->long_limit;
+
+               // Add run of ones (1 for RZ, many for NRZ)
+               for (int i=0; i < highs; ++i) {
+                       bitbuffer_add_bit(&bits, 1);
+               }
+               // Add run of zeros
+               periods -= highs;                                       // Remove 1s from whole period
+               periods = min(periods, MAX_ZEROS);      // Dont overflow at end of message
+               for (int i=0; i < periods; ++i) {
+                       bitbuffer_add_bit(&bits, 0);
+               }
+
+               // Validate data
+               if ((device->short_limit != device->long_limit)                 // Only for RZ coding
+                && (fabsf(pulses->pulse[n] - device->short_limit) > TOLERANCE)         // Pulse must be within tolerance
+               ) {
+                       // Data is corrupt
+                       if (debug_output > 3) {
+                               fprintf(stderr,"bitbuffer cleared at %d: pulse %d, gap %d, period %d\n",
+                                       n,pulses->pulse[n],pulses->gap[n],
+                                       pulses->pulse[n] + pulses->gap[n]);
+                       }
+                       bitbuffer_clear(&bits);
+               }
+
+               // End of Message?
+               if (((n == pulses->num_pulses-1)        // No more pulses? (FSK)
+                || (pulses->gap[n] > device->reset_limit))     // Loong silence (OOK)
+                && (bits.bits_per_row[0] > 0)          // Only if data has been accumulated
+               ) {
+                       if (device->callback) {
+                               events += device->callback(&bits);
+                       }
+                       // Debug printout
+                       if(!device->callback || (debug_output && events > 0)) {
+                               fprintf(stderr, "pulse_demod_pcm(): %s \n", device->name);
+                               bitbuffer_print(&bits);
+                       }
+                       bitbuffer_clear(&bits);
+               }
+       } // for
+       return events;
+}
+
+
+int pulse_demod_ppm(const pulse_data_t *pulses, struct protocol_state *device) {
+       int events = 0;
+       bitbuffer_t bits = {0};
+
+       for(unsigned n = 0; n < pulses->num_pulses; ++n) {
+               // Short gap
+               if(pulses->gap[n] < device->short_limit) {
+                       bitbuffer_add_bit(&bits, 0);
+               // Long gap
+               } else if(pulses->gap[n] < device->long_limit) {
+                       bitbuffer_add_bit(&bits, 1);
+               // Check for new packet in multipacket
+               } else if(pulses->gap[n] < device->reset_limit) {
+                       bitbuffer_add_row(&bits);
+               // End of Message?
+               } else {
+                       if (device->callback) {
+                               events += device->callback(&bits);
+                       }
+                       // Debug printout
+                       if(!device->callback || (debug_output && events > 0)) {
+                               fprintf(stderr, "pulse_demod_ppm(): %s \n", device->name);
+                               bitbuffer_print(&bits);
+                       }
+                       bitbuffer_clear(&bits);
+               }
+       } // for pulses
+       return events;
+}
+
+
+int pulse_demod_pwm(const pulse_data_t *pulses, struct protocol_state *device) {
+       int events = 0;
+       int start_bit_detected = 0;
+       bitbuffer_t bits = {0};
+       int start_bit = device->demod_arg;
+
+       for(unsigned n = 0; n < pulses->num_pulses; ++n) {
+               // Should we disregard startbit?
+               if(start_bit == 1 && start_bit_detected == 0) { 
+                       start_bit_detected = 1;
+               } else {
+                       // Detect pulse width
+                       if(pulses->pulse[n] <= device->short_limit) {
+                               bitbuffer_add_bit(&bits, 1);
+                       } else {
+                               bitbuffer_add_bit(&bits, 0);
+                       }
+               }
+               // End of Message?
+                if (n == pulses->num_pulses - 1                           // No more pulses (FSK)
+                   || pulses->gap[n] > device->reset_limit) {  // Long silence (OOK)
+                       if (device->callback) {
+                               events += device->callback(&bits);
+                       }
+                       // Debug printout
+                       if(!device->callback || (debug_output && events > 0)) {
+                               fprintf(stderr, "pulse_demod_pwm(): %s\n", device->name);
+                               bitbuffer_print(&bits);
+                       }
+                       bitbuffer_clear(&bits);
+                       start_bit_detected = 0;
+               // Check for new packet in multipacket
+               } else if(pulses->gap[n] > device->long_limit) {
+                       bitbuffer_add_row(&bits);
+                       start_bit_detected = 0;
+               }
+       }
+       return events;
+}
+
+
+int pulse_demod_pwm_precise(const pulse_data_t *pulses, struct protocol_state *device)
+{
+       int events = 0;
+       bitbuffer_t bits = {0};
+       PWM_Precise_Parameters *p = (PWM_Precise_Parameters *)device->demod_arg;
+
+       for(unsigned n = 0; n < pulses->num_pulses; ++n) {
+               // 'Short' 1 pulse
+               if (fabsf(pulses->pulse[n] - device->short_limit) < p->pulse_tolerance) {
+                       bitbuffer_add_bit(&bits, 1);
+               // 'Long' 0 pulse
+               } else if (fabsf(pulses->pulse[n] - device->long_limit) < p->pulse_tolerance) {
+                       bitbuffer_add_bit(&bits, 0);
+               // Sync pulse
+               } else if (p->pulse_sync_width && (fabsf(pulses->pulse[n] - p->pulse_sync_width) < p->pulse_tolerance)) {
+                       bitbuffer_add_row(&bits);
+               // Ignore spurious short pulses
+               } else if (pulses->pulse[n] < (device->short_limit - p->pulse_tolerance)) {
+                       // Do nothing
+               } else {
+                       return 0;       // Pulse outside specified timing
+               }
+
+               // End of Message?
+               if(pulses->gap[n] > device->reset_limit) {
+                       if (device->callback) {
+                               events += device->callback(&bits);
+                       }
+                       // Debug printout
+                       if(!device->callback || (debug_output && events > 0)) {
+                               fprintf(stderr, "pulse_demod_pwm_precise(): %s \n", device->name);
+                               bitbuffer_print(&bits);
+                       }
+                       bitbuffer_clear(&bits);
+               }
+       } // for
+       return events;
+}
+
+
+int pulse_demod_pwm_ternary(const pulse_data_t *pulses, struct protocol_state *device)
+{
+       int events = 0;
+       bitbuffer_t bits = {0};
+       unsigned sync_bit = device->demod_arg;
+
+       for(unsigned n = 0; n < pulses->num_pulses; ++n) {
+               // Short pulse
+               if (pulses->pulse[n] < device->short_limit) {
+                       if (sync_bit == 0) {
+                               bitbuffer_add_row(&bits);
+                       } else {
+                               bitbuffer_add_bit(&bits, 0);
+                       }
+               // Middle pulse
+               } else if (pulses->pulse[n] < device->long_limit) {
+                       if (sync_bit == 0) {
+                               bitbuffer_add_bit(&bits, 0);
+                       } else if (sync_bit == 1) {
+                               bitbuffer_add_row(&bits);
+                       } else {
+                               bitbuffer_add_bit(&bits, 1);
+                       }
+               // Long pulse
+               } else {
+                       if (sync_bit == 2) {
+                               bitbuffer_add_row(&bits);
+                       } else {
+                               bitbuffer_add_bit(&bits, 1);
+                       }
+               } 
+
+               // End of Message?
+               if(pulses->gap[n] > device->reset_limit) {
+                       if (device->callback) {
+                               events += device->callback(&bits);
+                       }
+                       // Debug printout
+                       if(!device->callback || (debug_output && events > 0)) {
+                               fprintf(stderr, "pulse_demod_pwm_ternary(): %s \n", device->name);
+                               bitbuffer_print(&bits);
+                       }
+                       bitbuffer_clear(&bits);
+               }
+       } // for
+       return events;
+}
+
+
+int pulse_demod_manchester_zerobit(const pulse_data_t *pulses, struct protocol_state *device) {
+       int events = 0;
+       int time_since_last = 0;
+       bitbuffer_t bits = {0};
+
+       // First rising edge is allways counted as a zero (Seems to be hardcoded policy for the Oregon Scientific sensors...)
+       bitbuffer_add_bit(&bits, 0);
+
+       for(unsigned n = 0; n < pulses->num_pulses; ++n) {
+               // Falling edge is on end of pulse
+               if(pulses->pulse[n] + time_since_last > (device->short_limit * 1.5)) {
+                       // Last bit was recorded more than short_limit*1.5 samples ago 
+                       // so this pulse start must be a data edge (falling data edge means bit = 1) 
+                       bitbuffer_add_bit(&bits, 1);
+                       time_since_last = 0;
+               } else {
+                       time_since_last += pulses->pulse[n];
+               }
+
+               // End of Message?
+               if(pulses->gap[n] > device->reset_limit) {
+                       int newevents = 0;
+                       if (device->callback) {
+                               events += device->callback(&bits);
+                       }
+                       // Debug printout
+                       if(!device->callback || (debug_output && events > 0)) {
+                               fprintf(stderr, "pulse_demod_manchester_zerobit(): %s \n", device->name);
+                               bitbuffer_print(&bits);
+                       }
+                       bitbuffer_clear(&bits);
+                       bitbuffer_add_bit(&bits, 0);            // Prepare for new message with hardcoded 0
+                       time_since_last = 0;
+               // Rising edge is on end of gap
+               } else if(pulses->gap[n] + time_since_last > (device->short_limit * 1.5)) {
+                       // Last bit was recorded more than short_limit*1.5 samples ago 
+                       // so this pulse end is a data edge (rising data edge means bit = 0) 
+                       bitbuffer_add_bit(&bits, 0);
+                       time_since_last = 0;
+               } else {
+                       time_since_last += pulses->gap[n];
+               }
+       }
+       return events;
+}
+
+int pulse_demod_clock_bits(const pulse_data_t *pulses, struct protocol_state *device) {
+   int symbol[PD_MAX_PULSES * 2];
+   unsigned int n;
+
+   PWM_Precise_Parameters *p = (PWM_Precise_Parameters *)device->demod_arg;
+   bitbuffer_t bits = {0};
+   int events = 0;
+
+   for(n = 0; n < pulses->num_pulses; n++) {
+      symbol[n*2] = pulses->pulse[n];
+      symbol[(n*2)+1] = pulses->gap[n];
+   }
+
+   for(n = 0; n < pulses->num_pulses * 2; ++n) {
+      if ( fabsf(symbol[n] - device->short_limit) < p->pulse_tolerance) {
+         // Short - 1
+         bitbuffer_add_bit(&bits, 1);
+         if ( fabsf(symbol[++n] - device->short_limit) > p->pulse_tolerance) {
+            if (symbol[n] >= device->reset_limit - p->pulse_tolerance ) {
+               // Don't expect another short gap at end of message
+               n--;
+            } else {
+/*
+               fprintf(stderr, "Detected error during pulse_demod_clock_bits(): %s\n",
+                       device->name);
+*/
+               return events;
+            }
+         }
+      } else if ( fabsf(symbol[n] - device->long_limit) < p->pulse_tolerance) {
+         // Long - 0
+         bitbuffer_add_bit(&bits, 0);
+      } else if (symbol[n] >= device->reset_limit - p->pulse_tolerance ) {
+         //END message ?
+         if (device->callback) {
+            events += device->callback(&bits);
+         }
+         if(!device->callback || (debug_output && events > 0)) {
+            fprintf(stderr, "pulse_demod_clock_bits(): %s \n", device->name);
+            bitbuffer_print(&bits);
+         }
+         bitbuffer_clear(&bits);
+      }
+   }
+
+   return events;
+}
+
+/*
+ * Oregon Scientific V1 Protocol
+ * Starts with a clean preamble of 12 pulses with
+ * consistent timing followed by an out of time Sync pulse.
+ * Data then follows with manchester encoding, but
+ * care must be taken with the gap after the sync pulse since it
+ * is outside of the normal clocking.  Because of this a data stream
+ * beginning with a 0 will have data in this gap.
+ * This code looks at pulse and gap width and clocks bits
+ * in from this.  Since this is manchester encoded every other
+ * bit is discarded.
+ */
+
+int pulse_demod_osv1(const pulse_data_t *pulses, struct protocol_state *device) {
+       unsigned int n;
+       int preamble = 0;
+       int events = 0;
+       int manbit = 0;
+       bitbuffer_t bits = {0};
+
+       /* preamble */
+       for(n = 0; n < pulses->num_pulses; ++n) {
+               if(pulses->pulse[n] >= 350 && pulses->gap[n] >= 200) {
+                       preamble++;
+                       if(pulses->gap[n] >= 400)
+                               break;
+               } else
+                       return(events);
+       }
+       if(preamble != 12) {
+               if(debug_output) fprintf(stderr, "preamble %d  %d %d\n", preamble, pulses->pulse[0], pulses->gap[0]);
+               return(events);
+       }
+
+       /* sync */
+       ++n;
+       if(pulses->pulse[n] < 1000 || pulses->gap[n] < 1000) {
+               return(events);
+       }
+
+       /* data bits - manchester encoding */
+       
+       /* sync gap could be part of data when the first bit is 0 */
+       if(pulses->gap[n] > pulses->pulse[n]) {
+               manbit ^= 1;
+               if(manbit) bitbuffer_add_bit(&bits, 0);
+       }
+
+       /* remaining data bits */
+       for(n++; n < pulses->num_pulses; ++n) {
+               manbit ^= 1;
+               if(manbit) bitbuffer_add_bit(&bits, 1);
+               if(pulses->pulse[n] > 615) {
+                       manbit ^= 1;
+                       if(manbit) bitbuffer_add_bit(&bits, 1);
+               }
+               if (n == pulses->num_pulses - 1 || pulses->gap[n] > device->reset_limit) {
+                       if((bits.bits_per_row[bits.num_rows-1] == 32) && device->callback) {
+                               events += device->callback(&bits);
+                       }
+                       return(events);
+               }
+               manbit ^= 1;
+               if(manbit) bitbuffer_add_bit(&bits, 0);
+               if(pulses->gap[n] > 450) {
+                       manbit ^= 1;
+                       if(manbit) bitbuffer_add_bit(&bits, 0);
+               }
+       }
+       return events;
+}