-
Notifications
You must be signed in to change notification settings - Fork 4
/
Spektrum.c
149 lines (116 loc) · 3.39 KB
/
Spektrum.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
/*
ChibiCopter - https://github.com/grantmd/ChibiCopter
A quadcopter platform running under ChibiOS/RT.
Talks to a Spektrum Satellite receiver over Serial and receives commands
*/
#include "ch.h"
#include "hal.h"
#include "Spektrum.h"
static WORKING_AREA(SPEKTRUMWA, 128);
static msg_t Spektrum(void *arg){
(void)arg;
chRegSetThreadName("Spektrum");
while (TRUE){
// Read a byte off the receiver
uint8_t c = chnGetTimeout((BaseChannel *)&SD3, TIME_INFINITE);
if (_SpektrumParse(c)){
}
}
return 0;
}
// Our config for the serial connection to the RX
static SerialConfig sd3cfg = {
115200,
0,
USART_CR2_STOP1_BITS | USART_CR2_LINEN,
0
};
// Most recent valid data, per-channel
int receiver_data[MAX_RC_CHANNELS];
// A struct to maintain decoding state
typedef struct {
char state;
unsigned char data[14];
unsigned char valid;
long frameNum;
} spektrum_t;
spektrum_t rx_state;
#define SPEKTRUM_NUM_BYTES_IN_FRAME (2*MAX_RC_CHANNELS+2)
/*
* Activates the serial driver 3
* PD8(TX) and PD9(RX) are routed to USART3.
*/
void SpektrumInit(void){
sdStart(&SD3, &sd3cfg);
palSetPadMode(GPIOD, 8, PAL_MODE_ALTERNATE(7)); // not currently connected
palSetPadMode(GPIOD, 9, PAL_MODE_ALTERNATE(7)); // incoming data from the receiver
unsigned i;
for (i=0; i<MAX_RC_CHANNELS; i++){
receiver_data[i] = 0;
}
rx_state.state = 0;
rx_state.valid = 0;
rx_state.frameNum = 0L;
chThdCreateStatic(SPEKTRUMWA, sizeof(SPEKTRUMWA), NORMALPRIO, Spektrum, NULL);
}
/*
* Returns the most recent data for the given channel
*/
int getSpektrumData(int channel){
if (channel < 0 || channel >= MAX_RC_CHANNELS) return 0;
return receiver_data[channel];
}
////////////////////////////////////////////
// Private functions
/*
* Takes a single character read off the serial connection. Combines it with our current state to progress that state.
* Sets receiver_data if the frame is complete and valid.
* Returns whether or not the frame is now complete and valid
*/
// Mostly borrowed from: http://mbed.org/users/offroad/libraries/spektRx/lzmwp4/docs/spektRx_8c_source.html
unsigned char _SpektrumParse(uint8_t c){
switch(rx_state.state){
case 0: /* new frame cycle */
_SpektrumInvalidateFrame();
/* first preamble byte received: now expect 2nd preamble byte */
rx_state.state = (c == 0x03) ? 1 : 0;
break;
case 1:
/* 2nd preamble byte received: Now expect first data byte */
rx_state.state = (c == 0x01) ? 2 : 0;
break;
default:
/* store received byte */
rx_state.data[rx_state.state - 2] = c;
++rx_state.state;
if (rx_state.state == SPEKTRUM_NUM_BYTES_IN_FRAME){
/* one complete frame was received.
* - Copy the data
* - mask out bits 10..15
*/
int ix;
for (ix = 0; ix < MAX_RC_CHANNELS; ++ix){
// TODO: This probably requires some other sort of conversion
receiver_data[ix] = ((rx_state.data[2*ix] & 3) << 8) | rx_state.data[2*ix+1];
}
/* output data is now valid */
_SpektrumValidateFrame();
++rx_state.frameNum;
/* ready for the next frame */
rx_state.state = 0;
} /* if frame complete */
} /* switch state */
return _SpektrumFrameIsValid();
}
long _SpektrumGetFrameNum(void){
return rx_state.frameNum;
}
void _SpektrumInvalidateFrame(void){
rx_state.valid = 0;
}
void _SpektrumValidateFrame(void){
rx_state.valid = 1;
}
unsigned char _SpektrumFrameIsValid(void){
return rx_state.valid;
}