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:
David Woodhouse
2015-12-05 02:05:52 +00:00
parent 244645c89f
commit 3470b45813
5 changed files with 111 additions and 1 deletions

View File

@@ -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

View File

@@ -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;

View File

@@ -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;

View File

@@ -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");
}

View File

@@ -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);
}