#include #include #include #define ecallf(e) asm("ecallf %0" :: "r"(e)); #include "xc_ptr.h" #define NO_INLINE_MIDI_SELECT_HANDLER 1 #include "usb_midi.h" #include "devicedefines.h" #include "testct_byref.h" #include "interrupt.h" #include "clockcmds.h" #include "xud.h" #include "usb.h" #define MAX(x,y) ((x)>(y) ? (x) : (y)) #define MAX_CLASS_ONE_FREQ 96000 #define MAX_CLASS_ONE_CHAN 2 #define CLASS_TWO_PACKET_SIZE ((((MAX_FREQ+7999)/8000))+3) #define CLASS_ONE_PACKET_SIZE ((((MAX_CLASS_ONE_FREQ+999)/1000))+3) #define BUFF_SIZE_OUT MAX(4 * CLASS_TWO_PACKET_SIZE * NUM_USB_CHAN_OUT, 4 * CLASS_ONE_PACKET_SIZE * MAX_CLASS_ONE_CHAN) #define BUFF_SIZE_IN MAX(4 * CLASS_TWO_PACKET_SIZE * NUM_USB_CHAN_IN, 4 * CLASS_ONE_PACKET_SIZE * MAX_CLASS_ONE_CHAN) #define MAX_USB_AUD_PACKET_SIZE 1028 //#define OUT_BUFFER_PREFILL (2*4*BUFF_SIZE_OUT/3) #define OUT_BUFFER_PREFILL MAX(CLASS_ONE_PACKET_SIZE*3+4,CLASS_TWO_PACKET_SIZE*4+4)*2 #define IN_BUFFER_PREFILL MAX(CLASS_ONE_PACKET_SIZE*3+4,CLASS_TWO_PACKET_SIZE*4+4)*2 //#pragma xta command "config threads stdcore[1] 6" //#pragma xta command "add exclusion out_underflow" //#pragma xta command "add exclusion freq_change" //#pragma xta command "add exclusion print_err" //#pragma xta command "add exclusion out_soverflow" //#pragma xta command "analyse path mixer_request mixer_request" //#pragma xta command "set required - 5200 ns" /* 192kHz */ /* Volume and mute tables */ #ifndef OUT_VOLUME_IN_MIXER unsigned int multOut[NUM_USB_CHAN_OUT + 1]; #endif #ifndef IN_VOLUME_IN_MIXER unsigned int multIn[NUM_USB_CHAN_IN + 1]; #endif /* Number of channels to/from the USB bus */ unsigned g_numUsbChanOut = NUM_USB_CHAN_OUT; unsigned g_numUsbChanIn = NUM_USB_CHAN_IN; #define MAX_DEVICE_AUD_PACKET_SIZE_CLASS_TWO ((MAX_FREQ/8000+1)*NUM_USB_CHAN_IN*4) #define MAX_DEVICE_AUD_PACKET_SIZE_CLASS_ONE (((MAX_CLASS_ONE_FREQ/1000+1)*MAX_CLASS_ONE_CHAN*3)+4) #define MAX_DEVICE_AUD_PACKET_SIZE (MAX(MAX_DEVICE_AUD_PACKET_SIZE_CLASS_ONE, MAX_DEVICE_AUD_PACKET_SIZE_CLASS_TWO)) /* Circular audio buffers */ unsigned outAudioBuff[BUFF_SIZE_OUT + (MAX_USB_AUD_PACKET_SIZE>>2) + 4]; unsigned audioBuffIn[BUFF_SIZE_IN + (MAX_DEVICE_AUD_PACKET_SIZE>>2) + 4]; unsigned inZeroBuff[(MAX_DEVICE_AUD_PACKET_SIZE>>2)+4]; unsigned ledVal = 1; unsigned dir = 0; void led(chanend ?c_led) { if(dir == 0) ledVal <<= 1; else ledVal >>= 1; if(ledVal == 0b10000000 || ledVal == 1) dir = !dir; if (!isnull(c_led)) { c_led <: ledVal; } } /* Returns the max and min packet sizes to send back to host for a given sample frequency * See page 13 of USB Audio Device Class Definitions for Audio Data Formats Spec (v2.0) * * Audio samples per frame = INT(sampFreq/frametime); Variation allowed is + 1; * * For HS frame time = 8 * 1000 * * so n = INT(SampFreq/8000) | INT (SampFreq/8000) + 1 * * In the case where INT(SampFreq/8000) == SampFreq/8000) n may vary between * * INT(SamFreq/8000) - 1 | INT(SampFreq/8000) | INT (SampFreq/8000) + 1 * * Note: Assumes HS (i.e. 8 frames per 1ms) * * Examples: * 44100: min: 5 max: 6 * 48000: min: 5 max: 7 * 96000: min: 11 max: 13 * 88200: min: 11 max: 12 * 176400: min: 22 max: 23 * 192000: min: 23 max: 25 * * Note: This function uses the multiple return value feature of XC */ void GetADCCounts(unsigned samFreq, int &min, int &mid, int &max); static inline void swap(xc_ptr &a, xc_ptr &b) { xc_ptr tmp; tmp = a; a = b; b = tmp; return; } // shared global midi buffering variables unsigned g_midi_from_host_flag = 0; unsigned g_midi_to_host_flag = 0; int midi_to_host_usb_ep = 0; int midi_from_host_usb_ep = 0; int aud_from_host_usb_ep = 0; int aud_to_host_usb_ep = 0; int int_usb_ep = 0; int g_midi_to_host_buffer[8]; int g_midi_from_host_buffer[MAX_USB_PACKET_SIZE+4]; // shared global aud buffering variables unsigned g_aud_from_host_buffer; unsigned g_aud_to_host_buffer; unsigned g_aud_to_host_flag = 0; int buffer_aud_ctl_chan = 0; unsigned g_aud_from_host_flag = 0; unsigned g_aud_from_host_info; unsigned g_freqChange_flag = 0; unsigned g_freqChange_sampFreq; int speedRem = 0; xc_ptr aud_from_host_fifo_start; xc_ptr aud_from_host_fifo_end; xc_ptr g_aud_from_host_wrptr; xc_ptr g_aud_from_host_rdptr; xc_ptr aud_to_host_fifo_start; xc_ptr aud_to_host_fifo_end; xc_ptr g_aud_to_host_wrptr; xc_ptr g_aud_to_host_dptr; xc_ptr g_aud_to_host_rdptr; xc_ptr g_aud_to_host_zeros; int sampsToWrite = 0; int totalSampsToWrite = 0; int aud_data_remaining_to_device = 0; /* Over/under flow flags */ unsigned outUnderflow = 1; unsigned outOverflow = 0; unsigned inUnderflow = 1; unsigned inOverflow = 0; int aud_req_in_count = 0; int aud_req_out_count = 0; unsigned unpackState = 0; unsigned unpackData = 0; unsigned packState = 0; unsigned packData = 0; #pragma select handler #pragma unsafe arrays void handle_audio_request(chanend c_mix_out, chanend ?c_led) { int outSamps; int space_left; int usb_speed; asm("ldw %0, dp[g_curUsbSpeed]" : "=r" (usb_speed) :); (void) inuint(c_mix_out); outuint(c_mix_out, 0); /* If in overflow condition, throw samples away */ if(inOverflow || sampsToWrite == 0) { #pragma loop unroll for(int i = 0; i < NUM_USB_CHAN_IN; i++) { (void) inuint(c_mix_out); } /* Calculate how much space left in buffer */ space_left = g_aud_to_host_rdptr - g_aud_to_host_wrptr; if (space_left <= 0) space_left += BUFF_SIZE_IN*4; if (space_left > (BUFF_SIZE_IN*4/2)) { inOverflow = 0; } } else { /* Not in overflow, store samples from mixer into sample buffer */ if (usb_speed == XUD_SPEED_HS) { unsigned ptr = g_aud_to_host_dptr; for(int i = 0; i < g_numUsbChanIn; i++) { int sample = inuint(c_mix_out); #if !defined(IN_VOLUME_IN_MIXER) int mult; int h; unsigned l; asm("ldw %0, %1[%2]":"=r"(mult):"r"(multIn),"r"(i)); {h, l} = macs(mult, sample, 0, 0); sample = h << 3; #elif defined(IN_VOLUME_IN_MIXER) && defined(IN_VOLUME_AFTER_MIX) sample = sample << 3; #endif write_via_xc_ptr(ptr, sample); ptr+=4; } g_aud_to_host_dptr = ptr; } else { for(int i = 0; i < g_numUsbChanIn; i++) { int sample = inuint(c_mix_out); #ifndef IN_VOLUME_IN_MIXER int mult; int h; unsigned l; asm("ldw %0, %1[%2]":"=r"(mult):"r"(multIn),"r"(i)); {h, l} = macs(mult, sample, 0, 0); sample = h << 3; #endif switch (packState&0x3) { case 0: packData = sample; break; case 1: packData = packData >> 8 | ((sample & 0xff00)<<16); write_via_xc_ptr(g_aud_to_host_dptr, packData); g_aud_to_host_dptr+=4; write_via_xc_ptr(g_aud_to_host_dptr, sample>>16); packData = sample; break; case 2: packData = (packData>>16) | ((sample & 0xffff00) << 8); write_via_xc_ptr(g_aud_to_host_dptr, packData); g_aud_to_host_dptr+=4; packData = sample; break; case 3: packData = (packData >> 24) | (sample & 0xffffff00); write_via_xc_ptr(g_aud_to_host_dptr, packData); g_aud_to_host_dptr+=4; break; } packState++; } } /* Input any remaining channels */ for(int i = 0; i < NUM_USB_CHAN_IN - g_numUsbChanIn; i++) { inuint(c_mix_out); } sampsToWrite--; } if(outUnderflow) { #pragma xta endpoint "out_underflow" /* We're still pre-buffering, send out 0 samps */ for(int i = 0; i < NUM_USB_CHAN_OUT; i++) { outuint(c_mix_out, 0); } /* Calc how many samples left in buffer */ outSamps = g_aud_from_host_wrptr - g_aud_from_host_rdptr; if (outSamps < 0) { outSamps += BUFF_SIZE_OUT*4; } /* If we have a decent number of samples, come out of underflow cond */ if (outSamps >= (OUT_BUFFER_PREFILL)) { outUnderflow = 0; } } else { if (usb_speed == XUD_SPEED_HS) { /* Buffering not underflow condition send out some samples...*/ for(int i = 0; i < g_numUsbChanOut; i++) { #pragma xta endpoint "mixer_request" int sample; int mult; int h; unsigned l; read_via_xc_ptr(sample, g_aud_from_host_rdptr); g_aud_from_host_rdptr+=4; #ifndef OUT_VOLUME_IN_MIXER asm("ldw %0, %1[%2]":"=r"(mult):"r"(multOut),"r"(i)); {h, l} = macs(mult, sample, 0, 0); h <<= 3; outuint(c_mix_out, h); #else outuint(c_mix_out, sample); #endif } } else { /* Buffering not underflow condition send out some samples...*/ for(int i = 0; i < g_numUsbChanOut; i++) { #pragma xta endpoint "mixer_request" int sample; int mult; int h; unsigned l; switch (unpackState&0x3) { case 0: read_via_xc_ptr(unpackData, g_aud_from_host_rdptr); g_aud_from_host_rdptr+=4; sample = unpackData << 8; break; case 1: sample = (unpackData >> 16); read_via_xc_ptr(unpackData, g_aud_from_host_rdptr); g_aud_from_host_rdptr+=4; sample = sample | (unpackData << 16); break; case 2: sample = (unpackData >> 8); read_via_xc_ptr(unpackData, g_aud_from_host_rdptr); g_aud_from_host_rdptr+=4; sample = sample | (unpackData<< 24); break; case 3: sample = unpackData & 0xffffff00; break; } unpackState++; #ifndef OUT_VOLUME_IN_MIXER asm("ldw %0, %1[%2]":"=r"(mult):"r"(multOut),"r"(i)); {h, l} = macs(mult, sample, 0, 0); h <<= 3; outuint(c_mix_out, h); #else outuint(c_mix_out, sample); #endif } } /* Output remaining channels. Past this point we always operate on MAX chan count */ for(int i = 0; i < NUM_USB_CHAN_OUT - g_numUsbChanOut; i++) { outuint(c_mix_out, 0); } if(usb_speed == XUD_SPEED_HS) { /* 4 bytes per sample */ aud_data_remaining_to_device -= (g_numUsbChanOut*4); } else { /* 3 bytes per sample */ aud_data_remaining_to_device -= (g_numUsbChanOut*3); } } if (!inOverflow) { if (sampsToWrite == 0) { int speed; if (totalSampsToWrite) { if (usb_speed == XUD_SPEED_HS) { g_aud_to_host_wrptr += 4+totalSampsToWrite*4*g_numUsbChanIn; } else { unsigned int datasize = totalSampsToWrite*3*g_numUsbChanIn; datasize = (datasize+3) & (~0x3); // round up to nearest word g_aud_to_host_wrptr += 4+datasize; } if (g_aud_to_host_wrptr >= aud_to_host_fifo_end) { g_aud_to_host_wrptr = aud_to_host_fifo_start; } } /* Get feedback val */ /* TODO, this should be syncronised ideally */ asm("ldw %0, dp[g_speed]" : "=r" (speed) :); /* Calc packet size to send back based on our fb */ speedRem += speed; totalSampsToWrite = speedRem >> 16; speedRem &= 0xffff; if (usb_speed == XUD_SPEED_HS) { if (totalSampsToWrite < 0 || totalSampsToWrite*4*g_numUsbChanIn > (MAX_DEVICE_AUD_PACKET_SIZE_CLASS_TWO)) { totalSampsToWrite = 0; } } else { if (totalSampsToWrite < 0 || totalSampsToWrite*3*g_numUsbChanIn > (MAX_DEVICE_AUD_PACKET_SIZE_CLASS_ONE)) { totalSampsToWrite = 0; } } /* Calc slots left in fifo */ space_left = g_aud_to_host_rdptr - g_aud_to_host_wrptr; /* mod and special case */ if (space_left <= 0 && g_aud_to_host_rdptr == aud_to_host_fifo_start) { space_left = aud_to_host_fifo_end - g_aud_to_host_wrptr; } if ((space_left <= 0) || (space_left > totalSampsToWrite*g_numUsbChanIn*4+4)) { // packet ok if (totalSampsToWrite) { if (usb_speed == XUD_SPEED_HS) { write_via_xc_ptr(g_aud_to_host_wrptr, totalSampsToWrite*4*g_numUsbChanIn); } else { write_via_xc_ptr(g_aud_to_host_wrptr, totalSampsToWrite*3*g_numUsbChanIn); packState = 0; } g_aud_to_host_dptr = g_aud_to_host_wrptr + 4; } } else { inOverflow = 1; totalSampsToWrite = 0; } sampsToWrite = totalSampsToWrite; } } if (!outUnderflow && (aud_data_remaining_to_device<3)) { /* Wrap read pointer */ if (g_aud_from_host_rdptr >= aud_from_host_fifo_end) g_aud_from_host_rdptr = aud_from_host_fifo_start; outUnderflow = (g_aud_from_host_rdptr == g_aud_from_host_wrptr); if (!outUnderflow) { read_via_xc_ptr(aud_data_remaining_to_device, g_aud_from_host_rdptr); //ecallf(aud_data_remaining_to_device <= 432); unpackState = 0; //aud_data_remaining_to_device >>= 2; /* if (aud_data_remaining_to_device % g_numUsbChanOut != 0) { asm("ecallf %0"::"r"(0)); }*/ g_aud_from_host_rdptr+=4; } #ifdef DEBUG_LEDS else { led(c_led); } #endif } } unsigned g_intFlag = 0; extern unsigned char g_intData[8]; void check_for_interrupt(chanend ?c_clk_int) { unsigned tmp; select { /* Clocking thread wants to produce an interrupt... */ case inuint_byref(c_clk_int, tmp): chkct(c_clk_int, XS1_CT_END); /* Check if we have interrupt pending */ /* TODO This means we can loose interrupts */ if(!g_intFlag) { int x; g_intFlag = 1; g_intData[5] = tmp; /* Make request to send to XUD endpoint - response handled in usb_buffer */ //XUD_SetReady(int_usb_ep, 0); asm("ldaw %0, dp[g_intData]":"=r"(x)); XUD_SetReady_In(int_usb_ep, 0,x,6); } break; default: break; } } #pragma unsafe arrays void decouple(chanend c_mix_out, chanend ?c_midi, chanend ?c_clk_int) { unsigned sampFreq = DEFAULT_FREQ; int aud_from_host_flag=0; int aud_to_host_flag=0; xc_ptr released_buffer; #ifdef MIDI xc_ptr midi_from_host_rdptr = midi_from_host_fifo_start; xc_ptr midi_from_host_buffer = array_to_xc_ptr(g_midi_from_host_buffer); xc_ptr midi_to_host_buffer = array_to_xc_ptr(g_midi_to_host_buffer); int is_ack; unsigned int datum; int midi_data_remaining_to_device = 0; int midi_to_host_flag = 0; int midi_from_host_flag = 0; #endif int t = array_to_xc_ptr(outAudioBuff); aud_from_host_fifo_start = t; aud_from_host_fifo_end = aud_from_host_fifo_start + BUFF_SIZE_OUT*4; g_aud_from_host_wrptr = aud_from_host_fifo_start; g_aud_from_host_rdptr = aud_from_host_fifo_start; t = array_to_xc_ptr(audioBuffIn); aud_to_host_fifo_start = t; aud_to_host_fifo_end = aud_to_host_fifo_start + BUFF_SIZE_IN*4; g_aud_to_host_wrptr = aud_to_host_fifo_start; g_aud_to_host_rdptr = aud_to_host_fifo_start; t = array_to_xc_ptr(inZeroBuff); g_aud_to_host_zeros = t; /* Init interrupt report */ g_intData[0] = 0; // Class-specific, caused by interface g_intData[1] = 1; // attribute: CUR g_intData[2] = 0; // CN/ MCN g_intData[3] = 0; // CS g_intData[4] = 0; // interface g_intData[5] = 0; // ID of entity causing interrupt - this will get modified /* Init vol mult tables */ #ifndef OUT_VOLUME_IN_MIXER for (int i = 0; i < NUM_USB_CHAN_OUT + 1; i++) { asm("stw %0, %1[%2]"::"r"(MAX_VOL),"r"(multOut),"r"(i)); } #endif #ifndef IN_VOLUME_IN_MIXER for (int i = 0; i < NUM_USB_CHAN_IN + 1; i++) { asm("stw %0, %1[%2]"::"r"(MAX_VOL),"r"(mulIn),"r"(i)); } #endif { int c=0; while(!c) { asm("ldw %0, dp[buffer_aud_ctl_chan]":"=r"(c)); } } set_interrupt_handler(handle_audio_request, 200, 1, c_mix_out, 0); #ifdef MIDI asm("ldaw %0, dp[g_midi_to_host_buffer]":"=r"(midi_to_host_buffer)); asm("ldaw %0, dp[g_midi_from_host_buffer]":"=r"(midi_from_host_buffer)); // wait for usb_buffer to set up while(!midi_from_host_flag) { GET_SHARED_GLOBAL(midi_from_host_flag, g_midi_from_host_flag); } midi_from_host_flag = 0; SET_SHARED_GLOBAL(g_midi_from_host_flag, midi_from_host_flag); // send the current host -> device buffer out of the fifo XUD_SetReady(midi_from_host_usb_ep, 1); #endif #ifdef OUTPUT // wait for usb_buffer to set up while(!aud_from_host_flag) { GET_SHARED_GLOBAL(aud_from_host_flag, g_aud_from_host_flag); } aud_from_host_flag = 0; SET_SHARED_GLOBAL(g_aud_from_host_flag, aud_from_host_flag); // send the current host -> device buffer out of the fifo SET_SHARED_GLOBAL(g_aud_from_host_buffer, g_aud_from_host_wrptr); XUD_SetReady(aud_from_host_usb_ep, 1); #endif #ifdef INPUT // wait for usb_buffer to set up while(!aud_to_host_flag) { GET_SHARED_GLOBAL(aud_to_host_flag, g_aud_to_host_flag); } aud_to_host_flag = 0; SET_SHARED_GLOBAL(g_aud_to_host_flag, aud_to_host_flag); // send the current host -> device buffer out of the fifo SET_SHARED_GLOBAL(g_aud_to_host_buffer, g_aud_to_host_zeros); { xc_ptr p; int len; GET_SHARED_GLOBAL(p, g_aud_to_host_buffer); read_via_xc_ptr(len, p); XUD_SetReady_In(aud_to_host_usb_ep, PIDn_DATA0, g_aud_to_host_buffer, len); } #endif while(1) { if (!isnull(c_clk_int)) { check_for_interrupt(c_clk_int); } asm("#decouple-default"); /* Check for freq change or other update */ { int tmp; GET_SHARED_GLOBAL(tmp, g_freqChange_flag); if (tmp == SET_SAMPLE_FREQ) { SET_SHARED_GLOBAL(g_freqChange_flag, 0); GET_SHARED_GLOBAL(sampFreq, g_freqChange_sampFreq); /* Pass on to mixer */ DISABLE_INTERRUPTS(); inuint(c_mix_out); outct(c_mix_out, 9); outuint(c_mix_out, sampFreq); inOverflow = 0; inUnderflow = 1; SET_SHARED_GLOBAL(g_aud_to_host_rdptr, aud_to_host_fifo_start); SET_SHARED_GLOBAL(g_aud_to_host_wrptr, aud_to_host_fifo_start); SET_SHARED_GLOBAL(sampsToWrite, 0); SET_SHARED_GLOBAL(totalSampsToWrite, 0); SET_SHARED_GLOBAL(g_aud_to_host_buffer, g_aud_to_host_zeros); /* Wait for handshake back and pass back up */ chkct(c_mix_out, XS1_CT_END); SET_SHARED_GLOBAL(g_freqChange, 0); asm("outct res[%0],%1"::"r"(buffer_aud_ctl_chan),"r"(XS1_CT_END)); ENABLE_INTERRUPTS(); speedRem = 0; continue; } else if(tmp == SET_CHAN_COUNT_IN) { DISABLE_INTERRUPTS(); SET_SHARED_GLOBAL(g_freqChange_flag, 0); GET_SHARED_GLOBAL(g_numUsbChanIn, g_freqChange_sampFreq); /* Misuse of g_freqChange_sampFreq */ inOverflow = 0; inUnderflow = 1; SET_SHARED_GLOBAL(g_aud_to_host_rdptr, aud_to_host_fifo_start); SET_SHARED_GLOBAL(g_aud_to_host_wrptr, aud_to_host_fifo_start); SET_SHARED_GLOBAL(sampsToWrite, 0); SET_SHARED_GLOBAL(totalSampsToWrite, 0); SET_SHARED_GLOBAL(g_aud_to_host_buffer, g_aud_to_host_zeros); // g_buffSizeIn = (BUFF_MULT * g_numUsbChanIn); // inWr = 0; // Reseting wr/rd prob not required since we will underflow and reset // inRd = (g_buffSizeIn + (int) inWr - (g_numUsbChanIn * 25)) % g_buffSizeIn; // sampsToWrite = 0; SET_SHARED_GLOBAL(g_freqChange, 0); ENABLE_INTERRUPTS(); } } #ifdef OUTPUT GET_SHARED_GLOBAL(aud_from_host_flag, g_aud_from_host_flag); if (aud_from_host_flag) { // the buffer thread has filled up a buffer int datalength; int space_left; int aud_from_host_wrptr; int aud_from_host_rdptr; GET_SHARED_GLOBAL(aud_from_host_wrptr, g_aud_from_host_wrptr); GET_SHARED_GLOBAL(aud_from_host_rdptr, g_aud_from_host_rdptr); SET_SHARED_GLOBAL(g_aud_from_host_flag, 0); GET_SHARED_GLOBAL(released_buffer, g_aud_from_host_buffer); read_via_xc_ptr(datalength, released_buffer); if (datalength) { // move the write pointer of the fifo on aud_from_host_wrptr = aud_from_host_wrptr + ((datalength+3)&~0x3) + 4; if (aud_from_host_wrptr >= aud_from_host_fifo_end) aud_from_host_wrptr = aud_from_host_fifo_start; SET_SHARED_GLOBAL(g_aud_from_host_wrptr, aud_from_host_wrptr); } // if we have enough space left then send a new buffer pointer // back to the buffer thread space_left = aud_from_host_rdptr - aud_from_host_wrptr; if (space_left <= 0 || space_left >= MAX_USB_AUD_PACKET_SIZE) { SET_SHARED_GLOBAL(g_aud_from_host_buffer, aud_from_host_wrptr); XUD_SetReady(aud_from_host_usb_ep, 1); } else { outOverflow = 1; #ifdef DEBUG_LEDS led(c_led); #endif // overflow } continue; } else if (outOverflow) { int space_left; int aud_from_host_wrptr; int aud_from_host_rdptr; GET_SHARED_GLOBAL(aud_from_host_wrptr, g_aud_from_host_wrptr); GET_SHARED_GLOBAL(aud_from_host_rdptr, g_aud_from_host_rdptr); space_left = aud_from_host_rdptr - aud_from_host_wrptr; if (space_left <= 0) space_left += BUFF_SIZE_OUT*4; if (space_left >= (BUFF_SIZE_OUT*4/2)) { outOverflow = 0; SET_SHARED_GLOBAL(g_aud_from_host_buffer, aud_from_host_wrptr); XUD_SetReady(aud_from_host_usb_ep, 1); #ifdef DEBUG_LEDS led(c_led); #endif } } #endif #ifdef INPUT { int tmp; GET_SHARED_GLOBAL(tmp, g_aud_to_host_flag); //case inuint_byref(c_buf_in, tmp): if (tmp) { /* Signals that the IN endpoint has sent data from the passed buffer */ SET_SHARED_GLOBAL(g_aud_to_host_flag, 0); if (inUnderflow) { int aud_to_host_wrptr; int aud_to_host_rdptr; int fill_level; GET_SHARED_GLOBAL(aud_to_host_wrptr, g_aud_to_host_wrptr); GET_SHARED_GLOBAL(aud_to_host_rdptr, g_aud_to_host_rdptr); // check if we have come out of underflow. fill_level = aud_to_host_wrptr - aud_to_host_rdptr; if (fill_level < 0) fill_level += BUFF_SIZE_IN*4; if (fill_level >= IN_BUFFER_PREFILL) { inUnderflow = 0; SET_SHARED_GLOBAL(g_aud_to_host_buffer, aud_to_host_rdptr); } else { SET_SHARED_GLOBAL(g_aud_to_host_buffer, g_aud_to_host_zeros); } } else { int datalength; int aud_to_host_wrptr; int aud_to_host_rdptr; GET_SHARED_GLOBAL(aud_to_host_wrptr, g_aud_to_host_wrptr); GET_SHARED_GLOBAL(aud_to_host_rdptr, g_aud_to_host_rdptr); read_via_xc_ptr(datalength, aud_to_host_rdptr); aud_to_host_rdptr = aud_to_host_rdptr + ((datalength+3)&~0x3) + 4; if (aud_to_host_rdptr >= aud_to_host_fifo_end) aud_to_host_rdptr = aud_to_host_fifo_start; SET_SHARED_GLOBAL(g_aud_to_host_rdptr, aud_to_host_rdptr); if (aud_to_host_rdptr != aud_to_host_wrptr) { SET_SHARED_GLOBAL(g_aud_to_host_buffer, aud_to_host_rdptr); } else { inUnderflow = 1; SET_SHARED_GLOBAL(g_aud_to_host_buffer, g_aud_to_host_zeros); } } { int p, len; GET_SHARED_GLOBAL(p, g_aud_to_host_buffer); asm("ldw %0, %1[0]":"=r"(len):"r"(p)); XUD_SetReady_In(aud_to_host_usb_ep, PIDn_DATA0, p+4, len); } continue; } } #endif // INPUT #ifdef MIDI <<<<<<< HEAD GET_SHARED_GLOBAL(midi_to_host_flag, g_midi_to_host_flag); if (midi_to_host_flag) { // An ack from the buffer thread means that the buffer has been // sent to the host, so we can ack the midi thread SET_SHARED_GLOBAL(g_midi_to_host_flag, 0); midi_send_ack(c_midi); continue; } else { GET_SHARED_GLOBAL(midi_from_host_flag, g_midi_from_host_flag); if (midi_from_host_flag) { // the buffer thread has filled up a buffer int datalength; int space_left; SET_SHARED_GLOBAL(g_midi_from_host_flag, 0); read_via_xc_ptr(midi_data_remaining_to_device, midi_from_host_buffer); midi_from_host_rdptr = midi_from_host_buffer + 4; if (midi_remaining_to_device) { read_via_xc_ptr(datum, midi_from_host_rdptr); outuint(c_midi, datum); midi_from_host_rdptr += 4; midi_data_remaining_to_device -= 4; } } } select { case midi_get_ack_or_data(c_midi, is_ack, datum): if (is_ack) { // an ack from the midi/uart thread means it has accepted // some data we sent it if (midi_data_remaining_to_device == 0) { // we have read an entire packet XUD_SetReady(midi_from_host_usb_ep, 1); } else { read_via_xc_ptr(datum, midi_from_host_rdptr); outuint(c_midi, datum); midi_data_remaining_to_device -= 4; } } else { // set up a single event packet write_via_xc_ptr(midi_to_host_buffer, datum); XUD_SetReady_In(midi_to_host_usb_ep, 0, midi_to_host_buffer, 4); } break; default: break; } } ======= GET_SHARED_GLOBAL(midi_to_host_flag, g_midi_to_host_flag); if (midi_to_host_flag) { // An ack from the buffer thread means that the buffer has been // sent to the host SET_SHARED_GLOBAL(g_midi_to_host_flag, 0); if (midi_data_collected_from_device != 0) { // printstr("agg"); // we have some more data to send // printstr("decouple->buffer: "); // printintln(midi_data_collected_from_device); // set the amount of data to send write_via_xc_ptr(midi_to_host_buffer_being_collected, midi_data_collected_from_device); // swap the collecting and sending buffer swap(midi_to_host_buffer_being_collected, midi_to_host_buffer_being_sent); #if 1 { int len; asm("ldw %0, %1[0]":"=r"(len):"r"(midi_to_host_buffer_being_sent)); XUD_SetReady_In(midi_to_host_usb_ep, 0, midi_to_host_buffer_being_sent+4, len); } #else // signal other side to swap XUD_SetReady(midi_to_host_usb_ep, 0); #endif // midi_send_ack(c_midi_buf); midi_waiting_on_send_to_host = 1; // reset the collected data count midi_data_collected_from_device = 0; } else { midi_waiting_on_send_to_host = 0; } continue; } else { GET_SHARED_GLOBAL(midi_from_host_flag, g_midi_from_host_flag); if (midi_from_host_flag) { // the buffer thread has filled up a buffer int datalength; int space_left; SET_SHARED_GLOBAL(g_midi_from_host_flag, 0); GET_SHARED_GLOBAL(released_buffer, g_midi_from_host_buffer); read_via_xc_ptr(datalength, released_buffer); if (datalength) { // move the write pointer of the fifo on midi_from_host_wrptr = midi_from_host_wrptr + datalength + 4; if (midi_from_host_wrptr >= midi_from_host_fifo_end) midi_from_host_wrptr = midi_from_host_fifo_start; } // if we have enough space left then send a new buffer pointer // back to the buffer thread space_left = midi_from_host_rdptr - midi_from_host_wrptr; if (space_left < 0 || space_left >= MAX_USB_MIDI_PACKET_SIZE) { SET_SHARED_GLOBAL(g_midi_from_host_buffer, midi_from_host_wrptr); XUD_SetReady(midi_from_host_usb_ep, 1); } else { // overflow midi_from_device_overflow = 1; // SET_SHARED_GLOBAL(g_midi_from_host_buffer, // null_midi_from_host_buffer); // asm("out res[%1], %0"::"r"(1),"r"(midi_from_host_usb_chan)); //printstrln("decouple h->d overflow"); } if (datalength) { // if weare not currently sending data to the midi-uart thread // intiate sending it some if (midi_data_remaining_to_device == 0) { read_via_xc_ptr(midi_data_remaining_to_device, midi_from_host_rdptr); midi_from_host_rdptr += 4; read_via_xc_ptr(datum, midi_from_host_rdptr); outuint(c_midi, datum); } } continue; } } {int cont = 0; select { case midi_get_ack_or_data(c_midi, is_ack, datum): if (is_ack) { // An ack from the midi/uart thread means it has accepted some data we // sent it // update the read pointer of the fifo midi_from_host_rdptr += 4; midi_data_remaining_to_device -= 4; if (midi_data_remaining_to_device == 0) { // We have read an entire packet if (midi_from_host_rdptr >= midi_from_host_fifo_end) midi_from_host_rdptr = midi_from_host_fifo_start; if (midi_from_host_rdptr != midi_from_host_wrptr) { // There is another packet to send read_via_xc_ptr(midi_data_remaining_to_device, midi_from_host_rdptr); midi_from_host_rdptr += 4; } } if (midi_from_device_overflow) { int space_left = midi_from_host_rdptr - midi_from_host_wrptr; if (space_left < 0 || space_left >= MAX_USB_MIDI_PACKET_SIZE) { midi_from_device_overflow = 0; SET_SHARED_GLOBAL(g_midi_from_host_buffer, midi_from_host_wrptr); XUD_SetReady(midi_from_host_usb_ep, 1); } } if (midi_data_remaining_to_device) { /* There is more data to send to the midi/uart thread */ read_via_xc_ptr(datum, midi_from_host_rdptr); outuint(c_midi, datum); } } else /* if(is_ack) */ { // the midi/uart thread has sent us some data midi_send_ack(c_midi); if (midi_data_collected_from_device < MIDI_USB_BUFFER_TO_HOST_SIZE) { // there is room in the collecting buffer for the data xc_ptr p = (midi_to_host_buffer_being_collected + 4) + midi_data_collected_from_device; // add data to the buffer write_via_xc_ptr(p, datum); midi_data_collected_from_device += 4; } else { //printstrln("decouple d->h overflow"); // too many events from device - drop it } // if we are not sending data to the host then initiate it if (!midi_waiting_on_send_to_host) { // printstr("decouple->buffer: "); // printintln(midi_data_collected_from_device); write_via_xc_ptr(midi_to_host_buffer_being_collected, midi_data_collected_from_device); midi_data_collected_from_device = 0; swap(midi_to_host_buffer_being_collected, midi_to_host_buffer_being_sent); // signal other side to swap { int len; asm("ldw %0, %1[0]":"=r"(len):"r"(midi_to_host_buffer_being_sent)); XUD_SetReady_In(midi_to_host_usb_ep, 0, midi_to_host_buffer_being_sent+4, len); } // midi_send_ack(c_midi_buf); midi_waiting_on_send_to_host = 1; } } cont = 1; break; default: break; } if (cont) continue; } >>>>>>> master #endif // MIDI } }