avr: Fix documentation for Bus
[avr-sim.git] / test / midi_int.c
blob92ab3d13d76c356dcec872841101757465abad1a
1 #include <avr/io.h>
2 #include <avr/interrupt.h>
3 #include <avr/eeprom.h>
4 #include <stdio.h>
5 #include "midi.h"
7 #define false 0
8 #define true 1
10 #define MIDI_SYSEX_MAX_LEN 64
11 volatile uint8_t sysex_buf_len = 0;
12 volatile uint8_t sysex_buf[MIDI_SYSEX_MAX_LEN];
14 volatile uint8_t sysex_read = false;
15 volatile int16_t midisync_clocked = 0;
17 #define IN_MIDI_Q_SIZE 32
18 #define OUT_MIDI_Q_SIZE 32
20 volatile uint8_t in_midi_q[IN_MIDI_Q_SIZE]; // cyclic queue for midi msgs
21 volatile static uint8_t in_head_idx = 0;
22 volatile static uint8_t in_tail_idx = 0;
23 volatile uint8_t out_midi_q[OUT_MIDI_Q_SIZE];// cyclic queue for midi msgs
24 volatile static uint8_t out_head_idx = 0;
25 volatile static uint8_t out_tail_idx = 0;
27 #define MIDI_BAUDRATE 31250UL // the MIDI spec baudrate
29 uint8_t EEMEM ee_midi_channel = 0;
31 void midi_handle_sysex(void);
33 // interrupt on receive char
34 ISR(SIG_USART0_RECV) {
35 uint8_t c = UDR0;
37 if( c == MD_SYSEX_START ) {
38 sysex_read = true;
39 sysex_buf_len = 0;
40 } else if( c == MD_SYSEX_END ) {
41 midi_handle_sysex();
42 sysex_read = false;
45 if( sysex_read ) {
46 sysex_buf[ sysex_buf_len++ ] = c;
47 } else {
48 in_midi_q[in_tail_idx++] = c; // place at end of q
49 in_tail_idx %= IN_MIDI_Q_SIZE;
51 if( in_tail_idx == in_head_idx ) {
52 // i.e. there are too many msgs in the q
53 // drop the oldest msg?
54 in_head_idx++;
55 in_head_idx %= IN_MIDI_Q_SIZE;
60 ISR(SIG_USART0_DATA) {
61 if( out_tail_idx != out_head_idx ) {
62 UDR0 = out_midi_q[out_tail_idx++];
63 out_tail_idx %= OUT_MIDI_Q_SIZE;
65 // output buffer empty
66 if( out_tail_idx == out_head_idx )
67 UCSR0B &= ~_BV(UDRIE0);
71 ISR(SIG_USART0_TRANS) {
75 void midi_init(void) {
76 // read and write, interrupt on recv.
77 UCSR0B |= (1<<RXEN0) | (1<<TXEN0)| (1<<RXCIE0) | (1<<TXCIE0);
79 /* setup the MIDI UART */
80 uint16_t ubbr = (F_CPU / (16 * MIDI_BAUDRATE)) - 1; // formula in datasheet
81 UBRR0L = (uint8_t)ubbr; // set baudrate
82 UBRR0H = (uint8_t)(ubbr>>8);
85 int midi_putchar(uint8_t c) {
86 while( (out_head_idx+1)%OUT_MIDI_Q_SIZE == out_tail_idx );
88 cli();
90 // Add it to the queue
91 out_midi_q[out_head_idx++] = c;
92 out_head_idx %= OUT_MIDI_Q_SIZE;
94 UCSR0B |= _BV(UDRIE0);
96 sei();
97 return 0;
100 int midi_getch(void) { // checks if there is a character waiting!
101 if( in_head_idx != in_tail_idx )
102 return 1;
103 return 0;
106 int midi_getchar(void) {
107 char c;
109 while( in_head_idx == in_tail_idx );
111 cli();
113 c = in_midi_q[in_head_idx++];
114 in_head_idx %= IN_MIDI_Q_SIZE;
116 sei();
118 return c;
121 void midi_send(uint8_t status, uint8_t chan, uint8_t data, uint8_t data2) {
122 midi_putchar( (status & 0xF0)|(chan & 0x0F) );
123 midi_putchar( data & 0x7F );
124 midi_putchar( data2 & 0x7F );
127 static uint8_t SYSEX_snd_checksum;
128 void sysex_start(uint8_t command) {
129 // Reset checksum
130 SYSEX_snd_checksum = 0;
132 // Send SYSEX start, manufacturer ID, model number and command
133 midi_putchar(MD_SYSEX_START);
134 midi_putchar(MD_MF_ID_1);
135 midi_putchar(MD_MF_ID_2);
136 midi_putchar(MD_MF_ID_3);
137 midi_putchar(MD_SYNTH_ID);
138 midi_putchar(command);
141 void sysex_data(uint8_t data) {
142 // split one byte of data in two
143 uint8_t msb = data >> 7;
144 uint8_t lsb = data & 0x7f;
145 midi_putchar(msb);
146 midi_putchar(lsb);
148 SYSEX_snd_checksum = (SYSEX_snd_checksum + msb + lsb) & 0x7F;
151 void sysex_end(void) {
152 // Send checksum
153 midi_putchar(SYSEX_snd_checksum);
155 // Send end of SYSEX
156 midi_putchar(MD_SYSEX_END);
159 uint8_t calcCRC(void) {
160 uint8_t i, crc = 0;
161 for(i = 0; i < sysex_buf_len; ++i)
162 crc = (crc + sysex_buf[i]) & 0x7F;
163 return crc;
166 void midi_handle_sysex(void) {
167 uint8_t crc = sysex_buf[ sysex_buf_len-1];
168 sysex_buf_len--;
170 // check crc
171 if( crc != calcCRC() ) {
172 sysex_buf_len = 0;
173 return;
176 if( (sysex_buf_len < 5) ||
177 sysex_buf[0] != MD_MF_ID_1 ||
178 sysex_buf[1] != MD_MF_ID_2 ||
179 sysex_buf[2] != MD_MF_ID_3 ||
180 sysex_buf[3] != MD_SYNTH_ID ) {
181 sysex_buf_len = 0;
182 return;
185 //handle_sysex(sysex_buf+4, sysex_buf_len);
188 uint8_t midi_readchannel(void) {
189 return eeprom_read_byte( &ee_midi_channel );