1 /* I-Bus servo mixer for FlySky iA6B receiver */
4 #include <avr/interrupt.h>
6 #include <avr/pgmspace.h>
7 #include <util/atomic.h>
8 #include <util/delay.h>
10 #define N_SERVO_CHANNELS 18
11 #define SERVO_FRAME_SIZE 32
13 /* ----------------- USART ----------------- */
15 // I-Bus uses 115200n8
16 #define UART_BAUD 115200
17 #define UBRR_VAL ((F_CPU + 8UL * UART_BAUD) / (16UL*UART_BAUD) - 1)
19 #define BUFLEN SERVO_FRAME_SIZE
20 static volatile uint8_t buffer[BUFLEN];
21 static volatile uint8_t buf_offset;
23 static void handle_rx_packet(void);
25 static void serial_init(void)
30 UCSR0B = _BV(RXEN0) | _BV(RXCIE0);
31 UCSR0C = _BV(UCSZ01)|_BV(UCSZ00);
34 static void serial_enable_rx(void)
36 UCSR0B &= ~(_BV(TXEN0) | _BV(TXCIE0));
37 UCSR0B |= _BV(RXEN0) | _BV(RXCIE0);
40 static void led_init(void)
46 static void inline led1_off(void)
51 static void inline led1_on(void)
56 #define serial_rx_vect USART_RX_vect
58 #define serial_data UDR0
60 static void recv_restart(void)
68 // USART receive interrupt
71 uint8_t val = serial_data;
73 // a shorthand - for now, we accept 4-byte packets only
74 if (buf_offset == 0 && val != SERVO_FRAME_SIZE)
77 buffer[buf_offset++] = val;
79 if (buf_offset == buffer[0]) {
85 /* ----------------- Timer ----------------- */
86 typedef uint16_t time_t;
88 #define SERVO_MASK (_BV(PD2)|_BV(PD3)|_BV(PD4)|_BV(PD5)|_BV(PD6)|_BV(PD7))
90 static const prog_uint8_t servo_bits[] = {
99 static void timer_init(void)
101 TCCR1A = 0; // no PWM or WGM output
102 TCCR1B = _BV(CS11); // clk/8
104 DDRD |= _BV(PD2) | _BV(PD3) | _BV(PD4) | _BV(PD5)
108 static time_t inline get_time(void)
112 ATOMIC_BLOCK(ATOMIC_FORCEON) {
119 // run this inside interrupt or in atomic context
120 static void interrupt_after(uint16_t delay)
122 uint16_t now = TCNT1;
125 TIMSK1 |= _BV(OCIE1A);
128 ISR(TIMER1_COMPA_vect) {
129 static uint16_t led = 2000;
135 interrupt_after(65000);
139 interrupt_after(led);
145 /* ----------------- iBus ------------------ */
146 static void ibus_init(void)
151 static void handle_rx_packet(void)
153 uint16_t csum = 0xFFFF, servo;
156 for (i = 0; i < buf_offset-2; i++)
157 csum -= (uint16_t)buffer[i];
159 if ((buffer[buf_offset-2] != (csum & 0xFF))
160 || (buffer[buf_offset-1] != (csum >> 8))) { // invalid csum
161 buf_offset = 0; // start over
166 servo |= ((uint16_t)buffer[13] & 0x000F) << 8;
169 * -120 % == 0x384 == 900
170 * -100 % == 0x3e8 == 1000
171 * 0 % == 0x5dc == 1500
189 interrupt_after(1000);