rc5 H

Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 11

/*** FILEHEADER

****************************************************************
*
*
FILENAME:
rc5.h
*
DATE:
26.07.2011
*
AUTHOR:
Christian Stadler
*
*
DESCRIPTION: RC5 decoder driver
*
*************************************************************************
*****/
/*** HISTORY OF CHANGE
*********************************************************
*
*
$Log: /pic/_drv/rc5.h $
*
* 8
19.10.11 21:32 Stadler
* - added Microchip C18 compiler support
*
* 7
16.10.11 20:18 Stadler
* - code cleanup
*
* 6
3.08.11 17:48 Stadler
* - made min/max bit times configurable by user
*
* 5
27.07.11 17:24 Stadler
* - updated comments
*
* 4
26.07.11 23:49 Stadler
* - updated timeout handling
*
* 3
26.07.11 22:21 Stadler
* - added interfaces to get RC5 command and RC5 device address
* - made timer ticks and timer get function configurable by user
* - documented the code
*
* 2
26.07.11 20:47 Stadler
* - only report new RC5 code received if RC5 code changed with respect
to
* previous received code
*
*************************************************************************
*****/
/* unified data type definitions */
#include "types.h"
/
*************************************************************************
****/
/* DRIVER CONFIGURATION
*/

/* ====================
*/
/*
*/
/* The following defines need to be defined by the user.
*/
/*
*/
/* The following items to be configured:
*/
/* - RC5_DATA_PIN:
RC5 input pin
*/
/* - RC5_TICKS_PER_MS: RC5 timer ticks per millisecond
*/
/* - RC5_GetTimer():
Macro to get RC5 timer value
*/
/*
*/
/* The following configuration items are optional:
*/
/* - RC5_HALF_BIT_TIME_MIN:
minimum half bit time in ticks per
milliseconds */
/*
default: (((RC5_TICKS_PER_MS) * 700) / 1000)
*/
/* - RC5_HALF_BIT_TIME_MAX: maximum half bit time in ticks per
milliseconds */
/*
default: (((RC5_TICKS_PER_MS) * 1100) /
1000)
*/
/
*************************************************************************
****/

/* === C18 compiler specific


=============================================== */
/* Note: This driver was written for CCS C compiler. The following macos
*/
/*
are required to compile this driver fo CCS C compiler.
*/
#if defined(__18CXX)
/* For C18 compiler the pin configuration must be provided by a config
*/
/* header file. This header file must define the #define mentioned in the
*/
/* driver configuration information above.
*/
#include "config.h"
#ifndef FALSE
#define FALSE
#endif
#ifndef TRUE
#define TRUE
#endif

(!(FALSE))

/* bit access marcos */


#define bit_set(value, bitpos)
(bitpos)))
#define bit_clear(value, bitpos)
(bitpos))))
#define bit_test(value, bitpos)
0)

((value) |= ((uint16)1 <<


((value) &= (~((uint16)1 <<
((((value) >> (bitpos)) & 0x1) !=

/* interrupt enable/disable macros */


#define GLOBAL
0
/* dummy value which would be
defined for CCS C */
#define disable_interrupts(x)
INTCONbits.GIE = 0
#define enable_interrupts(x)
INTCONbits.GIE = 1
/* input pin macro */
#define input(pin)

(pin)

#endif /* #if defined(__18CXX) */


/* === End C18 compiler specific
=========================================== */

/* pin where RC5 signal is connected needs to be configured in


RC5_DATA_PIN */
#ifndef RC5_DATA_PIN
#error RC5_DATA_PIN not defined!
#endif
/* number of ticks per ms which are generated by the timer which is used
*/
/* for RC5 decoding, needs to be defined in RC5_TICKS_PER_MS */
#ifndef RC5_TICKS_PER_MS
#error RC5_TICKS_PER_MS not defined!
#endif
/* function to get current timer value needs to be configured in
RC5_GetTimer() */
#ifndef RC5_GetTimer()
#error RC5_GetTimer() not defined!
#endif

/
*************************************************************************
****/
/* DRIVER INTERNAL DEFINES
*/
/* =======================
*/
/*
*/
/* Do not change any of this defines.
*/

/
*************************************************************************
****/
#define RC5_GetPin()

input(RC5_DATA_PIN)

/* min/max value for a half bit time (min = 700us, max = 1100us) */
#ifndef RC5_HALF_BIT_TIME_MIN
#define RC5_HALF_BIT_TIME_MIN
(((RC5_TICKS_PER_MS) * 700U) / 1000U)
#endif
#ifndef RC5_HALF_BIT_TIME_MAX
#define RC5_HALF_BIT_TIME_MAX
(((RC5_TICKS_PER_MS) * 1100U) / 1000U)
#endif
/* timeout time after last RC5 interrupt (3ms because maximum time
between */
/* two edges in a RC5 signal is around 1.8ms */
#define RC5_TIMEOUT
((RC5_TICKS_PER_MS) * 3)
/* decoding states: */
/* RC5_BIT_STATE_HALF: decoding
/* RC5_BIT_STATE_FULL: full bit
#define RC5_BIT_STATE_HALF
#define RC5_BIT_STATE_FULL

done until half of a bit */


has been decoded */
0
1

/* RC5 bit positions */


#define RC5_TOGGLE_BIT
#define RC5_START_BIT_2
#define RC5_START_BIT_1

11
12
13

/* RC5 masks */
#define RC5_MASK_CMD
#define RC5_MASK_DEVADDR

0x003F
0x001F

/* RC5
static
static
static

decoding status variables */


uint16 rc5_code = 0;
uint8 rc5_timeout_timer = 0; /* timeout timer, unit [ms] */
bool rc5_ready = FALSE;

/
*************************************************************************
****/
/* RC5_GetToggleBit
*/
/*
*/
/* Returns the status of the toggle bit.
*/
/*
*/
/* Return: TRUE if toggle bit is set, FALSE otherwise.
*/

/
*************************************************************************
****/
#define RC5_GetToggleBit(rc5code)
bit_test(rc5code, RC5_TOGGLE_BIT)
/
*************************************************************************
****/
/* RC5_GetDeviceAddr
*/
/*
*/
/* Gets the RC5 device address from a full RC5 code.
*/
/*
*/
/* Return: RC5 device address.
*/
/
*************************************************************************
****/
#define RC5_GetDeviceAddr(rc5code)
((rc5code >> 6) &
RC5_MASK_DEVADDR)
/
*************************************************************************
****/
/* RC5_GetCmd
*/
/*
*/
/* Gets the RC5 command from a full RC5 code.
*/
/*
*/
/* Return: RC5 command.
*/
/
*************************************************************************
****/
#define RC5_GetCmd(rc5code)
(rc5code & RC5_MASK_CMD)
/
*************************************************************************
****/
/* RC5_CodeReady
*/
/*
*/
/* Returns status if a new RC5 code has been received.
*/
/*
*/

/* Return: TRUE if new RC5 code is available, FALSE otherwise.


*/
/
*************************************************************************
****/
bool RC5_CodeReady(void)
{
bool rc;
rc = rc5_ready;
rc5_ready = FALSE;
return (rc);
}
/
*************************************************************************
****/
/* RC5_GetCode
*/
/*
*/
/* Returns received RC5 code. Use RC5_CodeReady() function first to see
if
*/
/* a valid code is available.
*/
/*
*/
/* Return: rc5_code
RC5 code.
*/
/
*************************************************************************
****/
uint16 RC5_GetCode(void)
{
return (rc5_code);
}
/
*************************************************************************
****/
/* RC5_TimeoutIncrement
*/
/*
*/
/* Function increments timeout counter to detect a RC5 timeout and
*/
/* resynchronize the RC5 decoding state machine.
*/
/* Functions shall be called cyclically in main loop or in a timer
*/
/* interrupt overflow routine which is called at around every 1ms.
*/
/*
*/
/* NOTE: Decoding will also work without calling this function, but
*/

/*
it could happen that RC5 codes are sometimes not getting
recognized */
/*
because of decoding state machine stucks due to erroneous RC5
*/
/*
signal.
*/
/*
*/
/* Return: none
*/
/
*************************************************************************
****/
void RC5_TimeoutIncrement(void)
{
static uint8 old_timer;
uint8 timer;
/* get current timer value */
timer = RC5_GetTimer();
/* disable interrupts since rc5_timeout_timer is also read and
written to in ISR */
disable_interrupts(GLOBAL);
if (rc5_timeout_timer < RC5_TIMEOUT)
{
rc5_timeout_timer += (timer - old_timer);
}
/* re-enable interrupts again */
enable_interrupts(GLOBAL);
old_timer = timer;
}
/
*************************************************************************
****/
/* RC5_InterruptHandler
*/
/*
*/
/* Interrupt handler for RC5 decoding. This function must be called by an
*/
/* "Interrupt-On-Change" interrupt service routine.
*/
/*
*/
/* Return: none
*/
/
*************************************************************************
****/
void RC5_InterruptHandler(void)

{
static uint8 rc5_timer = 0;
static uint8 rc5_pos = 13;
static uint16 rc5_code_tmp = 0;
static bool rc5_wait_start = TRUE;
static bool rc5_bit_state = RC5_BIT_STATE_FULL;
static bool rc5_pin_old = TRUE;
bool rc5_rx_last = FALSE;
bool rc5_pin;
uint8 tdiff;
/* get RC5 pin status */
rc5_pin = RC5_GetPin();
/* calculate time difference to last interrupt call */
tdiff = RC5_GetTimer() - rc5_timer;
/* start the RC5 timer again */
rc5_timer = RC5_GetTimer();
/* if timeout counter has expired, i.e. no RC5 signal was received
for some */
/* time, reset the state machine */
if (rc5_timeout_timer >= RC5_TIMEOUT)
{
rc5_wait_start = TRUE;
}
/* reset the timeout counter */
rc5_timeout_timer = 0;
if (rc5_wait_start != FALSE)
{
/* 1st half of start bit received */
if ((rc5_pin_old != FALSE) && (rc5_pin == FALSE))
{
/* leave wait state */
rc5_wait_start = FALSE;
/* 1st half of bit has been received */
rc5_bit_state = RC5_BIT_STATE_HALF;
/* 1st start bit is at position 13 */
rc5_pos = 13;
/* reset RC5 code */
rc5_code_tmp = 0;
}
}
else
{
/* rising edge of RC5 signal */
if ((rc5_pin_old == FALSE) && (rc5_pin != FALSE))
{
/* one half of the bit has already been received last time
and now */
/* we got the 2nd half of the bit */
if ((rc5_bit_state == RC5_BIT_STATE_HALF) && (tdiff >=
RC5_HALF_BIT_TIME_MIN) && (tdiff <= RC5_HALF_BIT_TIME_MAX))
{

/* logical 1 has been received => add to rc5 code */


bit_set(rc5_code_tmp, rc5_pos);
/* decrement bit position */
if (rc5_pos > 0)
{
rc5_pos--;
}
else
{
rc5_rx_last = TRUE;
}
/* we are at the end of a bit */
rc5_bit_state = RC5_BIT_STATE_FULL;
}
/* one half of the bit has already been received last time
and now */

/* we got the 2nd half of the bit and also the next half of
the following bit */
else if ((rc5_bit_state == RC5_BIT_STATE_HALF) && (tdiff >=
(2*RC5_HALF_BIT_TIME_MIN)) && (tdiff <= (2*RC5_HALF_BIT_TIME_MAX)))
{
/* logical 1 has been received => add to rc5 code */
bit_set(rc5_code_tmp, rc5_pos);
/* decrement bit position */
if (rc5_pos > 0)
{
rc5_pos--;
}
/* not done in else part because there will be no
additional interrupt for the last bit in this case */
if (rc5_pos == 0)
{
rc5_rx_last = TRUE;
}
/* we are at the half of the next bit */
rc5_bit_state = RC5_BIT_STATE_HALF;

1st */
half */

}
/* previously, we have sampled a full bit, since now only the
/* half of the next bit is available now, wait until the next

else if ((rc5_bit_state == RC5_BIT_STATE_FULL) && (tdiff >=


RC5_HALF_BIT_TIME_MIN) && (tdiff <= RC5_HALF_BIT_TIME_MAX))
{
/* we are at the half of the next bit */
rc5_bit_state = RC5_BIT_STATE_HALF;
/* we will not get an interrupt for the last half bit, so
we are finished here */
if (rc5_pos == 0)
{
rc5_rx_last = TRUE;
}
}

/* something wrong with the timing, wait for another start


condition */

else
{

/* wait for start condition */


rc5_wait_start = TRUE;

}
}
/* falling edge of RC5 signal */
if ((rc5_pin_old != FALSE) && (rc5_pin == FALSE))
{
/* one half of the bit has already been received last time
and now */
/* we got the 2nd half of the bit */
if ((rc5_bit_state == RC5_BIT_STATE_HALF) && (tdiff >=
RC5_HALF_BIT_TIME_MIN) && (tdiff <= RC5_HALF_BIT_TIME_MAX))
{
/* logical 0 has been received => add to rc5 code */
bit_clear(rc5_code_tmp, rc5_pos);
/* decrement bit position */
if (rc5_pos > 0)
{
rc5_pos--;
}
else
{
rc5_rx_last = TRUE;
}
/* we are at the end of a bit */
rc5_bit_state = RC5_BIT_STATE_FULL;
}
/* one half of the bit has already been received last time
and now */
/* we got the 2nd half of the bit and also the next half of
the following bit */
else if ((rc5_bit_state == RC5_BIT_STATE_HALF) && (tdiff >=
(2*RC5_HALF_BIT_TIME_MIN)) && (tdiff <= (2*RC5_HALF_BIT_TIME_MAX)))
{
/* logical 0 has been received => add to rc5 code */
bit_clear(rc5_code_tmp, rc5_pos);
/* decrement bit position */
if (rc5_pos > 0)
{
rc5_pos--;
}
else
{
rc5_rx_last = TRUE;
}
/* we are at the half of the next bit */
rc5_bit_state = RC5_BIT_STATE_HALF;
}
/* previously, we have sampled a full bit, since now only the
1st */
/* half of the next bit is available now, wait until the next
half */

else if ((rc5_bit_state == RC5_BIT_STATE_FULL) && (tdiff >=


RC5_HALF_BIT_TIME_MIN) && (tdiff <= RC5_HALF_BIT_TIME_MAX))
{
/* we are at the half of the next bit */
rc5_bit_state = RC5_BIT_STATE_HALF;
}
/* something wrong with the timing, wait for another start
condition */
else
{
/* wait for start condition */
rc5_wait_start = TRUE;
}
}
}
/* save current pin state for edge detection */
rc5_pin_old = rc5_pin;
/* the first two bits are the start bits and habe to be 1, else
something went */
/* wrong and hence wait for another start condition */
if ( ((rc5_pos == 12) && !bit_test(rc5_code_tmp, RC5_START_BIT_1)) ||
((rc5_pos == 11) && !bit_test(rc5_code_tmp, RC5_START_BIT_2)) )
{
rc5_wait_start = TRUE;
}
/* if all RC5 bits have been received */
if ((rc5_pos == 0) && (rc5_rx_last != FALSE))
{
/* if code is different from last received code, set flag to
indicate */
/* that a new code has been received */
if (rc5_code != rc5_code_tmp)
{
rc5_code = rc5_code_tmp;
rc5_ready = TRUE;
}
rc5_wait_start = TRUE;
}
}

You might also like