/elec/quadcopter

To get this branch, use:
bzr branch http://bzr.ed.am/elec/quadcopter
16 by Tim Marston
added (unfinished) rc-interface module to src; added arduino.mk
1
//
2
// receiver.cc
3
//
4
5
6
#include "receiver.h"
7
#include "config.h"
8
#include <Arduino.h>
9
#include <limits.h>
10
11
12
// channel sequence order
13
static const int channel_order_[] = { CHANNEL_ORDER };
14
15
// set to the time of the last pulse edges
16
static unsigned long new_pulse_up_[2] = { 0, 0 };
17
static unsigned long new_pulse_down_ = 0;
18
static char new_pulse_interrupt_;
19
20
21
// ISR to handle the PPM signals
22
inline void signal_handler( int interrupt, int pin )
23
{
24
	// record rising/falling edge
25
	if( digitalRead( pin ) )
26
		new_pulse_up_[ interrupt ] = micros();
27
	else {
28
		new_pulse_down_ = micros();
29
30
		// record which interrupt just had a falling edge
31
		new_pulse_interrupt_ = interrupt;
32
	}
33
}
34
35
36
static void signal_handler_0()
37
{
38
	signal_handler( 0, 2 );
39
}
40
41
42
static void signal_handler_1()
43
{
44
	signal_handler( 1, 3 );
45
}
46
47
48
void Receiver::setup()
49
{
50
	// set up an interrupts
51
	attachInterrupt( 0, signal_handler_0, CHANGE );
52
	attachInterrupt( 1, signal_handler_1, CHANGE );
53
	digitalWrite( 2, LOW );
54
	digitalWrite( 3, LOW );
55
}
56
57
58
static unsigned long calculate_duration( unsigned long then, unsigned long now )
59
{
60
	return now - then;
61
	
62
	if( now < then )
63
		return now + ( ULONG_MAX - then );
64
	else
65
		return now - then;
66
}
67
68
69
bool Receiver::read_channels( unsigned long channel_values[] )
70
{
71
	static unsigned long last_pulse_down = 0;
72
	static int next_channel = 0;
73
74
	// capture pulse values atomically
75
	noInterrupts();
76
	unsigned long pulse_up = new_pulse_up_[ (int)new_pulse_interrupt_ ];
77
	unsigned long pulse_down = new_pulse_down_;
78
	char new_pulse_interrupt = new_pulse_interrupt_;
79
	interrupts();
80
81
	// if the amount of time that has passed since the last falling edge is
82
	// greater than the frame gap, reset the next channel so that we can start
83
	// reading them again
84
	if( next_channel &&
85
		new_pulse_interrupt == 1 &&
86
		calculate_duration( pulse_down, micros() ) > MIN_FRAME_GAP_WIDTH )
87
	{
88
		// reset the next channel (which restarts reading them)
89
		next_channel = 0;
90
	}
91
92
	// check for a new complete pulse
93
	if( pulse_down != last_pulse_down )
94
	{
95
		// are there still pulses to read?
96
		if( next_channel < NUM_CHANNELS )
97
		{
98
			unsigned long duration =
99
				calculate_duration( pulse_up, pulse_down );
100
101
			// does this pulse look ok?
102
			if( duration >= MIN_PULSE_WIDTH &&
103
				duration <= MAX_PULSE_WIDTH )
104
			{
105
				// store channel value
106
				int channel = channel_order_[ next_channel ] - 1;
107
				channel_values[ channel ] = duration;
108
109
				// we got a channel
110
				next_channel++;
111
			}
112
			else {
113
				// set invalid channel number (to indicate error)
114
				next_channel = NUM_CHANNELS + 1;
115
			}
116
		}
117
118
		last_pulse_down = pulse_down;
119
	}
120
121
	// if we've read a frame, invalidate the frame (so we don't report it a
122
	// second time) and return true
123
	if( next_channel == NUM_CHANNELS ) {
124
		next_channel++;
125
		return true;
126
	}
127
	
128
	return false;
129
}