Add driver to receive Phillips RC5 IR protocol

main
Michael Hayes 12 years ago
parent ee5e67d4f1
commit 8099efaabf

@ -0,0 +1,151 @@
/** @file ir_rc5_rx.c
@author M. P. Hayes, UCECE
@date 21 May 2013
@brief Infrared serial receiver driver for Phillips RC5 protocol.
*/
/* The Phillips RC-5 protocol uses the following format of 14 bits:
1 start bit
1 field bit (this used to be a second start bit)
1 toggle bit
5 address bits
6 command bits
Manchester encoding is used for the bits. The start bit is a `1' bits.
`1' bits have the IR modulation on for the second half of the cycle.
`0' bits have the IR modulation on for the first half of the cycle.
Each bit period is 1778 microseconds (64 cycles of 36 kHz modulation)
thus a frame is 24.9 ms.
While a button is pressed, a frame is repeatedly sent. If the button
is repressed, the toggle bit is changed.
This is a simple polled implementation that will block for the entire frame
if it detects a start bit.
*/
#include "ir_rc5_rx.h"
#include "pio.h"
#include "delay.h"
#define IR_RC5_BIT_PERIOD_US 1778
#ifndef IR_RC5_RX_ACTIVE_STATE
/* Most IR demodulators have an active low output. */
#define IR_RC5_RX_ACTIVE_STATE 0
#endif
/** Return output state of IR receiver.
@return IR receiver state (1 = IR modulation detected). */
static inline uint8_t ir_rc5_rx_get (void)
{
return pio_input_get (IR_RC5_RX_PIO) == IR_RC5_RX_ACTIVE_STATE;
}
uint8_t ir_rc5_rx_ready_p (void)
{
return ir_rc5_rx_get ();
}
static uint16_t ir_rc5_rx_wait_state (uint8_t state)
{
uint16_t us;
for (us = 0; us < IR_RC5_BIT_PERIOD_US; us++)
{
if (ir_rc5_rx_get () == state)
return us;
/* TODO: figure out how to determine the fudge term. Ideally,
we should poll a counter incremented by the CPU clock. */
DELAY_US (1 - 0.4);
}
return us;
}
static uint16_t ir_rc5_rx_wait_transition (void)
{
uint8_t initial;
initial = ir_rc5_rx_get ();
return ir_rc5_rx_wait_state (!initial);
}
/** Receive RC5 data packet over IR serial link.
@return 14-bits of data or error status code
@note No error checking is performed. If there is no activity on the
IR serial link, this function returns immediately. Otherwise, this
function blocks until the entire frame is received. This must be called
frequently to ensure that a start bit is seen. */
int16_t ir_rc5_rx_read (void)
{
int16_t data;
int i;
uint16_t us;
/* Look to see if there is some IR modulation marking the second
half of the first start bit. It is possible that we may have
missed the start bit. In this case we are likely to
time out. */
if (!ir_rc5_rx_ready_p ())
return IR_RC5_RX_NONE;
/* The old RC-5 format had two start bits; this made a bit-bashed
software implementation easier. The problem is that we have
been called just before the falling edge of the start bit.
So we have to special case these two bits. */
/* Search for the next falling transition. */
us = ir_rc5_rx_wait_state (0);
if (us >= IR_RC5_BIT_PERIOD_US)
return IR_RC5_RX_TIMEOUT;
if (us > (IR_RC5_BIT_PERIOD_US >> 1))
{
/* The field bit is 0. */
data = 2;
}
else
{
/* The field bit is 1; so delay until middle of bit period. */
data = 3;
us = ir_rc5_rx_wait_state (1);
if (us >= IR_RC5_BIT_PERIOD_US)
return IR_RC5_RX_TIMEOUT;
}
for (i = 2; i < 14; i++)
{
data <<= 1;
DELAY_US (0.5 * IR_RC5_BIT_PERIOD_US + 100);
us = ir_rc5_rx_wait_transition ();
if (us >= IR_RC5_BIT_PERIOD_US)
return IR_RC5_RX_TIMEOUT;
if (ir_rc5_rx_get ())
data |= 1;
}
return data;
}
/** Initialise IR serial receiver driver. */
void ir_rc5_rx_init (void)
{
/* Ensure PIO clock activated for reading. */
pio_init (IR_RX_PIO);
/* Configure IR receiver PIO as input. */
pio_config_set (IR_RX_PIO, PIO_INPUT);
}

@ -0,0 +1,34 @@
/** @file ir_rc5_rx.h
@author M. P. Hayes, UCECE
@date 21 May 2013
@brief Infrared serial receiver driver for Phillips RC5 protocol.
*/
#ifndef IR_RC5_RX_H
#define IR_RC5_RX_H
#include "config.h"
/** Status return codes. */
typedef enum ir_rc5_rx_ret
{
/** No data to read. */
IR_RC5_RX_NONE = 0,
/** Timeout waiting for transition. */
IR_RC5_RX_TIMEOUT = -1
} ir_rc5_rx_ret_t;
/** Receive RC5 data packet over IR serial link.
@return 14-bits of data or error status code
@note No error checking is performed. If there is no activity on the
IR serial link, this function returns immediately. Otherwise, this
function blocks until the entire frame is received. This must be called
frequently to ensure that a start bit is seen. */
int16_t ir_rc5_rx_read (void);
/** Initialise IR serial receiver driver. */
void ir_rc5_rx_init (void);
#endif
Loading…
Cancel
Save