mirror of
https://github.com/merbanan/rtl_433.git
synced 2026-04-23 02:57:07 -04:00
Support framed FSK Manchester decoding compatible with Si4320/RFM01
Detection in pulse_analyzer() is left to a separate commit because it's ugly and wants separate review.
This commit is contained in:
@@ -115,6 +115,32 @@ int pulse_demod_pwm_ternary(const pulse_data_t *pulses, struct protocol_state *d
|
||||
/// @return number of events processed
|
||||
int pulse_demod_manchester_zerobit(const pulse_data_t *pulses, struct protocol_state *device);
|
||||
|
||||
/// Demodulate a Manchester encoded signal with preamble and postamble as used by HopeRF RFMxx modules
|
||||
///
|
||||
/// Each frame has a preamble of three high-level periods, followed by three low-level
|
||||
/// periods (which we presume might be four, if the first data bit is a 1. Although
|
||||
/// we actually have yet to see a transmission where the first data bit is a 1).
|
||||
/// The end of frame is marked by staying at the same level (high or low
|
||||
/// depending on the value of the last data bit) for two further periods.
|
||||
///
|
||||
/// +-----------+ +---+ +-----------+ high frequency
|
||||
/// | | | | |
|
||||
/// | | | | |
|
||||
/// + +-----------+ +-------+ low frequency
|
||||
///
|
||||
/// ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
|
||||
/// | preamble | preamble | 0 | 1 | end translates as
|
||||
///
|
||||
/// Clock is recovered from the data based on pulse width. When time since last bit is more
|
||||
/// than 1.5 times the clock half period (short_width) it is declared a data edge where:
|
||||
/// - Rising edge means bit = 1
|
||||
/// - Falling edge means bit = 0
|
||||
/// @param device->short_limit: Nominal width of clock half period [samples]
|
||||
/// @param device->long_limit: Not used
|
||||
/// @param device->reset_limit: Not used
|
||||
/// @return number of events processed
|
||||
int pulse_demod_manchester_framed(const pulse_data_t *pulses, struct protocol_state *device);
|
||||
|
||||
|
||||
/// No level shift within the clock cycle translates to a logic 0
|
||||
/// One level shift within the clock cycle translates to a logic 1
|
||||
|
||||
@@ -43,10 +43,10 @@
|
||||
#define OOK_PULSE_PWM_RAW 7 // Pulse Width Modulation. Short pulses = 1, Long = 0
|
||||
#define OOK_PULSE_PWM_TERNARY 8 // Pulse Width Modulation with three widths: Sync, 0, 1. Sync determined by argument
|
||||
#define OOK_PULSE_CLOCK_BITS 9 // Level shift within the clock cycle.
|
||||
|
||||
#define FSK_DEMOD_MIN_VAL 16 // Dummy. FSK demodulation must start at this value
|
||||
#define FSK_PULSE_PCM 16 // FSK, Pulse Code Modulation
|
||||
#define FSK_PULSE_PWM_RAW 17 // FSK, Pulse Width Modulation. Short pulses = 1, Long = 0
|
||||
#define FSK_PULSE_MANCHESTER_FRAMED 18 // FSK, Framed Manchester encoding as used by HopeRF RFMxx modules.
|
||||
|
||||
extern int debug_output;
|
||||
|
||||
|
||||
@@ -278,6 +278,82 @@ int pulse_demod_manchester_zerobit(const pulse_data_t *pulses, struct protocol_s
|
||||
return events;
|
||||
}
|
||||
|
||||
int pulse_demod_manchester_framed(const pulse_data_t *pulses, struct protocol_state *device) {
|
||||
int events = 0;
|
||||
unsigned time_since_last = -1;
|
||||
bitbuffer_t bits = {0};
|
||||
|
||||
for(unsigned n = 0; n < pulses->num_pulses; ++n) {
|
||||
if (time_since_last == (unsigned)-1) {
|
||||
// Waiting for start-of-frame pulse (HHH)
|
||||
if (pulses->pulse[0] < (unsigned)(device->short_limit*5)/2)
|
||||
continue;
|
||||
// First gap must be 3 or 4 periods.
|
||||
if (pulses->gap[0] < (unsigned)(device->short_limit * 5)/2 ||
|
||||
pulses->gap[0] > (unsigned)(device->short_limit * 9)/2)
|
||||
continue;
|
||||
|
||||
// If first gap is three periods (LLL), the first bit
|
||||
// first bit is a 0 (HL) and will be counted on the
|
||||
// next pulse. If first gap is four periods (LLLL),
|
||||
// the first bit is a 1 (LH) and must be counted now.
|
||||
if (pulses->gap[0] > (unsigned)(device->short_limit*7)/2) {
|
||||
time_since_last = 0;
|
||||
bitbuffer_add_bit(&bits, 1);
|
||||
} else
|
||||
time_since_last = device->short_limit;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Falling edge is on end of pulse
|
||||
if(!time_since_last && pulses->pulse[n] > (unsigned)(device->short_limit * 5)/2) {
|
||||
// End of frame */
|
||||
end_of_frame:
|
||||
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);
|
||||
}
|
||||
reset:
|
||||
bitbuffer_clear(&bits);
|
||||
time_since_last = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
// If there's no edge where we need one...
|
||||
if(pulses->pulse[n] + time_since_last > (unsigned)(device->short_limit * 5)/2)
|
||||
goto reset;
|
||||
|
||||
if(pulses->pulse[n] + time_since_last > (unsigned)(device->short_limit * 3)/2) {
|
||||
// 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 = 0)
|
||||
bitbuffer_add_bit(&bits, 0);
|
||||
time_since_last = 0;
|
||||
} else {
|
||||
time_since_last += pulses->pulse[n];
|
||||
}
|
||||
|
||||
if(!time_since_last && pulses->gap[n] > (unsigned)(device->short_limit * 5)/2)
|
||||
goto end_of_frame;
|
||||
if(pulses->gap[n] + time_since_last > (unsigned)(device->short_limit * 5)/2)
|
||||
goto reset;
|
||||
|
||||
// Rising edge is on end of gap
|
||||
if(pulses->gap[n] + time_since_last > (unsigned)(device->short_limit * 3)/2) {
|
||||
// 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 = 1)
|
||||
bitbuffer_add_bit(&bits, 1);
|
||||
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) {
|
||||
unsigned int symbol[PD_MAX_PULSES * 2];
|
||||
unsigned int n;
|
||||
|
||||
@@ -435,6 +435,9 @@ void pulse_analyzer(pulse_data_t *data)
|
||||
case OOK_PULSE_MANCHESTER_ZEROBIT:
|
||||
pulse_demod_manchester_zerobit(data, &device);
|
||||
break;
|
||||
case FSK_PULSE_MANCHESTER_FRAMED:
|
||||
pulse_demod_manchester_framed(data, &device);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unsupported\n");
|
||||
}
|
||||
|
||||
@@ -636,6 +636,7 @@ static void rtlsdr_callback(unsigned char *iq_buf, uint32_t len, void *ctx) {
|
||||
case OOK_PULSE_CLOCK_BITS:
|
||||
case FSK_PULSE_PCM:
|
||||
case FSK_PULSE_PWM_RAW:
|
||||
case FSK_PULSE_MANCHESTER_FRAMED:
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unknown modulation %d in protocol!\n", demod->r_devs[i]->modulation);
|
||||
@@ -676,6 +677,7 @@ static void rtlsdr_callback(unsigned char *iq_buf, uint32_t len, void *ctx) {
|
||||
// FSK decoders
|
||||
case FSK_PULSE_PCM:
|
||||
case FSK_PULSE_PWM_RAW:
|
||||
case FSK_PULSE_MANCHESTER_FRAMED:
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unknown modulation %d in protocol!\n", demod->r_devs[i]->modulation);
|
||||
@@ -703,6 +705,9 @@ static void rtlsdr_callback(unsigned char *iq_buf, uint32_t len, void *ctx) {
|
||||
case FSK_PULSE_PWM_RAW:
|
||||
pulse_demod_pwm(&demod->fsk_pulse_data, demod->r_devs[i]);
|
||||
break;
|
||||
case FSK_PULSE_MANCHESTER_FRAMED:
|
||||
pulse_demod_manchester_framed(&demod->fsk_pulse_data, demod->r_devs[i]);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unknown modulation %d in protocol!\n", demod->r_devs[i]->modulation);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user