X-Git-Url: https://git.rvb.name/rtl-433.git/blobdiff_plain/ca13278b24eb61443559bcb61e64627fba3d8823..6d15c6f967221af825cf84e3ed12b96c763b127b:/src/pulse_demod.c diff --git a/src/pulse_demod.c b/src/pulse_demod.c new file mode 100755 index 0000000..3935ce7 --- /dev/null +++ b/src/pulse_demod.c @@ -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 +#include +#include + + +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; +}